From 9701da35558b9b5cea06b43315d813c287d88649 Mon Sep 17 00:00:00 2001 From: Ivan_Kustau <Ivan_Kustau@epam.com> Date: Wed, 6 Sep 2023 11:53:10 +0300 Subject: [PATCH 01/25] Add caffeine cache manager --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3dc5ddc9e5..b157bd1b9b 100644 --- a/build.gradle +++ b/build.gradle @@ -84,7 +84,7 @@ dependencies { compile 'com.epam.reportportal:plugin-api' } else { compile 'com.github.reportportal:commons-events:e337f8b7be' - compile 'com.github.reportportal:commons-dao:b2db29b' + compile 'com.github.reportportal:commons-dao:34829fb198' compile 'com.github.reportportal:commons-rules:5.10.0' compile 'com.github.reportportal:commons-model:e0a12669' compile 'com.github.reportportal:commons:ce2166b' From 7024166a5c8a2e67af4df2b3a2054a656e66bfa6 Mon Sep 17 00:00:00 2001 From: hlebkanonik <hleb_kanonik@epam.com> Date: Wed, 6 Sep 2023 12:07:26 +0200 Subject: [PATCH 02/25] added github.run_number to rc build (cherry picked from commit 52ca2ef7089f465f6ce84be2afaec43a300f7478) --- .github/workflows/rc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rc.yaml b/.github/workflows/rc.yaml index 6dfb1317cd..a16303a460 100644 --- a/.github/workflows/rc.yaml +++ b/.github/workflows/rc.yaml @@ -38,7 +38,7 @@ jobs: - name: Create variables id: vars run: | - echo "tag=$(echo ${{ github.ref_name }} | tr '/' '-')" >> $GITHUB_OUTPUT + echo "tag=$(echo ${{ github.ref_name }}-${{ github.run_number }} | tr '/' '-')" >> $GITHUB_OUTPUT echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT echo "version=$(echo '${{ github.ref_name }}' | sed -nE 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p')" >> $GITHUB_OUTPUT From 3dcf60a6aa4a28cfdc4c81ceee2a32d9a4eaf41d Mon Sep 17 00:00:00 2001 From: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:19:59 +0300 Subject: [PATCH 03/25] EPMRPP-86400 || Fix the problem with 'undefined' for exported filename (#1794) --- .../epam/ta/reportportal/ws/controller/LaunchController.java | 2 +- .../epam/ta/reportportal/ws/controller/ProjectController.java | 2 +- .../com/epam/ta/reportportal/ws/controller/UserController.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java index 705bdfbd2d..5949add2c2 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java @@ -351,7 +351,7 @@ public void getLaunchReport(@PathVariable String projectName, @PathVariable Long response.setContentType(format.getContentType()); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, - String.format("attachment; filename=RP_LAUNCH_%s_Report.%s", format.name(), format.getValue()) + String.format("attachment; filename=\"RP_LAUNCH_%s_Report.%s\"", format.name(), format.getValue()) ); try (OutputStream outputStream = response.getOutputStream()) { diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java index ff8614e7b8..ee505599a1 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java @@ -343,7 +343,7 @@ public void exportProjects( response.setContentType(format.getContentType()); response.setHeader(CONTENT_DISPOSITION, - String.format("attachment; filename=RP_PROJECTS_%s_Report.%s", format.name(), + String.format("attachment; filename=\"RP_PROJECTS_%s_Report.%s\"", format.name(), format.getValue()) ); diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java index c4071d8838..4252f9033d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java @@ -282,7 +282,7 @@ public void export(@ApiParam(allowableValues = "csv") response.setContentType(format.getContentType()); response.setHeader(com.google.common.net.HttpHeaders.CONTENT_DISPOSITION, - String.format("attachment; filename=RP_USERS_%s_Report.%s", format.name(), + String.format("attachment; filename=\"RP_USERS_%s_Report.%s\"", format.name(), format.getValue() ) ); From 30612d724b501aa332c6ae78769b975df9709964 Mon Sep 17 00:00:00 2001 From: Hleb Kanonik <hleb_kanonik@epam.com> Date: Fri, 29 Sep 2023 10:21:02 +0200 Subject: [PATCH 04/25] tag latest added --- .github/workflows/rc.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rc.yaml b/.github/workflows/rc.yaml index a16303a460..ac8ae32983 100644 --- a/.github/workflows/rc.yaml +++ b/.github/workflows/rc.yaml @@ -65,7 +65,9 @@ jobs: GITHUB_TOKEN=${{ secrets.GH_TOKEN }} RELEASE_MODE=${{ env.RELEASE_MODE }} platforms: ${{ env.PLATFORMS }} - tags: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} + tags: Ё + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} + ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest - name: Summarize env: @@ -75,4 +77,4 @@ jobs: echo "## General information about the build:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "- :gift: Docker image in Amazon ECR: ecr/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_STEP_SUMMARY - echo "- :octocat: The commit SHA from which the build was performed: [$GITHUB_SHA](https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY \ No newline at end of file + echo "- :octocat: The commit SHA from which the build was performed: [$GITHUB_SHA](https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY From 5f92284efa63ba0ce8cd3114951cd23d1e4f3012 Mon Sep 17 00:00:00 2001 From: Hleb Kanonik <hleb_kanonik@epam.com> Date: Fri, 29 Sep 2023 10:22:35 +0200 Subject: [PATCH 05/25] Update rc.yaml --- .github/workflows/rc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rc.yaml b/.github/workflows/rc.yaml index ac8ae32983..98d9ca8724 100644 --- a/.github/workflows/rc.yaml +++ b/.github/workflows/rc.yaml @@ -65,7 +65,7 @@ jobs: GITHUB_TOKEN=${{ secrets.GH_TOKEN }} RELEASE_MODE=${{ env.RELEASE_MODE }} platforms: ${{ env.PLATFORMS }} - tags: Ё + tags: | ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest From f056315e6c9febeb90b5bc105cc694653b4b4867 Mon Sep 17 00:00:00 2001 From: Hleb Kanonik <hleb_kanonik@epam.com> Date: Mon, 2 Oct 2023 13:09:52 +0200 Subject: [PATCH 06/25] Create dockerhub-release.yaml --- .github/workflows/dockerhub-release.yaml | 69 ++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/dockerhub-release.yaml diff --git a/.github/workflows/dockerhub-release.yaml b/.github/workflows/dockerhub-release.yaml new file mode 100644 index 0000000000..127df9b298 --- /dev/null +++ b/.github/workflows/dockerhub-release.yaml @@ -0,0 +1,69 @@ +name: Retag RC Docker image + +on: + pull_request_review: + types: [submitted] + +env: + AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 + ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name + PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 + RELEASE_MODE: ${{ vars.RELEASE_MODE }} + +jobs: + retag-image: + name: Retag and push image + runs-on: ubuntu-latest + environment: rc + if: github.base_ref == 'master' || github.base_ref == 'main' + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + # role-to-assume: arn:aws:iam::123456789012:role/my-github-actions-role + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + with: + mask-password: 'true' + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: Create variables + id: vars + run: | + echo "tag=$(echo '${{ github.event.pull_request.title }}' | sed -nE 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p')" >> $GITHUB_OUTPUT + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Retag and Push Docker Image + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + IMAGE_TAG: ${{ steps.vars.outputs.tag }} + run: | + docker buildx imagetools create $ECR_REGISTRY/$ECR_REPOSITORY:latest --tag $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:$IMAGE_TAG --tag $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:latest + + - name: Summarize + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + IMAGE_TAG: ${{ steps.vars.outputs.tag }} + run: | + echo "## General information about the build:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- :whale: Docker image: $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:$IMAGE_TAG" >> $GITHUB_STEP_SUMMARY + echo "- :octocat: The commit SHA from which the build was performed: [$GITHUB_SHA](https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY From e25059f54be4aa6557cc676d8a06025ffe6fb528 Mon Sep 17 00:00:00 2001 From: hlebkanonik <hleb_kanonik@epam.com> Date: Mon, 2 Oct 2023 13:44:01 +0200 Subject: [PATCH 07/25] github.event.pull_request.base.ref --- .github/workflows/dockerhub-release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dockerhub-release.yaml b/.github/workflows/dockerhub-release.yaml index 127df9b298..827768c052 100644 --- a/.github/workflows/dockerhub-release.yaml +++ b/.github/workflows/dockerhub-release.yaml @@ -15,7 +15,7 @@ jobs: name: Retag and push image runs-on: ubuntu-latest environment: rc - if: github.base_ref == 'master' || github.base_ref == 'main' + if: github.event.pull_request.base.ref == 'master' || github.event.pull_request.base.ref == 'main' steps: - name: Checkout uses: actions/checkout@v3 From f88d8abae9a58fe11ca761aa7dffe875a32203b5 Mon Sep 17 00:00:00 2001 From: hlebkanonik <hleb_kanonik@epam.com> Date: Mon, 2 Oct 2023 14:21:45 +0200 Subject: [PATCH 08/25] rewrite target regestry envs --- .github/workflows/dockerhub-release.yaml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dockerhub-release.yaml b/.github/workflows/dockerhub-release.yaml index 827768c052..bebe70f7fa 100644 --- a/.github/workflows/dockerhub-release.yaml +++ b/.github/workflows/dockerhub-release.yaml @@ -5,9 +5,11 @@ on: types: [submitted] env: - AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 - ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name - PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 + AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 + ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name + TARGET_REGISTRY: ${{ vars.TARGET_REGISTRY }} # set to target regestry (DockerHub, GitHub & etc) + TARGET_REPOSITORY: ${{ vars.TARGET_REPOSITORY }} # set to target repository + PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 RELEASE_MODE: ${{ vars.RELEASE_MODE }} jobs: @@ -37,8 +39,8 @@ jobs: - name: Log in to Docker Hub uses: docker/login-action@v3 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_PASSWORD }} + username: ${{ secrets.REGESTRY_USERNAME }} + password: ${{ secrets.REGESTRY_PASSWORD }} - name: Create variables id: vars @@ -56,7 +58,7 @@ jobs: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ steps.vars.outputs.tag }} run: | - docker buildx imagetools create $ECR_REGISTRY/$ECR_REPOSITORY:latest --tag $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:$IMAGE_TAG --tag $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:latest + docker buildx imagetools create $ECR_REGISTRY/$ECR_REPOSITORY:latest --tag $TARGET_REGISTRY/$TARGET_REPOSITORY:$IMAGE_TAG --tag $TARGET_REGISTRY/$TARGET_REPOSITORY:latest - name: Summarize env: @@ -65,5 +67,5 @@ jobs: run: | echo "## General information about the build:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "- :whale: Docker image: $DOCKERHUB_REGISTRY/$DOCKERHUB_REPOSITORY:$IMAGE_TAG" >> $GITHUB_STEP_SUMMARY + echo "- :whale: Docker image: $TARGET_REGISTRY/$TARGET_REPOSITORY:$IMAGE_TAG" >> $GITHUB_STEP_SUMMARY echo "- :octocat: The commit SHA from which the build was performed: [$GITHUB_SHA](https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY From 13d6e1697792b620def74b45da35160d4525836c Mon Sep 17 00:00:00 2001 From: hlebkanonik <hleb_kanonik@epam.com> Date: Mon, 2 Oct 2023 14:22:50 +0200 Subject: [PATCH 09/25] modified: .github/workflows/dockerhub-release.yaml --- .github/workflows/dockerhub-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dockerhub-release.yaml b/.github/workflows/dockerhub-release.yaml index bebe70f7fa..f874986a45 100644 --- a/.github/workflows/dockerhub-release.yaml +++ b/.github/workflows/dockerhub-release.yaml @@ -5,11 +5,11 @@ on: types: [submitted] env: - AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 - ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name + AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 + ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name TARGET_REGISTRY: ${{ vars.TARGET_REGISTRY }} # set to target regestry (DockerHub, GitHub & etc) TARGET_REPOSITORY: ${{ vars.TARGET_REPOSITORY }} # set to target repository - PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 + PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 RELEASE_MODE: ${{ vars.RELEASE_MODE }} jobs: From 90137488c93f2a2e0a67d4c3c8acd20d95ee1bc4 Mon Sep 17 00:00:00 2001 From: Ivan_Kustau <Ivan_Kustau@epam.com> Date: Mon, 2 Oct 2023 15:51:38 +0300 Subject: [PATCH 10/25] Update to release version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d0a545f507..1dec792439 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=develop +version=5.10.0 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom From ef9d00bcd372fc69c0c55c165bc5a5d73f68e2a9 Mon Sep 17 00:00:00 2001 From: "reportportal.io" <support@reportportal.io> Date: Mon, 2 Oct 2023 13:07:39 +0000 Subject: [PATCH 11/25] [Gradle Release Plugin] - new version commit: '5.10.1'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1dec792439..a58c7cedca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.10.0 +version=5.10.1 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom From f0e8cbb36956f89e53f5484b0a4668ca656c9ca1 Mon Sep 17 00:00:00 2001 From: APiankouski <109206864+APiankouski@users.noreply.github.com> Date: Wed, 25 Oct 2023 11:03:28 +0300 Subject: [PATCH 12/25] Hotfix 5.10.1 (#1837) * EPMRPP-87223 || Fix duplicated logs --- .github/workflows/release.yml | 2 +- .../ws/rabbit/AsyncReportingListener.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d6d1335791..11f7c0cd29 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: env: GH_USER_NAME: github.actor - RELEASE_VERSION: 5.10.0 + RELEASE_VERSION: 5.10.1 REPOSITORY_URL: 'https://maven.pkg.github.com/' jobs: diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java index bccbac8713..574610eeef 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java @@ -296,14 +296,16 @@ private void createItemLog(SaveLogRQ request, TestItem item, BinaryDataMetaInfo Launch effectiveLaunch = testItemService.getEffectiveLaunch(item); logService.saveLogMessageToElasticSearch(log, effectiveLaunch.getId()); - saveAttachment(request.getFile().getName(), metaInfo, - log.getId(), - projectId, - effectiveLaunch.getId(), - item.getItemId(), - effectiveLaunch.getUuid(), - log.getUuid() - ); + if (Objects.nonNull(request.getFile())) { + saveAttachment(request.getFile().getName(), metaInfo, + log.getId(), + projectId, + effectiveLaunch.getId(), + item.getItemId(), + effectiveLaunch.getUuid(), + log.getUuid() + ); + } } private void createLaunchLog(SaveLogRQ request, Launch launch, BinaryDataMetaInfo metaInfo, From afb083d7738f4af8371fa697fa25cf01529985bf Mon Sep 17 00:00:00 2001 From: "reportportal.io" <support@reportportal.io> Date: Wed, 25 Oct 2023 08:09:43 +0000 Subject: [PATCH 13/25] [Gradle Release Plugin] - new version commit: '5.10.2'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index a58c7cedca..e415066637 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.10.1 +version=5.10.2 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom From 3c970cea6a75435e319692f5b992701ab0374740 Mon Sep 17 00:00:00 2001 From: PeeAyBee <pavel_bortnik@epam.com> Date: Fri, 1 Mar 2024 11:07:03 +0300 Subject: [PATCH 14/25] Release 5.11.0 (#1899) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * EPMRPP-77647 || switched to develop * EPMRPP-77647 || changed commons version * EPMRPP-77648 || implement POST endpoint * EPMRPP-77648 || copyrights fix * EPMRPP-77779 || Launch and test item description limits * EPMRPP-76804 || Add recalculation on items deletion * EPMRPP-76804 || Fix unit tests * EPMRPP-77779 || updated commons-dao version * EPMRPP-77779 || updated limit on service api * EPMRPP-77811 || Implement validation for POST endpoint * Newjenkins (#1587) * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile * Update Jenkinsfile Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> * EPMRPP-77779 || limited length to 2048 * EPMRPP-77779 || updated commons-model hash * EPMRPP-77779 || id field for SenderCaseDTO * EPMRPP-77779 || updated commons-model hash * EPMRPP-77777 || implement PUT request * EPMRPP-77623 || Clustering last run attribute removing * EPMRPP-77778 || implement DELETE endpoint * RC pipeline modified * description changed * tagging by gradlew updated * String parameter BRANCH added * Update Jenkinsfile-candidate * spaces * EPMRPP-77972 || Fix retries and nesteds counting * EPMRPP-77972 || Update dao version * EPMRPP-77972 || Update dao version * EPMRPP-77973 || Potential fix for perf issue * EPMRPP-77973 || Update batch size as env variable * EPMRPP-77973 || Fix launch logs counting * EPMRPP-78088 || List equality validation fix * EPMRPP-78107 || Dao with updated mapping provided * EPMRPP-77973 || Fix partition handling * EPMRPP-78071 || Dao with updated query provided * EPMRPP-77922 || Performance fix * EPMRPP-77922 || Performance fix * EPMRPP-64803 || Make async remove test items from index (#1604) Co-authored-by: Andrei Piankouski <andrei.piankouski@ukg.com> * EPMRPP-64803 || Make async remove test items from index (#1605) Co-authored-by: Andrei Piankouski <andrei.piankouski@ukg.com> * EPMRPP-78587 || Fix attribute grouping * Update README.md * Update README.md * EPMRPP-78284: Move all notification endpoints to ProjectSettingsController and add tests * EPMRPP-77947 || Move all notification endpoints to ProjectSettingsController and add tests * promote.yml update * Remove hardcoded publishing URL * Remove Sealights * Update promote.yml * EPMRPP-78764 || Changed number of allowed custom defect types * Epmrpp 75612 deletion from es (#1615) * EPMRPP-75612 || Deletion logs from ES * EPMRPP-79208 || Launch export. Empty file is exported if there is item with 'in progress' status in the launch (#1616) Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-79167 || Updated commons dao version (#1620) * EPMRPP-79329 || Update autocomplete in Notification. start from 1 symbol (#1622) * EPMRPP-79329 || Update autocomplete in Notification. start from 1 symbol * EPMRPP-79329 || Fix test Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-78998 || Flaky test cases widget. Increase the amount of items to be displayed on widget from 20 to 50 * EPMRPP-80255 || Save the Dashboards and widgets of deleted user * EPMRPP-79630 || Update Passing rate per Launch widget * Delete .travis.yml We don't use it anymore * EPMRPP-80176 || Update Passing rate summary widget * EPMRPP-78657 || Notification of an inexistent launch in Edit/Duplicate * Update release.yml * EMPRPP-80865 || Update commons-dao dependency (#1676) * EPMRPP-80865 || Merge master to develop (#1680) * EPMRPP-79211 || Changed Minio interface to JCloud * EPMRPP-79211 || Updated DataStore configuration and properties * EPMRPP-79211 || Updated docker-compose with right BinaryStore value * EPMRPP-79211 || Update commons dao version * Update commons dao dependency to 5.7.4 * EPMRPP-80865|| Update bom and other versions (#1663) 5.7.4 || Update bom and other versions * [Gradle Release Plugin] - new version commit: '5.7.5'. --------- Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> * EPMRPP-80809 marked API getLogByUuid as Deprecated (#1686) * EPMRPP-73535 || Added getting logMessage from ES + merging with PG * Add removeScripts task to Cleanup stage in Jenkins (#1689) * EPMRPP-76400 || Patternt analyze working with ES * EPMRPP-82405 || Fix es deleting bug * EPMRPP-82327 || Formatting code according to code style (#1688) * EPMRPP-82327-google-style google-style applied * EPMRPP-82327-google-style formatted new changes * EPMRPP-82327-google-style fixed import in test * EPMRPP-82614 || Fix pattern analysis for nested steps (#1693) * EPMRPP-82614 || Fix pattern analysis for nested steps * EPMRPP-82614 || Refactor ElasticLogService * Epmrpp-84251 || merge to develop (#1710) * Update spring boot version to fix CVE-2022-22965 * EPMRPP-76845 || Update spring boot * Update Jenkinsfile * EPMRPP-77678 || Description length increased to 2048 * EPMRPP-77678 || Redundant import fix * EPMRPP-79737 || Fix vulnerabilities and update libraries version (#1624) * EPMRPP-79136 || Add retrieving all logs with it's locations (#1619) * EPMRPP-79136 || Add retrieving all logs with it's locations * EPMRPP-79136 || Add filtering by log level and item type * EPMRPP-79136 || Change response to save correct ordering * EPMRPP-79136 || Fix exclude passed logs parameter * EPMRPP-79136 || Override page size limit * EPMRPP-79136 || Fix retrieving with passed logs exclusion * Update Jenkinsfile-candidate * EPMRPP-79136 || Update dao version * EPMRPP-80383 || Notifications. AND/OR attribute option * EPMRPP-80744 || Change email on the API page * EPMRPP-80601 || Timeline widget. Remove empty content * EPMRPP-80744 || Add item attribute max length validation (#1640) EPMRPP-80744 || Add item attribute max length validation * EPMRPP-81136 || Incorrect 'startTime' value is reported for tests via 'Import' functionality Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-81046 || Impossible to report test items to project with "demo" name * EPMRPP-81019 || Launch import. Error 'org.hibernate.exception.DataException: could not execute statement' occurs on importing launch (#1645) * EPMRPP-81052 || Most failed test-cases table (TOP-20). Increase the amount of items to be displayed on widget from 20 to 50 or 100 * EPMRPP-80606 || Cut notification attribute to max length (#1650) EPMRPP-80606 || Cut attributes to max length * EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit (#1651) * Revert "EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit (#1651)" This reverts commit 13a49a644635f76b9b38dcb7ea41f7601d1fab04. * EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit * EPMRPP-80606 || Update filter attribute cut logic (#1652) * EPMRPP-78741 || Remove duplicate onboarding endpoint (#1653) * EPMRPP-80606 || UserFilter cut attribute refactor (#1655) * EPMRPP-81358 || Fix vulnerabilities * EPMRPP-81193 || Wrong error code and message when creating notification rule without mandatory field * EPMRPP-81202 || Widget 'Flaky test cases table (TOP-50). It is possible to create widget with invalid 'Launches count' value via API (#1670) * EPMRPP-81202 || Widget 'Flaky test cases table (TOP-50). It is possible to create widget with invalid 'Launches count' value via API * EPMRPP-81202 || Change migration brunch * EPMRPP-81202 || Replace tab to spaces --------- Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-82300 || Typo in the error message when creating 'Flaky test cases table (TOP-50)' widget with some invalid values via API (#1674) * EPMRPP-82300-fix-typo-error uploaded commons-model dependency and fixed tests in service-api * EPMRPP-82300-fix-typo-error fixed tests in service-api * Epmrpp 78258 move acl (#1667) * EPMRPP-81233 || Move ACL tasks from RP-23.3 to RP-23.1 * EPMRPP-72320 || Fix unit tests * EPMRPP-81233 || Move ACL tasks from RP-23.3 to RP-23.1 * EPMRPP-81233 || Update bom --------- Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-81050 || Most Failed test-cases table widget. Increase the amount of items to be displayed on widget from 20 to 50 * EPMRPP-82116 || Update Notification template after launch finish (#1673) * EPMRPP-82116 Updated template for Notifications after launch finish * EPMRPP-82116 edited invitation templates * Update common model * EPMRPP-81362 || Fix security vulnerabilities (#1671) * EPMRPP-82116 || Update Notification template after launch finish (removed attachments) (#1678) * EPMRPP-82116-remove-attachments removed vk and fb attachments from specific email notifications * EPMRPP-82116-remove-attachments removed vk and fb links from all templates * EPMRPP-81154 added xml to api description and added file size check (#1677) * EPMRPP-81970 || Autocomplete in Recipients filed on Notifications tab in Project settings should show options starting from 1 symbol (#1681) * EPMRPP-81970 changed symbol limit from 3 to 1 * EPMRPP-81970 added code formatting * EPMRPP-82375 || Implement notification when changing password and make some template updates (#1682) * EPMRPP-82375 added a trigger to send a password change email * EPMRPP-82375 updated YouTube links and footer text * EPMRPP-82375 fixed test * EPMRPP-82375 minor change in index template (#1683) * EPMRPP-82545 || Update validation for Widgets (#1694) * EPMRPP-82545 Updated validation for Widgets * EPMRPP-82545 changed indent * Update commons dao * Master merge to 5.7.5 (#1695) * EPMRPP-79211 || Changed Minio interface to JCloud * EPMRPP-79211 || Updated DataStore configuration and properties * EPMRPP-79211 || Updated docker-compose with right BinaryStore value * EPMRPP-79211 || Update commons dao version * Update commons dao dependency to 5.7.4 * EPMRPP-80865|| Update bom and other versions (#1663) 5.7.4 || Update bom and other versions * [Gradle Release Plugin] - new version commit: '5.7.5'. --------- Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> * EPMRPP-83030 || Create RC branch * Update version * EPMRPP-82707 || Add single bucket configuration (#1696) * EPMRPP-82707 || Add single bucket configuration * EPMRPP-82707 || Refactor according to check style * EPMRPP-82707 || Refactor according to check style * EPMRPP-82707 || Change delete plguin from data store logic * EPMRPP-83068 || Fix checkstyle * EPMRPP-83068 || Update Admin permissions. Read/Write permissions without assign. (#1700) * EPMRPP-83068 || Update Admin permissions. Read/Write permissions without assign. --------- Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * Merge master to hotfix/next (#1702) * EPMRPP-79211 || Changed Minio interface to JCloud * EPMRPP-79211 || Updated DataStore configuration and properties * EPMRPP-79211 || Updated docker-compose with right BinaryStore value * EPMRPP-79211 || Update commons dao version * Update commons dao dependency to 5.7.4 * EPMRPP-80865|| Update bom and other versions (#1663) 5.7.4 || Update bom and other versions * [Gradle Release Plugin] - new version commit: '5.7.5'. * 23.1 release (#1698) * Update spring boot version to fix CVE-2022-22965 * EPMRPP-76845 || Update spring boot * Update Jenkinsfile * EPMRPP-77678 || Description length increased to 2048 * EPMRPP-77678 || Redundant import fix * EPMRPP-79737 || Fix vulnerabilities and update libraries version (#1624) * EPMRPP-79136 || Add retrieving all logs with it's locations (#1619) * EPMRPP-79136 || Add retrieving all logs with it's locations * EPMRPP-79136 || Add filtering by log level and item type * EPMRPP-79136 || Change response to save correct ordering * EPMRPP-79136 || Fix exclude passed logs parameter * EPMRPP-79136 || Override page size limit * EPMRPP-79136 || Fix retrieving with passed logs exclusion * Update Jenkinsfile-candidate * EPMRPP-79136 || Update dao version * EPMRPP-80383 || Notifications. AND/OR attribute option * EPMRPP-80744 || Change email on the API page * EPMRPP-80601 || Timeline widget. Remove empty content * EPMRPP-80744 || Add item attribute max length validation (#1640) EPMRPP-80744 || Add item attribute max length validation * EPMRPP-81136 || Incorrect 'startTime' value is reported for tests via 'Import' functionality Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-81046 || Impossible to report test items to project with "demo" name * EPMRPP-81019 || Launch import. Error 'org.hibernate.exception.DataException: could not execute statement' occurs on importing launch (#1645) * EPMRPP-81052 || Most failed test-cases table (TOP-20). Increase the amount of items to be displayed on widget from 20 to 50 or 100 * EPMRPP-80606 || Cut notification attribute to max length (#1650) EPMRPP-80606 || Cut attributes to max length * EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit (#1651) * Revert "EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit (#1651)" This reverts commit 13a49a644635f76b9b38dcb7ea41f7601d1fab04. * EPMRPP-81029 || There is no validation for the creation of dashboards exceeding the limit * EPMRPP-80606 || Update filter attribute cut logic (#1652) * EPMRPP-78741 || Remove duplicate onboarding endpoint (#1653) * EPMRPP-80606 || UserFilter cut attribute refactor (#1655) * EPMRPP-81358 || Fix vulnerabilities * EPMRPP-81193 || Wrong error code and message when creating notification rule without mandatory field * EPMRPP-81202 || Widget 'Flaky test cases table (TOP-50). It is possible to create widget with invalid 'Launches count' value via API (#1670) * EPMRPP-81202 || Widget 'Flaky test cases table (TOP-50). It is possible to create widget with invalid 'Launches count' value via API * EPMRPP-81202 || Change migration brunch * EPMRPP-81202 || Replace tab to spaces --------- Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-82300 || Typo in the error message when creating 'Flaky test cases table (TOP-50)' widget with some invalid values via API (#1674) * EPMRPP-82300-fix-typo-error uploaded commons-model dependency and fixed tests in service-api * EPMRPP-82300-fix-typo-error fixed tests in service-api * Epmrpp 78258 move acl (#1667) * EPMRPP-81233 || Move ACL tasks from RP-23.3 to RP-23.1 * EPMRPP-72320 || Fix unit tests * EPMRPP-81233 || Move ACL tasks from RP-23.3 to RP-23.1 * EPMRPP-81233 || Update bom --------- Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-81050 || Most Failed test-cases table widget. Increase the amount of items to be displayed on widget from 20 to 50 * EPMRPP-82116 || Update Notification template after launch finish (#1673) * EPMRPP-82116 Updated template for Notifications after launch finish * EPMRPP-82116 edited invitation templates * Update common model * EPMRPP-81362 || Fix security vulnerabilities (#1671) * EPMRPP-82116 || Update Notification template after launch finish (removed attachments) (#1678) * EPMRPP-82116-remove-attachments removed vk and fb attachments from specific email notifications * EPMRPP-82116-remove-attachments removed vk and fb links from all templates * EPMRPP-81154 added xml to api description and added file size check (#1677) * EPMRPP-81970 || Autocomplete in Recipients filed on Notifications tab in Project settings should show options starting from 1 symbol (#1681) * EPMRPP-81970 changed symbol limit from 3 to 1 * EPMRPP-81970 added code formatting * EPMRPP-82375 || Implement notification when changing password and make some template updates (#1682) * EPMRPP-82375 added a trigger to send a password change email * EPMRPP-82375 updated YouTube links and footer text * EPMRPP-82375 fixed test * EPMRPP-82375 minor change in index template (#1683) * EPMRPP-82545 || Update validation for Widgets (#1694) * EPMRPP-82545 Updated validation for Widgets * EPMRPP-82545 changed indent * Update commons dao * Master merge to 5.7.5 (#1695) * EPMRPP-79211 || Changed Minio interface to JCloud * EPMRPP-79211 || Updated DataStore configuration and properties * EPMRPP-79211 || Updated docker-compose with right BinaryStore value * EPMRPP-79211 || Update commons dao version * Update commons dao dependency to 5.7.4 * EPMRPP-80865|| Update bom and other versions (#1663) 5.7.4 || Update bom and other versions * [Gradle Release Plugin] - new version commit: '5.7.5'. --------- Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> * EPMRPP-83030 || Create RC branch * Update version * EPMRPP-83239 || Impossible to change password without Email Server integration * EPMRPP-83239 || Impossible to change password without Email Server integration --------- Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-78998 || Update dao --------- Co-authored-by: Maksim Antonov <Maksim_Antonov@epam.com> Co-authored-by: Ivan_Budayeu <Skileton2018> Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> Co-authored-by: Ivan_Kustau <Ivan_Kustau@epam.com> Co-authored-by: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> Co-authored-by: rkukharenka <125865748+rkukharenka@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> * Update release.yml * [Gradle Release Plugin] - new version commit: '5.8.1'. --------- Co-authored-by: Ivan_Kustau <Ivan_Kustau@epam.com> Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> Co-authored-by: Maksim Antonov <Maksim_Antonov@epam.com> Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> Co-authored-by: rkukharenka <125865748+rkukharenka@users.noreply.github.com> * Update commons-dao version * Add removeScripts task to Jenkins * Epmrpp 83130 || Update the token generation and its storage (#1706) * Create Jenkinsfile-release Added Jenkinsfile-release * Epmrpp 83130 || api key trim (#1707) * EPMRPP-83130 || Trim Api key. * EPMRPP-83130 || Trim Api key. --------- Co-authored-by: Andre Piankouski <andrei_piankouski@epam.com> * EPMRPP-83098 || Update all datastore variables naming (#1709) * EPMRPP-83536 || Reporting with new API Keys (#1708) * EPMRPP-83536 || Reporting with new API Keys --------- Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> * EPMRPP-84251 || Fix test * EPMRPP-84251 || Fix test * EPMRPP-84251 || Decrease branch limits --------- Co-authored-by: Maksim Antonov <Maksim_Antonov@epam.com> Co-authored-by: Ivan_Budayeu <Skileton2018> Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: Pavel Bortnik <pavel_bortnik@epam.com> Co-authored-by: Ivan_Kustau <Ivan_Kustau@epam.com> Co-authored-by: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> Co-authored-by: rkukharenka <125865748+rkukharenka@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> Co-authored-by: Hleb Kanonik <hleb_kanonik@epam.com> * EPMRPP-83882 || Add normalizing project name in ProjectExtractor (#1714) (#1715) * Fix migration scripts * EPMRPP-84705 || Remove vk and fb from email templates (#1773) * EPMRPP-85137 || Remove cookie auth for plugin files endpoint (#1775) * EPMRPP-85137 || Removed cookie auth for plugin files endpoint * EPMRPP-85137 || delete test by removed endpoint * EPMRPP-84310 || added check for integration type (#1777) * EPMRPP-81792 || Fix names validation * EPMRPP-81753 || Limit test item nesting * added github.run_number to rc build * EPMRPP-54905 || Launch report for one project is allowed for export by the members and customers of another project * EPMRPP-86199 || 500 Server Error when trying to delete deleted API Key (#1789) * EPMRPP-86199 || 500 Server Error when trying to delete deleted API Key * EPMRPP-86199 || Update rules * EPMRPP-84794 || Add new type of event on creating invitation link * EPMRPP-78737 || Fix luanch attribute link * EPMRPP-84794 || Change Object Name * EPMRPP-79633 || Remove staled notifications endpoint (#1792) * EPMRPP-80519 || Add project attachments deletion (#1793) * EPMRPP-80519 || Add project attachments deletion * Update dao version * EPMRPP-83956 || Remove null from email link after launch force finish (#1795) * EPMRPP-83956 || Add slash in url * EPMRPP-86221 || Fix test * EPMRPP-86221 || Fix test * EPMRPP-86221 || Fix test * EPMRPP-86660 || Notification rule names are empty after the deploy in case any notification was created on the project * EPMRPP-86660 || Notification rule names are empty after the deploy in case any notification was created on the project * EPMRPP-86363 || updated commons-dao version * EPMRPP-86348 || Implement immediate pattern analysis on test item fin… (#1798) * EPMRPP-86348 || Implement immediate pattern analysis on test item finish event. * EPMRPP-86348 || Add headers * EPMRPP-86348 || Update dao version * EPMRPP-85806 || added timestamps with offsets handling (#1800) * EPMRPP-84226 || Remove access token logic from the code (#1801) * EPMRPP-84226 || Remove access token logic from the code * EPMRPP-84226 || Update dao * EPMRPP-84226 || Cut attribute in notifications * EPMRPP-86361 || Add possibility to filter items by composite system (#1804) * EPMRPP-86348 || Implement immediate pattern analysis on test item finish event. * EPMRPP-86348 || Add headers * EPMRPP-86348 || Update dao version * EPMRPP-86361 || Filter items with immediatePa system attribute on launch finish pattern analysis * EPMRPP-86361 || Update dao * EPMRPP-86361 || Add missed headers * EPMRPP-86361 || Return back analyzer existence check * EPMRPP-86400 || Fix the problem with 'undefined' for exported filename (#1794) * EPMRPP-86208 || Update api key cache resolver * EPMRPP-86542 || fixed loading resources for email (#1816) * EPMRPP-85520 || Improve the filtering option 'User' on Project Monitoring page * EPMRPP-86219 || Implement immediate AutoAnalyze on TestItemFinishing (#1818) * EPMRPP-86775 || Add possibility to have no auth in ES * EPMRPP-86947 || ImmediateAA works when immediateAA attribute is not marked as system * EPMRPP-86775 || Add possibility to have no auth in ES * EPMRPP-86945 ||Check application name into Swagger base-path (#1820) * EPMRPP-86359 || Implement pattern analyzer handling using rabbitmq queue (#1822) * EPMRPP-86359 || Implement pattern analyzer handling using rabbitmq queue * EPMRPP-86361 || Add some checkstyle refactoring * EPMRPP-86359 || Change default single item prop value * EPMRPP-86967 || ImmediateAA works when Step finishes with immediateAA:false attribute * EPMRPP-86742 || extended launch import response (#1821) * EPMRPP-86742 || extended launch import response * EPMRPP-86969 || ImmediateAA works not only for TI defect type (#1824) * EPMRPP-86967 || Add null check * EPMRPP-86742 || message fix (#1825) * EPMRPP-86969 || ImmediateAA works not only for TI defect type * EPMRPP-86742 || launch name fix (#1826) * EPMRPP-86742 || launch name fix * EPMRPP-86969 || ImmediateAA works not only for TI defect type * EPMRPP-84054 || Add DeprecatedUserController and updated route for UserController (#1827) * EPMRPP-84054 || Add DeprecatedUserController and updated route for UserController * EPMRPP-84054 || Update DeprecatedUserController * EPMRPP-86466 || changed activity parameters upon creating invited user (#1828) * EPMRPP-80574 || Update dao version. Remove redundant encryptor (#1830) * EPMRPP-87028 || Update security configuration for user endpoints (#1831) * EPMRPP-86812 || extended actuator with "jobs" module info (#1832) * EPMRPP-86867 || updated logos in email templates (#1833) * EPMRPP-86867 || updated logos in email templates * EPMRPP-80574 || Update dao version. * EPMRPP-86248 || Auto-Analysis should skip already analyzed items on launch finish * EPMRPP-80989 || Add attribute operator in duplicate operation check (#1835) * EPMRPP-80989 || Add attribute operator in duplicate operation check * EPMRPP-80989 || Fix unit tests * EPMRPP-86109 || changed response model for GET {activeProject}/activity/item/{itemId} (#1838) Co-authored-by: rkukharenka <ryhor_kukharenka@epam.com> * EPMRPP-86867 || updated icons || re-organized template directory structure (#1834) * EPMRPP-86867 || updated icons || re-organized template directory structure * EPMRPP-86867 github icon fix (#1840) * EPMRPP-86743 || Move all launch fields to the request body for import (#1839) * EPMRPP-80989 || Add attribute operator in duplicate operation check * EPMRPP-80989 || Fix unit tests * EPMRPP-86743 || Move all launch fields to the request body for import controller * EPMRPP-86743 || Update commons-model * EPMRPP-86743 || Add import launch json request part * EPMRPP-86743 || Update commons-model * EPMRPP-86743 || Add import rq to swagger param * EPMRPP-86361 || Add swagger docs * EPMRPP-79482 || Add JCloud filesystem implementation (#1842) * Update commons-dao version * EPMRPP-87044 updated commons-dao version (#1843) * Add GitHub actions for building dev image * Patch Action Build develop Docker image * EPMRPP-87394 || Add configrurable connection factory for pattern anal… (#1845) * EPMRPP-87394 || Add configrurable connection factory for pattern analysis. Provide default parameters 'single-item:true', 'prefetchCount:0', 'consumersCount:1', 'connectionTimeout:10min' * EPMRPP-87394 || Remvoe connection timeout * EPMRPP-87394 || Fix tests * EPMRPP-87394 || Provide default params * EPMRPP-87394 || Fix tests * Hotfix 5.10.1 (#1837) * EPMRPP-87223 || Fix duplicated logs (cherry picked from commit f0e8cbb36956f89e53f5484b0a4668ca656c9ca1) * [Gradle Release Plugin] - new version commit: '5.10.2'. (cherry picked from commit afb083d7738f4af8371fa697fa25cf01529985bf) * EPMRPP-87332 || Send launchNumber to analyzer * EPMRPP-87394 || Add missed constuctor * EPMRPP-87482 || Fix potential npe (#1847) * EPMRPP-87394 || Add a separate queue per pattern template type (#1849) * EPMRPP-87382 fixed user attachments double removal (#1848) * EPMRPP-87173 updated commons-dao (#1850) * EPMRPP-87173 updated commons-dao * EPMRPP-87173 updated commons-dao * EPMRPP-87173 fixed tests * EPMRPP-87537 || Launch number not indexing (#1851) * EPMRPP-87537 || Launch number not indexing * EPMRPP-87537 || Update SuggestInfo * EMPRPP-87316 || Add proper exception handling. Update versions (#1853) * EMPRPP-87316 || Add proper exception handling. Update versions * EMPRPP-87316 || Fix tests * EPMRPP-87493 || Update build.gradle (#1857) * Update build.gradle * EPMRPP-87493 || Fix tests * EPMRPP-87493 || Fix compile errors * EPMRPP-87493 || Fix compile errors * EPRMPP-82591 || Logs with attachments null pointer (#1858) * EPMRPP-82591 || Add check for null file path * EPMRPP-82591 || Add waiting for log to be saved before attachment creation * EPMRPP-82591 || Update dao version * EPMRPP-82591 || Update dao version * EPMRPP-87271 updated commons dao (fix filtering by date) (#1855) * EPMRPP-87271 updated commons dao (fix filtering by date) * EPMRPP-87187 || Parent status is recalculated only when status is undefined (#1859) * Update build-rc-image.yaml * EPMRPP-87516 || Rename immediateAA parameter * Platform specification for Docker build stage * EPMRPP-87590 || Replace ElasticSearch with search engine * Update build workflows for Docker images (#1862) * EPMRPP-87591 || Page crashes when logging into RP * EPMRPP-87613 || Add back compatibility with older plugins * EPMRPP-87613 || Fix unit tests * Replace workflow build with java-checks (#1863) * EPMRPP-87590 || Capitalize article * EPMRPP-87591 || Page crashes when logging into RP * EPMRPP-86835 || Update releaseMode to use Maven instead of Github (#1870) * EPMRPP-86835 || Update releaseMode to use Maven instead of Github * EPMRPP-86835 || Update libs version * EPMRPP-87593 fix CVEs (#1868) * EPMRPP-87593 fix CVEs * EPMRPP-87421 fixed attachments handling (#1871) * EPMRPP-87421 fixed attachments handling * EPMRPP-87692 set auto analyzer mode "All launches with the same name" by default (#1872) * EPMRPP-87692 set auto analyzer mode "All launches with the same name" by default * EPMRPP-87813 || Send to the analyzer the id of previous launch * EPMRPP-88291 || Fix case when child recalculates parent status when status is already defined (#1874) * EPMRPP-88291 || Fix case when child recalculates parent status when status is already defined * EPMRPP-88291 || Fix tests * EPMRPP-87596 || No possibility to switch on/off AA and Unique Errors from UI * Update build.gradle (#1878) * EPMRPP-87433 || Update build.gradle (#1879) * EPMRPP-81547 || Java code documentation fixes for Service API (#1880) * EPMRPP-81547 || Java code documentation fixes for Service API * migrate to java 21 (#1877) EPMRPP-87047 || migrate to java 21 and gradle 8.4 * EPMRPP-88359 || Remove parent status recalculation when status changed (#1882) * EPMRPP-88359 || Remove parent status recalculation when status changed * EPMRPP-88359 || Make update parent status only for test item update * EPMRPP-87547 || Fix notification rule check when only attribute value is provided (#1883) * Update build-dev-image.yml * Update build-feature-image.yaml * EPMRPP-87547 || Fix case when all attributes are matched and ALL operator (#1885) * EPMRPP-87401 || Add openmetrics text converter (#1886) * EPMRPP-88577 || Analyzer uses information from deleted launches (#1891) * EPMRPP-88577 || Analyzer uses information from deleted launches * EPMRPP-88577 || Remove waiting rabbitMQ response * EPMRPP-88638 || Add name validation for launch import endpoint (#1892) Co-authored-by: Pavel Bortnik <pbortnik1207@gmail.com> * EPMRPP-88636 || Change system attribute for skipped is not issue (#1893) Co-authored-by: Pavel Bortnik <pbortnik1207@gmail.com> * EPMRPP-88727 || Support null value for name in import (#1895) * Add prefix and postfix for filesystem (#1896) * EPMRPP-88726 downgrade jasperreports version (#1897) * EPMRPP-88726 downgrade jasperreports version * EPMRPP-88726 fix commons-dao reference * rc/5.11.0 || Update versions * rc/5.11.0 || Downgrade apache poi version for back compatibility with jasperreports * rc/5.11.0 || Change to release version if not release mode * EPMRPP-88915 || Pattern Analysis of REGEX type doesn't work (#1906) * EPMRPP-88955 || increase thread executor pool size (#1908) Co-authored-by: APiankouski <109206864+apiankouski@users.noreply.github.com> * EPMRPP-82292 || Enable detailed health endpoint (#1796) * EPMRPP-82292 || Enable detailed health endpoint * EPMRPP-82292 || Enable detailed health endpoint * rc/5.11.0 || Update commons version * rc/5.11.0 || Perf. Add task executor for log creation handling * rc/5.11.0 || Update dao version * rc/5.11.0 || Update dao version * rc/5.11.0 || Update dao version --------- Co-authored-by: Chingiskhan <Chingiskhan_Kalanov@epam.com> Co-authored-by: miracle8484 <76156909+miracle8484@users.noreply.github.com> Co-authored-by: Hleb Kanonik <esscyh@gmail.com> Co-authored-by: Ivan_Budayeu <Skileton2018> Co-authored-by: Ivan <budaevqwerty@gmail.com> Co-authored-by: Maksim Antonov <Maksim_Antonov@epam.com> Co-authored-by: APiankouski <109206864+APiankouski@users.noreply.github.com> Co-authored-by: Andrei Piankouski <andrei.piankouski@ukg.com> Co-authored-by: Dmitriy Gumeniuk <dmitriy_gumeniuk@epam.com> Co-authored-by: Ivan_Kustau <Ivan_Kustau@epam.com> Co-authored-by: Vadzim Hushchanskou <vadzim_hushchanskou@epam.com> Co-authored-by: Vadzim Hushchanskou <HardNorth@users.noreply.github.com> Co-authored-by: Andrei Piankouski <andrei_piankouski@epam.com> Co-authored-by: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Co-authored-by: reportportal.io <support@reportportal.io> Co-authored-by: Ryhor <125865748+rkukharenka@users.noreply.github.com> Co-authored-by: Hleb Kanonik <hleb_kanonik@epam.com> Co-authored-by: siarhei_hrabko <siarhei_hrabko@epam.com> Co-authored-by: Siarhei Hrabko <45555481+grabsefx@users.noreply.github.com> Co-authored-by: Reingold Shekhtel <13565058+raikbitters@users.noreply.github.com> Co-authored-by: rkukharenka <ryhor_kukharenka@epam.com> Co-authored-by: raikbitters <raikbitters@gmail.com> Co-authored-by: Dzmitry Kosarau <Dzmitry_Kosarau@epam.com> Co-authored-by: Pavel Bortnik <pbortnik1207@gmail.com> --- .github/workflows/build-dev-image.yml | 35 + .github/workflows/build-feature-image.yaml | 37 + .github/workflows/build-rc-image.yaml | 43 + .github/workflows/build.yml | 40 - .github/workflows/java-checks.yml | 22 + .github/workflows/manually-release.yml | 6 +- .github/workflows/rc.yaml | 80 - .github/workflows/release.yml | 6 +- Dockerfile | 10 +- README.md | 6 +- build.gradle | 165 +- docker-compose.yml | 2 +- gradle.properties | 3 +- gradle/wrapper/gradle-wrapper.jar | Bin 58702 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 282 ++- gradlew.bat | 38 +- postman/RpCollection.postman_collection.json | 802 +++---- postman/service-api.postman_collection.json | 92 +- project-properties.gradle | 12 +- sealights.gradle | 29 - .../ta/reportportal/auth/ApiKeyUtils.java | 3 + .../auth/PermissionsRegisterBean.java | 55 +- .../reportportal/auth/ReportPortalClient.java | 6 +- .../reportportal/auth/UserRoleHierarchy.java | 126 +- ...ortPortalAclAuthorizationStrategyImpl.java | 39 +- .../RegisteredUserAuthenticator.java | 40 +- .../auth/authenticator/UserAuthenticator.java | 2 +- .../basic/DatabaseUserDetailsService.java | 54 +- .../UiAuthenticationFailureEventHandler.java | 90 +- .../UiAuthenticationSuccessEventHandler.java | 21 +- .../auth/event/UiUserSignedInEvent.java | 11 +- .../permissions/BaseProjectPermission.java | 86 +- .../auth/permissions/LookupPermission.java | 15 +- .../permissions/NotCustomerPermission.java | 29 +- .../auth/permissions/Permission.java | 22 +- .../PermissionEvaluatorFactoryBean.java | 69 +- .../auth/permissions/ProjectAuthority.java | 65 +- .../permissions/ProjectManagerPermission.java | 30 +- .../ReportPortalPermissionEvaluator.java | 99 +- .../auth/permissions/ReporterPermission.java | 24 +- .../ta/reportportal/auth/util/AuthUtils.java | 97 +- .../ta/reportportal/auth/util/Encryptor.java | 60 - .../core/ElementsCounterService.java | 92 + .../core/activity/ActivityHandler.java | 75 +- .../activity/impl/ActivityHandlerImpl.java | 7 +- .../activityevent/ActivityEventHandler.java | 11 + .../impl/ActivityEventHandlerImpl.java | 21 + .../core/admin/ServerAdminHandler.java | 27 +- .../core/admin/ServerAdminHandlerImpl.java | 79 +- .../core/analyzer/auto/AnalyzerService.java | 29 +- .../analyzer/auto/AnalyzerServiceAsync.java | 33 +- .../core/analyzer/auto/LogIndexer.java | 114 +- .../core/analyzer/auto/SearchLogService.java | 3 +- .../auto/client/AnalyzerServiceClient.java | 103 +- .../auto/client/IndexerServiceClient.java | 100 +- .../auto/client/RabbitMqManagementClient.java | 3 +- .../impl/AnalyzerServiceClientImpl.java | 249 ++- .../auto/client/impl/AnalyzerUtils.java | 76 +- .../client/impl/IndexerServiceClientImpl.java | 264 ++- .../RabbitMqManagementClientTemplate.java | 56 +- .../auto/client/model/IndexDefectsUpdate.java | 72 +- .../auto/client/model/IndexItemsRemove.java | 72 +- .../auto/client/model/IndexLaunchRemove.java | 71 +- .../auto/client/model/SuggestInfo.java | 318 +-- .../analyzer/auto/client/model/SuggestRq.java | 141 +- .../client/model/cluster/ClusterData.java | 46 +- .../client/model/cluster/ClusterInfoRs.java | 65 +- .../model/cluster/GenerateClustersRq.java | 74 +- .../auto/impl/AnalyzerServiceAsyncImpl.java | 33 +- .../auto/impl/AnalyzerServiceImpl.java | 267 ++- .../auto/impl/AnalyzerStatusCache.java | 168 +- .../analyzer/auto/impl/AnalyzerUtils.java | 174 +- .../analyzer/auto/impl/LogIndexerService.java | 271 +-- .../auto/impl/SearchLogServiceImpl.java | 313 +-- .../auto/impl/SuggestItemService.java | 279 +-- .../analyzer/auto/impl/SuggestedItem.java | 43 +- .../impl/preparer/LaunchPreparerService.java | 10 +- .../preparer/LaunchPreparerServiceImpl.java | 197 +- .../preparer/TestItemPreparerService.java | 19 +- .../preparer/TestItemPreparerServiceImpl.java | 89 +- .../auto/indexer/BatchLogIndexer.java | 250 ++- .../auto/indexer/IndexerStatusCache.java | 41 +- .../CollectingAutoAnalysisStarter.java | 86 +- .../starter/LaunchAutoAnalysisStarter.java | 2 +- .../decorator/AsyncAutoAnalysisStarter.java | 23 +- .../decorator/AutoAnalysisEnabledStarter.java | 20 +- .../decorator/ExistingAnalyzerStarter.java | 40 +- .../IndexingAutoAnalysisStarter.java | 32 +- .../analyze/AnalyzeCollectorConfig.java | 50 +- .../analyze/AnalyzeCollectorFactory.java | 14 +- .../analyze/AnalyzeItemsCollector.java | 21 +- .../strategy/analyze/AnalyzeItemsMode.java | 52 +- .../analyze/AutoAnalyzedCollector.java | 47 +- .../analyze/IgnoreImmediateCollector.java | 59 + .../analyze/ManuallyAnalyzedCollector.java | 58 +- .../analyze/ToInvestigateCollector.java | 38 +- .../search/CurrentLaunchCollector.java | 11 +- .../auto/strategy/search/FilterCollector.java | 66 +- .../strategy/search/LaunchNameCollector.java | 39 +- .../search/SearchCollectorConfig.java | 45 +- .../search/SearchCollectorFactory.java | 14 +- .../search/SearchLaunchesCollector.java | 5 +- .../auto/strategy/search/SearchLogsMode.java | 26 +- .../core/analyzer/config/AnalyzerType.java | 49 +- .../core/analyzer/config/AnalyzersConfig.java | 21 +- .../config/PatternAnalysisConfig.java | 58 +- .../PatternAnalysisRabbitConfiguration.java | 87 + .../config/StartLaunchAutoAnalysisConfig.java | 70 +- .../analyzer/pattern/PatternAnalyzer.java | 43 - .../handler/ItemsPatternsAnalyzer.java} | 39 +- .../impl/ItemsPatternAnalyzerImpl.java | 110 + .../proxy/ItemsPatternAnalyzeConsumer.java | 58 + .../handler/proxy/ItemsPatternAnalyzeDto.java | 103 + .../proxy/ItemsPatternAnalyzeProducer.java | 80 + .../pattern/impl/PatternAnalyzerImpl.java | 183 -- .../selector/PatternAnalysisSelector.java | 19 +- .../condition/PatternConditionProvider.java | 3 +- .../PatternConditionProviderChain.java | 53 +- .../AbstractPatternConditionProvider.java | 34 +- .../AutoAnalyzedPatternConditionProvider.java | 19 +- ...diatePatternAnalysisConditionProvider.java | 48 + .../impl/ManualPatternConditionProvider.java | 44 +- ...ToInvestigatePatternConditionProvider.java | 32 +- .../impl/AbstractPatternAnalysisSelector.java | 51 +- .../impl/RegexPatternAnalysisSelector.java | 40 +- .../StringPartPatternAnalysisSelector.java | 46 +- .../CreatePatternTemplateHandler.java | 22 +- .../service/LaunchPatternAnalyzer.java | 45 + .../CreatePatternTemplateHandlerImpl.java | 46 +- .../CreateRegexPatternTemplateHandler.java | 39 +- .../impl/LaunchPatternAnalyzerImpl.java | 119 + .../AbstractLaunchAnalysisStrategy.java | 45 +- .../strategy/LaunchAnalysisStrategy.java | 3 +- .../strategy/LaunchAutoAnalysisStrategy.java | 109 +- .../LaunchPatternAnalysisStrategy.java | 52 +- .../core/annotation/Datastore.java | 5 +- .../reportportal/core/annotation/Regular.java | 5 +- .../core/bts/handler/CreateTicketHandler.java | 23 +- .../handler/GetBugTrackingSystemHandler.java | 11 +- .../core/bts/handler/GetTicketHandler.java | 64 +- .../handler/impl/CreateTicketHandlerImpl.java | 120 +- .../impl/GetBugTrackingSystemHandlerImpl.java | 113 +- .../handler/impl/GetTicketHandlerImpl.java | 93 +- .../core/configs/AspectConfig.java | 20 +- .../core/configs/AttachmentSizeConfig.java | 126 +- .../core/configs/BatchJobConfiguration.java | 54 +- .../reportportal/core/configs/Conditions.java | 24 +- .../core/configs/DemoDataConfig.java | 44 +- .../core/configs/EmailConfiguration.java | 15 +- .../core/configs/ExecutorConfiguration.java | 260 ++- .../core/configs/IntegrationConfig.java | 38 +- .../ItemStatusChangingStrategyConfig.java | 53 +- .../core/configs/JacksonConfiguration.java | 26 +- .../core/configs/MergeStrategyConfig.java | 111 +- .../core/configs/MultipartDataConfig.java | 25 +- .../reportportal/core/configs/MvcConfig.java | 361 +-- .../core/configs/PluginConfiguration.java | 199 +- .../core/configs/ProjectValidationConfig.java | 30 +- .../core/configs/ReportPortalApp.java | 13 +- .../configs/ReportPortalClassLoadHelper.java | 65 +- .../core/configs/SchedulerConfiguration.java | 324 +-- .../core/configs/SecurityConfiguration.java | 289 +-- .../core/configs/Swagger2Configuration.java | 409 ++-- .../core/configs/WidgetConfig.java | 402 ++-- .../core/configs/WidgetValidatorConfig.java | 127 +- .../core/configs/XmlImportConfig.java | 1 + .../auto/LaunchAutoAnalysisConfig.java | 80 +- .../GenerateClusterPipelineConfig.java | 71 +- .../DataProviderEvaluatorConfig.java | 51 +- .../data/provider/DataProviderConfig.java | 50 +- .../resolver/DataProviderResolverConfig.java | 15 +- .../UniqueErrorAnalysisStarterConfig.java | 18 +- .../event/listener/EventListenerConfig.java | 34 +- .../event/publisher/EventPublisherConfig.java | 42 +- .../publisher/LoggingEventErrorHandler.java | 10 +- .../subscriber/EventSubscriberConfig.java | 73 +- .../rabbit/AnalyzerRabbitMqConfiguration.java | 67 +- .../BackgroundProcessingConfiguration.java | 38 +- .../configs/rabbit/DeserializablePair.java | 38 +- .../configs/rabbit/InternalConfiguration.java | 206 +- .../configs/rabbit/RabbitMqConfiguration.java | 90 +- .../rabbit/ReportingConfiguration.java | 346 +-- .../configs/remover/ContentRemoverConfig.java | 23 +- .../ResourceAttributeHandlerConfig.java | 74 +- .../dashboard/CreateDashboardHandler.java | 19 +- .../dashboard/DeleteDashboardHandler.java | 19 +- .../core/dashboard/GetDashboardHandler.java | 2 + .../dashboard/UpdateDashboardHandler.java | 70 +- .../core/events/AnalysisEvent.java | 53 +- .../ta/reportportal/core/events/Event.java | 1 + .../reportportal/core/events/MessageBus.java | 58 +- .../core/events/MessageBusImpl.java | 20 +- .../core/events/ProjectIdAwareEvent.java | 2 +- .../core/events/activity/AbstractEvent.java | 4 +- .../core/events/activity/AroundEvent.java | 26 +- .../core/events/activity/AssignUserEvent.java | 14 +- .../core/events/activity/BeforeEvent.java | 26 +- .../activity/CreateInvitationLinkEvent.java | 58 + .../events/activity/LaunchFinishedEvent.java | 19 +- .../events/activity/UnassignUserEvent.java | 3 +- .../events/activity/UserCreatedEvent.java | 15 +- ...shedEvent.java => IssueResolvedEvent.java} | 38 +- .../events/activity/item/ItemRetryEvent.java | 40 +- .../activity/item/TestItemFinishedEvent.java | 43 + .../activity/util/ActivityDetailsUtil.java | 1 + .../attachment/DeleteAttachmentEvent.java | 55 +- .../AttachDefaultPhotoEventHandler.java | 52 +- .../handler/ConfigurableEventHandler.java | 2 +- .../handler/DefectTypeDeletedHandler.java | 73 +- .../GenerateWidgetViewEventHandler.java | 94 +- .../handler/StartAnalysisEventHandler.java | 39 +- .../handler/TestItemRetryEventHandler.java | 24 +- .../item/TestItemAutoAnalysisRunner.java | 87 + .../handler/item/TestItemIndexRunner.java | 40 +- .../item/TestItemPatternAnalysisRunner.java | 55 + .../TestItemUniqueErrorAnalysisRunner.java | 63 +- .../LaunchAnalysisFinishEventPublisher.java | 24 +- .../launch/LaunchAutoAnalysisRunner.java | 41 +- .../launch/LaunchNotificationRunner.java | 393 ++-- .../launch/LaunchPatternAnalysisRunner.java | 45 +- .../LaunchUniqueErrorAnalysisRunner.java | 47 +- .../listener/LaunchFinishedEventListener.java | 27 +- ...aunchUniqueErrorAnalysisEventListener.java | 30 +- .../TestItemFinishedEventListener.java | 28 +- .../TestItemIssueResolvedEventListener.java | 41 + ...DelegatingApplicationEventMulticaster.java | 122 +- .../events/subscriber/EventSubscriber.java | 2 +- .../ProjectConfigDelegatingSubscriber.java | 28 +- ...enerateComponentHealthCheckTableEvent.java | 56 +- .../widget/GenerateWidgetViewEvent.java | 32 +- .../core/file/DeleteFilesHandler.java | 68 +- .../core/file/GetFileHandler.java | 52 +- .../core/file/impl/GetFileHandlerImpl.java | 83 +- .../core/filter/DeleteUserFilterHandler.java | 19 +- .../core/filter/SearchCriteriaService.java | 2 - .../core/filter/UpdateUserFilterHandler.java | 60 +- .../impl/DeleteUserFilterHandlerImpl.java | 8 +- .../filter/impl/GetUserFilterHandlerImpl.java | 53 +- .../impl/UpdateUserFilterHandlerImpl.java | 97 +- .../predefined/PredefinedFilterBuilder.java | 22 +- .../predefined/PredefinedFilterType.java | 29 +- .../filter/predefined/PredefinedFilters.java | 5 - .../AbstractFinishHierarchyHandler.java | 363 ++-- .../hierarchy/FinishHierarchyHandler.java | 21 +- .../impl/FinishLaunchHierarchyHandler.java | 75 +- .../impl/FinishTestItemHierarchyHandler.java | 79 +- .../core/imprt/FileExtensionConstant.java | 6 +- .../core/imprt/ImportLaunchHandler.java | 6 +- .../core/imprt/ImportLaunchHandlerImpl.java | 149 +- .../imprt/impl/AbstractImportStrategy.java | 122 +- .../core/imprt/impl/DateUtils.java | 32 +- .../core/imprt/impl/ImportStrategy.java | 26 +- .../imprt/impl/ImportStrategyFactory.java | 20 +- .../imprt/impl/ImportStrategyFactoryImpl.java | 36 +- .../core/imprt/impl/ImportType.java | 9 +- .../core/imprt/impl/ParseResults.java | 53 +- .../core/imprt/impl/XmlImportStrategy.java | 27 +- .../core/imprt/impl/ZipImportStrategy.java | 33 +- .../imprt/impl/junit/XunitImportHandler.java | 95 +- .../core/imprt/impl/junit/XunitParseJob.java | 4 +- .../integration/CreateIntegrationHandler.java | 1 + .../ExecuteIntegrationHandler.java | 61 +- .../integration/GetIntegrationHandler.java | 114 +- .../impl/CreateIntegrationHandlerImpl.java | 10 +- .../impl/ExecuteIntegrationHandlerImpl.java | 172 +- .../impl/GetIntegrationHandlerImpl.java | 408 ++-- .../integration/plugin/GetPluginHandler.java | 20 +- .../core/integration/plugin/PluginLoader.java | 148 +- .../plugin/binary/PluginFilesProvider.java | 76 + .../plugin/impl/GetPluginHandlerImpl.java | 39 +- .../util/AzureIntegrationService.java | 35 +- .../util/BasicIntegrationServiceImpl.java | 189 +- .../util/BtsIntegrationService.java | 214 +- .../util/EmailServerIntegrationService.java | 244 ++- .../integration/util/IntegrationService.java | 11 +- .../util/SauceLabsIntegrationService.java | 93 +- .../util/property/AuthProperties.java | 16 +- .../util/property/BtsProperties.java | 57 +- .../util/property/SauceLabsProperties.java | 41 +- .../util/validator/IntegrationValidator.java | 64 +- .../core/item/DeleteTestItemHandler.java | 41 +- .../core/item/ExternalTicketHandler.java | 9 +- .../core/item/FinishTestItemHandler.java | 23 +- .../core/item/GetTestItemHandler.java | 269 +-- .../core/item/StartTestItemHandler.java | 37 +- .../core/item/TestItemService.java | 51 +- .../core/item/UpdateTestItemHandler.java | 84 +- .../core/item/UpdateUniqueId.java | 372 ++-- .../history/ITestItemsHistoryService.java | 66 +- .../item/history/TestItemsHistoryHandler.java | 28 +- .../core/item/identity/IdentityUtil.java | 91 +- .../item/identity/TestCaseHashGenerator.java | 3 +- .../identity/TestCaseHashGeneratorImpl.java | 59 +- .../identity/TestItemUniqueIdGenerator.java | 100 +- .../core/item/identity/UniqueIdGenerator.java | 32 +- .../item/impl/DeleteTestItemHandlerImpl.java | 350 +-- .../item/impl/ExternalTicketHandlerImpl.java | 192 +- .../impl/FinishTestItemHandlerAsyncImpl.java | 66 +- .../item/impl/FinishTestItemHandlerImpl.java | 691 +++--- .../core/item/impl/IssueTypeHandler.java | 63 +- .../core/item/impl/LaunchAccessValidator.java | 26 +- .../item/impl/LaunchAccessValidatorImpl.java | 71 +- .../impl/StartTestItemHandlerAsyncImpl.java | 107 +- .../item/impl/StartTestItemHandlerImpl.java | 334 +-- .../item/impl/UpdateTestItemHandlerImpl.java | 632 +++--- .../impl/filter/updater/FilterUpdater.java | 2 +- .../updater/IssueTypeConditionReplacer.java | 62 +- .../impl/history/ItemHistoryBaselineEnum.java | 72 +- .../history/TestItemsHistoryHandlerImpl.java | 253 ++- .../history/param/HistoryRequestParams.java | 196 +- .../history/provider/HistoryProvider.java | 26 +- .../provider/HistoryProviderFactory.java | 23 +- .../ItemHistoryProviderConfiguration.java | 45 +- .../impl/LaunchBaselineHistoryProvider.java | 71 +- .../impl/TestItemBaselineHistoryProvider.java | 188 +- .../strategy/AbstractLaunchMergeStrategy.java | 314 +-- .../strategy/BasicLaunchMergeStrategy.java | 37 +- .../BasicStatisticsCalculationStrategy.java | 32 +- .../strategy/DeepLaunchMergeStrategy.java | 30 +- .../merge/strategy/LaunchMergeFactory.java | 15 +- .../merge/strategy/MergeStrategyType.java | 11 +- .../StatisticsCalculationFactory.java | 16 +- .../impl/provider/DataProviderHandler.java | 15 +- .../item/impl/provider/DataProviderType.java | 33 +- .../impl/provider/ProviderTypeConfig.java | 69 +- .../impl/BaselineLaunchDataProvider.java | 130 +- .../CumulativeTestItemDataProviderImpl.java | 93 +- .../DelegatingClusterDataProviderHandler.java | 72 +- .../impl/LaunchDataProviderHandlerImpl.java | 83 +- .../core/item/impl/rerun/RerunSearcher.java | 4 +- .../item/impl/rerun/RerunSearcherImpl.java | 23 +- .../item/impl/retry/DefaultRetryHandler.java | 98 +- .../core/item/impl/retry/RetryHandler.java | 5 +- .../core/item/impl/retry/RetrySearcher.java | 3 +- .../impl/retry/UniqueIdRetrySearcher.java | 55 +- .../AbstractStatusChangingStrategy.java | 284 +-- .../item/impl/status/ChangeStatusHandler.java | 4 +- .../impl/status/ChangeStatusHandlerImpl.java | 165 +- .../impl/status/StatusChangingStrategy.java | 3 +- .../ToFailedStatusChangingStrategy.java | 93 +- .../ToPassedStatusChangingStrategy.java | 112 +- .../ToSkippedStatusChangingStrategy.java | 163 +- .../core/item/merge/LaunchMergeStrategy.java | 6 +- .../merge/StatisticsCalculationStrategy.java | 3 +- .../utils/DefaultLaunchFilterProvider.java | 92 +- .../parent/NestedStepConditionValidator.java | 40 +- .../validator/parent/ParentItemValidator.java | 14 +- .../validator/parent/PathLengthValidator.java | 48 + .../parent/RetryConditionValidator.java | 30 +- .../parent/StartTimeConditionValidator.java | 32 +- .../state/NotNestedStepValidator.java | 24 +- .../validator/state/NotRetryValidator.java | 27 +- .../validator/state/TestItemValidator.java | 2 +- .../core/jasper/GetJasperReportHandler.java | 64 +- .../core/jasper/JasperReportRender.java | 90 +- .../core/jasper/TestItemPojo.java | 371 ++-- .../constants/LaunchReportConstants.java | 44 +- .../constants/ProjectReportConstants.java | 18 +- .../jasper/constants/UserReportConstants.java | 18 +- .../impl/AbstractJasperReportHandler.java | 183 +- .../impl/LaunchJasperReportHandler.java | 147 +- .../impl/ProjectJasperReportHandler.java | 77 +- .../jasper/impl/UserJasperReportHandler.java | 131 +- .../core/jasper/util/ExportUtils.java | 76 +- .../core/jasper/util/JasperDataProvider.java | 33 +- .../core/launch/DeleteLaunchHandler.java | 38 +- .../core/launch/FinishLaunchHandler.java | 24 +- .../core/launch/GetLaunchHandler.java | 273 +-- .../core/launch/MergeLaunchHandler.java | 19 +- .../core/launch/StartLaunchHandler.java | 52 +- .../core/launch/StopLaunchHandler.java | 45 +- .../core/launch/UpdateLaunchHandler.java | 74 +- .../core/launch/cluster/ClusterGenerator.java | 2 +- .../launch/cluster/CreateClusterHandler.java | 2 +- .../cluster/CreateClusterHandlerImpl.java | 91 +- .../launch/cluster/GetClusterHandler.java | 4 +- .../launch/cluster/GetClusterHandlerImpl.java | 63 +- .../cluster/UniqueErrorAnalysisStarter.java | 37 +- .../launch/cluster/UniqueErrorGenerator.java | 90 +- .../cluster/UniqueErrorGeneratorAsync.java | 37 +- .../cluster/config/ClusterEntityContext.java | 72 +- .../config/GenerateClustersConfig.java | 60 +- .../pipeline/DeleteClustersPartProvider.java | 41 +- .../pipeline/SaveClusterDataPartProvider.java | 29 +- .../SaveLastRunAttributePartProvider.java | 57 +- .../data/AnalyzerClusterDataProvider.java | 56 +- .../data/AnalyzerItemClusterDataProvider.java | 44 +- .../AnalyzerLaunchClusterDataProvider.java | 22 +- .../pipeline/data/ClusterDataProvider.java | 3 +- .../resolver/ClusterDataProviderResolver.java | 16 +- .../ClusterDataProviderEvaluator.java | 26 +- .../launch/impl/DeleteLaunchHandlerImpl.java | 264 ++- .../impl/FinishLaunchHandlerAsyncImpl.java | 53 +- .../launch/impl/FinishLaunchHandlerImpl.java | 158 +- .../launch/impl/GetLaunchHandlerImpl.java | 661 +++--- .../launch/impl/MergeLaunchHandlerImpl.java | 223 +- .../core/launch/impl/MetadataUpdater.java | 13 +- .../core/launch/impl/ResourceUpdater.java | 6 +- .../impl/StartLaunchHandlerAsyncImpl.java | 55 +- .../launch/impl/StartLaunchHandlerImpl.java | 82 +- .../launch/impl/StopLaunchHandlerImpl.java | 3 +- .../launch/impl/UpdateLaunchHandlerImpl.java | 367 ++-- .../core/launch/rerun/RerunHandler.java | 53 +- .../core/launch/rerun/RerunHandlerImpl.java | 338 +-- .../core/launch/util/LaunchValidator.java | 153 +- .../core/launch/util/LinkGenerator.java | 47 +- .../core/log/CreateLogHandler.java | 53 +- .../core/log/DeleteLogHandler.java | 19 +- .../core/log/ElasticLogService.java | 332 +++ .../core/log/EmptyLogService.java | 190 ++ .../reportportal/core/log/GetLogHandler.java | 107 +- .../ta/reportportal/core/log/LogService.java | 196 +- .../core/log/LogServiceElastic.java | 48 - .../core/log/LogServiceEmptyElastic.java | 23 - .../log/impl/CreateLogHandlerAsyncImpl.java | 135 +- .../core/log/impl/CreateLogHandlerImpl.java | 169 +- .../core/log/impl/DeleteLogHandlerImpl.java | 197 +- .../core/log/impl/GetLogHandlerImpl.java | 702 +++--- .../core/log/impl/PagedLogResource.java | 21 +- .../core/log/impl/SaveLogBinaryDataTask.java | 63 - .../log/impl/SaveLogBinaryDataTaskAsync.java | 71 +- .../core/logging/HttpLogging.java | 8 +- .../core/logging/HttpLoggingAspect.java | 371 ++-- .../core/logging/RabbitMessageLogging.java | 4 +- .../logging/RabbitMessageLoggingAspect.java | 165 +- .../core/onboarding/OnboardingService.java | 36 +- .../core/plugin/Pf4jPluginBox.java | 118 +- .../ta/reportportal/core/plugin/Plugin.java | 79 +- .../reportportal/core/plugin/PluginBox.java | 50 +- .../reportportal/core/plugin/PluginInfo.java | 106 +- .../core/preference/GetPreferenceHandler.java | 3 +- .../preference/UpdatePreferenceHandler.java | 39 +- .../impl/GetPreferenceHandlerImpl.java | 48 +- .../core/project/CreateProjectHandler.java | 18 +- .../core/project/DeleteProjectHandler.java | 3 + .../core/project/GetProjectHandler.java | 162 +- .../core/project/GetProjectInfoHandler.java | 57 +- .../core/project/ProjectUserHandler.java | 2 +- .../core/project/UpdateProjectHandler.java | 98 +- .../project/config/ProjectConfigProvider.java | 23 +- .../impl/CreateProjectHandlerImpl.java | 3 +- .../impl/DeleteProjectHandlerImpl.java | 61 +- .../impl/ProjectInfoWidgetDataConverter.java | 509 ++--- .../project/impl/ProjectUserHandlerImpl.java | 5 +- .../impl/UpdateProjectHandlerImpl.java | 3 +- .../CreateProjectSettingsHandler.java | 38 +- .../DeleteProjectSettingsHandler.java | 37 +- .../settings/GetProjectSettingsHandler.java | 14 +- .../UpdateProjectSettingsHandler.java | 40 +- .../CreateProjectSettingsHandlerImpl.java | 413 ++-- .../impl/GetProjectSettingsHandlerImpl.java | 22 +- .../UpdateProjectSettingsHandlerImpl.java | 242 ++- .../CreateProjectNotificationHandler.java | 32 + .../CreateProjectNotificationHandlerImpl.java | 88 + .../DeleteProjectNotificationHandler.java | 32 + .../DeleteProjectNotificationHandlerImpl.java | 91 + .../GetProjectNotificationsHandler.java | 29 + .../GetProjectNotificationsHandlerImpl.java | 46 + .../notification/ProjectRecipientHandler.java | 2 +- .../notification/RecipientRemover.java | 54 +- .../UpdateProjectNotificationHandler.java | 34 + .../UpdateProjectNotificationHandlerImpl.java | 93 + .../attribute/DelayBoundLessRule.java | 24 +- .../attribute/DelayBoundValidator.java | 95 +- .../attribute/ProjectAttributeValidator.java | 151 +- .../ProjectNotificationValidator.java | 126 ++ .../core/remover/ContentRemover.java | 2 +- .../core/remover/item/ItemClusterRemover.java | 18 +- .../remover/launch/LaunchClusterRemover.java | 20 +- .../project/ProjectClusterRemover.java | 20 +- .../project/ProjectContentRemover.java | 17 +- .../remover/project/ProjectWidgetRemover.java | 35 +- .../core/remover/user/UserContentRemover.java | 38 + .../core/remover/user/UserPhotoRemover.java | 66 + .../core/remover/user/UserWidgetRemover.java | 33 +- .../core/statistics/StatisticsHelper.java | 78 +- .../core/user/CreateUserHandler.java | 103 +- .../core/user/DeleteUserHandler.java | 18 +- .../core/user/EditUserHandler.java | 65 +- .../core/user/GetUserHandler.java | 120 +- .../core/user/impl/ApiKeyHandlerImpl.java | 5 + .../core/user/impl/CreateUserHandlerImpl.java | 34 +- .../core/user/impl/GetUserHandlerImpl.java | 282 +-- .../core/widget/CreateWidgetHandler.java | 19 +- .../core/widget/UpdateWidgetHandler.java | 18 +- .../widget/content/BuildFilterStrategy.java | 18 +- .../widget/content/LoadContentStrategy.java | 6 +- .../MaterializedLoadContentStrategy.java | 5 +- .../MaterializedLoadContentStrategyImpl.java | 39 +- .../MultilevelLoadContentStrategy.java | 10 +- .../constant/ContentLoaderConstants.java | 40 +- .../AbstractStatisticsFilterStrategy.java | 55 +- .../filter/ActivityFilterStrategy.java | 30 +- .../filter/GeneralLaunchFilterStrategy.java | 26 +- .../filter/LaunchHistoryFilterStrategy.java | 62 +- .../filter/ProductStatusFilterStrategy.java | 61 +- .../content/filter/ProjectFilterStrategy.java | 18 +- .../AbstractStatisticsContentLoader.java | 312 +-- .../loader/BugTrendChartContentLoader.java | 39 +- .../loader/CasesTrendContentLoader.java | 152 +- .../ChartInvestigatedContentLoader.java | 141 +- .../ComponentHealthCheckContentLoader.java | 212 +- .../loader/FlakyCasesTableContentLoader.java | 77 +- ...cutionAndIssueStatisticsContentLoader.java | 39 +- .../LaunchesComparisonContentLoader.java | 54 +- .../loader/LaunchesDurationContentLoader.java | 43 +- .../loader/LaunchesTableContentLoader.java | 39 +- .../loader/LineChartContentLoader.java | 64 +- .../MostTimeConsumingContentLoader.java | 217 +- .../loader/NotPassedTestsContentLoader.java | 39 +- .../OverallStatisticsContentLoader.java | 46 +- .../PassingRatePerLaunchContentLoader.java | 62 +- .../PassingRateSummaryContentLoader.java | 39 +- .../loader/ProductStatusContentLoader.java | 1 + ...oductStatusFilterGroupedContentLoader.java | 48 +- ...oductStatusLaunchGroupedContentLoader.java | 58 +- .../loader/TopPatternContentLoader.java | 66 +- .../loader/TopTestCasesContentLoader.java | 93 +- .../loader/UniqueBugContentLoader.java | 43 +- ...CumulativeTrendChartContentLoaderImpl.java | 93 +- .../HealthCheckTableReadyContentLoader.java | 223 +- .../MaterializedWidgetContentLoader.java | 5 +- .../generator/AbstractViewGenerator.java | 63 +- .../CumulativeTrendChartViewGenerator.java | 38 +- .../generator/FailedViewStateGenerator.java | 56 +- .../generator/HealthCheckTableGenerator.java | 70 +- .../materialized/generator/ViewGenerator.java | 5 +- ...CreatedMaterializedWidgetStateHandler.java | 41 +- .../EmptyMaterializedWidgetStateHandler.java | 14 +- .../FailedMaterializedWidgetStateHandler.java | 32 +- .../MaterializedWidgetStateHandler.java | 9 +- .../ReadyMaterializedWidgetStateHandler.java | 65 +- .../ProductStatusContentLoaderManager.java | 39 +- .../MaterializedViewNameGenerator.java | 11 +- .../state/WidgetStateResolver.java | 16 +- .../DelegatingStateContentRemover.java | 52 +- .../remover/MaterializedViewRemover.java | 28 +- .../remover/StaleMaterializedViewRemover.java | 47 +- .../content/remover/WidgetContentRemover.java | 2 +- .../ComponentHealthCheckPostProcessor.java | 30 +- ...omponentHealthCheckTablePostProcessor.java | 39 +- .../CumulativeTrendChartPostProcessor.java | 37 +- .../MaterializedWidgetStateUpdater.java | 10 +- .../content/updater/WidgetPostProcessor.java | 18 +- .../widget/content/updater/WidgetUpdater.java | 8 +- .../validator/ActivityContentValidator.java | 44 +- .../BugTrendChartContentValidator.java | 72 +- .../validator/CasesTrendContentValidator.java | 78 +- .../ChartInvestigatedContentValidator.java | 39 +- .../ComponentHealthCheckContentValidator.java | 85 +- .../CumulativeTrendChartValidator.java | 80 +- .../FlakyCasesTableContentValidator.java | 13 +- ...ionAndIssueStatisticsContentValidator.java | 69 +- .../LaunchesComparisonContentValidator.java | 69 +- .../LaunchesDurationContentValidator.java | 39 +- .../LaunchesTableContentValidator.java | 58 +- .../validator/LineChartContentValidator.java | 69 +- .../MostTimeConsumingContentValidator.java | 61 +- .../MultilevelValidatorStrategy.java | 9 +- .../NotPassedTestsContentValidator.java | 37 +- .../OverallStatisticsContentValidator.java | 40 +- .../PassingRatePerLaunchContentValidator.java | 61 +- .../PassingRateSummaryContentValidator.java | 39 +- .../ProductStatusContentValidator.java | 63 +- .../validator/TopPatternContentValidator.java | 48 +- .../TopTestCasesContentValidator.java | 36 +- .../validator/UniqueBugContentValidator.java | 39 +- .../WidgetContentFieldsValidator.java | 94 +- .../updater/validator/WidgetValidator.java | 2 +- .../validator/WidgetValidatorStrategy.java | 6 +- .../widget/util/ContentFieldMatcherUtil.java | 14 +- .../util/ContentFieldPatternConstants.java | 104 +- .../core/widget/util/WidgetFilterUtil.java | 48 +- .../core/widget/util/WidgetOptionUtil.java | 130 +- .../demodata/model/DemoDataRq.java | 30 +- .../demodata/model/DemoDataRs.java | 33 +- .../demodata/model/DemoItemMetadata.java | 128 +- .../demodata/model/DemoLaunch.java | 21 +- .../demodata/model/RootMetaData.java | 52 +- .../ta/reportportal/demodata/model/Step.java | 46 +- .../ta/reportportal/demodata/model/Suite.java | 60 +- .../ta/reportportal/demodata/model/Test.java | 60 +- .../demodata/model/TestingModel.java | 32 +- .../demodata/service/Attachment.java | 9 +- .../demodata/service/Constants.java | 18 +- .../demodata/service/ContentUtils.java | 285 +-- .../service/DefaultDemoDataFacade.java | 142 +- .../demodata/service/DemoDataFacade.java | 19 +- .../service/DemoDataLaunchService.java | 126 +- .../demodata/service/DemoDataService.java | 44 +- .../service/DemoDataTestItemService.java | 173 +- .../demodata/service/DemoLogsService.java | 77 +- .../generator/DefaultSuiteGenerator.java | 292 +-- .../service/generator/SuiteGenerator.java | 2 +- .../generator/SuiteGeneratorResolver.java | 15 +- .../SuiteWithNestedStepsGenerator.java | 35 +- .../generator/SuiteWithRetriesGenerator.java | 48 +- .../generator/model/SuiteGeneratorType.java | 2 +- .../exception/DataStorageException.java | 14 +- .../exception/HandlerNotDefinedException.java | 8 +- .../PermissionNotDefinedException.java | 8 +- .../UserAccountExpiredException.java | 8 +- .../health/JobsHealthIndicator.java | 79 + .../info/AnalyzerInfoContributor.java | 31 +- .../EnvironmentVariablesInfoContributor.java | 26 +- .../info/ExtensionContributor.java | 3 +- .../info/ExtensionsInfoContributor.java | 24 +- .../info/InfoContributorComposite.java | 33 +- .../info/JobSchedulerInfoContributor.java | 76 +- .../info/JobsInfoContributor.java | 61 + .../info/ServerSettingsInfoContributor.java | 33 +- .../job/CleanExpiredCreationBidsJob.java | 27 +- .../job/CleanOutdatedPluginsJob.java | 216 +- .../ta/reportportal/job/FlushingDataJob.java | 11 +- .../job/InterruptBrokenLaunchesJob.java | 221 +- .../reportportal/job/JobExecutorDelegate.java | 30 +- .../ta/reportportal/job/LoadPluginsJob.java | 144 +- .../epam/ta/reportportal/job/PageUtil.java | 114 +- .../reportportal/job/SelfCancelableJob.java | 45 +- .../job/service/PluginLoaderService.java | 5 +- .../service/impl/PluginLoaderServiceImpl.java | 207 +- .../pipeline/PipelineConstructor.java | 14 +- .../reportportal/pipeline/PipelinePart.java | 2 +- .../pipeline/PipelinePartProvider.java | 2 +- .../pipeline/TransactionalPipeline.java | 11 +- .../plugin/Pf4jPluginManager.java | 1334 ++++++------ .../plugin/ReportPortalExtensionFactory.java | 93 +- .../ApplicationContextAwareFactoryBean.java | 142 +- .../util/BinaryDataResponseWriter.java | 46 + .../ta/reportportal/util/ControllerUtils.java | 145 +- .../reportportal/util/DateTimeProvider.java | 9 +- .../ta/reportportal/util/ItemInfoUtils.java | 118 +- .../epam/ta/reportportal/util/Predicates.java | 70 +- .../util/ReportingQueueService.java | 57 +- .../util/email/EmailRulesValidator.java | 94 +- .../reportportal/util/email/EmailService.java | 29 +- .../util/email/MailServiceFactory.java | 4 + .../email/constant/IssueRegexConstant.java | 16 +- .../util/message/MessageProvider.java | 2 +- .../ws/controller/ActivityController.java | 17 +- .../controller/ActivityEventController.java | 19 + .../BugTrackingSystemController.java | 163 +- .../ws/controller/DashboardController.java | 33 +- .../controller/DeprecatedUserController.java | 268 +++ .../ws/controller/FileStorageController.java | 145 +- .../ws/controller/IntegrationController.java | 425 ++-- .../ws/controller/InternalApiController.java | 35 +- .../ws/controller/LaunchAsyncController.java | 134 +- .../ws/controller/LaunchController.java | 761 ++++--- .../ws/controller/LogAsyncController.java | 211 +- .../ws/controller/LogController.java | 439 ++-- .../ws/controller/OnboardingController.java | 15 +- .../ws/controller/PluginPublicController.java | 85 + .../controller/ProjectSettingsController.java | 274 ++- .../ws/controller/SettingsController.java | 55 +- .../controller/TestItemAsyncController.java | 99 +- .../ws/controller/TestItemController.java | 824 +++---- .../ws/controller/UserController.java | 2 +- .../ws/converter/LogResourceAssembler.java | 12 +- .../ws/converter/ResourceAssembler.java | 63 +- .../converter/TestItemResourceAssembler.java | 26 +- .../converter/builders/AttachmentBuilder.java | 72 +- .../builders/IntegrationBuilder.java | 79 +- .../builders/IntegrationTypeBuilder.java | 79 +- .../builders/IssueEntityBuilder.java | 61 +- .../converter/builders/IssueTypeBuilder.java | 79 +- .../ws/converter/builders/LaunchBuilder.java | 199 +- .../{LogBuilder.java => LogFullBuilder.java} | 63 +- .../builders/PatternTemplateBuilder.java | 81 +- .../converter/builders/TestCaseIdEntry.java | 48 +- .../converter/builders/TestItemBuilder.java | 354 +-- .../ws/converter/builders/UserBuilder.java | 83 +- .../builders/UserPreferenceBuilder.java | 59 +- .../converters/ActivityEventConverter.java | 2 + .../converters/BaseEntityConverter.java | 18 +- .../converters/ClusterConverter.java | 35 +- .../converters/ExceptionConverter.java | 19 +- .../converters/IntegrationConverter.java | 108 +- .../IntegrationFieldsConverter.java | 96 +- .../converters/IntegrationTypeConverter.java | 32 +- .../converter/converters/IssueConverter.java | 76 +- .../converters/IssueTypeConverter.java | 19 +- .../converter/converters/LaunchConverter.java | 109 +- .../ws/converter/converters/LogConverter.java | 140 +- .../NotificationConfigConverter.java | 17 + .../converters/OAuthDetailsConverters.java | 68 +- .../converters/ParametersConverter.java | 31 +- .../converters/PatternTemplateConverter.java | 47 +- .../converters/ProjectActivityConverter.java | 21 +- .../converters/ProjectSettingsConverter.java | 87 +- .../RestorePasswordBidConverter.java | 21 +- .../converters/ServerSettingsConverter.java | 23 +- .../converters/StatisticsConverter.java | 61 +- .../converters/TestItemConverter.java | 190 +- .../converter/converters/TicketConverter.java | 27 +- .../converters/UserCreationBidConverter.java | 25 +- .../converter/converters/WidgetConverter.java | 129 +- .../handler/attribute/ItemAttributeType.java | 6 +- .../attribute/ResourceAttributeHandler.java | 3 +- .../launch/LaunchResourceAttributeLogger.java | 26 +- .../LaunchResourceAttributeUpdater.java | 15 +- .../matcher/ItemAttributeTypeMatcher.java | 4 +- .../PredicateItemAttributeTypeMatcher.java | 30 +- .../resolver/ItemAttributeTypeResolver.java | 3 +- .../ItemAttributeTypeResolverDelegate.java | 18 +- .../ws/converter/utils/ResourceUpdater.java | 2 +- .../utils/ResourceUpdaterProvider.java | 2 +- .../item/content/TestItemUpdaterContent.java | 31 +- .../provider/PathNameUpdaterProvider.java | 27 +- .../item/provider/RetriesUpdaterProvider.java | 49 +- .../utils/item/updater/PathNameUpdater.java | 30 +- .../utils/item/updater/RetriesUpdater.java | 32 +- .../reportportal/ws/handler/QueryHandler.java | 2 +- .../ws/handler/impl/QueryHandlerImpl.java | 58 +- .../ws/rabbit/AsyncReportingListener.java | 551 ++--- .../ws/rabbit/ConsumerEventListener.java | 76 +- .../ws/rabbit/MessageHeaders.java | 30 +- .../reportportal/ws/rabbit/QueryConsumer.java | 16 +- .../ta/reportportal/ws/rabbit/QueryRQ.java | 28 +- .../ws/rabbit/ReportingStartupService.java | 22 +- .../reportportal/ws/rabbit/RequestType.java | 2 +- .../reportportal/ws/resolver/ActiveRole.java | 11 +- .../ActiveUserWebArgumentResolver.java | 71 +- .../ws/resolver/FilterCriteriaResolver.java | 137 +- .../reportportal/ws/resolver/FilterFor.java | 22 +- .../ws/resolver/JacksonViewAware.java | 44 +- .../ws/resolver/JacksonViewAwareModule.java | 56 +- .../JacksonViewReturnValueHandler.java | 88 +- .../resolver/JsonViewSupportFactoryBean.java | 61 +- .../PagingHandlerMethodArgumentResolver.java | 64 +- .../PredefinedFilterCriteriaResolver.java | 111 +- .../ws/resolver/ResponseView.java | 9 +- .../ws/resolver/SortArgumentResolver.java | 81 +- .../ta/reportportal/ws/resolver/SortFor.java | 18 +- .../JaskonRequiredPropertiesValidator.java | 88 +- src/main/resources/application.properties | 15 +- src/main/resources/application.yaml | 20 +- src/main/resources/bug_template.ftl | 80 +- src/main/resources/demo/attachments/css.css | 22 +- src/main/resources/demo/attachments/html.html | 12 +- .../resources/demo/attachments/javascript.js | 116 +- src/main/resources/demo/attachments/xml.xml | 28 +- .../resources/demo/launch/002_launch.json | 350 +-- .../email/change-password-template.ftl | 283 +-- .../templates/email/create-user-template.ftl | 326 +-- .../delete-account-notification-template.ftl | 512 ++--- .../email/delete-account-template.ftl | 500 ++--- .../templates/email/email-connection.ftl | 256 ++- .../email/finish-launch-template.ftl | 518 +++-- .../resources/templates/email/ic-github.png | Bin 816 -> 0 bytes .../resources/templates/email/ic-slack.png | Bin 686 -> 0 bytes .../resources/templates/email/ic-twitter.png | Bin 593 -> 0 bytes .../resources/templates/email/ic-youtube.png | Bin 297 -> 0 bytes .../email/{ => images}/create-user.png | Bin .../delete-account-notification.png | Bin .../email/{ => images}/deleted-account.png | Bin .../templates/email/images/ic-facebook.png | Bin 0 -> 896 bytes .../templates/email/images/ic-github.png | Bin 0 -> 1125 bytes .../templates/email/images/ic-linkedin.png | Bin 0 -> 1015 bytes .../templates/email/images/ic-slack.png | Bin 0 -> 1285 bytes .../templates/email/images/ic-twitter.png | Bin 0 -> 1233 bytes .../templates/email/images/ic-youtube.png | Bin 0 -> 1076 bytes .../email/{ => images}/illustration.png | Bin .../templates/email/{ => images}/logo.png | Bin .../email/images/new-ic-facebook.png | Bin 0 -> 976 bytes .../email/{ => images}/new-ic-github.png | Bin .../email/{ => images}/new-ic-linkedin.png | Bin .../email/{ => images}/new-ic-slack.png | Bin .../templates/email/images/new-ic-twitter.png | Bin 0 -> 1593 bytes .../email/{ => images}/new-ic-youtube.png | Bin .../templates/email/{ => images}/new-logo.png | Bin .../email/{ => images}/restore-password.png | Bin .../email/index-finished-template.ftl | 2 +- .../templates/email/new-ic-twitter.png | Bin 690 -> 0 bytes .../templates/email/registration-template.ftl | 325 +-- .../email/restore-password-template.ftl | 311 +-- .../email/self-delete-account-template.ftl | 499 ++--- .../resources/templates/report/projects.jrxml | 280 +-- .../resources/templates/report/report.jrxml | 1488 +++++++------ .../resources/templates/report/users.jrxml | 290 +-- .../ta/reportportal/ReportPortalUserUtil.java | 35 +- .../com/epam/ta/reportportal/TestConfig.java | 95 +- .../ta/reportportal/auth/OAuthHelper.java | 99 +- .../auth/UserRoleHierarchyTest.java | 38 +- .../basic/DatabaseUserDetailsServiceTest.java | 35 +- .../auto/client/impl/AnalyzerUtilsTest.java | 74 +- .../impl/IndexerServiceClientImplTest.java | 157 +- .../RabbitMqManagementClientTemplateTest.java | 25 +- .../auto/impl/AnalyzerServiceServiceTest.java | 295 +-- .../analyzer/auto/impl/AnalyzerUtilsTest.java | 249 ++- .../auto/impl/LogIndexerServiceTest.java | 249 +-- .../auto/impl/SearchLogServiceImplTest.java | 207 +- .../auto/impl/SuggestItemServiceTest.java | 316 +-- .../LaunchPreparerServiceImplTest.java | 61 +- .../auto/indexer/BatchLogIndexerTest.java | 202 +- .../CollectingAutoAnalysisStarterTest.java | 112 +- .../AsyncAutoAnalysisStarterTest.java | 45 +- .../AutoAnalysisEnabledStarterTest.java | 68 +- .../ExistingAnalyzerStarterTest.java | 75 +- .../IndexingAutoAnalysisStarterTest.java | 53 +- .../analyzer/config/AnalyzerTypeTest.java | 34 +- .../analyzer/pattern/PatternAnalyzerTest.java | 155 -- .../LaunchAutoAnalysisStrategyTest.java | 85 +- .../LaunchPatternAnalysisStrategyTest.java | 76 +- .../ReportPortalClassLoadHelperTest.java | 37 +- .../impl/CreateDashboardHandlerImplTest.java | 47 +- .../core/events/MessageBusImplTest.java | 21 +- .../events/activity/LaunchEventsTest.java | 4 +- .../events/activity/UserCreatedEventTest.java | 2 +- ...onentHealthCheckTableEventHandlerTest.java | 174 +- .../handler/DefectTypeDeletedHandlerTest.java | 225 +- .../handler/item/TestItemIndexRunnerTest.java | 46 +- .../TestItemPatternAnalysisRunnerTest.java | 76 + ...TestItemUniqueErrorAnalysisRunnerTest.java | 79 +- ...aunchAnalysisFinishEventPublisherTest.java | 41 +- .../launch/LaunchAutoAnalysisRunnerTest.java | 40 +- .../launch/LaunchNotificationRunnerTest.java | 117 +- .../LaunchPatternAnalysisRunnerTest.java | 74 +- .../LaunchUniqueErrorAnalysisRunnerTest.java | 79 +- ...hUniqueErrorAnalysisEventListenerTest.java | 55 +- ...> TestIssueResolvedEventListenerTest.java} | 32 +- ...ProjectConfigDelegatingSubscriberTest.java | 2 - .../LaunchFinishedMessagePublisherTest.java | 2 - .../FinishLaunchHierarchyHandlerTest.java | 375 ++-- .../imprt/ImportLaunchHandlerImplTest.java | 39 +- .../core/imprt/XmlImportStrategyTest.java | 14 +- .../impl/junit/XunitImportHandlerTest.java | 35 +- .../impl/ExecuteIntegrationHandlerTest.java | 112 + .../impl/GetIntegrationHandlerTest.java | 145 +- .../impl/util/IntegrationTestUtil.java | 124 +- .../util/AzureIntegrationServiceTest.java | 123 +- .../EmailServerIntegrationServiceTest.java | 174 +- .../util/JiraIntegrationServiceTest.java | 178 +- .../util/RallyIntegrationServiceTest.java | 123 +- .../util/SauceLabsIntegrationServiceTest.java | 115 +- .../validator/IntegrationValidatorTest.java | 108 +- .../impl/DeleteTestItemHandlerImplTest.java | 404 ++-- .../FinishTestItemHandlerAsyncImplTest.java | 75 +- .../impl/FinishTestItemHandlerImplTest.java | 351 +-- .../core/item/impl/IssueTypeHandlerTest.java | 61 +- .../impl/LaunchAccessValidatorImplTest.java | 129 +- .../StartTestItemHandlerAsyncImplTest.java | 56 +- .../impl/StartTestItemHandlerImplTest.java | 383 ++-- .../impl/TestCaseHashGeneratorImplTest.java | 97 +- .../impl/TestItemUniqueIdGeneratorTest.java | 137 +- .../impl/UpdateTestItemHandlerImplTest.java | 494 +++-- .../IssueTypeConditionReplacerTest.java | 63 +- .../TestItemsHistoryHandlerImplTest.java | 80 +- .../mock/ClusterItemDataProviderMockTest.java | 307 +-- .../state/NotNestedStepValidatorTest.java | 32 +- .../state/NotRetryValidatorTest.java | 44 +- .../cluster/CreateClusterHandlerImplTest.java | 196 +- .../UniqueErrorAnalysisStarterTest.java | 76 +- .../UniqueErrorGeneratorAsyncTest.java | 209 +- .../cluster/UniqueErrorGeneratorTest.java | 155 +- .../DeleteClustersPartProviderTest.java | 67 +- .../SaveClusterDataPartProviderTest.java | 79 +- .../SaveLastRunAttributePartProviderTest.java | 85 +- .../AnalyzerItemClusterDataProviderTest.java | 184 +- ...AnalyzerLaunchClusterDataProviderTest.java | 89 +- .../ClusterDataProviderResolverTest.java | 50 +- .../ClusterDataProviderEvaluatorTest.java | 59 +- .../launch/cluster/utils/ConfigProvider.java | 26 +- .../impl/DeleteLaunchHandlerImplTest.java | 82 +- .../FinishLaunchHandlerAsyncImplTest.java | 38 +- .../impl/FinishLaunchHandlerImplTest.java | 303 +-- .../launch/impl/GetLaunchHandlerImplTest.java | 518 ++--- .../core/launch/impl/LaunchTestUtil.java | 41 +- .../impl/StartLaunchHandlerAsyncImplTest.java | 38 +- .../impl/StartLaunchHandlerImplTest.java | 108 +- .../impl/UpdateLaunchHandlerImplTest.java | 235 +- .../launch/rerun/RerunHandlerImplTest.java | 413 ++-- .../core/launch/util/LaunchValidatorTest.java | 55 +- .../core/log/ElasticLogServiceTest.java | 62 + .../impl/CreateLogHandlerAsyncImplTest.java | 90 +- .../core/log/impl/DeleteLogHandlerTest.java | 328 +-- .../core/log/impl/GetLogHandlerImplTest.java | 128 +- .../core/logging/HelperController.java | 51 +- .../core/logging/HelperListener.java | 18 +- .../reportportal/core/logging/HelperUtil.java | 45 +- .../core/logging/HttpLoggingAspectTest.java | 176 +- .../RabbitMessageLoggingAspectTest.java | 165 +- .../config/ProjectConfigProviderTest.java | 51 +- .../impl/CreateProjectHandlerImplTest.java | 78 +- .../impl/DeleteProjectHandlerImplTest.java | 7 +- .../ProjectInfoWidgetDataConverterTest.java | 348 +-- .../CreateProjectSettingsHandlerImplTest.java | 246 ++- .../DeleteProjectSettingsHandlerImplTest.java | 66 +- .../GetProjectSettingsHandlerImplTest.java | 39 +- .../UpdateProjectSettingsHandlerImplTest.java | 164 +- ...ateProjectNotificationHandlerImplTest.java | 166 ++ ...eteProjectNotificationHandlerImplTest.java | 87 + ...etProjectNotificationsHandlerImplTest.java | 67 + ...ateProjectNotificationHandlerImplTest.java | 202 ++ .../remover/user/UserContentRemoverTest.java | 49 + .../remover/user/UserPhotoRemoverTest.java | 101 + .../core/statistics/StatisticsHelperTest.java | 151 +- .../user/impl/CreateUserHandlerImplTest.java | 527 +++-- .../user/impl/GetUserHandlerImplTest.java | 129 +- .../FailedViewStateGeneratorTest.java | 64 +- ...lthCheckTableReadyContentResolverTest.java | 110 +- .../MaterializedViewNameGeneratorTest.java | 49 +- .../DelegatingStateContentRemoverTest.java | 59 +- .../remover/MaterializedViewRemoverTest.java | 33 +- .../StaleMaterializedViewRemoverTest.java | 45 +- .../ActivityContentValidatorTest.java | 40 +- .../BugTrendChartContentValidatorTest.java | 56 +- .../CasesTrendContentValidatorTest.java | 56 +- ...ChartInvestigatedContentValidatorTest.java | 40 +- ...ponentHealthCheckContentValidatorTest.java | 97 +- .../CumulativeTrendChartValidatorTest.java | 2 - .../FlakyCasesTableContentValidatorTest.java | 1 - ...ndIssueStatisticsContentValidatorTest.java | 55 +- ...aunchesComparisonContentValidatorTest.java | 55 +- .../LaunchesDurationContentValidatorTest.java | 40 +- .../LaunchesTableContentValidatorTest.java | 56 +- ...MostTimeConsumingContentValidatorTest.java | 67 +- .../NotPassedTestsContentValidatorTest.java | 40 +- ...singRatePerLaunchContentValidatorTest.java | 66 +- ...assingRateSummaryContentValidatorTest.java | 53 +- .../TopPatternContentValidatorTest.java | 57 +- .../UniqueBugContentValidatorTest.java | 40 +- .../util/ContentFieldMatcherUtilTest.java | 198 +- .../widget/util/WidgetOptionUtilTest.java | 102 +- .../job/CleanOutdatedPluginsJobTest.java | 166 +- .../job/InterruptBrokenLaunchesJobTest.java | 174 +- .../job/JobExecutorDelegateTest.java | 30 +- .../reportportal/job/LoadPluginsJobTest.java | 111 +- .../job/PluginLoaderServiceTest.java | 232 +- .../job/SaveLogBinaryDataTaskTest.java | 59 - .../job/SelfCancalableJobTest.java | 49 +- .../plugin/Pf4jPluginManagerTest.java | 400 ++-- .../store/service/DataStoreServiceTest.java | 113 +- ...pplicationContextAwareFactoryBeanTest.java | 56 +- .../reportportal/util/ItemInfoUtilsTest.java | 163 +- .../util/MultipartFileUtilsTest.java | 37 +- .../ta/reportportal/util/PredicatesTest.java | 137 +- .../util/ReportingQueueServiceTest.java | 57 +- .../util/TestProjectExtractor.java | 20 +- .../util/email/EmailRulesValidatorTest.java | 303 +-- .../util/email/EmailServiceTest.java | 84 +- .../util/sample/LaunchSampleUtil.java | 51 + .../epam/ta/reportportal/ws/BaseMvcTest.java | 70 +- .../BugTrackingSystemControllerTest.java | 341 +-- .../DashboardControllerValidationTest.java | 434 ++-- .../controller/IntegrationControllerTest.java | 468 ++-- .../controller/LaunchAsyncControllerTest.java | 216 +- .../ws/controller/LaunchControllerTest.java | 732 ++++--- .../LaunchControllerValidationTest.java | 415 ++-- .../ws/controller/LogAsyncControllerTest.java | 206 +- .../ws/controller/LogControllerTest.java | 152 +- .../ws/controller/PluginControllerTest.java | 21 +- .../PluginPublicControllerTest.java | 115 + .../ws/controller/ProjectControllerTest.java | 7 +- .../ProjectSettingsControllerTest.java | 469 ++-- .../ws/controller/SettingsControllerTest.java | 65 +- .../TestItemAsyncControllerTest.java | 209 +- .../ws/controller/TestItemControllerTest.java | 1931 +++++++++-------- .../TestItemControllerValidationTest.java | 668 +++--- .../UserFilterControllerValidationTest.java | 466 ++-- .../constants/ValidationTestsConstants.java | 19 +- .../converter/LogResourceAssemblerTest.java | 86 +- .../builders/IntegrationBuilderTest.java | 149 +- .../builders/IssueEntityBuilderTest.java | 48 +- .../builders/IssueTypeBuilderTest.java | 44 +- .../converter/builders/LaunchBuilderTest.java | 130 +- ...ilderTest.java => LogFullBuilderTest.java} | 60 +- .../builders/PatternTemplateBuilderTest.java | 39 +- .../builders/TestItemBuilderTest.java | 339 +-- .../converter/builders/UserBuilderTest.java | 49 +- .../builders/UserPreferenceBuilderTest.java | 31 +- .../converters/IntegrationConverterTest.java | 125 +- .../IntegrationFieldsConverterTest.java | 100 +- .../converters/IssueConverterTest.java | 70 +- .../ItemAttributeConverterTest.java | 20 +- .../converters/LogConverterTest.java | 78 +- .../converters/ParametersConverterTest.java | 66 +- .../PatternTemplateConverterTest.java | 61 +- .../ProjectActivityConverterTest.java | 54 +- .../RestorePasswordBidConverterTest.java | 22 +- .../converters/TestItemConverterTest.java | 301 +-- .../converters/TicketConverterTest.java | 38 +- .../UserCreationBidConverterTest.java | 47 +- .../LaunchResourceAttributeUpdaterTest.java | 54 +- ...hResourceMetadataAttributeUpdaterTest.java | 63 +- ...PredicateItemAttributeTypeMatcherTest.java | 56 +- .../ws/handler/impl/QueryHandlerImplTest.java | 93 +- .../ws/rabbit/AsyncReportingListenerTest.java | 14 +- .../ws/rabbit/QueryConsumerTest.java | 38 +- .../ws/validation/BusinessRuleTest.java | 34 +- ...JaskonRequiredPropertiesValidatorTest.java | 101 +- .../db/data-store/data-store-fill.sql | 12 +- src/test/resources/db/launch/launch-fill.sql | 12 +- .../migration/V001003__integration_type.sql | 6 +- .../V0027__attachment_creation_date.up.sql | 3 +- .../db/migration/V0030__log_project_id.up.sql | 3 +- .../project-settings-fill.sql | 33 +- .../resources/db/shareable/shareable-fill.sql | 89 +- .../item-change-status-from-failed.sql | 31 +- .../item-change-status-from-interrupted.sql | 27 +- .../item-change-status-from-passed.sql | 60 +- .../item-change-status-from-skipped.sql | 35 +- src/test/resources/db/user/user-customer.sql | 6 +- src/test/resources/db/user/user-fill.sql | 16 +- src/test/resources/db/widget/bug-trend.sql | 52 +- src/test/resources/db/widget/cases-trend.sql | 54 +- .../resources/db/widget/flaky-test-cases.sql | 85 +- .../db/widget/investigated-trend.sql | 41 +- .../resources/db/widget/launch-statistics.sql | 26 +- .../db/widget/launches-comparison-chart.sql | 56 +- .../db/widget/launches-duration-chart.sql | 12 +- .../resources/db/widget/launches-table.sql | 34 +- .../db/widget/most-time-consuming.sql | 43 +- src/test/resources/db/widget/not-passed.sql | 24 +- .../resources/db/widget/old-line-chart.sql | 24 +- .../db/widget/overall-statistics.sql | 26 +- .../db/widget/passing-rate-per-launch.sql | 58 +- .../db/widget/passing-rate-summary.sql | 50 +- .../resources/db/widget/product-status.sql | 42 +- .../resources/db/widget/top-test-cases.sql | 74 +- .../resources/db/widget/unique-bug-table.sql | 39 +- src/test/resources/logback-test.xml | 24 +- 1023 files changed, 50910 insertions(+), 42587 deletions(-) create mode 100644 .github/workflows/build-dev-image.yml create mode 100644 .github/workflows/build-feature-image.yaml create mode 100644 .github/workflows/build-rc-image.yaml delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/java-checks.yml delete mode 100644 .github/workflows/rc.yaml mode change 100755 => 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100755 sealights.gradle delete mode 100644 src/main/java/com/epam/ta/reportportal/auth/util/Encryptor.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/ElementsCounterService.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/IgnoreImmediateCollector.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisRabbitConfiguration.java delete mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzer.java rename src/main/java/com/epam/ta/reportportal/{ws/converter/builders/Builder.java => core/analyzer/pattern/handler/ItemsPatternsAnalyzer.java} (53%) create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/impl/ItemsPatternAnalyzerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeConsumer.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeDto.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeProducer.java delete mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/PatternAnalyzerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/IgnoreImmediatePatternAnalysisConditionProvider.java rename src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/{ => service}/CreatePatternTemplateHandler.java (58%) create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/LaunchPatternAnalyzer.java rename src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/{ => service}/impl/CreatePatternTemplateHandlerImpl.java (54%) rename src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/{ => service}/impl/CreateRegexPatternTemplateHandler.java (61%) create mode 100644 src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/LaunchPatternAnalyzerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/events/activity/CreateInvitationLinkEvent.java rename src/main/java/com/epam/ta/reportportal/core/events/activity/item/{ItemFinishedEvent.java => IssueResolvedEvent.java} (61%) create mode 100644 src/main/java/com/epam/ta/reportportal/core/events/activity/item/TestItemFinishedEvent.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemAutoAnalysisRunner.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunner.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemIssueResolvedEventListener.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/integration/plugin/binary/PluginFilesProvider.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/item/validator/parent/PathLengthValidator.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/log/ElasticLogService.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/log/EmptyLogService.java delete mode 100644 src/main/java/com/epam/ta/reportportal/core/log/LogServiceElastic.java delete mode 100644 src/main/java/com/epam/ta/reportportal/core/log/LogServiceEmptyElastic.java delete mode 100644 src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTask.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandler.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandler.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandler.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandler.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImpl.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/project/validator/notification/ProjectNotificationValidator.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/remover/user/UserContentRemover.java create mode 100644 src/main/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemover.java create mode 100644 src/main/java/com/epam/ta/reportportal/health/JobsHealthIndicator.java create mode 100644 src/main/java/com/epam/ta/reportportal/info/JobsInfoContributor.java create mode 100644 src/main/java/com/epam/ta/reportportal/util/BinaryDataResponseWriter.java create mode 100644 src/main/java/com/epam/ta/reportportal/ws/controller/DeprecatedUserController.java create mode 100644 src/main/java/com/epam/ta/reportportal/ws/controller/PluginPublicController.java rename src/main/java/com/epam/ta/reportportal/ws/converter/builders/{LogBuilder.java => LogFullBuilder.java} (51%) delete mode 100644 src/main/resources/templates/email/ic-github.png delete mode 100644 src/main/resources/templates/email/ic-slack.png delete mode 100644 src/main/resources/templates/email/ic-twitter.png delete mode 100644 src/main/resources/templates/email/ic-youtube.png rename src/main/resources/templates/email/{ => images}/create-user.png (100%) rename src/main/resources/templates/email/{ => images}/delete-account-notification.png (100%) rename src/main/resources/templates/email/{ => images}/deleted-account.png (100%) create mode 100644 src/main/resources/templates/email/images/ic-facebook.png create mode 100644 src/main/resources/templates/email/images/ic-github.png create mode 100644 src/main/resources/templates/email/images/ic-linkedin.png create mode 100644 src/main/resources/templates/email/images/ic-slack.png create mode 100644 src/main/resources/templates/email/images/ic-twitter.png create mode 100644 src/main/resources/templates/email/images/ic-youtube.png rename src/main/resources/templates/email/{ => images}/illustration.png (100%) rename src/main/resources/templates/email/{ => images}/logo.png (100%) create mode 100644 src/main/resources/templates/email/images/new-ic-facebook.png rename src/main/resources/templates/email/{ => images}/new-ic-github.png (100%) rename src/main/resources/templates/email/{ => images}/new-ic-linkedin.png (100%) rename src/main/resources/templates/email/{ => images}/new-ic-slack.png (100%) create mode 100644 src/main/resources/templates/email/images/new-ic-twitter.png rename src/main/resources/templates/email/{ => images}/new-ic-youtube.png (100%) rename src/main/resources/templates/email/{ => images}/new-logo.png (100%) rename src/main/resources/templates/email/{ => images}/restore-password.png (100%) delete mode 100644 src/main/resources/templates/email/new-ic-twitter.png delete mode 100644 src/test/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzerTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunnerTest.java rename src/test/java/com/epam/ta/reportportal/core/events/listener/{TestItemFinishedEventListenerTest.java => TestIssueResolvedEventListenerTest.java} (52%) create mode 100644 src/test/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/log/ElasticLogServiceTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImplTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImplTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImplTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImplTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/remover/user/UserContentRemoverTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemoverTest.java delete mode 100644 src/test/java/com/epam/ta/reportportal/job/SaveLogBinaryDataTaskTest.java create mode 100644 src/test/java/com/epam/ta/reportportal/util/sample/LaunchSampleUtil.java create mode 100644 src/test/java/com/epam/ta/reportportal/ws/controller/PluginPublicControllerTest.java rename src/test/java/com/epam/ta/reportportal/ws/converter/builders/{LogBuilderTest.java => LogFullBuilderTest.java} (55%) diff --git a/.github/workflows/build-dev-image.yml b/.github/workflows/build-dev-image.yml new file mode 100644 index 0000000000..9dbee6bb91 --- /dev/null +++ b/.github/workflows/build-dev-image.yml @@ -0,0 +1,35 @@ +name: Build develop Docker image + +on: + push: + branches: + - develop + paths-ignore: + - '.github/**' + - README.md + +jobs: + variables-setup: + name: Setting variables for docker build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Create variables + id: vars + run: | + echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + outputs: + date: ${{ steps.vars.outputs.date }} + + call-docker-build: + name: Call develop Docker build + needs: variables-setup + uses: reportportal/.github/.github/workflows/build-docker-image.yaml@main + with: + aws-region: ${{ vars.AWS_REGION }} + image-tag: 'develop-${{ github.run_number }}' + version: 'develop-${{ github.run_number }}' + date: ${{ needs.variables-setup.outputs.date }} + secrets: inherit diff --git a/.github/workflows/build-feature-image.yaml b/.github/workflows/build-feature-image.yaml new file mode 100644 index 0000000000..757cf2eb51 --- /dev/null +++ b/.github/workflows/build-feature-image.yaml @@ -0,0 +1,37 @@ +name: Build feature Docker image + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - 'develop' + +jobs: + variables-setup: + name: Setting variables for docker build + runs-on: ubuntu-latest + if: (!startsWith(github.head_ref, 'rc/') || !startsWith(github.head_ref, 'hotfix/') || !startsWith(github.head_ref, 'master') || !startsWith(github.head_ref, 'main')) + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Create variables + id: vars + run: | + echo "tag=$(echo ${{ github.head_ref }}-${{ github.run_number }} | tr '/' '-')" >> $GITHUB_OUTPUT + echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + outputs: + tag: ${{ steps.vars.outputs.tag }} + date: ${{ steps.vars.outputs.date }} + + call-docker-build: + name: Call feature Docker build + needs: variables-setup + uses: reportportal/.github/.github/workflows/build-docker-image.yaml@main + with: + aws-region: ${{ vars.AWS_REGION }} + image-tag: ${{ needs.variables-setup.outputs.tag }} + version: ${{ needs.variables-setup.outputs.tag }} + branch: ${{ github.head_ref }} + date: ${{ needs.variables-setup.outputs.date }} + secrets: inherit diff --git a/.github/workflows/build-rc-image.yaml b/.github/workflows/build-rc-image.yaml new file mode 100644 index 0000000000..31dc2ff39e --- /dev/null +++ b/.github/workflows/build-rc-image.yaml @@ -0,0 +1,43 @@ +name: Build RC Docker image + +on: + push: + branches: + - "rc/*" + - "hotfix/*" + +jobs: + variables-setup: + name: Setting variables for docker build + runs-on: ubuntu-latest + environment: rc + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Create variables + id: vars + run: | + echo "platforms=${{ vars.BUILD_PLATFORMS }}" >> $GITHUB_OUTPUT + echo "version=$(echo '${{ github.ref_name }}' | sed -nE 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p')" >> $GITHUB_OUTPUT + echo "tag=$(echo ${{ github.ref_name }}-${{ github.run_number }} | tr '/' '-')" >> $GITHUB_OUTPUT + echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + outputs: + platforms: ${{ steps.vars.outputs.platforms }} + version: ${{ steps.vars.outputs.version }} + tag: ${{ steps.vars.outputs.tag }} + date: ${{ steps.vars.outputs.date }} + + call-docker-build: + name: Call release candidate Docker build + needs: variables-setup + uses: reportportal/.github/.github/workflows/build-docker-image.yaml@main + with: + aws-region: ${{ vars.AWS_REGION }} + image-tag: ${{ needs.variables-setup.outputs.tag }} + release-mode: true + additional-tag: 'latest' + build-platforms: ${{ needs.variables-setup.outputs.platforms }} + version: ${{ needs.variables-setup.outputs.version }} + date: ${{ needs.variables-setup.outputs.date }} + secrets: inherit diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index a508772bc0..0000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Build - -on: - pull_request: - push: - branches: - - master - - develop - paths-ignore: - - '.github/**' - - README.md - - gradle.properties - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - distribution: 'adopt' - java-version: '11' - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Setup git credentials - uses: oleksiyrudenko/gha-git-credentials@v2 - with: - name: 'reportportal.io' - email: 'support@reportportal.io' - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Build with Gradle - id: build - run: | - ./gradlew build diff --git a/.github/workflows/java-checks.yml b/.github/workflows/java-checks.yml new file mode 100644 index 0000000000..958772ddd2 --- /dev/null +++ b/.github/workflows/java-checks.yml @@ -0,0 +1,22 @@ +name: Java checks + +on: + pull_request: + types: [opened, synchronize, reopened] + paths-ignore: + - '.github/**' + - README.md + - gradle.properties + push: + branches: + - master + - develop + paths-ignore: + - '.github/**' + - README.md + - gradle.properties + +jobs: + call-java-cheks: + name: Call Java checks + uses: reportportal/.github/.github/workflows/java-checks.yaml@main diff --git a/.github/workflows/manually-release.yml b/.github/workflows/manually-release.yml index a4ac9994db..b40635ee11 100644 --- a/.github/workflows/manually-release.yml +++ b/.github/workflows/manually-release.yml @@ -19,11 +19,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: distribution: 'adopt' - java-version: '11' + java-version: '21' - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -42,4 +42,4 @@ jobs: -PgithubUserName=${{env.GH_USER_NAME}} -PgithubToken=${{secrets.GITHUB_TOKEN}} \ -PpublishRepo=${{ env.REPOSITORY_URL }}${{ github.repository }} \ -PgpgPassphrase=${{secrets.GPG_PASSPHRASE}} -PgpgPrivateKey="${{secrets.GPG_PRIVATE_KEY}}" \ - -Prelease.releaseVersion=${{env.RELEASE_VERSION}} \ No newline at end of file + -Prelease.releaseVersion=${{env.RELEASE_VERSION}} diff --git a/.github/workflows/rc.yaml b/.github/workflows/rc.yaml deleted file mode 100644 index 98d9ca8724..0000000000 --- a/.github/workflows/rc.yaml +++ /dev/null @@ -1,80 +0,0 @@ -name: Build RC Docker image - -on: - push: - branches: - - "rc/*" - - "hotfix/*" - -env: - AWS_REGION: ${{ vars.AWS_REGION }} # set this to your preferred AWS region, e.g. us-west-1 - ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }} # set this to your Amazon ECR repository name - PLATFORMS: ${{ vars.BUILD_PLATFORMS }} # set target build platforms. By default linux/amd64 - RELEASE_MODE: ${{ vars.RELEASE_MODE }} - -jobs: - build-and-export: - name: Build and export to AWS ECR - runs-on: ubuntu-latest - environment: rc - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - # role-to-assume: arn:aws:iam::123456789012:role/my-github-actions-role - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ env.AWS_REGION }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - with: - mask-password: 'true' - - - name: Create variables - id: vars - run: | - echo "tag=$(echo ${{ github.ref_name }}-${{ github.run_number }} | tr '/' '-')" >> $GITHUB_OUTPUT - echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - echo "version=$(echo '${{ github.ref_name }}' | sed -nE 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p')" >> $GITHUB_OUTPUT - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build - uses: docker/build-push-action@v4 - env: - VERSION: ${{ steps.vars.outputs.version }} - DATE: ${{ steps.vars.outputs.date }} - IMAGE_TAG: ${{ steps.vars.outputs.tag }} - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - with: - context: . - push: true - build-args: | - APP_VERSION=${{ env.VERSION }} - BUILD_DATE=${{ env.DATE }} - GITHUB_USER=${{ secrets.GH_USER }} - GITHUB_TOKEN=${{ secrets.GH_TOKEN }} - RELEASE_MODE=${{ env.RELEASE_MODE }} - platforms: ${{ env.PLATFORMS }} - tags: | - ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }} - ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY }}:latest - - - name: Summarize - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - IMAGE_TAG: ${{ steps.vars.outputs.tag }} - run: | - echo "## General information about the build:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- :gift: Docker image in Amazon ECR: ecr/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_STEP_SUMMARY - echo "- :octocat: The commit SHA from which the build was performed: [$GITHUB_SHA](https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11f7c0cd29..ef232831f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: env: GH_USER_NAME: github.actor - RELEASE_VERSION: 5.10.1 + RELEASE_VERSION: 5.11.0 REPOSITORY_URL: 'https://maven.pkg.github.com/' jobs: @@ -21,11 +21,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: distribution: 'adopt' - java-version: '11' + java-version: '21' - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/Dockerfile b/Dockerfile index a2543c295a..7953abb037 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,20 @@ -FROM gradle:6.8.3-jdk11 AS build +FROM --platform=$BUILDPLATFORM gradle:8.4.0-jdk21 AS build ARG RELEASE_MODE ARG APP_VERSION -ARG GITHUB_USER -ARG GITHUB_TOKEN WORKDIR /usr/app COPY . /usr/app RUN if [ "${RELEASE_MODE}" = true ]; then \ gradle build --exclude-task test \ -PreleaseMode=true \ - -PgithubUserName=${GITHUB_USER} \ - -PgithubToken=${GITHUB_TOKEN} \ -Dorg.gradle.project.version=${APP_VERSION}; \ else gradle build --exclude-task test -Dorg.gradle.project.version=${APP_VERSION}; fi # For ARM build use flag: `--platform linux/arm64` -FROM --platform=$BUILDPLATFORM amazoncorretto:11.0.20 +FROM --platform=$BUILDPLATFORM amazoncorretto:21.0.2 LABEL version=${APP_VERSION} description="EPAM Report portal. Main API Service" maintainer="Andrei Varabyeu <andrei_varabyeu@epam.com>, Hleb Kanonik <hleb_kanonik@epam.com>" ARG APP_VERSION=${APP_VERSION} ENV APP_DIR=/usr/app -ENV JAVA_OPTS="-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom" +ENV JAVA_OPTS="-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom " WORKDIR $APP_DIR COPY --from=build $APP_DIR/build/libs/service-api-*exec.jar . VOLUME ["/tmp"] diff --git a/README.md b/README.md index 791a2c1eee..742e13338d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # ReportPortal. Main API Module + +[![Docker Pulls](https://img.shields.io/docker/pulls/reportportal/service-api.svg?maxAge=159200)](https://hub.docker.com/r/reportportal/service-api/) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Freportportal%2Fservice-api.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Freportportal%2Fservice-api?ref=badge_shield) @@ -6,9 +8,9 @@ [![Build](https://github.com/reportportal/service-api/actions/workflows/build.yml/badge.svg)](https://github.com/reportportal/service-api/actions/workflows/build.yml) [![Code Coverage](https://codecov.io/gh/reportportal/service-api/graphs/badge.svg)](https://codecov.io/gh/reportportal/service-api) [![Maven Central](https://img.shields.io/maven-central/v/com.epam.reportportal/service-api.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22com.epam.reportportal%22%20AND%20a:%22service-api%22) -[![Docker Pulls](https://img.shields.io/docker/pulls/reportportal/service-api.svg?maxAge=159200)](https://hub.docker.com/r/reportportal/service-api/) - +[![Total alerts](https://img.shields.io/lgtm/alerts/g/reportportal/service-api.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/reportportal/service-api/alerts/) ## Copyright Notice + Licensed under the [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) license (see the LICENSE file). diff --git a/build.gradle b/build.gradle index b157bd1b9b..1ff5d40461 100644 --- a/build.gradle +++ b/build.gradle @@ -15,10 +15,10 @@ */ plugins { - id "io.spring.dependency-management" version "1.0.9.RELEASE" - id 'org.springframework.boot' version '2.5.12' + id "io.spring.dependency-management" version "1.1.4" + id 'org.springframework.boot' version '2.5.15' id 'java' - id "org.owasp.dependencycheck" version "5.3.1" + id "org.owasp.dependencycheck" version "8.2.1" } import org.owasp.dependencycheck.reporting.ReportGenerator @@ -37,124 +37,126 @@ project.hasProperty('sealightsSession') && sealightsSession?.trim() ? apply(from repositories { mavenCentral { url "https://repo1.maven.org/maven2" } - if (releaseMode) { - dependencyRepos.forEach { path -> - maven { - setUrl("https://maven.pkg.github.com/reportportal/${path}") - credentials { - username = findProperty("githubUserName") - password = findProperty("githubToken") - } - } - } - } else { + + if (!releaseMode) { maven { url 'https://jitpack.io' } } -// maven { url "http://jasperreports.sourceforge.net/maven2" } -// maven { url "http://jaspersoft.artifactoryonline.com/jaspersoft/third-party-ce-artifacts" } maven { url "https://jaspersoft.jfrog.io/artifactory/third-party-ce-artifacts" } } //https://nvd.nist.gov/vuln/detail/CVE-2020-10683 (dom4j 2.1.3 version dependency) AND https://nvd.nist.gov/vuln/detail/CVE-2019-14900 -ext['hibernate.version'] = '5.4.18.Final' +ext['hibernate.version'] = '5.6.15.Final' //https://nvd.nist.gov/vuln/detail/CVE-2020-10693 -ext['hibernate-validator.version'] = '6.1.5.Final' +ext['hibernate-validator.version'] = '6.2.5.Final' //https://nvd.nist.gov/vuln/detail/CVE-2020-13692 //ext['postgresql.version'] = '42.2.13' //https://nvd.nist.gov/vuln/detail/CVE-2020-9488 and https://nvd.nist.gov/vuln/detail/CVE-2021-44228 and https://nvd.nist.gov/vuln/detail/CVE-2021-45046 -ext['log4j2.version'] = '2.17.1' -ext['log4j-to-slf4j.version'] = '2.17.1' +ext['log4j2.version'] = '2.21.1' +ext['log4j-to-slf4j.version'] = '2.21.1' //https://nvd.nist.gov/vuln/detail/cve-2022-22965 -ext['spring-boot.version'] = '2.5.12' +ext['spring-boot.version'] = '2.5.15' dependencyManagement { imports { - mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.10.0' : 'com.github.reportportal:commons-bom:6aa55fc0') + mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.11.6' : 'com.epam.reportportal:commons-bom:5.11.6') mavenBom('io.zonky.test.postgres:embedded-postgres-binaries-bom:12.9.0') } } dependencies { if (releaseMode) { - compile 'com.epam.reportportal:commons-dao' - compile 'com.epam.reportportal:commons-rules' - compile 'com.epam.reportportal:commons-model' - compile 'com.epam.reportportal:commons' - compile 'com.epam.reportportal:commons-fonts' - compile 'com.epam.reportportal:plugin-api' + implementation 'com.epam.reportportal:commons-events' + implementation 'com.epam.reportportal:commons-dao' + implementation 'com.epam.reportportal:commons-rules' + implementation 'com.epam.reportportal:commons-model' + implementation 'com.epam.reportportal:commons' + implementation 'com.epam.reportportal:commons-fonts' + implementation 'com.epam.reportportal:plugin-api' } else { - compile 'com.github.reportportal:commons-events:e337f8b7be' - compile 'com.github.reportportal:commons-dao:34829fb198' - compile 'com.github.reportportal:commons-rules:5.10.0' - compile 'com.github.reportportal:commons-model:e0a12669' - compile 'com.github.reportportal:commons:ce2166b' - compile 'com.github.reportportal:commons-fonts:d6e62dd' - compile 'com.github.reportportal:plugin-api:fb8845f' + implementation 'com.epam.reportportal:commons-events' + implementation 'com.epam.reportportal:commons-dao' + implementation 'com.epam.reportportal:commons-rules' + implementation 'com.epam.reportportal:commons-model' + implementation 'com.epam.reportportal:commons' + implementation 'com.epam.reportportal:commons-fonts' + implementation 'com.epam.reportportal:plugin-api' } - compile 'org.springframework.boot:spring-boot-starter-aop' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.springframework.boot:spring-boot-starter-quartz' - compile 'org.springframework.boot:spring-boot-starter-freemarker' - compile 'org.springframework.boot:spring-boot-starter-actuator' - compile 'org.springframework.boot:spring-boot-starter-amqp' - compile('org.springframework.boot:spring-boot-starter-batch') + implementation 'org.springframework.boot:spring-boot-starter-aop' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-quartz' + implementation 'org.springframework.boot:spring-boot-starter-freemarker' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-amqp' + implementation 'org.springframework.boot:spring-boot-starter-batch' - compile group: 'com.opencsv', name: 'opencsv', version: '5.7.1' + implementation 'com.opencsv:opencsv:5.8' // Fix CVE-2021-41079, CVE-2022-23181, CVE-2021-33037, CVE-2021-30640, CVE-2022-42252 - compile 'org.apache.tomcat.embed:tomcat-embed-core:9.0.68' - compile 'org.apache.tomcat.embed:tomcat-embed-el:9.0.68' - compile 'org.apache.tomcat.embed:tomcat-embed-websocket:9.0.68' + implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.82' + implementation 'org.apache.tomcat.embed:tomcat-embed-el:9.0.82' + implementation 'org.apache.tomcat.embed:tomcat-embed-websocket:9.0.82' // //https://nvd.nist.gov/vuln/detail/CVE-2020-5411 - compile('org.springframework.batch:spring-batch-core:4.2.3.RELEASE') - compile('org.springframework.batch:spring-batch-infrastructure:4.2.3.RELEASE') + implementation('org.springframework.batch:spring-batch-core:4.3.9') + implementation('org.springframework.batch:spring-batch-infrastructure:4.3.9') // Optional for spring-boot-starter-amqp - compile "com.rabbitmq:http-client:2.1.0.RELEASE" + implementation "com.rabbitmq:http-client:5.2.0" - compile 'com.sun.mail:javax.mail:1.6.2' - compile 'net.sf.jasperreports:jasperreports:6.12.2' - compile 'com.lowagie:itext:2.1.7.js7' + implementation 'com.sun.mail:javax.mail:1.6.2' + // check authentication error response format for versions higher than 6.18.1 + implementation 'net.sf.jasperreports:jasperreports:6.18.1' + implementation 'xerces:xercesImpl:2.12.2' + implementation 'com.lowagie:itext:2.1.7.js7' // JasperReport's export to XLS uses Apache POI - compile 'org.apache.poi:poi:4.1.1' - compile 'io.springfox:springfox-swagger2' + implementation 'org.apache.poi:poi:4.1.2' + implementation 'io.springfox:springfox-swagger2:2.9.2' + implementation 'com.google.code.gson:gson:2.8.9' + ///// Security //https://nvd.nist.gov/vuln/detail/CVE-2020-5407 AND https://nvd.nist.gov/vuln/detail/CVE-2020-5408 - compile 'org.springframework.security:spring-security-core:5.5.8' - compile 'org.springframework.security:spring-security-config:5.5.8' - compile 'org.springframework.security:spring-security-web:5.5.8' + implementation 'org.springframework.security:spring-security-core:5.8.8' + implementation 'org.springframework.security:spring-security-config:5.8.8' + implementation 'org.springframework.security:spring-security-web:5.8.8' // // Fix CVE-2022-22969 - compile 'org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE' - compile 'org.springframework.security:spring-security-jwt:1.0.11.RELEASE' - compile 'org.springframework.security:spring-security-acl' - compile 'com.github.ben-manes.caffeine:caffeine:2.8.0' + implementation 'org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE' + implementation 'org.springframework.security:spring-security-jwt:1.1.1.RELEASE' + implementation 'org.springframework.security:spring-security-acl' + implementation 'com.github.ben-manes.caffeine:caffeine:2.9.3' // Fix CVE-2022-22965, CVE-2022-22970 - compile 'org.springframework:spring-beans:5.3.20' + implementation 'org.springframework:spring-beans:5.3.31' // Fix CVE-2021-22060, CVE-2021-22096 - compile 'org.springframework:spring-core:5.3.20' + implementation 'org.springframework:spring-core:5.3.31' // Fix CVE-2022-45685, CVE-2022-40150, CVE-2022-40149 - compile 'org.codehaus.jettison:jettison:1.5.2' + implementation 'org.codehaus.jettison:jettison:1.5.4' // Fix CVE-2020-15522 - compile 'org.bouncycastle:bcprov-jdk15on:1.69' - compile 'org.apache.commons:commons-compress:1.21' - compile 'org.yaml:snakeyaml:1.32' - compile 'org.hibernate:hibernate-core:5.4.24.Final' + implementation 'org.bouncycastle:bcprov-jdk15on:1.70' + implementation 'org.apache.commons:commons-compress:1.25.0' + implementation 'org.yaml:snakeyaml:1.33' + implementation 'org.hibernate:hibernate-core:5.6.15.Final' // Metrics - compile 'io.micrometer:micrometer-registry-prometheus:1.7.10' + implementation 'io.micrometer:micrometer-registry-prometheus:1.8.13' + + // add lombok support + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" // Tests - testCompile 'org.springframework.boot:spring-boot-starter-test' - testCompile 'org.flywaydb.flyway-test-extensions:flyway-spring-test:7.0.0' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.mockito:mockito-core:5.7.0' + testImplementation 'net.bytebuddy:byte-buddy:1.14.9' + testImplementation 'org.flywaydb.flyway-test-extensions:flyway-spring-test:9.5.0' } processResources { @@ -164,7 +166,9 @@ processResources { } } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 options.encoding = "UTF-8" options.compilerArgs << "-parameters" options.debug = true @@ -191,25 +195,10 @@ test { exceptionFormat = 'short' } reports { - junitXml.enabled = true + junitXml.required = true } } -jacocoTestReport { - doFirst { - classDirectories.setFrom( - classDirectories.files.collect { - fileTree(dir: it, exclude: [ - 'com/epam/ta/reportportal/core/events/AnalysisEvent.class', - 'com/epam/ta/reportportal/auth/acl/ReportPortalAclAuthorizationStrategyImpl.class', - '**/Abstract*.class' - ]) - } - ) - } - -} - publish.dependsOn build publish.mustRunAfter build checkCommitNeeded.dependsOn removeScripts diff --git a/docker-compose.yml b/docker-compose.yml index be3ea15f13..ee9e4e2b8d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -70,7 +70,7 @@ services: MINIO_SECRET_KEY: minio123 command: server /data healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ] interval: 30s timeout: 20s retries: 3 diff --git a/gradle.properties b/gradle.properties index e415066637..489863e567 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.10.2 +version=5.11.0 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom @@ -12,3 +12,4 @@ dockerJavaOptsDev=-DLOG_FILE=app.log \ -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 dockerServerUrl=unix:///var/run/docker.sock org.gradle.jvmargs=-Xmx2048m +lombokVersion=1.18.30 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100755 new mode 100644 index cc4fdc293d0e50b0ad9b65c16e7ddd1db2f6025b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch literal 0 HcmV?d00001 literal 58702 zcma&OV~}W3vL#%;<*Hk@ZQHhO+qTVHwr$(CZQFL$+?np4n10i5zVAmKMC6WrGGd+F zD|4@N<RpPXAOQft!2tjO`2QLJ0MP$B0suh#JxdEK@l%V-h|mH9$o-q6bsY~k-(Lsb zzlQXGI!g1)h>Hj-D$z)bJV;MYNJ&!D%)v-fQ%q0JG$_z5GVUJTPg0MHPf1Tvic<kX zo`)DE9~Nqmx1tgk9~M#sp%SAY6{6fZ+&KXLml^*~^1mMq<nOhugX#bERR5<B)IWVp z9rTT?jQ^jmi2v^D>Y#6DXYBBQ4M`$iC~gA;06+%@0HFQPLj-JXogAJ1j+fRqw^4M` zcW^RxAfl%+w9<EUj8>SiS>QwBUTAfuFAjPXc2DHf6*sr+V+jLQj^m@DQgHTPmAb@F z8%GyCfcQkhWWlT31%4$PtV4tV*LI?J#C4orYI~WU(cSR{aEs^ycxY`1>j1po>yDMi zh4W$pMaecV*mCsOsPLxQ#Xc!RXhpXy*p3S2Hl8t}H7x#p5<WRyv}DXB?O~G(<$s$* zKaOKsPlhxwVsG;yzcbFHI7dn;N@!ew>V6G5va4jV;5^S^+>+x&#zzv4!R}wB;)TyU zE_N~}nN>DTG+uZns%_eI=DL1E#<--Sccx30gvMT}^eu`2-u|{qQZ58(rA2aBYE*ZD zm|*12zg*@J$n|tbH%Mp|d|O9W%VT~<mtdFxoyg6#?kijTREKTws{`nYl9fj8r{K~0 zMu0f8cYQ}X31$v~y4H25-D)q8#heTIRfC~{opJg3^7Ooc5b-v2z7D{(ZN1$J#;pIq zcmMvi?bwYCS7hZ>xG})R=Ld5z<(z%DOO6=MF3Xh-aF%9Hf$?1N9%8Pkev{wun$jZ2 z^i*EhRt8Ve<7`Wyz~iMZDye+XVn}O%qbhV`wHL+%P+n)K&-UMuZw^RRfeQ)%K=k*m zq5l7mf`4K_WkV5B73~MxajljrjGiJqpiV#>0FkyyrB)@HY!;Ln(7JJ*W(>d5#^ubU zVAkTMs*CHzzvUa^nRu0<X(7d>*f-(ek+VZw+@P~}a;;(K=|!9Mhv(~y-ml<QTm%4- zL1zFI0#z_Ik&f69<7WJpKZ%Y|Uqu8u#Yk(|li~Oe@<?YCJc^N4pR#=?u7HeOb+Daw z|1Sgu27*?6Lo8NeuhnoJFCu;@efib#$O1fA8h!C$A3(g2{2*g6<8h|8Ec!-=v=sD! z5+_Ah8OB$HF-qv~DCJ$~4dt!FhNO9dmXjvoKr;QMam!)kspTQh=u_8Z=lVD$>W);J zb&bB=vySHG`u?j&_6dh^*se*l_B3avjlE|!!Cb0pXyEXRbLy*@WEQ4|)M<`p8<Y|5 z2%93>Q!rfDJ2RI!u1hPzNjy&)(kcY~GaD6?)7#dCbm`NF<g;7l5g5&;Mj%py#Ra;y z1f5hxOf`Wvp;B#xff%qI8u3<?PxNalP0$dvK)<OJ=xo<{oLC}PR#F@5qU=twiZ#W7 z67lXxhom0vf~r;n1SbcUy7Uvu7@IU>h?Y_g$#!+Qrie7%<7P}<-+W@{sxi4JYI{iY zk0(>m$DxOI=~-&eXf2bfh^&(U@o)>(iA1_wJ%B(+nFH+ceib%H<b^rOPv2E&MDz*+ zr2XQfL74H-frDv=SY0Pdq#DCW*_^D%3zICZ*|CytwcjZFf`LbQNP;uT36ha5;8j5z zkkE-B2=@&q?8HR?nCy^Lm13`I{xIWZ1-Sv7kk=8002K(!NL~T5$eRP+<1|gK;}^wB z*p}nK<Oun@j9xNT6dC~v8w$#xy1SB~x_g%Ag&y;aA<D=3-H_dVde~Z37)+5$(13@U zpgVj10XKJk#h1vTR=Z&VxVMA@vy>Eck32QL=J(BNFh`f>St1%llF8chX7#cp*;z}& zcTeXkwsXhf+e;#<mHvK))RWS2J3{sLW+lTJ7aYn7N;z>#!FS2yi=2cChcYfzm$wQJ z9%4kAq)wLHf5wfcj!A|xDsAiAOHRzf*)Z-|daN9y5jK-*R{Q0?xaSX-3m|WeuZ`BJ z>eTi@uQ{OGSDIJ#Iu@JPtOy!C?q)g*6SHORg)eAJGh8b-I*X_+xNqZ|OXEsQ-RWte ze`zjjeV9PpE3ac2za+Rs=PA;%QZ>T{x(TRzwWLp_X^2yC-DOEMUy5So!npzL&-@}u z#>uK#&`i&c%J$!bsntEJhY@rF(>6eY;6RoI5Qkn!&<80X5+1(<A$tFH9m~_-ye9aQ z>x$T|wR-ad?4N1N^a0)nBj#&EkVvQ?I_+8t*%l#VK&I?uo$ERI1HMu4P2rLMeH%m3 zZ|HA^*O^dA$gb<A+8nWE*k|^~9YyriduFNhhxV~rFy`G?Fp=Nyxg%Hcw9t{3e=8LB zF)zo5Es8J(TDV5xlhq!cIHF5nZif)&_hum~A2pjjr;tmkr{n=0C`K<u%<PnC^Yk2C zzTu%X@i-=%OlQX7fplhWP?xe~(g>$`Cw;z9?G?m3@nH6TNYJ04Fd-M2wp8@(;vAvJ ztFoni)BLwncQ3@cO*^+6u;(&D<;N;RKb)_NQ_Qu&?@h3MWvo>6FHG%%*smTwj3;dG zQJnT7Wb?4!XmV^>N@ZkA7Jv9kAfD-gC<I~>Hu2i+!A!}y98SO><8g}t;1JOOxj>#l zM!?y|j5fR3WY2(&_HSGjgMa?Zif<<W?VbNO!_NOT!vCCUg=}4ItZem-{<X$>M@d8W z)4>Ptm@zj|xX=bbt$=j}@a_s|xdp6-tRlq6D|xb_;`9oJlkYF1AH%?Pzv$eIAogMi zf(_H*5t({Arfs5XAPj46pjiudQw?dulW-=OUqBVa)OW9E;^R+NDr&LES&m_nmP>Ga zPf)7_&Gn(3v1qu_a^qW9w4#XIEfgiHOQ(LDi=E&(-DcUSfuQE0`ULsRvS}fpS@<)3 z|CbQSi49rU{<4|XU;kiV|C7}Gld$}Yh5YXjg^W$~ovobybuZ^&YwBR^=qP3G=wxhT z?C_5Trbu~95mOoIXUmEOY646_j4ZL)ubCM{qFkl1u*%xs%#18a4!(*b<&edy<8t2w z_zUxWS5fypUp9ue+eswoJSyv*J&=*3;2;q9U?j>n^q?)}c8+}4Ns8oToBJgD;Ug=y zOa0>{VFrLJutjR{PJmm(P9lPzoPi{K!I{l)pGwDy59p-uxHB9I&7zl11lkCu(}*A< zh492AmxsgwEondBpB^{`I*L&Ut40fjM^JS8VdAWQMlwc>_RUM5|Mjes!36DGqW`xs z4tU4`CpOk|vew8!(L}fEvv5&-3#GqZ(#1EZF4ekDQ@y*$tMDEeG?nOUiS-KXG=rAZ zHUDlMo@X&yzo1TdE6b6!s#f{*45V-T3`e2)w5Ra3l>JWf46`v?Y6B&7*1$eS4M(3% z9C~G@<i(!>N@RXm)8~EXL*9IObA+PwD)`%64fON_8}&pqjrg|<uecKJ--R_&hYSS; z45Wc65)1%>2LmP{W^<0@W`9s^*i#F}V;E8~`-}(4@R4kz?t(RjA;y-r%s^=)15%C> zbF;NZET~nybEsmUr8sH^Hgq^xc^n$ZP=GcZ!-X-Go7J4nByj8%?aQ`c{88;p15K<V z_d~|1+?4Of*5i$x2xWRe8tvdys2dG>f>|0h+5BLkM&@KI-(flp^npO3MC~W@Uyjv* z6Hu!4#(NtZJ0*;_{8<J7i=0az&%(<wS04-($bOqbcbe=uYc<`1Rb#j%;6L!T%ZS_V zMbGG<3YW{=7)G%MCMRNB>^xcLrC4-zK$BVo7S5V=eg?R8P;BOpK3Xwms+Jt-8R6us zf_rUHFYHn~lu!)U$e$#%UBz7d8YS;mq}xx$T1PIi=4={c-_cY6OVc<=){mOVn>~J$ zW*2PB%*40eE^c<dlxK9Bvqt-M7aU^3PVe-^Jdu~jOmq^mOt%KN4?i~W$Rz0zz3gTI zO10DxC0A~Xt|6f*@>+d=PP7J@bqIX_h4u6b6#W|ir<;IlR`#s`Q*_Z8Q?*s<ipU}C znJI(0^W}FQE#0cJ?}zrKq&LVFW@=gW@-3uOe9H}<#JHT}p&{DB{3o-4!x`}b_o6VK zx_QKsJ{r-=Y5h-fZFj+CH)$d6Y$&chBrmxO`M#7{#wFMtQhdY~p2sMLLWhoXb?h@o zqg!S0;-k+JS<Moesi8@EgD2<{{X!b%EaE#h7NN;r&^HdO_%wt!GRa&Fc2{T!e6b=# zR{1MnI@pu!?=15b)mgWnY9L&^02S(JQaRCkQ;Kui#Z+B;pq{udS&lnShF4(1SIHuW z_)%trHzwlpgrUL&*@|H!)`f}k!qoM#LZ&1o>_&emuu8D;NSiPX9mK?>$CwcbjhCuv zO&u(0)@}8nZe=Fl*0uMri02oYDjs#g$OHCZ6oTXV2Y0TrZ}+o%{%i)OAJBj2xHC<V zJg9%`K&ii}iRu3%^Zw04ZtncfPG-h7PUeRCPPYHdL`jNQHVFJk+zoOlEs{gZeHtJ7 znimR5MLxoT^yYLVBxdPK8L8jt{UFO$u48m!?v&9G@X}rYxZ`f7l9c8UOJ8-2jyLQl z*_^Bo7cVb4066<)!Rl1%wRJ`Y?9s?jEp_R`8W<NIo+JHW*BWBI%ys7bID+TFxbNr0 zg8kH&^hA{M+H_jg?|E)3>|F5o+`Qmq`$`2EaL=uePwq%k<;6S2n=w%_9vj$8NO|{` zTEg*tK8PU#DnQ#dQ2mMJaaL|HV;BCn?eQ%d0v<K_HfTbf-99?GlXN@q7NMtGV#^~A zK1d9eZNcZH-)WwCa@$67YlGe)%B~iBRrS~FY!viVx&TJCE(I}_;Va$O+>Y@S7Pu@7 zsf5u`T=bL7NfyYO?K^PR_|jap@<F00udMd{#(px%QdVnBTcYiwhKRCg5kIbJ&~1u_ zrU;RW878B{gMOhfwk<0v`+xLRW`sq8l(<7+S~$Su=ixAq`rqIO8X$Uo3r%K*M}s0L zq-k1;4vh%TP@XBF-yn#eDLwk36xRnKyD%`{C3|NBLAn4q+#Bbi=^EJm?vhx*>K|qQ zmO8CK+&O3fzgEnp2|_=^K9ln~QhxjgMM>EQqY@k@@#np@FnZq|C{EyEP7^NurUm0q zW5rKmiy%__KE>YItA<BWGcGAzq0!#vJ2KS5%v%gT395&RU@W@)Dr)Tn2kOsw{~c(u zSvk0UumAvvH~;|n|8JoEV|}Yqhj7zUb^eYuahEM988Xy-UJYlAF%(_K;EchZ2uGZ_ zSiKipR%56?V3VCsV0tzaNpm;URQKcCLNS93ZVcuFhZpm!WkZUULZWk`r`A3dK$SR4 zpYL+YD{2IJ>TyMhE({0%ve10la=mUd<^AcB{T_$Y`2_N-x;F#3xTORXvhPZ7psm<b zUAnad>qhXy?WxxB5w!m*4&Q;?t$4Kt?m_em-htVDxora24&6~5z$MG(RT{trtp(L( zy&VDT{@p9_DGoq+I|abw$E!TyTO7j6dWQ<wiR)Vy(!+3D@A2&nAbX$*_zCl^0^_SH zZS8Bjj|=oF`kCPG%W`)Gz_O?7CFhIbhw(}IP3>25dqdKV*z3E?n-p|IG42ZUnNok? zY4K{y{27bUT@#|Zcni!tIgjE`j=-0rl(tVlWEn>5x7BJBkt0iw6j^4n1f2i^6ebo; zt^&Yb##}W0$3xhH&Nz*nANYpO$emARR6-FWX;C?(l7+}<97Ay#!y%BI6^st=LaJ>n zu{ORVJ9%`f*oy85MUf@Fek@T_+ML0-0b$lkEE2y8h%#P^<E#sUGr^uAAmf?6z=dV+ zT2fn#MB!P?mV-Ijg(2<QZP<B~3_RY+-a>X6+cn<CYt==OX!%7nR>)IEXa@T7CQ{fV z-{^wJGN*+T!NsAH@VNM3tWG;%y{pV<xGCY<FKd*exDmpl{T&W#b;p$ig}qG|?>F2m z2*0+i?o40zSKVq_S18#=0RrJIse+;5cv#a`*`wNs+B%Ln8#e0v^I>7a_33h?lHo14 zg)CbDfGMyH2cj%7C`>|Rrg;U?$&y!z(U10>(dHKQsf9*=z)&@9u@w%y+e@*CnUS|E z*O^cQqM*!sD|e!u(yhXPi$Sl<$daf3sq@Ie<ZQHLniQg<q{eeW>xafxt3F#2R&=cK z!gT-qto{oVdGUIxC0q`tg)B-Zy(pxGx}&svoA}7p=}jb3<Deq;uYCwnOS;Rr-^Lgh z20WA(rh{XxcSiiGTc2H2eqX4eS>jEjQ!v6=afKI!2`&M{#tY$~3LR}#G#U2up2L{} zMGSX>Yjg6-^vWgeX0i;Nb0=gQmYa!|r0rRUshm2+z3AlehjfTqRGnRAmGhHY3`R_@ zPh4GAF@=nkRz;xMO3TPh$)9Iq?Fs5B@~)Q<G^#^w-p1z4@tK-Tg<F4M1#K9OBJnk0 z+Ooh*FXc;ku~92E;V-A4fXBlIVb(;ppgmHu!r^G8PLCtrG%kb2we(sar!y-`MdAy{ z`=|e8**Dv6<X|mR*OrwDm@5nX385dEvX#Jf-n>IntSyeBy^10!ts?9Z@tK&L6xJd9 zNzaaz<rXw;6ED)9yFL}aX;}zw-PcebRxU3jIEY~o>6zvrtr&MPQ@UD)njFUtFupwB zv+8%r`c@#asm}cKW^*x0%v_k3faHOnRLt7vzVFlqslue32rt(NNXnkS+fMSM&^u)8 zC`p{on>0pf=1id|vzdTnBLB;v%*ta`o_lzj21u+U-cTRXR%sxE%4k<(bU!orfsJ&v z3FLM2UT_*)BJm1^W;Z{0<d(!lZ_}A{gA{p}>;z^_e=N&QXSO>rdB`*cp>yGnjHJt$ zcJd~52X&k1b<-`2R{bqLm*E(W{=|-)RTB*i$h4TdV12@beTkR&*iJ==ck*QlFiQ52 zBZ|o_LP06C?Sgs3VJ=oZQU0vK6#}f9gHSs)JB7TU2h~}UVe%un<qkD{F?01SaaNX7 z)^EWW&3Rg@z9Zs4r{qbscuGj<-Fl||#+VyPb-*E+wTI3OW@F;)#D4fM>JA!URBgJ# zI~26)lGD4yk~ngKRg;(s4f@PccDZaL{Y=%6UKHl&k|M@Zc4vdx-DX4{belQ);URF? zyxW+|Ziv}%Y<r9Dq}a^~ObiFm4~Y;n`Vy<s!I7z$$Hlk&*e$o<6C~KU;}qG?cDDWa z>!sFdY@YO))Z|f34L(WjN*v#EfZHn6m)X@;TzQ@wIjl4B_TieZY}qY`mG}3VL{w?; z&O>sZ8)YnW+eLuW@rhClOOCZe2YP@4YWKN?P{c~zFUj*U?OayavPUo!r{uqA1<8h! zs0=rKKlwJYk~34F9$q6fQ&jnw_|@cTn{_kA8sUZ#2(Lb@R$NL*u>08yYGx{p6OeX~ zr7!lwGqMSury(v5=1_9%#*MORl2apGf(MQIQTMN35yE3l`^OS7r;SKS6&v-5q}Gw* zNWI*4OKBD&2YbCr8c{ifn~-9w-v+mV49W+k)$jjU@WA+Aok01SA#X$Sspj}*r52!- zNqOS<0%uMUZeSp+*i1TEO$KGKn7EwzW=s?(b5X^@3s5k*80ns2I2|bTHU+bWZ$x;j z`k@<m7i|D;)p+5h2=doQb#<n7oFI?h-8r2Le0MiDcODojim!C5C7&lD!*Tb;{j^M! zwo4_dJ|LYnc7;R>>)1G#JgT=F!8awgol?DqK^S4R*g?<j)Em0v<Rr^iEUud)JcOH( z;j}xl%Ki+t#kp}5-1LyHCEG}dwhXenu4yedz7AtrlzTlWS~@$is%I}VLm5qXh=H9c z=RD{ouN=1VZE5UvE5AADipriSPn0vLPSj+*b)YLV>e}2rOYRVMUKKxSudO(hOLnnL zQqpxPNouLiQFYJs3?7!9f6!-#Pi83{q3-GgOA|{btKup4fYDu-JFOK~Q1c3KD@fdJ z?uABYOkHA^Fc~l0gTAy4geF<-1UqdS=b=UM6Xi30mPhy1-f^aQh9H(jwFl5w*X`Mh z=Ee5C<tYtM&3HgW2B%f^TRXT=U62{6MBC$8$4Z|{?j2f=zZggy{xnO!otRFog--_9 zp;oV#6Ml}L5D_jvr_=ldE2?RSY|XQmVlDd>?038GEqSVTd!67bn9*zQg-r8RIH3$$ zf8vWEBbOc`_0U{b)t)Toa~~<7c-K_=G%*iTW^?6mj9{#)<L8!847Sdr#z3mABv$w= zEvStNJ~?l6I@Kk@27iwDE^HS$6ph<mYmV@yOUSNX1EEp~l?On9(o~Lc2;tl5;RQ9Y zjkp8xA(PaCi5E)TBzXDOUUEn0z7y?nm3B)!K6veo!9no=A7=FnV&NWZ@_OCgt8Z-* zR9P?lL2XPGWimt_QAsr$D9B_!LBI3p<p05_)1XA)RxB@nlp=pHL$;+Vb^E1Us>@|# zku9R^IDzbzzERz~fpxFrU*it;-Iu&<j;5*?pXVX-!@&XPBzIw**a7Oi8iCxJ)wdQB z-72`zNKM;jv``!`ozd8#?2)|0QkGUfElI&!1G)TUX6cXI*Q>m!CAtM&$)6^2rMyV4 z$+e!$(e)!UY(Sc9n6hkr^n&cvqy8}NfZz+AQc8fU9lNczlP>5D3qzWoR55YvH94^* z-S%SVQ<IE2ZA<>96pK3|Yo`75D&85)xij9Dl8AO<OG)v-)LY{lc$!e^^sZ4&kUDTL z^8>8{J*{_yhs-KtsLXUYqwieO(nfrkB@%|OyI>yF+1G?m7>X&djb(HBNNw3KX;M<Q zZL^M3x-GBRRlsrxmBt?Qt3_3n8|H*!`NZzQv-X~G6~2==G@5ah39Zu^LwW_nQbk3# z-gS{_`P|gn@Cwo@yVPf&Tulp7%VS@>a*oMV)cV0xzxmIy+5>yz>l_LLH)VyRnYYce zw$?q!hJzX0TlE0+o5QJDM~sPrjVCN7#|32#rUkc>?-eN6Q0RqQTAl~`&isrQg)ass z+x5XapaYh{Dj`+V096?w)w2!Cnmh?x1WmFC$jEFY4;V)XAl3*tBS)V)3TbL)g46_g zCw9pl^!3OCTOcaEP!?==guEAw;VZ}fE6K-;@qD-Rx~td+j(N>)Wv$_mq<O4G#`)_D zg%4ybW4PuW2>FTH_wVZNEEuDG!0T`HXLsf+_E=X3lw4`_&d5&YMl%H733ckO){vZm znF<wT-MSz)%0zh6H-vHoxb5hdUc&M}_nclvZU{HVN=o#;5dP|r)y%ciy(qvpjJJvY zFPLuYy}zIz(W4UF%1lwDB^|<#*Js%z1-~NS!lW9UOtvABw4uH1lE0Q}&5B+_p|MQP zWQ5y{y$#BD9FWrQ!2?U%&A*_Vp;=C9mDx6@bF4qx0(m#y8VoU9b!eK(bZyymm!B{0 z^hKOxhD1l-sIn<bUyT5jU0GYC3{4xaCT_doFRk*bv0S(zBv-DrE4P++w-{Hs*`hrI zUXE)^(!e)|Okq9Oq8x7%Li<C_Mh2jl2%!%z>LS`;5J#^`5~unet`V#*Y5In3yb|Ax z|A6b^F37!_z$_{6h{7l~<{u7{Fx*A*#zw{GD)6e}n6f<|)&7`S-txiz3Jm4S5hV&8 zm|Ncc{j_~`^pQ*I#w21;(jwi8GnH4efO;R|r4<G1p%Ku<jzuUqgF5G$#u;0Y_4VKy z(y0*MvA`MV-?s}9tXk6{f++pmOHa}y`+-3@Seh2+f1TuN!2FS)^;MgoZ6CF?HKKuQ z+SKF!^o2&LHFUuvqQ}h6(`V&A+69=iKPfqG;f0Zs)@MJ=ChHlc?hBZ+R~fr{3zbP8 z=F^FEG2*P{{(y((i=t{)5Mc*ZZc?^gV40BhN0Asi<H-J;I!<g>$tH~i;Bcmp^sP9) zjhJne@yzU&XvFNoc~i(wQ?nE`o6Hk~!;x(%xh7?zvigH2g`!v<HwxDXh*xMMM<3HW z_4L_Fy~v7Oy+?S3!Iq}+)$tv#C5(_ZnW6~n9#W&J%Udh6PZE@~ho88dPWG4VLjU#d z*ZMl+`1&p|7H1c~Cbw4~{?qNRP)w;Tz2zQOmeZpFR7|6^L9j3U>8L-vEN0DvV3?m( zSW(TZ%2AWf`rS}GGMqUj!8yCp#|fR--Vxfj=9}YD<U6o`xy0)+sf@3V>97Gocdj=S z0zkF-jsO>EcPTB1zRO$++k^bH%O`=UkHdHT^5?{$)ot<-K2XIE7js*4OjF)BsVjCJ z*KN<g*T3%mQu%p*>)!FdM*sh=fB$p8*EzZmGJp?B_=a-90$FI{S$LLjBU$(lxUj;9 zIBszmA*129W+YE;Yy{J~3u<Twd*;f=9Y}3|Z{SIuZ0cY+jRWz)tb}ITlr##&NYEYC z=%IE*Kowigv*k{XF8F|)GRMAlI-`F3SD9!P!qhNGS)Ep`PBV#qo)ZBA^+Bd^m9cs~ z$`4ZiX~slGCz}>yOr<2A(`*cu0IJN#tmUfz2jIWQi_h)_-V6o+5CjbX!1$lz6?QYU za&|O#F%~hmGUhil{M+J|*0<3&{a1%ONp-^!Qx*LOTYY}L!r9BbTxCjHMuUR0E(uH` z!b$*ZMdnB{b2vsb<&P6})+%O=%a8@~$fjbtfF@Z>^Q@enTOJ%V<CRnekz2@P*(BWn zCbTbLtoL3pIvQP110{Pmu@v|7nq&9FR?p7M)w}G^*B34TR$q-1SA?lX?tyyKq=lP| zD3b1?os1~fOzA+%;&o>T)Rdc!wX|@iq9i}HaFZAeY6g8xGZY7h-r1sy_<#YU6}I?L zwvf0ePE5PKbK>2RiJOFO5xNhMY+kt`Qi?Oxo&@xH$<^Q;Nb(&rjPBAcv;XtmSY90z z;oIFFl%lDq$o&kYQ;aSHZHD@W({Y1hw<-I>7f_X8wc?%hNDlo~Ig;63RlHNhw~#R3 zA*f5D_Qo`4_ajY4Gr{mLs*(Fxh(U%oua_u3r%`H!TI)@R!!iqV8IOhIOzI@=7QJ=G zV$(9mEVL(7DvPn0j%_cOZN|vvNg8*PHma`6+oS;PDz%iOFyo0n0e%$<#A3r~$=I0T zDL*{AREUGx&C2}?I9cVL`UcPyawTqA4j-4%Mr-4`9#8GX1jiJkKGpHVr1~Rj#zFaZ zqmE!<|1JCi!LDG?1^Ys62xz(p;Uu!QZB7!C0#piy1_9=e?^s@-sd1gs!h$;Q`TNtf z3N4Elsgl#={#U`~&}FNvH78MLjjavl1x*4pNVr338>%sfHu>bxo2#eZN2ee9q#*Jg zDk_=OBR;8t6=pBN0aj)&Nj}pzqqUYW(tfk?bXTdKbNQFSUMCyN-!b0#3?Z;ijzx$M z^Eo6Eq*NO!Y8K;84H4MHj_xwBYc|3>+D(PFj7ejhECG@5@Pk&8dG<)HwwO2~j7KV6 z0$s}=*D;ek#8$a*sxVlC_`qFkM0%BQQ@v2H&Aq@G9XCQt^^x<8w*=MbZV)@aPrrn; z`6r*&f`x&1lp)`5>-|-4%l&W4jy~LydfN;iq?Y8Xx>Sh#2Lx@FXo|5{WKp@y-x;)7 zl;;<Qz|a;@wP~yH(!0er%z<lyLwxk~5K2ICIx(q03AW??arZ^Re4=vD+%Qa;I&F4g zI?4Z}!kS90ccrTM|0F)(Ny9-x)u-w(Q0I(6NYylHaaesf-hgEvl07qa8t-ycTfDaU zx7ce8&_aJAsH)F$^4CN*dou!oK5rsAM1OQNDH3*Uz(&F7NYT1oE0o5oWkLM*;uv*K zt$dbxIX2IaJ4#gFKbn?$aS7zCp4~$VPn%r6s6ueAExSADz!%@`ZRT#}|J@axf)XB9 zJC_Y*Qlfn4E~S>_Y*-Nu3pcH-)p0(tP~3xO_u~>HpCdEfgyq7V-!ZZ{?`6v_b-vx< zuu|gm5mG6c@D{FYMLuzvG+A2T&6&`n>XM%s`+Qtj)5XdpyFOnz3KLSCOxaCEUl()M z3b~FYqA3FT1#SY{p36h%M^gBQpB2QzEdtM9hMBMRMu{<KhV173&yh!JiTXWL8LIaT zOjx!yF5Y~@2QX6?DmX7nm~fkm{Z=drRxd2qWGo6EcEsMotJG@|eCqE$8T1IdA2uFI zn)L8bboxf1{cvO<Q@CY#O@6OuFeaM}OS3a6yRyDk|7FFl&M9HVISd!A5ySJfXB33< zH6Ltk%G1=U2^SZIu+0}{BiC(|w$#xf^zkq58$yREuJUj#$?~IEG^NJE=l2b^_JBhx z+Y?~cTRocOh^0T{LyC78IFM+nKj{%WgVjn=P|8f&9pPIyl|H3PkJYSQp)5(^7|$-( z2j9D3tgu@G8h9loVyBQu^A&ug*qw%WMLijkRx=5$S&Yl{7%gc(JqLz!!&uGXuunqr zLPD-~Jf+!(a!($Jv3A~xOXDDXYyx;#rq<I96eLi(M5<|vkQdKDl#dvek6<wl%igd( zBCtLDygreDi)2j!{2JK9BW&Tmw*z-MpB$g4!?h9izxxVj*{Wcm7cvqE!aG-k<?B!l z_W^ErgCRVa$zc;t>|rf}(;S85&|A!|Aj}?fMKaju!y>_AS}#hRe_!&%8V=6+oPPtE zOOJ-Rcrf>hNq<InXW^Acyh4TC67d>@lG{{@$H?6ikt@!A2OePLe{MBIWSPz7{u(I} z$PXzD;leHG?Xl0FnWt+Wr<rd)0uIC(aO;XiGnyqUc^y$z?J9`@apilEzT621F50PL zR^-affr-}-;(F?Jexj+E$T?v|csvv}yJ`y-1=;3z`s9u;FtRFIE9TQisLKt0+W|T| zad(XQdi&&fvX1gimra6ziGzr)?_|StV|w^6ZSOyqK~(O4_g6yx?yvke8Y0pEC0kQ= zG<FcPwKkTrwY7A%`=^FTaYJT<51t!}$R)~uF;Nl{NrIfHaS(KU9!fZ0kB>krk*|<T zm_!{ku#RvfFJE^l5~Nhj`%<u{teoQ_ND>e3P~YVF@N$y<VvG03=NpJF5EN8CO5Baa zP^%AQ9{~YUAT{w$t5R2JHh>&L929cc=#-!*k)HZKDo8!#+t|?9p0z1KSDKclB<j;< zSnOn_nFSh*+F1`LqurW=nESvpS@FG>&M6~hN5<9~^DIltXKR$+iK<Ozh!vaHa$Q;G z>*h9k$|@Qoy9H}PSI;b(v>w`8(k70@sfa4nRweeiwZ-syP3zPSsyK_8Te9*(FQdm+ z84ZDah4PGehH72w=Q8bx;pK5juT67rJKb|ovD#COI^l6z0eBidn$!Y?T2;5sN+vTV z$`%Edb<%-Oq@NPZy<2Z3m;$}!9JzIuVK6;fJi>><V{U}bUe=tba9BbGLiTzA7eS}O zEs!1TshDr>m3q!Lr!2xXRq+l0LvZIR_PNYrP57E#sCvD^4UU2GVr*Rx`QcT}yQanF z3i~!-2Vkk4S%4Hd2baDvrM2g(&1jZaA1!vLi!I#5wX6g^&PE`0-TovM(%wuaPXAno z`a&j{ai=TsgKpc1C3|)tY#!4>SPBbMnchi}glCBwaNE(4`gi}JY0;`|m`s{HtaP@& zHxwCt#2&z9A7O+=v>za}LW~}G>_tWo$dsRX)f1L=+tZF5E&RBA#jUC|N9ZPa_&z5= zekCOsIfOh`p(&S8dnkE~9#(;BAh8qzi5JYT0nP7x&Hga3v`XFdRN|$5Ry#mq*AN$J zV)l~LSq}2d{EJ@%{TLnkRVn*sdM{_b|4!x73|Ux9{%S;FPyhfZ{xg;P2ZmMuA*cMG zipYNeI7{u98`22!_phwRk|lyX#49r%Lq1aZAabxs6MP79J3Kxh0z1E>MzLS6Ee5u+ z@od~O#6yMa;R}eI*a|ZB$ar0BT`%X4+kyxqW4s+D3rV176EAsfS**6-swZ9OIPRZ& zlmIH>ppe;l28`Kd0z(alw^r<%RlDpI6hv)6Gs?GIpffKApgx^)2-6jAzjZE0BtPBC z0z8!#C5AP${zTF$-Z^v%^ie8LI*rvR+*xc=>fa;`SRUSLAio?qL;jVFV1Bw4K>D+i zyEQ}vyG2HTx>W?Ul&MhxUXK7n;yfN)QS`foM!4>4-(PGwxW!^^UyKOz(v+1BejI*& zQSkV|m5=JF4T0k*+|h|3dx`ZKBVX7H4{5iakAxnD#J=9igW@LS;HE_8$lZy1l|$wX zn<8-$u=7&li+^MB(1y~Mz7lj7?oYf%1k{wT#?(Mep094qqnPv7*OYkQ#7$pkU5U24 zzPLEwAb<<WoR&Nlw`OCRo!3>VIp_uUE~+r5)jt(>>Bg48_{)twH$QJDSBrUS!j{lX z)SK$6dfLWt)c9%Cml+sRp*OHXB?e<YL%nKD`AAfR55^ByJME|HKb?>4hbYZQo!@=6 zBPTpi&6&atD*#Cn6f@5<>79Mq7o0^E!NH)bD26g}?@qg%*AYeE6Tec@F?y9Q8i}^s zz`)l`8>;h75!kL!`&*<Cny^?$4#8Bbz^Rj<UZuvxBLNOENOw?+Y)9a4NuYnKrPi1- z;aFNQBSLVm(ME4w-NKhLSdhpfirJ`XcIKUEjk6$hIOg92XpA)f7NifoL_0XapO0I} zX^FjDP!O(linG*Rj~U7sKAV?8wZu)jVnS?eAh3aj7BfEa5XRr9a?q7dp7&V}E4EJf zjO=`cLvj#rX~~JksAh-kp58tE`Wmu<Zzb14`_rEmRdp`mkfb9wxGje@y<REs#!wtA zx%z2uQnW~&@>_hsX1%2)(lWr|7!}@gn%MfwY8vN0=pMm3WesCRv5e*5m4z|u(zb<a z<hzW!8Hc+~5!b;%r;imxC73kEBD`Far0GlqU&(W_5t(`OF<afCTSd%Y3K%Yo<w1(U z=KKreIbU=DF>YCpuxO9$bY)hkL|}mRj{3dlRgNK)#PJp#vR=k<Ex81u)$5OX?%u|0 zOu&uBD^9m;wj$6`$vpi4irSYi7AFjEFC6nHIIqerB24Ul$z=YW;9^+`7`hM)@4yW5 zr@#R19VHAsm+%0*j5(Ws3B_wu$j)vHkR#XRdHfL@&dHt&>a^TZ(tKVI<>M~ekIfd2 zm3UDUNW*ZvS5L|SF334|YD>LJk(EqgPpVxtzwclUNaH70zWDVt^1+cz|F?RdF4HHn z@4~Gs`lj!0dWi2n#>7C@B$Q<wpK@Qa@7|8Xjv?fC!Jhr6Y91c`Ad+yRc|YkmvV0zd z@N1eZD;xjgqMOX6H0hOE|0p$ru9Ag7lE!O{qPw&bgtVSxMYdGBOX*H-97G5mQqqY{ z*f%6LYn9wGDgN@?to?*kP`;J;$YbK~a^1{wUHLzuTO%@P@|uW>f7|t{1!3mtrO1H7 zi{=I#^Oa1jJiF<s{+1D`W#Q@uEQ|^u$n>I!j>PualW+ncHJ)TelW$bv2MqUG1xK7R z%TsQfTn)7D3}XYU+{?Hq!I&fqi4>DmryMiO?!aN!T4fnwq2vsuB^s6fPW@u*h-JwG zNniJFR(RI*?5HV=tqO)lv}CRv_eNEBR%z}Vnftv0+<L2TR|d~&9c0$|63rt}R#`&I z(}Mb-YqN4psHxY)BHNtvE|HaJ{&w^r-nDl7*OHiSc(6#W0xj^B<mPz^7AL`As86Z$ zdTu)l7LmpYF0UcII-t&#l<w6iiL#=825c&`kAgbp2ju-#YuT1M#4B-*ktfQ<tDw<1 ze}=5f6VQ=TR2w*oj|W|g=La1WG+NxSwo+A(kEPn{9%(v>DUH^OCODH#&;{+aw^1vR z-c~|Mk+o?j-^Z+rR4s<fWU8E{OXgT6m@b4f&bk3mV#sq0#Hv!gtIJYN2h`5GX+ke> z-gNA5guTuab7N`{Y@eT&)!xF8#<YnYQKehlL|Kqf9>AeetvQ6d!W4BlO;0#0TxS_( zMm-A-u+h7-PjmOQHlh{Hxn+J$jh?uEtc8RG8tu->o<eV4;cW9B){Rg)FmgRhNN>g@ z86A%eUt+P8E3oLXIrq#K(nCF@L12>=DVT3ec6Vn=B^B;>D=O%op+0BT;T)FHZ`I93 z^5|bpJC_kB92`alM40Am>Yz5o1gxkIGRYQ)x^+R|TCK)r;Qyq6+~S9Uy9nr^nkvc- zxw~#_9eBBJcZNK0yFZxUK4h>u$8;4k-KpNTblRgS(y&u~u&J;O!aqAMYJp+(BED*d z^I#F7vPOEADj}Pziprs=a{%qgz#eso$j`At7p<W_8t?MLKPKsl80)I%mY2++&U!GU zrt?3swTZ-+h~N9mFFKg!wsEP^yexxyN25#GR-^SrnGl!$(V&k=GfGS9yMzwlubwo2 z{`EB>N~bDw%&ba-+4pI}T*?w-z^_~DfD~Z3Tg+#M#u{s&uRF^dr5RFZh7<|WNEG;P z-_SzXTbHc^yD$r;WJqqJkA7^(zN`nzQ5V16nG~Zobuy)a)(T@<ha)S<cs(qVX&ObN z2UVTBWWV+20tc%<OXgDKjf+FdRfQms@H1TiA|=cT&G>Ik>V!qOf<yFMm{;2;Q41`F z5eqDf$B&;Z(fL<ROep%u!{R=O48j%AQzT)Z9T7G=5J}J5^QZ{BL?!t=1BV0BUiUEH z03C*CZ6eQPeDZPJFt&p9ke_v_;IHIaFY`qyR7jL0zX#_<dWj_3?#kY#wZ?LT&*Zir z8WiG{n9jp;hfg4ZRrauCsvRoPJ?P{ITj5;tT82Q)(7JN8YEC#C71)@XIjYS9r>w;e z)?AZXjzDJg%BkIEY&bm&BczLuWY~k}3Zyx#)jxg1A9R`sz!_dCb!|13b*3PiA@(E6 z9HmG2R>-YrW93UMQO}XE4loI(*er9J*wDUd1se!pzdp<L$3aT<v1RADvUBMM+QQeJ z<z{5S)X%p^dzb8X%ro~YV>oB_v6^lQl}+!6e5MS`+bU#_b*a5Pkt;o+lOV4loyn2P z$3;z-cX>$R{6M4q%b}aMBF}6N+0RCE70bB;XwHV~JLO&!EB)Cgo9ta_>>Os1HNfaY z4PNu7BGhw`6}cm>glh6i^)Ja{rpLHix?C?u;(e&GI{?!E7$9hd*5c^iL?;6Kwn z@qbBE|3UMF|F$Ok>7YY?CeMzMes@CZJQ?&|R8v5M@XvW}jjxhjl`gzl;rvy6Nn9$K z;1TKGpUgZs`vR!t-sD~2<GqGgCoXc~OBH8i>ar{58-;2k`H(MIWr_cujtSCpjue(R z(a7R{q`G+;8qD8D1e?1zWv+pPFtk=k#>f`yqZo)3KwCBgABgQbq%hu4q}h+Bdyh?* z#Rlr*$38^Ru%m9FUTQL2Xy^j|f%*4H*{zWFRsMbs6@u{JM{48fq;F;QFV%6Dn!6X0 zEAr2G{RmY8;Jlmws#%7Hl_TvQMbLnN0KGK=9)1u=Vb&#V27UwM#U+)$hn#hlXxBxO zM~<3s(W;fe-0%mVWtZ)oN|h-01@5z=u(z!V>)I9-IepH|_q6NR_DA>2hxGK<NnR*m zWk2t+J}{L{{ATAL%!~{q)|e=iLSn4A-~C}h1q?=o?ha9+Eupsr*SeFGw0p-zn^-5u zu;>t-QX;H6(^FXwcBndi1s%qn2sH-rsuON7*ARP6Qt$2XIy3d#cn8sLh&7#USTFn3 zQm-o6-Bnofon2V;oq-v1@Ye@NuH$Z~+th}Cs>F7=H#=4PKLp%-!EwR&0`a}XL=br< zF>&?HNr}9ahB-EA7a({^_6`taBwmB~hJG)p>8r^vq0J_+o`sOq<{s2~2t}W&1f5`l zj;E0nmt?YRp{ONhti9{4&rvt5uoS0CO@%+Yv>+}ROQAGP3VLu^S4fe{ZRoGviEXMF zhM=I=Eg2~^5PIwEq{~Wt?inz13!axZU3knx_)Ey9<)z<=!TnCPHvs1l^spF`@INYQ zY|J1RWri-^D9mVY5Z<j$Ujv8AlCwzWydcK4C|+vv1pTa1iR$dG6=ZFyb~2D_cqt9U z3LS@qozPiYcF)#+d>{u+bXg#}3rUwSXX>&@PN+017W@!L5H8CvZf0wZxQ=UrHJ{Um z$Z;~3t<fSfV_$nKB$9GL7$e7eGk`|rFBnpk*l@Ms#aN18Lz{qD!dbS8_3AD&uT#ok zHo!>6ARGql*O1^YY(h4awy!h_brE6&k9B&5l;ya>jDyW5?o$q~=1iV!t7#8&QOx6P zhQIm55sij*Ef-G_?k^$AjK2j?=QQ?^=r{MDaGZ7`Y<Ik^MKRub@OW%3<1o)yw9XR$ zV+vp_%4EHfekP<b7G7B$#O)B9)Lf8$QmAE>o*Kp1uoZ=&5|O)D#xAHL)n9_l6-E!b zVV@8ny;`XU#X2((4cTmv5unmYzUmJ>Hm+Kvht&a+j3nr!sljTHUZn^0w@L|WKw2TO zRO>T!>jutIzNI5U_KL}vd00oi6$aJqPeJwq)lIr(2Gt#52i@sqCFaWC)pS$pYoRCK z<Am&vynz5ok1xL>d*$)r6FCClYp+n>gCqVF>x)ghAbl+h${~Mc_sQGk@+sR@b(88l zcx?*Usr}v|kV!RPfS%HK>Bn{7tdEV$CB5Z@=uy4>^(o(%@R|_7dq69s1(X_8szPZ! zSS~$LCX>-}F=io=YcY~9!vqo3&dh9_Mosio<F(tfcLSN-U)Vcue&bvsEh=lKD6ppL z6qI#&c+@~lX-+#F)tl51AhP=|DK)1x+fWoa?xN2jH<zYk=E_8&m7MhuZz-RhlB}ae zp2uQgS$=R_-5V00)NB-;DWBuTtVMJ(!fcu{Uh;g;m+zjEJ{!?s_s*iXMv@daoQ`1Z zI;?<lJc#B%Wh=hBo~~fr)9RCQQPzw#tL0c`1NxL`dLmHoc%e7WFdx$_=^QdjZ^2Yv zbegXruBz-cttz)ie=L{QV3DD2Jz!-4#s0>`zO6i|$&p;-9%+~sdYNrVE?Q8rS+eHx z4O$l|b3FUT#2jb(WU<`oKAjGQUsoCgE1(c>3byBNPhKeJ7f4S-hBRqRyePY)im;>H z)hyFuFTDqx*ZgXo$hn+u>TGs~=Bjqr3bhPmXG)v8){EU;N*58NKU5;EIZ<q#-eG>l z9%|JomX+b6M#jS2`B%~!+`EStMD{|y^P=`xPbD$o6;|!((h!+y%7Y{DuC!NCKDIN1 zER-J?vZ$2el4y~!<J6G}$XW{+?MSbe>-0vWjNRoC|ARB`IX@M&;?ZpULcAIu`zlH9 z&JK#H);Ij~fqoT{59}OI#ViA%!lPYyd@kHg*hyI;iMdCtw2&eLHOd1*N%2Y!BG*H_ zu@E?VbtZlI{7B{C>A^b3njh=KdF!=rQ!)oIjwkP{t^I{2q&<K(evUD+TLJYkvRec7 zYZ$&1>emQ-C1&U&fPC_viACTbT;(A3qRJeGINz^!0N26vQ~o|#pmjp-Zq46%+{X9n zLGKqhLh4`-(*oDHqHU~-45_+pe(BICF$*0jD&FW?ED=vn=t?p9X(%AH9+;6NcJ8JF zASkf}LfT7Z3u*#i$ml`gKIS>3jrTla--x##EDM{w{>Iu9qV!x95ECU*W_O`q>hcCa zswU!;H3R{}(A6aQ(B)lImTF$BzF;$V_?It*+8ZeiZa|b8n_DN4jUfI0jIA<yNEz-< zUAZU5rNnB5g&~PSflg90>6Q6*c0f(uq~DxrNm!$~G=Uz=qP*)?qc(}|7MQZT&B=Um zr{Lj_R7QJAlwD=CoYpjQsUyu1)C9p5CE)%3nb<t{qTHZCa3>)~WtP;@6(qGG`*qDT zS(zM>&R<;Z23V|80%3s!`0<bQH?H)~tkw2Eq4I%CK{w1nB~7P!a39`Gm_(f;5IclH z_Xj~YoDf^25IZFhTd@e;xP+73;-x+qR|XI^C>QpTt0Ay;*xLJeE|DP5@x?a!1)`g= z-1}G_LxiiO(*?R*{(yH#&yl|Seyx6*+ETayQtv7Htk3WPvI;U!@h-e$)gw9>pyKmB zk8#$3BF-ou%=`9_3)Q`0ttk$cymvULFS`Khmjes=2(-QY@eVjJ)rSD)z)1No&o+dz zrGItPZ$QuD;Nqt~U{J?9VlM0g{kx!4$?!?=o?um>#7tjMzrLfv<@pI&cp*5H>XPPZ zu8Xh<Y%l^G*aDwQBur}de;dit5r?efr|696x8R2CT@&l&Cx|39HUn<!vQ|CwedGQ+ zD*>&6y7v0pGDiQqd-~tBjK%-SO8$8kG&44|{09|FO5BoNkV6~JX>g{b#NHJW?gmM# zhbcS|M9fDc44(seG%$hK#va#4YL98mddGDi2qr;@CeiWO!!`DrF<%=_^*3JgoZiSj zdEv30G5`7ex`XP4#6cG;AQ}(|>CcCTGiom^pc*j-Mz1_oGp4iP*>N125YeWCw#L4H z*>u2Ih8jVRJ?rOj-7KbU7KXpYs2UZf)Vf}(lsM(oiB>tgqX2tILJit<W`zs#E>w_x z&7gq;`b}qrL{lEA3DaXDOi~HQ!^?xxjjVW|#Z+Ek&GKA2dYgO@zB2V*eY<n7t=eX> zx>@D06X)(FUz3xz99V3v*k7x|wxiFxv>=N$1Chfp>CErJq)gnf=P!u-QKrYnulzdQ zP56u!AH2^QVnuxTJjcQtlflq>PSm4C!$^fv4V_XsIO2d=O8|J`4bUDtjBchJ!14~3 z#mgUPYF*Z?k;Y)Igdx3yQg8L)M=c%}p3!P-0KOuXI+{*LXJ&w)$gzxeTyr`)h-Nc! z`$xa<>T2pbuU0VR?#FPEM44XDRw+cM6U1R2aLQpGHX40=4Er=lp&2aN#P1IA3|r+L z?5jaRyCgN)b(KuS+(x9rPLLjY&4^YY{0T2Ai%`f0p}sG*R!}{DSf7GdPJ=C2MT1ND zUJ@#y06`CNc9n?13R2KY1K*SYeV87wG%bjcIbn+AR8*FS<{?wWomTT5@`}~z3bFAJ zLR-wmE$iwwJ-Tn<Q5K*6H7Xi<7gjmiO=VIt?rKq7b!GrN6Ul@)bkLRFm0!xF9aqiP z9_Pg)EI}1<$M(ui^AkIKVo;qp+t%8pBvqRv=D97`;5VVg%UOaj{Ceqs=^8hD!q*o5 z{b2y#Uku~@H)X^>VEhl{{?+??DJ?DWk~VaX-L3-RLtprT2%z-GfD{UVBR~T}zymA0 z6VZ;1Qr%5q#+Oz#3)`D(%WVWWS4BW6%ZvAtt!u25FO@e{X`)_LH>p&pFzx(wvNEO- z!2$Z}`iynmY<d2b`M>2j&UCmRNB)9Cn3MXRls&PFVHzkzr;)B^BCMY~6lYY>0rsKT zm4}RV`Q7tbn)Aseay%@-I6ZT~PBsO?D|>kG*%(PGo=|gZ#0zsmE})xxtAvaCe&$1? z(7GyH&^jm!cguuMo@CPA&-lrdE&Aq8GIOuUK9jt{K0ldcvJJp7I`ZMx-EYj$)hl~) zFM!U~HxgO+lb$1cIK-nvz<5OPs(@d4tB6DUa3?-bJ98|dv-kIdtMS;9BuLc{a~_wW zO$u`rNyms<O+qXSuTB+_W%5p)Jq_HP^8*g_)!h=}PWkkjk27Z;>AeMH9zh(|w=<*V z&&B{&O0Am`<$iBa)>pNZ6cO`d^3B5%=gmsH(HYZw6!U(c@}#)19F}`BT+yOfamJY$ zYOmy2m^k+ADH2klhAJMLq;6>t3)NREUgk*cjJHg{NBkVhDORNK;v5362&NN=y*Ef- z$vxYTG5Ga{SI&C93^Gsu9G-osqbC9PbsC&@xxGlF?o{!rs9|YpEE?P8ix#yS`7JUy z%ez(_Q%I^RwPrW%rFF(+mE}rp#Wtg@^>O7T(@LFA7j{LNrL=XGDyB-|3<*mqLL_UA zUZz?ulF$5O59-WWZ!d@hRxC@4d6?okW%`1$#<5w9eh>4Cyr#xe5%VPG@TBe#HA^O} z1&q{T_TMTr($f<()ah%TXapiGp}`MAC7>0I=Cx*t+bXy+gMyk*#(A~ft=&4YBdQki zQ}I=c;etc@sD4?l`eYaksPtJnx5OUaZ6u;7p64DUuI`omrWjht5$8+cqb6Hw75WNX z@D(fl7tDl2H)H%QYyX3>cL0*DZPv8+ZgaP7+t_W}wr$(CZQHhO+qUig`^@>y%s1~j z6Y)pXii(P=SQS<4iS=aOnR(rqe#b*BR~GN+bMNQSnhcMHxh<oN+p_*@?ZNyQ{F31O z4E(hxex*(G{Iznmp)Gk__F1N9vOiHL^vV{PrPRnf8^HwQh!M`><eZ~9Id5FLsN8(T zWClYsF`O<sI`U$&kp#I1Sy1`gABIV;yhM^m^}tM|Raesy5y-{-dNa!|yaoL08X}v# z=8?LVzU@GDTGec@{th$%Y08sH!!r4Ymb6D^;y=69@L3iOE5?Gb@cNc_En3;Md`9l4 zVmfd<8t7(o`$ZKNh{eZ6&m|E}gc3K4jbKJ-MmJVcjLZ-V^~}_~4VG5H&rI_AV?#wv zKoSJ+qKyM;L{U|Ajc-&GjmVJ35Z=<e<A`nPrUOcwU`$QMY1WdIAS#&~!iQhz?0!Vx zbE2uC;P1zV_`0Ro)qnY@n*2AR@c_qQYG3uaG}MslD)yRHX`%&nhT%H%3p<IB=z6&z zQJ#?9X8{6fu4Ng}+LKglZ!a?ZzQV9%Z37zNYdyhWOdgH+Ak|q$qlV#yI;{lze|1(0 zR{wnjF&{!{`VFq=KczFKut~7<`*bI=QxwS!B7GqsEiWyVw&wML;O5L2I)|_-9m&!s zj|@bk5+hcIgZf7J*V7@0U_DS8!TdgR-a`;m+mep)T+1q~c#7$ZnmSE58r&o!6@W8p zDvXC3GeNj9s(m9|d`1T$9K?EtO~zc!7Z82^b6Aw(X^dvfQ+Hz?eHc}w0Axg#DE$nG zoGT^#Y#x{}k^mh6S^$Lh@A#m-#$3`V+LJT#l(yeygL{i<zi8TdVb0^sp+Vn$WI{<Q z>Vf6<CY86L9HFp!u$yM-M1NgDbONG~<QWI&+`0_2j6e7YN2dw7uYo7|);1uLRqz=R z7WV?4CgAnP>D7_zYs}@<K!DfX(WfX1Ai!~EE^8*KT!Co*K{>oo$eK9sZig1_lH0|C z&<1W;8dh6lutS+|02t0VqRfh9R+%!~9YsQ>cw-uGi!YMSo?19?Sty(u{GRqmTx8Zv zLz|nph}CNn+4a~dDzMog(j+NForDvDjLwub!b;p@dLHSBO0kjaI0CPZ)8B2(HNL&A zdr8Pw@u(POF1J*groJ~!1|E(Gm<U0SF<{bvqbm<z{6eP~UDu5*>nR3L6`P*3C;v?R zDw-pBC=u%}<}P_);mn-_cE}am&b1_WlqnWVzFS;*NhwoOb%+#0nI|H*Bw6_0R(=Kj z;7@eEqYkW2OvWkoz|yY1gZAJw8=>KShthS*ANzYdDT61^AK)>0H%LV4q3}hw?bkA$ zF$tz;<5T59v0Zd$)unmJ{vu_7eGDP6+pe(H&n^3E)g^rB?pn?GT<XDnE%*A{E#7oq zG^wO_f)9^{h?|RO1$KVF*JJ`JPlc&bhOtC&o!4l`CQ_6>9l1gztAUpR*+Kvt=FE~M zq5rZM&9v>ww1mzrK)vx*0;;?tnqA@Q;FBC@$2~=gy#jW$bAJUNIl_YpT)``*9nnkV zF!&XBK8(PeQfnScH*JaYqy{1bN4MwF=&g2)`!Kuo165*d^1Sc_d{I4>6V=>74c%g4 zXE_M`b@syq%jQx9VRp@ba!rY|MRhr!S3bN!1RT}^I(2gXE`KT57Y;maGA&dHM#`4* zy%<P60u?#!lJ{hm+I{teQZ&zA%?=v`TI>@6YB0A6Z^?fg!$4Gq0auM47(jE$Y4osH zhydBwQ-S~vMS7)hg;AC=MRf~AHZu|Ue*bk=ff`!Ol1%=|W-a+~l)QH04q^oeMZHj~ z8$8jQn(n1#O!_7sg1hi;{v%?nd&gK7<l$g#FetZCyif6!)lL5J_%)fl8&{g9&-fuI zz}MTJG%Z3cbXI$Jg<E5E0dl6)`j@n)Jz)^~Fq8EZW}-Hqi|_b2d3Rs8(yL<c3)rz- z6xoiA!n!^AcaS$lgcr%Ad1r!HvKx8#RJ#mI2slyAmPqU)^{RrG{K$}}>tfN3I{A0j zcg`ISk^Ir4G=(SvV$v}DE(nE+%rgFkT%cu5VR0Qa^H4-xPC*7Y*+<jZ^$o*_eeFvF zsTfD%_k_3XOEvj-<agB__e*w)d1E<m;`ZUQ!WT++G{8dbm+UF$SMwN72+DUqPSM1A zwTS#HfvDp*5>E8#xvyepS#xYE+FyIIi0|5$J%mKAB58%MgleT%Zx42e^L`TdA~Ips z=NvgHNpYZju?*J>oNcmd^(nFUc+-bu4*+9)qIwU^g?1_4-&-`uZm&f7F^1?@3I<Pc zR+jZ}=8fI>vJc{gnlh?no$<XHR=hHI%%?`ym%)e<m+sK?buh9+gMBvu!{q@xu@_Sg zL$w<39);`)8C-hm**vC?Zqy1NIpW&I7Vl$$s@COLjdoK=`O4y62~<uW9d$E)1V}mq z&1tG?e|CYuI;ov5(0@bx@$pLnnRPQ^>E9jFIfJ8i+33;o-!b2hD@}}{o}J4{l{44v z3Cd{3Lj%9^E43SBXmIvwsA2_8sXgRu=4=H{j9R(fYcCzOXriTZ51l+HcXr@)^?rK* zmc89=w8MW+txdobBh`X4rMvY#vuv0GIEO67sgL}mIw$pNW6s8Fd<Bov!}@g2V8>=t z@58{pFs^Oz&g}CPr8EL~QyUjk&}1qyO4;-6m0MRd4J9T2r5_j+YdeKP%Q+jnWNdV| zUJLU&d%m|g&3B83R^8K^WM{0at+=9UdVAzTnL+CqdcT#($38|-fQ|BJbHY4vk=ANj zvX?ek_oYp6t8bQz-T){|-5OGrv`IGd?>X*h(s{MvQ{j>fZbx<^-)&(j8(N+z^sftB z;V$0+Wd0oUR^&)Q+2bHfLt#V~jZT$UPU<McT?X43`{{xPGdu)fXen%p1BR%`j);!s zcQ>bkd#vD#zZJ&huG+-;T%sU~ONA?a`Va|T%I0yd%0*Xr3>p#slVg7Y<6o&Bx856S zg;7Q>mCFF?xq_m}VG5`(0fIX(V=yvQ;xjpwNhrLFMui8xdBw2aFOvI3t6-NG3%+d= z>1un%A{1+tFrn2nu2%`-hiqYhXDga3%{ZVkC@ROtTcA;g*E@K4i_G1&^P#Pl_9*m& zwBVKqZhrf4<CZn2jxKjiiI5NgAJti7cg9jZZMx)u3Vl*fh%q=`I#Rf>bhw@M)78cm zBMB!;A)H{6<Kn{rpK!2cr*s82Q@$}Dj(7rR*&p2Xoi)!3DtXgs`gx(6&=g+hePVA- zfr9>h6AjEv&|DGxYRmY|e_ARf_dMIvm*-i4h<r_8tvkwv-mtv3OW%+`67Gbr1Y*j9 z1&T&I%Q7}RZ_tLx5Xdau=2t~nmnA^llqFC`c`kZjr|ST!83-3^#QiGD+g(!P4^l0_ zP|$Ys8$BR6*YL`x-QRAEV-A|)Ue80PXI-%W90G95r?{o0Al{DMWFSAm*&2tnm~WWR zhB~N%h%v2*_wF<)WBhV+&W<{-{1jc}Aoumb^X+%biz)LbtdgCsCEjHL4sZSJ%spEh zwgQ4F)TR#!&1T4=RYeE5`3<M_dH=EAM06^oozPWr&lokjqVj@hez~UoCV%h@e;2)U z75g~|x;*@i!%Rx+mB#bq<~0f^N0kOCtCREd`XCl#6_i?3^?89#>R#IU_#<!!sCCgP ze<}OU<m2Sqkyn~b64uC7PUsbeDGv`CeW!m^IW#FfW2sYmw6ilejtm>A_QYP@L|sHs zo@Ky_Bx6e2??_k;7vjibD#pM*T7`h9V&s(moOn_x^N|9{gkOtFY~gDqSo+7meUjBR zK2jiOsA%PwD|1*KC^m(-WZ5j2AWi;81kCi5t)KouHKt|R6m{m!!n|4YN3yyBo0mSZ zN^yj9>I9Y6dI&$!T7&$%3Ccxua0-&DoNJFbCV%1;h^-U&1Q+@47qrKld+QNGOrh{a z27PfD|L06XuL1+ZMc{_7rB7bd&WD%*lbypj>|K|<#2#t+qPX<E^hRp}5ifDWr}U>H zTm`5QC)ktLW5+G&4lhvX8DgOK)|mvQ_b^HuJ&=wP%Z6%;E+Bx|#|Q}vOoGR(jK}sD zk9x4A-V%Hs#G>J5XldT-W&|Kv(!mEi;J38jdK>L|Q7~<_no&|~Fdc~yhC~%VqQc2e z2|pva(YaxgaE`xa5=u=WkhtI|f`XRHhA6|>1`)hDgYzt9kByS$l*OQ2O-a#Iq%SLz zV^&-mn{^KrM6&BueyiV}>&)9rr)de2+DkV8##PSmko(<`nqPVr^n_V~UoIi`_yVdB zzcj4`b5QijKNrR%0AYi<`{NDb!y1^#Pv|K2N8<&wlO7-JDa5Yp?eM)pf>PbMq@)Wr zvki0Y1yLr2WfDb`RBPgq^VC(KH;ofR#9^i$TaMi9J6p5TP5F8<&ofnvL|`*(;urRO z?0k?7WiOd&^v);ux~R9Hznc3moOxE+O$lYV0Ku|hENFV~?Lt!QZlMNp1%d#^Rv!pC zfq`*V)n<`Io8N2XGBOjLYB}#{g#>o-?Hmb6$VyvSN@nI?3{y-pdNvcYe%&%CIeh?s zWfdM@$o~R)P|M>ElHW0BAMI=ozdH-Fle#Dvq-bpmPg-!rDY|1*o|1dvDh9{`{gt%n zFemDyrWMrywXJ+rV5r%UR~0T*75`i&rM4=%7}ulJyHu{rZw;C$r+nn@cLyLgh0d-A z(3SS5tW>ZK0in8bOH$vW>HIcipgUXYGUq49#>Ixff27cCfWz$0vR4Dmq}CBw<~4Sh zDe9adM$vVItE_)3FJT5Bgk}V=1g+Qvf5+<KeZeKg27tmTqE9gb&&x%=tpSf&2MEao zUC{VNpb0ds0kEy%dt82E>hpxwh78gHe$<|r1^Nh?B&_~xSq+nVdY+~dc4GJ?e5EpV zXs-H~6poV`Kh5kok2qSUMD<MdZn`+nJNYMw{&G)!^_(?T4R_K|kG_&kKB*w~M<(!- zhQZMCoK7`vb~VQPn;h4Wbt|7ZqMK$e62u$?R-P>?0&WXKs7T0?Z-J8zti^WD-*_fo zhAqM(p+l2*(|b>aZC+?aK~^_VCZkP0>}TxdEC-KcmAx*YS?wTK?cW>PjS+NxM==Wg zg}e_*NcH%2(J=+WVL+;P)kz0c@48^4ZuemowCO=rriJFSD|#7D2oO{}$kCbL0#0%2 zQe&D2wwJ3%d|+L`bE=&9k_~(BOe$ZFap$YMGL$&$D0=mJ9n%He#RRlC3f=|WyrI0L zA_qS=<Vgd!^sQRNl;o#=j*2#}(jFc=Pbq)IH^}HuM2WfsZQ)UbZ$S&{*oOS@w8ILR zRS_=vsZ=Vvsel_;qaI4VVF?G4!%(}yJ9vLLtOY+Am(uVlK1?*n&LcLmEm7jIY#;R? z_}|tfmWe55o05Q+CuY#3(HB=;YRs1LyxEV4H=K1SVp&1_TRsjTe;iIff4w?AtlNHB zNMqEX>kzzw8f_QiJ<uGSKkH_|=yZI~fIr~fJr3_YkhypY(dCTuY)5@*ykUN{nPNZ= zTeU%bCW`RsT`<**6S5_K{prH4z?S|7a;AA{o^xN}hu@BBsCCv6e(zZ4{chs%Cfc%K z;|90`6xnOi$c?>Yg_b?xA6UgBS0tT_Y$!9>(J-Q|m=O+8+wIPlb5i=-aU~kBf=4dD zd6Q8*EoKqRCcMNO5q%nez-osz1XT6PZ+r7r7A_{!vpDIfE$$yCUU66H>HOUO>u7aE zs*>|KS24COy<^3O^xXssCI`2iF%;A&<Kxv-{GflzSv6^-_`6rn?k>7{j1UDk9dvv< zsUbj2HMoFr%{j!bRrmyt%jM|4U<OHrC`kz-+@|l{4Z^UxanM9OAV-o<n@~_@M{FGp zB3{v>Kza#}%V<gr#D>f*_fEvi$*6J-h}oRdsdinr_W1<aeI;E(BS}I<tGvKo%aVl9 zT8*N*66uB1#vc&pIZOW_e)6jzRk@!n4%w5IflFM&9gB4pN3@HP1cznSFcKzGbLr(5 z%;-ZZvhr^v5@#b;>-)p24zB*p9tfDdUa27+<E>yi5W`#8+~eE_NyvNZgCP48jF8P; zgYS#IP!@sLe^SeCy4jwre}sC*A4Vk3|EzFISR4QEai+j{bL%-B#Nlt4WJN3eh+Uo) zVtaBF&A%PtbaaH`A~$h0I(5#|WARn>4Hbxy+Jn-$LdJWL+&({?oGdxCC?@gw`D44O zZ)fV$Yi@4u-zGU|!cfh6Eq?2C3Nn%TL2ZoA1+5g5O#q6$QGS|1C!;H{)PU?dDlSGU zLGKxOa;zm!C-Zghet4U7l(%LaEQnKF+>ECNt@`F07q-JO?%%X~*k}Yndc#f*iq0<E zh-aX|Fu{GY>`hgW#iOvymYI0Ur<nK88ceN)<(kWMl$~V0V>}T;8qZ+%f1paM#v7e! zUS~+CMQqEbYZ%Ix+4iKAGa>>DLya7d_5zQo_zm&bP6F_75Qk^L7A%?p74r#_+3V6R z@m)%h$SZlQi)PpLLYyya^FulLkrPuM%+!YnWBCX|f#M*ph-`6S5IH3F;Os;ZZ&cDq z<~WF?be7SQre3OHq63A%t27ee4>e--Q*N)lFkAI_P@Yoq?Bd0s)IIqLY)xtXU`k>x zfQK0;b2n0v{oPhQju4$`uD>)Syw=X_l}YEfVF8)awhULL-sJNdq;z8~(wyAEW&sDx zxqHk8ufaTXHNnIUP~eE&k>D!g#IVt<k6q){kZ+Xa5{E*O4m>73wHY+ugJwtuy74u* z1qC32jRV4EWbz*0B5d5qGm7FB;V0Z>C63g4n6hW?!BfHU=<o!#m$<U^6GCf6@zfb2 zCK6(EF~y7{8irNw(TEqZa;=^EL_~#5FA*W{6Ch;E3Y4Bn8%0+V;vUKD8l#|Tf+?%! z$v>hqZbuGx&ccdij#|lWok<JeWHyPdKD0NJ{;sEc|6?4_+6oP>>4#{m^Fy>{`JdOS zjIM(Tuf4sYrJltP%2vW!U)Mt5hd5_vs^{onYW=T{?nF6taSUF>uPLMY@>8Y#vd&fU zJg$MqI>EOkIj}Gpu%?+k{%zvX7zqvMeuMm%YD6eLoHxL?e6eW>J~|~Z&lHB^r_Ag0 z{*SlMeG(r}i;4UY6e1TDhAnY@tyh=*e7>7?vlwq>&py6<k}1K8x)%|myUzlL62{)~ zcC(t-q?)Y}2a+q3St$dLT)}P{#}C1S%{Lv~>9o*=h<mOQg+m<h$F++m)45ZV^MD;} z14~gAixLHFnCUb*Zv-g9fXE7>IE389P!iE)Fe1v;HN5fVGS&&jBzQk*Q}Rb%{FF5H zt;vL@*J)TU^_AGy%>+&9)+R@9XQHe9%Cr#w>Q$NM0~WAiktZl>9`I-Ypc0UjVU1rn z_FPNg@88w2iz;NHBJ8)vM$%1oe7QzSs;NxSieG5h->Cq6`M#YqU;tx=1hYym@h%fi zzWLOcEgsbZ>jW|mkR)qpxv-Z}J6iTzy?L3sZiv!nbZ3a;A~Hu3j6-^%FcrouBW^*9 zwOO;eD$2J8edza=ZDF&}5X#=B9O(;A4zyM&5yTvxuoqjP+FZY!ZYI`_D=;czTJF-e z1-$=(BE%9~*+c%p5UT&+n27&>tc8D77L`o(F_e)w^~KRuv4^AdNE-D~2I(p(SCPRP zc{V^gm}JdYd(~~{max<jT;W{{qJ%=B4as7XJjrB86YBU^HBAa+06(X!_1K+_C|9c_ z)?wVPyNchhSe;#;C%M1xhq!-b3~m!(+EIn*a{?eN6C_xT#3bwT2NJCVt0F3LVDSR6 zuGR{Y2kwq&MDYwtu67ai7ll=VMeQQMdB}Z*@2ApoA@vsDrh++mC>0nhdPp5j3){eJ z$LuzR9V>9)451K&?27Aps3vsd_bU(1EDOA~g;@vOO2Ty`4MFO9u=`!_wEKPQp>9L& zzuUbCBGHhsuxYBy-^Uw`)=n<g=_6ADtF6^Rx#L$SiwTMLhKAeg$Ir`Cgx|~CQzRQP z$Wz=y+MlL|L*&gbKc>5pSF5)!a6qfH$^u&=0GA(}B-Ixjj|ce?Bp(~$q^7BqWU|H8 zKU!?5P@+8*_63=^7)|h<=`vW)2%PZF(`Q0Lr0x5QLjWKIQZB9)OOB_ISy!Mx`E{lJ z1=1d&Ic*{{_h#6sNH^Hz)~vB7gCTbuUkVrOm(pCye57-0<dsb45#E2#1+L^YW_jPQ zg|{|1r?W0<UY^icT@rM5xUrN4-Ga9XU0u_nfIv?(1uMbrC`*n&(*!`9nyVmbS_=f& ztm#Z7_qI6{SDwi8TYXWlf2RJhh;ePSIHox*bQFuoCD~m5Rk*v`1f8!iXFpVs${-fy z$0c2AP?2akzba<<^d<SZbCyJ~xa#1j;me29{-lz*roj;A<-tdU;s<sg)#XHxkMhZ9 z+8i0#C#i2XPgfC#@#J$TB(Cd_z^H$s?1$3twT&=tBNuLe%Fl<ptJ!ehn76f9bc;XE zGYEqyVB(x1YL77I?c#HWf{)93)ceY}s>NUsKiFMeA#@NBB+F5<+s{(H7mQAPQx`OR z8xRz&uf&f&-?8paW&Q%EHCq$Lv~}lCIW%s>Wxj&$Majn9D~*<r5R^S?hRD5q0~zZT zs*IT7`7B7o>{Yn8jBZ3b9-fuz!82Hn?&ZI2_JZYAy$kb_?<bYK2x3_{G^w#>7m*?J z7Ec<Xr+(5=w4>rbL2*)gJ(Wl`yg~c)vC1w>dR$LezB90-T0%EZo|KuQOirNpKJAd) zr+w2F#9m@j64vevMEx_$M}ESx!oajKsI7|Q#c-fWRsS7nAgMlxf$l`eoBx6_u1LP` z5wVEEAYNPN*iXKJza7=aP+z_r$z;5})S<oi+}-~^-hbQc5A1fqvyb6yUd6CgGXp~& z{!K_DqomY(!`}Af6)K8g57Ew*!8H?)fvR?Q1-qUyJge=3IfU+X{+Zbg*SGbTXB`6_ znB-fU;%-e~>+)<Zxm)3ukS-Zw|J@2{{Btj2|*FTy-<IRp;ZZg%-llvq6UA^3q{& z9-1NEWMTQ79rE01H;IvFc~*(*jxd{v*|<7%6lCMnTfDTRZCx;Wcs|m$@c3O(heLDe zz7X)KqYewJqpsVoSuCn{7x=bLQ>QGWl0SrU7qL5T>MpzjZPVq~an6pv29s{gIn1Rh z$*Vp>0p=05JN|HRiyOCbpgpZ@;9Xj|o3DNV!%Xn6t3hE>(=2$dFuEx{osGXYv`m73 z@j>86*-gsSS^3m<oE3c-)n~5N*se_9lLX+^`1AncyC%QkMGrmLV=Ho6!+4146a;OE z=`t$t9k^-$9aX;|lxOSwN9>R)HB6Bj1fy+E{@9e{bcRLU_iAqDzdQUqG)+sqNE`h1 z$3w4loJ+!{F4NdK!E7Vu6L}j5d=VnffP!j5b(b5(u}{;?o9PB`YLsrEsOeE8IUM8F zj!}~kYF^$l^i7CS$AnS+a4#EnWySE!?hNnzWe>=ETyc4WCXpNzZ9R&vLWR9n2)aFS zeT`FE>ZzLpjPr*qdk%A3<`U8cpr3K~?abpqM})l-j}Hz+9tJcw;_-BzCtzpYoNVk^ zd4xI@9~_|+Y_6S*Kx+?A$c)OqC718Wiat0Sl%qFMhix0?j{gw1XO9$zQhjjoeDj|S z8hS*$R7Ol=9=Sd-9s*OgZAC1sMC*(iexn}3CMYJdNZu8^S5)5@Bxo7ayS4fG2D@ns z(Y9t<TvhILu3uTgNy#qP3#T@k<{6-VswRt1u&eW*57dPh$?Zc_!H*7qqO83%5^W=J zUDb1tF}tG{zti)_rTId70^zJ-pFwgc_I^4(>_4DB(20CAx~=eL=RM?RRc4|4V{?Qe z=>g3K7H^2nxwHm|*N+zhk9ET-=0ak5wZAxM<)DFY7|^q+@a_=>AXMj@vZG11mH%nQ zn9XfRt<p14uRBgwWE`}!Ge7riPu`nI2MyttnjsO{6D=|e6fC%I-Hd12iyv8n7o-+$ zd+FXqK4mJ>7)!V&u0~v+`DaED;5~WX_cQ6~@iQ$)`#<lj@~%G+U&|lF!;kNPgQ=mt zh_2O-X~DlpnvqKX$@JBXtHGnBngM{GLk_3fWvC2OkgG`o3B4oYC4J1N)=j4j*lbx% z*i-)Wx`^MG@VuGqMH^0ii~B>bKdk&+uvYtZMGQ??&<Ml&ykYNkykYNsyp{g>zRmpw zbc5donS&q;jPQE_7rh5{ONJKBM;cxKH>r!f)K=VDf}bfc1B4Nv3C}__D{B|kU<cyu zF9k}G7xqV$0Xa_Uy)eXayVw@La<2}I9(Nb*FqncC;#r&}eZ(|BB;TVKI}bcIPfIH= zrzm_jxOTq%g)}FA$YLf2v?%r_U19<N=>4Q04E((6!W^q+&Xb=m`c#S!$wEEp4py_0 zDJO?v%A16hzF;#-Lt+DUyec?VXUS?%21=wBiJ<}TTQMa&n$+5wnHr4sni_Hb`tFO; z((K<Oi*SVDnfmxN(dJ3`C_=~LISLzk1=8i3J_I4P=m*3i)?tz0;zp?bkDyV@leHk8 z8Ym0~2G-&oe2JQxq&RM7jLy^<hA7?C2iK)XD&n~d11tW&nRZb|%1aLc{0q4frPQfe zL3eXNXW=1KO2n&WluR+J&Gk#3SDjeG1^E&4l@t0}!D9$oEGr}aNp!0lE%`)CXuC(U zF)}q}K4Xr)Z7s2kOeDq(-Vdi5-1lz2Es6CAZoUOkBn}=jL1iw#i-FUgmQok$$f^qQ zLlb&t%@DyGICCfIGjsKz&&lWLZ)3?nkxjPC-MEa|hJw1LSCv`|#aRhD%hmxjW!IZ7 zrX~}toQkL{6T7B5gPgRCsq)F0b;NW_M|KEQV=D0>g?Xh0p)JZ<LKDKMJSb=0FP{C4 zDb(+v$X^5oi(e!Lk6Q}&AU#U=C_F0nFgz$`R9u~00mjhDa;`{j=p?NM_{N%;!=2q} zNRLjMj#Mb~mq@X_xS*6*TgM0pa3DpadTKeBztTzJx&+q7#*~GwRtcSch}eXWn6yaj zaHTycG$->nUc=-mE(Ls`z5)+Qr8;F0R92sj9yEJx1kK&wQ8S2S`)h+Qk?^jShBw0n z^g^Pht7xCZvs&|5W95{bypf4acXhX`O_>*QyEk183j48^Ws>JcasVrhs5G9;&2dyi z%>jCf;J1W^x5i(=Cvt|^PAWSdNG}XTJ@;UD+R!_#xn5!VD8@`C$I>Ipes@q*x>0`l z)z8=i*VF~+bxTYjaCr)lzaDau^|9V&q!IlGwQu0TKbn4oBljDL$D`d(xUR1D_M2H5 z_D)E{)YMOgPe9j&Ta=X`w!K8L8Fz1tOon!uWan9)huounS4Mh4dF)BRXPW~rZ){=b z8GKrX8h<5U_7;gkNu2?Vha=mHR?g_-tDJ7e(~<p`5So+xCj_-OKdxm*zb&kc2OZP* zS*dMJml5H=AgV98Q*HXN{iwX0%>;kBqw^DncZb0-heR1$Eu84i7(X`&aR*AQIwovW z>fz)N@L0uBeI%!;>fF*(y?a<c_!g>B?LspSl*h;#V3|hH@lSBCC>z%=##r4vBD?~% zIcaMD#Ep&MMR|QloYSVm4m`6&D~o=K)KUR!2dn`<yN`auN<s+X&^0ReqACJ&1&%`i zS9AJ&$N9ZQ1((R%+~P=Z=oBq)CTZ&h*($ex{G*kzjI$J`=0_pn{>e7}AFYi4ni=M| zwlXp`cKoTc{O?pVGTu@effshzIQL;~Uran3$O8b$6lS*o0s<dgL{S2X9~gc+hAQJw zq&2R+oY;$8l90IT2Jj^}g25Rw!7x3An4zBGKKt|X>T!BoyZd(zz&P7axA%@Nz)_qI zkD$LWxQoOtM=CJA^aux0eMxT|$TTV{XcUf%R6YWWWpb~~Wr+7tk~!$o(-O!M!{#H? z)jCw2taNz0WO)=*Gud<JaW9@fpL3bl$WP$^I7J6|S#A$6nMZmSNyA=+P(gb_ljw{( zpw$3VlU2o9^;u=VQPT<2F$?i*b$!3|=NVHi+<=nB!2{$_ZQWc=G8(7B;yip<TFPR2 zE%GD0>3!7Hi9?DqB;9JQ_pLDASj_PC!c^M|om%q>Zz+S3oK5Y^V&l+!?6vHO@6@c? z%)vqVE`pRD|ItbFC1kt4ApdNC)&9im8NW=RUr><p>@up^y4&I8N>~wvL%f(S2W%NN zf&x46sN${5Gh+I9cd>g-O|x3@x#@hdvU54zx*WtnC#5%quWk43w{;_G!4&;N;wy-O z?urjbDnKfp2u4gknf&*wBJS`YfdzBa#pf^Lo9ei}Z)MCk6MP}h0OYrd8`j<XJ`}!e z0HI@HcE57X35JKili58J7T;t86BZwc4YX1Lws-ENID+Z{zZ+abbPM)lpp3$4gSdHe zY+yBlF;38gng@uH-O8X-xOu*vxG1TCQ1*Q7Z!J+#_K+^F@~!OO5Fa2BIVYrYj-*&} zQ5{3U5obGRh7eY4kqC+XCCGWN`Z$q9BtXdWhc15e!SG{9lk+m783=*fX+!6Y;@X## zKKvSmh#?~y$$_G;1|lov1u={fT%dgXH3}Y62TzFS&!Oy>VipqsRTq}lh>h#|o4yiA zbPQLKXatZ+L=I$?XEGfd7x*_lf|=3xKLi)yj}jQ9pD+OPrv;Mqe+~uywe$sD4D}uV z4@_J6*&E>)?K_L=^<ZCx9>f9)ZpbIb0tyI>qF^OuZ;8LrA_T9JRowWUXNjyBVFxj7 zcFv)I!ZI!9%3&ro1=#}qZ!W@`!*%Do@xlC)>lS-KJPYY3@3mXj^ZUgyXXo8DiZ)0M z@ORv8NQ5xIiv%yy7Wuv<gda;WPv83Mfi2oK*ls5MR^blRR%H&dG-*n(J^fa`4&Kxv z{IR>M3l7ZnaX8M-u4s`LZ2-*e2V%BIin4U@4b=3ps|#~L^v#DXv3G<r4$LkBhj(1C zbl?r<boS9M13ec;-?54><iwXNu=74-#U6_5BaxOTYe03)+cZNzBz=*qSJtTXNK1(h zd)L@OHJQjhyuX$bt-mU;^35ZxR>Dk8H#;lK%qAV<%I5Z8dd3-sIMfqq2WY52;$Y7| zC@8Z_G%EJ3tOhCq_Ad3l4=IN9=Ee$7k#R%^@JPd7SnqL~*a3EWdfPj^Ft)B}bgnkr zBT1I)!g2ha@JU#wQW1op@1SkuaGVJcEJVhstebVvoHV+n`EI?;^p~M~tfk#K1CBi- zF<+3FQvDXkoVE)E6Bj9T)Vlo9rjgCj>S}EH&DnJgn49L@7ZaI=<x<;pRn<=KT z8T)QyTh=O!X-f$Km9us?>v&F?OY*>NLOQ-u43cR-0P{LGZCyKsW{^hNC8iDiqJ{~) zNqU!S?7Gb=jXSc_T>xTosLbq!#)VKVs^hKlReb|!_v(O0B(=A8tA0Fic+K)>Lc!(J zge-eb*cuWjJCE_q)D}kLQ`X73XAD=didg`EDAk|<!CB}ip9-sH7-$E3o;#ynu|z(_ zJW@g6JNly$0rBNIfH}-MdIvmxv(o?)Dn6kkc-3X%aHp8r%~g$Frzq#~m!ODbgAR!+ zoMp>uw*rjJ1Yj*bj<;`v&<aSHn4f_YVQXq??gA_7CW)csCEYaU)8a!nrY7-vi%oc2 z2$LliRrO;6{{&i05pc<71XA765|}Tlu|8!ah?st-nGC}8<Jk8N9U04t@U4ms5N=P! zX1(G!MxoVR`)jG#xwjOhk&P1#_G_@y5E_M%IUGuv+~QKwC=swM0}(W3vTD*=$?+?u zJ6Aob)p9~XWcJ3Ef;@cYIxz6b?{=pV2<uw05TzUTb!O-G+J!3xsJ(Q;wd%IiCo1e9 z1rLnv+#$_6*PNKfNYPFeGk7)4Onjo75mYh+)o$i)t~h4Xbf(J?ue35_f<#I1a_<E8 z#IWl<cgjn2rfl{KY^3V`b4AP^b45&nW{5~fPQQHes{MCD!b`HnKUCG_FTb^9V~0hN zxD7-NF~KLZWNrzLUg!|cI|mK|glJ^zXiN7<{tTHSaT_u};t?blke);ZWYaw!8v=p8 zph&zBA)I-%5xLgPQyR?miErfL7kglurN;N=Vywz{%h^U)elh`mgLEt2vTJ=}3zy0k zj;EOfAra$b2YM2yZbXSz7yotU@QfDx;2p%dB|-8&l0Y4nMe~-uRsN71+E)Ak{7$H; zo{k6+h|ZwD2ps|U91C^fDlU$o<ChkWsHi6UYv&)Q8>pOnps=(g<^CaeJRd*q!NQ`O zTAcA*KCphxtD>M<0l)OpWo@|W=Vs)XFpM7C;96VQR+W3~AXoqC9@yN@7J9kuboR-H zHL8|U?V*D#Jg&`hR95a1#ByH}mfw|kcIP#b2%C}r_nxhIoWdo%k*DB;N)%#~P458H zR&1-?mh?}HxGi(-dh@nkK_H45IB{y)%qwup^p85vZeUpqh|G;9wr%q$_*4*|PS(bw z3$<2M;y;*(WAtHSM--PRyA1<)1Xe^(yuRRaZX9nR0oP5%Wg)P(ak|_q$^7Cd)NP#f zFt*;;hP)je2EkvO_Juc*@6Fd}(xbH@+`c?h1(9yjJzcLY^!{hs3;2?q^IfrF`+D{7 zeAjrrb~tUbxms|met4=I%jCVN6O3DEeY8_%NiNb1EvTu>AI1J!n@36jd$2##c}B>0 z4L;|^v$`6=K#^tk;MTA+ji{smQT)gaODj-((|WI%X2JbpJ46#0RZ&FMJeh+Z<&>04 z)cI;7Dm)CZ1Q9H0Ge@zDXKAsB9dZbg4?1joh3}_)K2k;c^(s6)kl-$}hLll_T0$(y z-4SgpruNv<L+aH!q8IS8MzY-gg?eaOL-SBc(|NiekyEP>#}%R(l@3!%tj5l<!T1a+ zmzd1#!RA2v;r2~Stm-6FOWHj8**5(k!_c-){Ogo@$~19ba2$cgu#Q+WzJiQa_~uJ9 z--DAXeBY@UCoqOU>!d~Np>{BXo}gF5QWAP7*n?JW-N~>|I~-Sokci&_Ho87f;<jMH zf#SudKQ=r{7b2n+Ec|5w;>meu+(2@Yz45X{^W92m`3_^%9FadE5^cGO72ffn`$&G} zGOIPIF?FsLh^0eater8)<@~LjNIyP(W<U$h2l%YS9YU1AkliE19yN#0-#D!bNwB$c zlcdqBzq8al#RLPM6(ys9dr<g5yEjE>7F~ackhd7ase+Gfo@-RBG6$Q+CeDbE-eiO! z66k;0^Ze3P9kEj(yiZ!_vx)K5>+Jrl2af_iKMbiG*Z6y})9{?`w@LyvBpEEC99HEm z94J&4%248p>c%Nb+Y?Mm9%w8P;5(?F8nINf&_*-><^LeQ6{hj_UPeUhLmtxd+Vmgt zX+WF*G|x;d1!gF0D5?$*b6|tDV#m<_?(f{b+Jd?J92?)y8t>gZ+-KQ+Bj*PJW__xR zdf03Su)GBsi{L~F7m?zTiiu`Wk!YO=QO{H#)PP2?loJ6bfRs0oKxO3+aYm9`#}5V$ z`x646$<?I+_|&qB9yVC`3(2AonpGM(C=8yTG=zFgghaCdFhJoFxA6^cH4AquVxU~U zp$tBySaago1O>5C08JvW-c>mV&jy+a+V^zH9IQ#Inj?BmB?I0~jhx7qLD!cSQ9{<) zCB(xvh>|7z&?P1A6fTeZ=vH4`HaRJenyQMrBMl$uNuOX#!uWTr0YsU$pvq9H4wY>t zl^X-E=|ppy073iT6Xv?zU&~*SO<KFj!<^Vw<Y#jSXZX8Re&4&_0RQ)Z)Pi9+<bTv# zv3`#KaEtm+8zriL*(g!{FAGMSpJLX}1pI%gEEJ?;(_)g;WKEJZViKdGi;`2L2jt|F z6r&T8jfVjLsE_=d@_+kJlKuDd+vxuEXBqz3JyKcyJlp@<xBSyO^WRSd^Yh~0JfHL} zO#hqf<l+W*6~|AuB>z)S{s$uTKR(W@_aA<f`VRcomX<%Fk%Xz0;ZN4&^dlqvmwc3{ zplSUdMl67k;pc1kO^sgs+zHWg<kCg3@N*`Nc$IK-1H-zi%a%IHQ2hDcecO37jI#qc zJJIx8STQn54G+4<TdeNat@cM-o7~>sUm!9<t2_YgY);SuHTpcm_dV`#E~;3pSgu&W zK`x7r8mjssM)t)}Yq8t4Xi6AW#yBwUmg)^I?cyS3yXqb8V}TeKBss*~?SMgg{U}nS za2@lF;!4X@i|c@7Ekw~DTG8&AJ{Kd;Q<iv^vbrlR6OWDG+0`Bhd1mE`rEuw1k#Ir% z7W)y|_j1YZQm0sfKoyB-7X_Y1>UD9D`~`uK!3`Buc{%2B4{J%ioRlMx&#kB{e!Avb zJrlj#<)~p=4r6CfO9_3Cn1xhg=x7nk+LY}yn%fvBEBY;q4p`CSxj7W<Dru1=c41fi zjgF{FvXK1BA>fX^CU5+@tJWJi(W&KcO*jj5x;xDLZ*AxFvIAYA@P8yW`o)9#pos(U zSgS*I-N9vd=^11lccI*yNQxzMgJ!_I?64MNHZL9-U_DIfm>8g{k^fj)WeFHM8I_z& zZ3l@3<|n0jQSo~R0*Qcqvf~?+vNohOl*bzy=)XeN;2a3p1~0V$$gAWoVuI=*iPkyO z;E~luur&+0{@(mshrT+g9pcf!^T48w$vch$Nigsv6ylw&q=E-ICa#nDgi$8vmBC($ z=yLuLM0U-^2^S`{_ZwTz$|kB|ZzUr`AM@J;{X1nZJEj`$4skl+fss?6#-GZt`JdU# zvVUW}%8!tF0rBe>`+r}#|FsnVkBs^MUX+ze>dHSpWnWVCqdl~T@Zci3NHq%q1q0&Z zjiRz*rIA75MSd&j>=Hq=uts|mK)cc}S884FYT9`Ym2Gbq-?zNU&7M-!u<)j1^s21K z7oJaB$L#M;cjw#E-oI~{yJTr2o((;6binRCTJm*%J0nr<VUutll)ppFy@>P<k38sr zk8`FBLf|O1--H6-a9#2>f%?1jgigQI5bI~2dsFN451~NyCYYvfVfu5!YwE`!Uv%`& zB-2spw{|p}vcNP<;@k3}sV|3_r|H|Z4JC9~&KtI*)@JhM?U=mg#m<Bq>3PjRVoE+M zVYM5uWSO==K5b<g9k#9ludk65?GmDaKnQ7`*c2Y5HVx9Eh8j6Fcv8tORPf=Svlc1h z&c-6owg(lb3KC4yE*VWPV$~bfsyA0s)yp`6-6<R}t{}`PF%1)GY{2!#sW3=%sbm#g zuE`pUD#yk)R48lq*c1at(x!6fCRVWJU!)EW#3_jhNzWp-#!2$(m_p1|*|roRjSubd zj?!r;^FTD-7ij=rH1TeP`S6l4;g81eGy3Ho9k5U?A{+?So0K7mQ5Z)-X^pt0b%~?* zMMVSy>E81EEz2?F$jdRB^ec45FWK&Dz+e}E=Op=h#{z^;qey2Dx+2Q2qzwA-MpAB% z6U&685w0+}tjouEmcVXOF$U)7w=8u*B7piVzASTr-X|xfrQR1uvc@IZr$CD4MUVF| zMre!R*v|cBT}rB>9#r~c4@(}lBCp$9)X`O$7f_9s)8|{>$Da!Go<Jm-tOz&ASh&&Z z2DkZ2v>_qr=;4rtnr7TgXUpffMV9akHEvEw*Z&g!2Env6(!b;)$Zkq!j9UGy>Zopi zUQ<$5Ex<;<A+9Dl>BxM?&1+E#8>B$er2c?TqH!q^=LX)1lV=@=!xtMbm`$gt70@|} z8AM$V_n1o@=*E15EncO@{D<SVX-=L()z8Fh8{LsQU1^I&WmONXx!p1C`IWx38^d(* zswUB)-7ssxAUa>Fc)hEBSA@Nbk=GkNsF#}_mBtmF20k$-)eOP+G`q*EAP^>>5d@ea zg6^gb37{ol+=uYC3->5=jbqd}&J|19Oh}yYviQ}E@&>94`r85c>mo=XKA{q~2C*8q z1(8IqD#!fuWdW8DT^RfX)ssdyOzHq^sC=mmY``qcE8^g-<WoQ-{q~4g?&D$m<N<fG z6_vZ$?+PM;;DMG>o852h1`FBL)_0fHqqzW%Y(brO+X5H!1sl*7|2>*^XZQ^Um1qp- zj{+=uY~SxwTj1)2rmt7luK=kSptJD<xtPC2BM1x!fzBf^_W{=aF`W1sA0W%%^FQsf zk@IF@C*}h8>qqF#W3sech+R{=RBs5U1mcd@_EU~~8?dsmUjsf7tKBg%yZYVwFEDFu zWWQwnb~$%v)IaYXT;h~afPZz{<k4e=a}VnP?~?q0c1nHOnoi4AC3l-rj=%olW9C^o z<tqHs-y;6AfBp}9=fB;ac<qcGEq@%$e(2MNHvdO$OpKir1EfO?lzwB#Z){Stq&Vxl zYET5-P=dgR=-cT_x|%ml5i)`wohYe3EZgY=y~!OQq*81EGqR0$x4U+h9(f-=$M9ib z6erag53odWM1cl4&VbB%0y_)-;`A)g5)eFjlphpa;Y5c=q&`f6Q}Co-u|$qeL7$N= zNKB&vM29ZjBhC&Fbm&9yL(ndpfkeU*o`A%^(i~$c(zC!tA)nAAo-050;VjSyqxQw9 zC(O+){IcVn(b~IAr%xe$H8@i5AM`N_C0<Ncf=zg%m;c><G-Q2FqhI{9jl)HOBl%5n zYYEo8GksGdkVUWV!BZVP(xfB;(jhoFI4;e*N?l8}GXT5RK2xwIRje%}va2i>4^@br zn<wq%L^w{;R*Yph<{KY8UNx}~%O804Jvq#G1!7H%A=5hlVJIeNt{9YD*L(;1zazE! z?Y%d&pQ~d0b5;H$lKMvg^lw+?ACXL?tfY8953J|>($GS68Obz0BZLqKb0MyvEEp-F z%XZOu9nt29ll<E{#|z+x>>hI<yaa@%iqp|#*K<&6_I9=PuV)tL8Als2n>Y!o7Ulpi znv6Q&d-<Y(Z@m_y{RB{=3rCK_Q1A|NffEjDgfCNrqN6`kU{-{Idc?~aHp(O%q`I-Q za-lk?1GYP>;x1Q#smNV37IAjmqJ`f>4;j)zs}@5Ggb8NHQ&r9}YcFk1=s0qSmfDIT zL}IzQfY+Hb7z3YWw>3^;vPtIw+@lL;+6f0j=R`K1?Rs$3&Ft1)@NM5zV1L&`Vbl&7 zswRx&Edg?U7fqYMBpWQ6jO&vI*KI5odc0(9&B?LUS$lNhs$&T-QLab-p|8suK`a9N zU;>Q)dneC-M2!FT|4RScQqNRUcScY|-Hb2FWK7ixX)w*zIKVgM!)R>CsoYSb9@Lsy zLJk9)H;@1=N~KM;fxCA80PT1w>bSwB_El6JKa7XzdPVs_qfTy_HegHLC>RgUxX-lj zs_$O^k~(_!_WA<u8Gj*;uw)_G_dxxfVJ?W1q-Oiu8uBy`bt`lSmRj%zf;yZxu@;jT z9Stol!nxmsW^)X}R8YhXOt~+kIxG;buZ(3hv=@<IYom)8L|lkBh>Dl_zRBtc0-mj? zs$_XlVRk8UA;TzI%p`NZo^_F0EiGU(u~@&bF!!jgly!a1es#9LBez7Usio}j;#J*M zYwchj{qF*wFL`?T^AP-=5n(>kT+$T_0iGHp4PM3Z+@Rs&k(ghDz;|7e>IBW%Q&>Q* z*|!8m`k0#8(2SfZzjS1JdAS)iL*a3Q>Tt-uHB0^>6;<V$nh@W3O4j^kKfIo8_N%CR z{emGs#-(-)EaqQ^G!Z0Sqp<SvG$xv<fPN!2CS(P16m#eLL5F_uH3~L{j`LM1#iQYR zs@(RuU-RearN`#}XAP69W^ZQ=Y0gz+q+>1Ac&)lXvA#A+^~TF&^<-Px{Arzw?$8;b z6(xcC)ary#!{#M(-LV!}WvwJ94Y}p+dl+)^9$xeZPD9+g#b-y4E)=6{dZvMSy(4bs zQqd@m1o^6YxMp0{hxGGmxj9Cv;|d+QcXE|*vQbI!0Pil2SOuAXlwDZl!rN-01kujv z`f06S5M~gsjn6G_ql(Z9v;Hz>hvm)t+G*Reo}Oz2DoZC~IJYFxV3=*1bcDI#V-ehb z`yS4?O;M_uUKUWRm9-0*%jA%+L}L(ouJ)NW*6>k4H0cLNq(fNgHv4Jnoecj0zTR!} zd#20Z0rVivt#5;(=aRdj<I<fS%aM2UZ3tz;_4Dg=;q4{lQj8JEIPH+}>Zc}W37m&` zO8hf+O$5W$AK*8A8`$z*=vRHy=*QmoFlAg=(s#RhNTHVYC1}1K@hC|GVLZ=F6-*0x z{+sO$vPen^=y*Dt6A!PzJ!}(6LIqT()R5jys9m(YH-ka(Nn?~~Rtl-H*pP{zU-MQ? zlXus*&2qLymA^@KO>Y@ZjhbR)e1(|kVQ~2STn}<nr}~EMrrv&o5vmQJl(b{lz1B=? z`G(`WrTO+e2Uxb3yoO5yxCIAx;BLwNg#ZCF_3#K2DdT<$;e#miQ|jt+_}8+(#-}ea z5Noz5M^J)`U(f5XiCc)yo-iY~fViu$R23efuG=@d8qvm}5`->zH$Hv*3wW<D6X|ct zE%&!$z&zmCy%tEksP)#cTtLo~A*HuY!2E|(!a`BA4w1;r2i+eco4|K^0L=$7Ism3A z`=6O@-7$#cxhb$h|Acl}m$8^MgNIQT!uxPAZ@3D?n{oy8!4wRmFbdmF)t5K_{204B za^`0?t%RF&&2^%f<rZgDVU3u-ETAmop#>t5KBjg$eN#@{G$fcMS8-`5K^IA7m_aM6 z`$)$n`bVh3x<&!)d?X1WLQ9uG9!?;qPGiS*BaH;RE}RifZm9eNEHWtim<ZHESjbbe zo_<btIr?F(=O55waud-trgV4(CJ(K{D;FV}vsPiF!Xb(B^?^Y>)l0DD^SyZww8iac z7r6e^#bzT+IQYWSF&Kq!LAalh*r_;Wzi*>jtu~LuXq%d^sr49_?y34lr!u2w+EXxL ztvGKYoa^y*IC%Ypz%YnJV8{reNW^fpBHc9m`O*l>0iqm+au0Ze=X^~VrnQF?&PU+5 zvDnPzI3)KOpigkw6k+Ys(1~ggta{l}hmoJQoMZf-VJ+IOf#vtk(!25;+d@FGwm{aR zAx2bT?D_&PU}I*Rt}$?_UtrnE;npz+3Wm#cQDminaPZX-ZsD&rZgNMlOP>~lPs)5- z1VY9g@uu8tU)@>Vy33Lo9Nkp)j+fdu6g^!Frwn87+^Rz~KEqI<wPRV2ZBv|i8Izgm ze)kDGLS{?i5iivw>ZNvGPU)wR*jLB$B}I$TO*f~!7t4654oLO6t8V2r?1+T_Q&0K0 z4682u*_{u6j(?P@{;`Y5=-T~Y%Kr<77Z}0&gZ+aQ{5EN9gm5}+3o-ZC$|VI0^CJnl zlu@4piaXoYaQOv8RMg_I3w0k1bN&6lEJ=n~1W@$^LZ*+5?6;J{!0RU%BNqm{<~-t- zYBiVcsKMtWrxI-wsbMy>B;oLhCnBi?O$~EZ4$9!UcL&30S4}6G<>y$P0t(I%#Lna} zX_$_w@IIB}3veH9GP|^0P;_>@eR7vav@g)kd<ftEA?>8j3{^_~v_K#JRObGNy!PKV z%zyn<UZWp%Mab07-a+0`?_Y2KXFu$q(zz6ZEbNz*I*XxtjskB7fl@%z3?x2o2y#L= zA_TAK&30XdW9~)VC4QIR^e&`M9xoBy7sIWr2Z(+~y?Ty{4kX^~G^@SQk%#?i>gxUd z^s@D@xs>D?9|0^XQSe9+5fMBr9-1rL2ipylxZmKI{+KW<K}0~b_`H1tQNx&ML2BoX zN)d!;YxO~?(g%{Rg*n6teo3edOUs6yMCGSv85YQj_8|?yOq%sVsKjiWi{Fbis}zQA z{F>oVU3B__h9-y+tCNq0iyqW8C?N<_=wTWv36hc-;u6_5$-8<-iG^wVX{rs#%*o<0 zP`zZD%9FKz8kA)Pi`QrR2c(!`3^|x4*s*D2BB*E3p1pCB6wSJ(K~r=?GY2zKWbkSM zk97>~<lV6dz^c<E$dvN)_xy<&)XvisHKU-_7Ds}6<ToedXiZ$KipXkJ1MH{k>}>cv zb$Jz&BN$J`J1%`SPSlD!*ydwZh|}u@Dsp<F3<71X!?;wa=|y=_=6N1!<PL5EReoUm ze6V<owj9uUm<X8hyb`-;{ORgus34kHuDR8xLrGo&oDJ9{5PRfR;KN2GF`Cd4IDp%B z89D7^0QL|eYULlK8)-=5QMuO=oJx`sQG*lzA7$?tooUx)jaJ3BS+Q+bY};1Fwv#)y zZQHhO+cqow(*5)}<Mi8ozVV*_*S~A+z2}-(E6K7f*pO2uhSzIe?y_BVHdJ_rTt0I& zEDtR_){j`(+y*sr_ORi!s1OxtK{>A<j-e#;zHD$to|nOXyu8fda+Ai?Zen(W6J@PE z-(-@b!SL@)X_H%Vd78&!-Uny@4o7RBtO8wR&sSpGi@DsaNcX#lJ5G(97z}e>$4$sz zuve=&^SCLUwSd_bGS|G?7q|}mlM8;PN?3s*Qn`LoL_I|_0v+g4G5lm(&>D&~sR6?l znI)Ws=bL^}57Jk}tm&J<?wp~3>ypgNPrn=57ljDoPx5vC%_rIdlHBI-9tCQd3ccs7 z8t-*ywH72aUrR7)OSDPqV2JeQ%}`Fj)8^<7+S({A|0d~}AU_#mFK*xIuPXctHbR_6 z0>4#tdv;L;zy3>@ngEyuC~{UEld$Xby%R!P6GeG0aQ`p@>*JR7p_5+YHPKN^V4fk3 zP=|o0bY4goP@xf7HieU5*Pudrp}QZK@B~{n6cMl7DMdWz@t^;~@D^eU<>!6(45Z(_ zk$+hp^uOOo|9MRR!MG0pHBKn;ANR<Y2Ti9vO+(2qUR4l3DqG($!Xcp>0%BC@7!g<f zx&~8@&a2eR+!w@m+O8NOlGy?HonXc(ooV~IIAFuHi>ZmJPZJXt>$m&mX8a!}cI&=T z^1$X1PVvlD`DVXD#eo%T9Hq`v^hcCB+%v=fj3To3%Z<jfl#{wGHdcn6tI4)nt}GUM zWrG41a7EcawE?lUuFtoOg7%~3NZiFRRO^q@n!NkzwCXYm9Z)XgTAUK_k>Wn%=JZC_ zoex%j4<fH!1xm*SR_sR)BLUK7PW1M~CNY6HQCGzk_fDVQ^E!{M59uO+&)PYv&m>J+ zbQX)n<fsyw2pf9hmWtAYH8f0jZbbf*6yp<%vB{E#6Gd2T+!0)ZLG;-nmE-H6zoy)^ zd!c-bMxSGPwTf1^w|TLST83)8eYnGhrvAJ$&P9vAwb?uqXkdoQnrWz>1VtYQf2U6; zl+lO7)ctA65@v(JWy3f!Jhj+syx9tcQ)P2qi3?*W-Zw#Ork|#Fs{k`fVV_!Mn!xL3 zIk}JIQwGd7Ve?#cLD_l3;B&IP`k1Ad;eT4RS=pW5A1<B+;OgEnx-?%3>i9B3J!lo3 z!WN4Denb)1o>9t<EeviDEih*`m1+W?r1s`FNLGUFWPT##=gQ6xuk6>u9*MQeIgR3$ z0rD%TiSRC-!526-Q_<1bGYn58#9j%95VT-muFHVK2w+EN#G8i;i`sA@UJgGpB~}7x zXT$xV`dKsMX!X;9Ku-Kvd`_&(SCYV;p<-2TVNbPS!mBJ-Wd&_+BDCO7!-z<HhH8*5 zoZItvE?zcukf&x77_&;4QL2%h0tR%rsDKIsju8veS*I`^NUDu2bBOnjQ}BMZ;Psiw zF80VD=wSW<+{^%I$mYMd$_2y2J3qe}*L3I~Ke+#|t@3}pOajIxHum4Ev;Oy|Nnu?C z<#P$Gf+&2TB_*(_0FLFSXYWRwUOF*onx>tt23Z4X=cs@kswD@}xU^1g^h~pu=^6pW ze8CszeDle6mmn7p6^EWdfD|dyNB$<y+i8XkUnUQy&*$4Y^bZHuUxpCjWGAt)h`ofO zGJrr5Om!`|J*X;sPhzxj94ervS{Te__9}4Ofc>Hf%@?7eA4}|ajD2dy<hC37C(YeV zShbjdTF=e00;;4o<;8i8MX~B73zo%=G3+95(MGJcM52c{eXJ)`0CxP=%`#$?TRCiU z`kG#h%DE<IKZU-U&C*z#lPZnsDALq2OJiHE20*R(d%@l~g8D4}0?kL8KFftc{l?vB z&IY6OrbcC1BtWJ{ST?S<D(a+w-wJ<CIAf}w9%f-OuTsN#H`Z!FI%*mNY_k<RoYm^C zkt5Zo#Jjqvyi8pj-D;eks#Rt@f$b4)d!V;k1C>BKnD5ou30#)271<>qDF}GnvD)t$ z2fj&M*=&%VGF>YIAwtb!y?Ie|YWR?x(Xu<S<BqqlBHp8mjA@U73eN$iR%gpFCj7Ce zP<|>T5a+5#3i=W?qc_A~KjWxnJccu=Xz$PiiuHzL7#&Jt#VEx6v~-8J%V@+^q|MYi z{c+eNd4k(vCCT3b1G%D0UknFNZ?%lsqRm{_Bk#15n|;|H)9O&HOroVE-FG(hc4&ZE z(2P$V`Y^c7#KE)tx3Id<0tT%cp7~`AFs#cqf_JH!mS_Fm3^W1T!JXma96S=IrQy{} zb0%%7OB-G)J8g)5WpUWTd10Kg^gMRt${vh%)nB};`vmNAbL>TCRA6}wIE<1qWykbg zPcCUTMV-!d>owCDM3^BD{hCpJcQE*pH$gV#ErC;Wx|Pm9SnipSi4GEzX%cltZ8sf0 z4GJEGTyuxoh}YL_<o$SGkk|NqUnJId>^g{rSCj(Mn9xB&ZpEqiyz-a5H?)=3b8E8s zNV4xhy4<lFeqUr7Z#Q^6vSB=|(Y#H*zuJADM_Hvj0*A@}0+{muNU{Rp?Ya&h=|E;g z^Shu+6U6FpA1a4^0N0qW@zcFtFSvdc%!D6)>dT&cqJb_1$w&<_Ly*<nn}fe8JQZGH zizPmlZZQS8Fg#nsZN)ocv0`-yw%yKfBxZP^WgMA=Si<F#`Y|*G;<QDgv<r{y26MZ2 zkk<374T0i?G$)G8jsy|XLx{wAMa8pFib|cNxxgPkz6T8tAYwrI31wK}Hvd)&6}dVY zetJAdk6O(@X1@}60&@71Aj{>)afAyxX!#R8gU)gG)(#SXrbXZnoP4uq5;X(XFv+a6 zX>3lBn@9^3=&!a@<q#c?@b$p(nU~UoepO~~n$dq1a~deiHKe~^)9df+MdaVPS_JhS zjK4=q8e2P<JASX{Q~b^VTAO}@-~UiP{~x1Tp`!M;Jrjk;<*in(Sz$alj4(vmj33RF zp(wCKS}JWJx*+g57x!$(IeEf5)MxOkC!8+jMbGmIAM<v9>Iy7C*kVuccxvO@qV6GM z%IEWSgV;mL3SA>lp*KOzvB5IVgDpwgX_;?gI5<Q}&|T<>YK6==zNjtGgy=}3pI7Ml z*K=k&-d*&<ErX)jKkCLgNaZMlw0@Qf73m0@FhQCx!MlXeiFiF$#k(5u0X_&#J_k}} z{<+ZFl@NyHd)XRj+woJwiTm88>zJ{n?u+*PW8qBhLLy><lmBL@Eceiy{rPVk$Yo^j zY3Z29U8%-VmR|h=AfNsdOrQ*Ho4UHHwQVwlWt8>UlMZiEIK|oHw$2r<n9LI1j8ays zjp$yYLhFUd`=xXzfkWMyz}u#?zl2yAx0*g_CI}SMABQVTH9J;ClnnuXS0lw^V(FNF znoYuRP;5tgv9!R?Z6OP{OL3$O#=zcQPkg>s9WFwD^(_d8L4@aT5=s?a8<Ckkz5kY+ z&!+e4O=qApdWVr#!w{afUU?6)L-lb`R~sVZ<?yuUKpNJ%<f(A!sFgclv59*CO?JB` z{vnk!5gQR?UTfl*Wawu62$Fi)+B`Ceo9^|LQlFYqYKicG>c%PT*VUVg&tO4QDy2SY zjm2bF%vg0dwTFqL)$eqaDox6HxHo5b<wJD&<$KMD6W*98J5qUf4f1!tJA|C{QbG^> zNFgp5r*h$E+lpT*h%KuH+&3V2#-tv2SyzkL$JGiwZeF>fbV(hQ2BwSr_!rt3?1T{# z<Qw|+BL4Wn^Y0X_q_vHU^*`|MpVv{*QQy({A0W7?_U3}Ji2Jo+6u)W-2H^*Sj3Oc} zR_BIv<7cpz;t#?K&5D6_+grnB4aUl3XTl2EwXR`x{wDwDhaXzPA9GL(B!wL1=*G%m zpZw#82icR|lI`n>3+p)Tl>z*Z!>MQQ>u0C#>Grq9WuFghUm2<38IZ<^qz{5X#CQaF zf*+9#(YJ9s#v$mL$-q)RasrGY`j8?J&3!QZLlA<|;QEREfPSG;1T6Zobq2^_0kt5q z09VRDG;Z8JCf6j{ENFc;@3BBW=)L0zw=Nv`9rTWlU%SG*pCtHSWjNhK_eeShOUWc1 zguBW=S8?nd=TBUyH^szUGwHcZ_085TFwz#|m8>-DLDz_i63t}Q{&1Hz4#&BBM00Rg zVBLmTo3$&AFIBXyzJFV$-LXKdTj9!w1s4u$sTtwJ%L#eIW7Q-qMV*+xeM-%y0(?Xu zYf$T);aSqS%JCFk#=-}_oMlbLI6SL(vsS@VW3P{axttW?Aj^|nTNjt{WwB<@*PDZT z83dbE=PjR;JkTlb_0}gc$vw%DL8IuHL48?t7bk-p_2$2S%@_`iYL2H6r(tbXtG6$H zi1#UpOr)gY$kAjz^D_2qA(d?Drx*fE7c<PPDJ_3{tK3<QFt=3-{ZV7W@$<lT=wEDD zQGzVPbW3dA14%;AztGF(+}pOM7#3*EC}F*dp#Z{-3}0$x&gEEF;_`^!8!7_d97jAB zQ!u1UY@v`!)Z-LPYn-R!aT|a&bx)7i<CuM_7wAhz+KRhr>iOz|S65GQ?@VtM-pB2z zI4+D&hV8ICIAo>$0u9M+c}S<ADzaMS_*~>*w#r~(Y`X!*Ot*s<>_$|Jy`<huD#Y7+ z>Jtq%-UyXuOq-?62R=8(;>I?z9KdCKML;#{YLY$;T>XZm?=UMn_|2rJTDP1Hb8<Fp z<aUbnsQr#8qC6!OWw`~&osnw>tg|jxd^v+7b=!NmtTqBeh&ZS#8&>3NHz5w>{Y4R_ zO^gPq`R-cbRMDwPNbP_#R>)zaj_`d(XF|e#kUT~iLdsnipk{POw`}Y61ZAD0nZ%DK z`9$<-)~~Drk;!X=k_bh1nq3~u>-~rbzMYZ?_?z4aK6~P}R|Rp=V)u!VrbLFxIW+2b z>QCbRY0tN4TkELh&c0Z?EZk3qPr_Z~pM`RmqbUOkJ-FMoK2VOdHC4y-G}8eV+DZWk zX6jN-&=s0$n)ykYm32Cz^-9AHW)kRCfBXP_Rx{TG3mN7#g=+BS3*~Hwshl1}_t0Tr z@>%){i8cncHw7ld83d}Tbd$lY)kp&6w=djR4OnT|iOe!>@!}5DO!8*$5^bG9=g)2C zhntFe*FYJuTv6y}J@zbU^Oo(_A470wLp;z+iI}Hu+#FvD9GC*|JoXx#vUsEWFMWzs zrZu`29dr4^OWAsvC}BUpF4b3865d`bCI=`twM+)7OHA!s+~FKJo5g*Z3)bGBekB6l z{^OH$w2KE<?zf&8@k_6yRIJr}hcudOqE1~y0Eq*_fPs1cky+8)Sv7i7LpNB?Om!yx zM;fItNi@4ZrQ2AmE|%j}vPtG!AqRwCI|OatCMqg7xAqiaR-xma;2N$7gT8N)?LBc= zp8?k3Za4&tOui9P;ck++*zS@zNI#38ctVf`1UBcj#6^)4Eb(s~ezA@KN;{OsJ&dI= z7kRp<eD#c;PN8~45^8*&6`&S`b?pNIOSf9++RLBl2IrC^ZIvz4&9}tn`mbiLP=}&5 zuY?D^V<dj#YMg2~pCAffpw#IigWKuFHQZiWsUA|c=JzlvDEjb_8g5a<Xzk4<#_%DE zF$3mxpI#NnrZXhGzpGznI{6!mc^m@Bn{tya*JW&f2wN;8bO0l6uXzO`KU9)=^-?HF z=Kxryb2RjTBxwy6f3^PwI5<SAjYT2gBQA1~?-{DrUO?WV+PIhp35dCmysUAajtlYY zuCGd2N?^){)%p8({py_ti`FeU(0qDBeYym}GD$t-s3WZ=8h7>i*_gGoh!}k-;;t>d zONzdN&YtPqo8~CDbOb*JqmAK3!_<<xsDfx4-c#JdvbMn))W)>^zKpEMCm1_Aw;5Ap z5mLu5wB~x0{)K=s#@QHe4QB^QHDEk8EK5<Ay(@pqF*Jbwp!5Y!I*`mx`WYm-xBVjE z8RQd2Rn^^h5Z_Dz?INEMZWqe!(w$wZ>WS~XtNf1f;f+>NG|?7@i{z{;oEixJ8NF5> zqrFoEMY^>gJf2r0h7)7!AZa0;Q)Gm-_udiHd6-r+nLkdP8Idjb7YZHg0a|P*pi7<c z=@pcCpP<<n!yO~K<?yqlTpxc;D>*?SHZmWTU_)ek9rzu5jNMxZ1-PQ*8;dpg0KMZ+ zvg<$xcKwT1PCU?+SNM$wAHJ2tf2-A$Hg|CNMu7i3u;2Rm|Lb+l{H9sv<-UiSxL|KC zp<+^oL`w;+0@uOD5|ltr1!It<>CyM9qAyLPU7^`<<=sZwJj}lcAO#Jed;j1|xZP-) z_$diC9(R?o{+&~-z0B_J_6ANFjEe%X=ZqU66Q?A1(h!AWTU?EZ3$shuPcfd!pqaK8 z!fD0;=)T-Z(rPPKxo<FGMidLA)ctW-X3++;rV(Ke0uG$ksjb&kYR{O{wH7Rr=z+UO ziDF2??3a;}T(WcHF2Q3o4MUVOIS-i%U{p0GVHLafuvs%RsyNa&boS>I++8v5w=@#2 zMjXbSXl5Z|#_JGO8fUn|tFn|N+D7@TQwqfCT14gR8eKfo(XD8)29;&w))lNX3C4^C z4_yvO`*Vokel4~CYWw|m?mdP`6}1AN$VtBqzG;7rd!*;vK*TA97s|PqHCZ{xFnm)~ z9s2x4@urFRS56_BvH!qM3*$k#n1pR|IB6|zmWY+93=<3xqmsN1=9s}qAI$)aN{!JH zA_;b-#~mdM`1_d@qW?<#VVuI_28>DS-W;HRhS3j+m07d#0Xp|#ZnIhhr8t)5s_EE` zT3JNF4UnQUH9EOWEO^G^5&wflY#veqIXg;kE-My3<3l<9gfNQkP1q**CvbxQNd9i4 z?}rC`rg%nf{cI18sklEK1$F*5M?}!fAVS$8bbE-G#XWNyeA8y{>>3X2v0d-+Oj2Nm zDM~hDkKQMEUONW4)V08yH^lSkurW|St2O-qg*X|7z@2eK@Q#PRzc^?S&VF!iHkZ9r zQ|_p96s8ueJgP3de8T?u*X4X7*PB1c+u43Z4}DJ|zhVoT0A8Fiv)KyX%2cjV8ZN3c ztL2<cM_koDKzBCbI<+v(4|2eaodkp75tK?F<m^qk4|R?V<yYnl_<v_wlt3hT%f8Eh z;Jf_)Ep+)`b?>5YZ~Q;dWu@}E_5AmW*7O3qy%ypGR;@9T0t)F($+h1UowgLH!l=2w zK!qu7u!lkB2db9ff@F80U3Y&HLxo6uuR{t-k=~4><flcY+saI>KaMap`91+%-=X4x zPIjb`(iwV6mt`gQh|&>5t)M7K(0ED|DJt@k5JMGy`CcbL;4X9eMpYv9y3t4yjy&B0 zXf?}(|7;DEY^&|$+8O=?lHh`ed24Gb-U*!6TTaZ0@pw}Q7YzJ;?~UHyTPQ)J#Zvh? z@zWJEmhvLkp>o(em;{^vHcBnExu;CTR9eB;(I!)lr!hG6E{)ZFyun7Nb=JW@0qs@d zEkQlh4xOnd+KSSjO@HD@I=o=|<+>iix{rdun$Lsk$f(=9m_IWJCWN&~H&6?b*q;D~ z_z1*N#2($~+O|WY^B2XDwT~$_Z>S36GLjfaX(W-3%cth0B?O@ffccd9nP^2UYXi03 z4uGbbTuq5S<T#9jUus3ija01(<T6!rnRkkQO|oX$rb!AX-m!OQiJwL>1&7(wk?e{h zVAQ9y(!U+Xu-73g-D=uy!XCaY0}{*g46Aw(uj3Y^`bK2@ecVX7t+Z{Sba#VZYI$;U za)t(vXQ(p)x&2Z1>e|kteyh;gzRHrGHZFI%Py~Mt0qoEdxHKWd^)3)GmjLTWKW3do zAjEvy9GP>k;}a@@mp%Hf?5FySdRRTR601M)xPFMIdDtwb#x(F{<^lxbF(}O2M7WWp zl2Z1I|46W47x`fC9WM8*U=}&;9?~EtEz$n{MNV}j<ykf&X&JA^Dx1(YK_|Geq6VWt z>hKm(Yw$~vO&R{W4Hb*>XipJ>;XH2Jpx|a+wMXI;lt6wo3Z)Ljs`DHXyJ)$LIq``b zD^gxc6cys%uUQ7+5cWzYV*7mU@Rfg|8&gPjCfdIbLD}~qVEcDktbY!{zmfonO8<HN zdtWWh%5&mWLv{JWY(fPv{zeFcpq-^w?=b=lL>n{L7g&g|Bl-aN0_nVe5{2&8e+`xB zMjki8%CJ(<YEO@QO*vfg96xw}JpP6D6;2>Aq9@AD?tZ1GGLZ5Aq1*=~L5L<yEiUH3 z6-h>@!tSX&ponNexP<A>Dz*N=h8YKH9L-P81rF9<S!RySRe994+co=4a|ff6*=But zS~Yq(Lh*7f6;06YagZLR?VKjsR{j<>{!7(z-F7_b$_<PlsVr(;4!g=*5A)9^qjDds z)0=OxTV;FJu8i*C490-Fo_wC_H`MAAqruBn3Ymv|K<ZcW>>=@tomyjdThM!y<6Bae zY{vdG=_1{p8)N}8ioS;C@(dr@R_)}T5C%c>V|b~c;5LhRi;iAu8)R}ulL@=&s@Zk6 z>}ySWoQ>vDwvcTPx>kHaVbZ+SX}@rki*GH~J4<nV#NhW3SXO9Gsz#^&a=$>+^t9PC z=u|fHt=14)lle{6cYvOX)mZ&GBJ2{g$@KN8b~e?65RAYOh7N;tzih~EAExjN@1q+I z%{fZHMf2P&Y=78aW10S)9?~lu7_`s|<`1A++aoC^NWXxm+jurhppAHvH?dRhvT4g} zhq=&!vD%Yows`SWp3<?__@pggGK}{3Pe@*SBiOjYI3r?3CQ~s_ViG?B_h(zOH-P@! zA%ZXB2EnLnc-{`YP!eG)qes{QM_}^>OsVWit8a_qg>5DDv6w@<i?tMckfVKSCB8V} zXB5E`u-g;UNE;5LsCuh2`m=v##SX7IH)Ak(O3n&5u4NoELA!Lj2gap!qDlyQYU(QV z1L~;{)Zc?NB9lHN_0I#sIF`8365a|AFA>3>Lm9=CAtDXgJv-m&d;~GjW^oz$Nk(#o z1@_a2@uE@10q#}vxN(esT?KbwBA8PA?NrPEpYyT)cg5-dgKbER+m`sAk2Ta?uU_9) zg!RR|*tAsgGaqGH!bakI{!w92PLLRFM>=soXI*OIYUm4;7fv+@-Rlppk~yYy-;f~Y zcJ%Gk`t85CQyCv0$GhmhL<<5aHHdw~BEFM9lm%|p%#Hbwp&mQodTollzGque(8vY{ zR52gtrQ4dcCO!$xA&Ru#v!AX@CL$(HRaHtn!s|1duc@egD!o=UGEWK_r5cS7tNhs` zXU)qVDM>CVNreLwc-GFA*S^Fo;8zo42_DKC(|j8o_}K(;FZ+tK^h}zcEzqyTWWgS@ zh9q-VNo7ZrCv?L8M>F4XBPFc`LGn%7C|ap&BD@1pRflYD?8kcG=Bv?7FhDcF#Y3#* zBRajkVLtbCw0g{{;BLZUXNXE4Z14wHVE*azZ*o4JS@ma$C)d8`c`ZbJk2~_fGvavN z!>{FFkFc8!sb3(TVQQgHCSQ14xZrpu4#;GuWJm0@kuVUqKsRotYGY2ARIOEe##N}v zbX>=47@whw*!`#5H)A98{>QVNI>*K~_FtOT@KY!+UcqjB1B4c-kBRlkrvGYy$QybV zF8{s^o4$h=|CZeN&(Hsd7yXB2N>uui`3|dpKDi%`*(GRz2+1RcH;9hQ4`lzsvXF{^ zASDO;(yU6hckQ&eg3FKILw=zn1_~wR^}Q~zbJj$#j2DQXx|*2syq}!7`gpznAoJzm zJ{9JZ${c8jVh$6aDWuQe$D)R<=VV3+B8O&3?z7tEs@|;vc)&p7En(D+ufG#Db6+i2 zG_pH>tN{ti&V+3C6i?=zx8Hu>Rb89an+j^Ca#Z|_`WR}?UZ%#yU8jLIFGa^8Qht-2 zPIzqsHkga9<B=E<%BeMwf@jd%E`4Fc`6IcC790>3Dl`Ym)3uh<jg<VIQy*nww`sw# z$VW0mia$@&kog?)0mFRNH=Kv9DRhpM4L&qSPr<4k1gB;#(=lNIN3{TO7`kaC7Z-2i zRqVt03It<<BMf`fP{Wh`rb{9DDsDc>-Nbi}_SsrnFPardtK(KG0R0Alo=5;j>-W%a zv;YBaW_n*32D(HTYQ0$f1D}mzt}0b00pREwqaDs63=9t4-W0$vOrgWA$;f-Z?&gN` z#Y@8Jh((?U{Aty(@Y^H#kv>kR!#)il7cQQrqnK(M8+N!FX;TKysz_yWVeZyih+bxz zPFhwq*I9wiJQ<ayh=sx`ASYa64a^);1AIb|c;eKn#KaEYQWgL=N{_1d;GW{Ilk_{S z6od55l?jHZ1!g2utp7lUSiwwo-mEaR0FF9sJI5p*{N%5HE&dEETrAQbx>ZaX@R@Fd zhm)M^g<jf0GU8%9zd`2FezUzMSFOTsFyp&Q5qwh8E8%co;c{E4G;n(7=yD4}OtP3b z>4J!ocM&Sr#Je(})eKrZfmJTtsBOj#%QhS~p?;xq0xat>K!`S6yqJ+fOHe7RiPEXH z=n0VtGLi<r&KQu$p(hH~Bd(Ue3{$Qy=_C4oN5iK4c6ABgweR{}`~N@C@c*s}WGYSn zhbHi8;=CSY42_ygsqwpFM!|^US6~8y7;+q`veX~32i62>buH)7tE89ep3(GVosQpm zp|j;a@eEz7Rpe-uw=-^hN9oU9&rT-Yo*rL_J%lQb4~8PawCJ#I-}SFFF?tvaaBG!b zTBym%9f;9t*5>+-4c`T6gEj75YQhMztT$#gMLkh}wXQgjGilvp^{t|I(d@IA0>GVn zVpcietfni2yDnL&wq|Q@girp$h%7qMbnk`ys)1-$xqmNOeHiRAOobh0h4dia@LIh{ zy#XGd*48bZ$YIF~Nt-&b2;LJ)iLy;M0aw48LMd|`3NK3}exvO<d?E}*z;X2!V}H66 z{k^KhgA%DKJ7C9snK;Dd5v)Q)?P3b03>%Kva$Hkbmypq|qc`#aotE2e&8Cg`t<RqO z7|cUi4Zl-txj$cED@jy)&~)ott=l(9skXbhjrjT{_>oXsxK7lp#v2NQs4T)#v(*T` z4V-l$BJ&{B?HBmT8)3|K-<zm?OhY>ss)<qqV$T;0QqDePXGrX*n=$c(rUBM#M%7Ge zIWENk`o21)P_#jXW-)~E)I{kioj-g;;f4_^#ZwQU<_@rNe^~1UQpev71oH{za@Qzx z2j_M96?FxbSx$UlRhFzOp5&ilB6Vc)#9vV${dogkK)(PACCrVtqRbPD96qi8nbq@4 zmT;U!>Yn$YH3|v82T4{qFo{drP++b-XdQ8sW`iIaxs@bhmv(W2Fxcau^uSMsEK>Rj z73{pi-93B=GkRE^q(gv}Me`lRD$4u##NtahUMW~WV<_G(mZgpxEkT>ktO&T}AiKv) zYPQQC9FaFTI5u-gy3R1+TJ&fCfwY)wTXYdcPDt(be=m1EX>Vna?{aVX*1{P79o+jr zI=)23ZJRl{?>rL)3bcdo`T_?kA{z$wVkc$<DU!6*h>8Dd{}$~`4ejC5hO@{QnXc#T z0QlFBFY^6Xn)J<I{AmrxqTTnI*BR@dpZE9ZzQ7GuM)LKsf;7>?tY@wU`ojVNF&?|( zbnfCK%xS|Q_1F<weSfCouXg_$?UcbA>^Kz7K?C~u(8lI(naxFtb;QU!&?z02`H&FF z!mkS)m6y@=PwvK@>EsMeD+WefGIOsvHuV@0?F+bwogS6kg5}ae=zx=nP;tE?I({Q9 zVRtg!inDjc7#8DG$VPEZA`5Im)BVEC9nv_2iK;;wK}ioH&CPgGb<CbHXDq(lvora2 z!V<&;`*k3^xo>exUQ@(Sj9_!r)kv<GQy;l4&5BxidP|gi!Kdjx2RN`eZo9uOu$j<X z@kk@0-GP+fQd(X$YocigU*uZqXV)}OSaPp*U*f<{ZRiWJt9f4ruI=qsF-u1Io2G=A zxt4Wroe_f7k9DiSz1HcSp!(Vd5CzlJPF{Wb-bUgAv+_A`ij$zM(2@RVD)$|gkc$eX zv_y`BQ^ibcQy%pU{`-hEsUcM#`x_~3r9FrR0l8{lM#>XCJ%encU1>SYu&bJCU4kM% zu&#jOS{6FHo~6ie5+zx|y)N0k&eb>APMu|luTQ!uedH$Hsv?C|)pDP8od%Zf@L%DB z?d11_^zWLo_?E2r{+*gqwzl}c2v(iS;|kx#LLQem@jm+B5D2$HA>`r^fywY7wJ~#Z zlu(rd>NV}eigu2Sg3_d8bT4$Y1!1Cz(0o0K*t*bc)*B~uYR<An0)cV_v>T4w>&?@r zUBxz}*FN1|;CfKaECVr%Gk{uFjmY}Z+SHu@@koWD{1&W1mY<Cm;?p5}fZuOKr%A9b ziNHXw!0W6VB$7$vBI<gct9Ie7c~sCzvE!O1)}s`O1=?z?R{3GrRRPnGfd!f<V$^)` zbVgHg&J4|Gtwq`e`A_dZRrF5i>!%e<_Q}MIwi={u_<O`~jV)znH11DX{BGhDbB@~B zjSCgl=r@M#`x#$EWOOtv=2+bDLHf58<Au(A4EUNezsGw^Pdi?8A8_+S5Br_IW(xPW z(~XB)*D5etMlVPgE>m2rB<#9V4J9>?*vl5oRZfXJTmY|e!7f;(GLTw$3dyXdC-ur& zs_ZQKr0CpVi2L-7ErFzqvnpB^fdXWKiYzKQQQ2%ZnB1O5i8%H>MR9pfj2#q3(f2sp zVrO!56^9YP@>1p*qBZ4b(z8B}iwWo#QPzJfZ2n5J5;l5WWJQ<IBX*k8hhg;q0m7}5 zYiU1hwU^dFU3+G6FNZCON*MU%1-gDBi7DU@E>I2<J@U*<a)(IH%`1nxmS~1fx}A*p zCdZiH4q;r^4q-avoNGPr=TE#!tn}M6kdl`lIeV6*D@WCHkb-ku334Wy$+vsYzfadr zd{Ebpi6AU%ur<dqiQAN7ce#-hF)GA{w_1k>))jQh@YnAnpn|kj!GlSHn`h1%4Pf10 z#$`L|cVl)t_`K}u(j}W>gTh}T{@E_S>wj}-5oWCtG&&=!2_|H?_mnV%zl1v9mRA+J zCMJ^31?>7-WTFszA&y6w3_lSx!8<+n4o@pN{Lvn?<(T0BQ29+UM7(g`QwA~LQZnP4 zU<-r)B?xOkj>kLd9>>fmqNQU{&&ZyHsS0l7`|r20kw*Fg+V}Ep%kOXy>A!Ju{=wRr z>gIY{gR!3yX{l`P-^*cF>v;4mcY)877@BGh6?uPPO0p)^#==jixyOm%O^2i+HnD$i ze?W{vh|)s_^3w|j@ozPP_FI*1=|dX1LRy)u(_anX@r5O@{4qT2{jrrkJ8^;;`Yz`p z>!R$W?6kPNC|ix|@r2;3ey4=Td0YGEQ<bHAxfU(k>?Ht>j(7H!;<Lozl?nE%cvtrC z3oP$)?mjfG+lxZK{&yVW*b}FB*7IVRVG(CJ5Jffog+z21V{~yK->}2=V^6W0W$^`7 zI4ep!?~O!v5~B<=*F@yi7{w_Ts5@e*KyKL4voF&)g4EC{VF$Szr8e2F46~Y@w1hMV zB%|OUt0FB_LN@$5!IPUVer2bGG~Q`Jtd_L+EQLyuIkjw*8Ta0}ElPt!T7GJ#Kxo*& zonOLfp)?We+vTM-Y)^7ym3oj2<t|LQD3PdJwn)pQ?9fJAe*nXhRymsCS&@X*ol!cf z#gb9nRPi|OS@;apO|8_8ZeFJ*$^<%&gmWl%<_a=aVS-sbs?bfX=uER*tE^HotM1LA z>2{2xeP&!pdpt(j%`AtU70i5Ar?K>M$lchY5>M(Uj~|*+YrLz+Z9N3Kui`=?Fe|1= zh!)mB7k+gDHRK;^CKd1GKRWJjSI>*YMszDj=op$RO-x?XI{$YHU5cHrjt6NIvle|B z#L$juDFK31N_xp**g>|YiJyMW_!Wp>UXUE`c<JencEzSf9*vU~B$LVX5Q{llM5D<R z)Zkud(UsMLg(&@;#81h|CbNl&v}Gg1v7b&{0Srur+tU8;5uuYC^qZRg4CTue<+__K zjkQ(!gG($<=S!7p>*Np>XD~WQ6<0EWeTxkBn;XiVq$xQnv48#L<uz9edBidE=Sr~s zwF^cqpc+N}L$5Gsv|?M^dOk7XMApi!e%`AJ8(uD6*6LZTR9Hg>m*K9f1Q8ZhUc3t@ zaByP4iMp@`I;U1fwS$bkGAwxxx!D;{Fr(r!oG;(WaktP|&V_b?=8BQmip6Luj5$0| zhc~53_*^ZlbQ-2(Y8FF)29@X0^xnMcQ5Se~#b*hLhQt+n2DLTSmsT`OMuM0oSz=k* zm^XohSF%XMksLI`ycclL8ia^bIX9+^&a4uqXvT>sPv0wq!P{{4E3DjB=sm@V$Y7%! zC+sm1RYq9hN$~{yN{e7VltX_cA)c|!n;*q?dYXczgf!fg(noPLrn<H#v<5pv%a3<b z7EDhz|Bm(ho}5a61*H#b3uuAfKtNfnPNCGOv9!w7{8_o^=NuRXrVt3R1tQl$#}rF3 zCkX&)4XU<=)R=s?z_x~I55?S!%N*6s<dtbE&hv*theJY~2FW00;s-D>nxesgD==To z8kL8^Xe6-n;aMKLfz8PlRF#MSv?4>??F%vaeY|2;u^2((FqEY{<}^6LdJYlC1ZqB3 z2{oA5)w({3mp4GtYs<#=m=-G}^`WExESws{F`1^KHG35pCaemZYTNP4S&coDVz1)h z8*Z79OCNUVzXp0;MeWe`E?DxliQF|%2gv+p-JXPDdv`g^VtVM@?JFJ?P6J_C73sK& z0ASccOU!}Lgai6b!cl)%Gh6~G=;U>AUOIwkc2>p<plqp!-!7yYUH3ADrk5)8H&?b- zO5;ui@?+C9sw_BLo%v69_<@7ak}GDZUs%U#;1tR0auq73mV#?)Ot^ZkWu!8J&PxJB z{1kL%IoeI&Y^RhnOksi@<kVwP7-U0l=zgVprJqaBUa3J_5Cx6wgNc_Z*u!juX~Jyy zV#97!h-~*>3YGZLOhFEDwM3HA02;!~cRX5T<+xEU;Np547z(7<S_2$Q0L@yHG0Tw_ zPQ@);EUVUHYR(u)u_XlB_6&$5Z#OWZkp1+<b#pO+j?k3B8w{N{O4!;0E0q-+j=Oy{ zhk%QO7J~MI;TXw7MnT$SDhOPX@clx#!M-v^!7c(-$~+q^`$R2i*M_CVI*mcAmLTN_ zCe_x$vIx6uFs;!uOJQoXNKE@k1^4%z28bX{<spd6HkB%-15Nu*0yc8d4RTcs`*_dw znDoOxg4Vs4fDOuK%sX5X%C`-$!8(HGaTj&9)}Df}NOZ<2C+!Jlw<`bnV0AQDZn6Z6 zYq`lxzy^s6S)^kPQ{ASe6Hv4|ht%$BG=^Xo*|SlK0(v;82MQw-F=ZHRM}QB#QL`4E zFM-E_j$jwvvzdLiAKM`~U?Y1l3&=tcPj2@p6)ziaG=vlTC+y!`Ez6OBJA~&{Yuwpr z4B^{7gF(HKe#*h2R>REiT>>AxDj?=02(=YF7$%UbodGTeWgW)mhUq%ohVGsscH}xZ zFvAmi7P59!*J~lG8ifrnwf6T!fOnxnfy+8QVkBu4a81qdeDe<eJCQgh8dhm;#0Ziw z7XT9OAQPpj66On9)$&0xfSWSf{EjIRPQJHDUxGSHq>pEiW>$<4BTR0#DoQW#Xh48w zkOr5#77d`5aa;OS*H+0?*2SoI*}r^XC-_7qOqyh=<N5cfYW%D(!DFy!p~U_?sZK#K zD~9ZJfxs}7<T;KY6yV7_jjb>csx#Lg>hkQ;q_?!}lL-SJD0?H4&BRTO`(T7`&1=fH z0g9@7?8b;wGwu11oSm{o@(2a)+v}dEcFaqdFJr`Tp%QNrqmIDFSa17nefwd?;NaEU z(#gt`FJTu}HP<`XFin|1%8^^}AmpUB1EQQ$c0SzBm)=_Eg<(8417DwupI)rljtaNr zZ!AN8cyEV!L^3VFlg#OVE8?Kq_gdBKK8{@L9YI6kM5O`k4C2vLnrurQ>zRO>*pd){ zz3B0|ccsUkB^<*IiL?N3Kcj2iHMHJbD41!e)8V1H5xSTc=e~^O90+yHjLh1Wa+A!h zsoiZ6;mE2e)6``%fiuL#d5-M={fwoxF9fU!#-A<PEw!f?Y3>*n=IWKM&w6fl-e<0p zdsn$Tzxt~Hkl3`0vvVNwF?<Nq+~1R0%6RKGrE0P;<#d}Za%)O$$Iw}cE<@p{q)vU` z%?cQ>#PRg}gj1OfgXZX(wfV=*t!t0bR$4n!F}W{m&0LlNF>A&2Jm-taK&Yln0GU5z zg!R9P+|Jc4c&$~?;e0^r=y@EmV%*K6r^IyM+Jo+v?U}Zaph@_=ol40*wb0{(PeHbw z>xTsnVu8b9`43^L!`Rw3ZM>{%%-%P=J3nCihI4UopHu_=f*oEV;eU>t>SB?$kzD<z zc3bb;yp1{-j6LMu^6iI_K3?U%wm410tgqS`Mqa9{qqi1S&{)j6<>v;~WH^`S`elYG z*-6@0jA_om<Y`pTwjy<}P0U7o7%357^tsAEV#czco3fhb&Ql6<edNE?chZp6ts6T} zn|*Ib$ytl$i%wQrmYk3CC<53awRpGsylu6Nv{Clz1$nI7zeX(B#ZJ3)`D=k_&#`B} z`qOpnb=Qjb$2QZ5Ti;$sK;;x(3NZZ9o=g->I-bj}^^@vts~0>)LPgL8s+ErVUw*UB zn`>FfTXiWa>Yw|TgrdG!mqU0}+vBytAJ2b>*|<^jXExZ(40s1!Ut^ay;5%C{%nu$2 zbZvhO{fsa>86G*RgW~X&k394u-+}H!zIo7Z&};6f5()C}?n}|IG45FpuWdi9^=+;x zLEm@I&%xhMM?DW5^0LP-2JU1xXOkf`?vdP!_h6`9Lce+3LqXD#@fSzqSMJfQsX>po z@MJYcqzFT;M4JJ6KWrV@<4Ke<jW-V)bSx7-zvV1I!M=G_aE#9$Sl}Tid}LO*=J)0+ zx+j<M@S`R!d!(ob?&6&o$!#B^Q0FxjmE`I;9I0BQmYB@#D67LKK~d6BTMD-q*4he( zT9mDL1b^==*@*1(<uj*M?v?)2RyL~{ubNP-rSkFXXpZtz!5MY=ES1nnv>*#febLn_ z>w@cZkC(cLHm<6wz6*Xncuo@WbSZYya>K>a#F$Q|dc{UKB&?WBzW0e+N)Jg&82PLQ zj>?XA{Sm?dxM?5gAqP{{fM{M1+0cp!ZwQS$68d&|B}{jputRd}xdt{nA9Q$@l1OjN zwPBRPEZM+OjDqt}$}*WW&=}cSj4W?1h_)37eOx+ZRA=B&{?i+b>yYDNWV}UbYk=)Q zP>aH+hvg2lDxPoOodbaFV4spi`Gh}cc6QhgZ_BsdPLKH=`oZCekYCCWnS}93Y+G@} za!L0GzeR8iHDvG>isJs$IH~dIu+43%6sAgXN?`AKa`S4wTD&sOfq!<Oez8ANUPqDY zg>yL+ooa`CK*a5zP0v<5_Vz--GC62C>eyW3Jv6(Yq3-K%NWL6Xy!!|CEm|)Mz%W>E z8o}p}6cv@1RSD1*Et%D)=A1BlM=CzT0YvvVP&fOXK}KZ{D8k`P?nVeeRZiT)*pEM% z=FU_qeKs+p%;7KvQdJQe#e{H?@5!Jesxq)<)e46sH(6w?SKJ)^FkwkxQ^6~{Jy>!L z?-0%cPaPB9Qg7@EGm^=Q4d9)a>IGPIM!an+Kj=s0)XsqsL{vM{mxvH33e!z(xV#6{ z`Ke{~DFS`$k{wC!l};Mz_P4M{A9wg2cg30(J!DExlI6~DOy0jNOTs*m^C+sdVS>|8 zKQbY|-cZxXWaaYAPh&a(6n8nM<Q~jV7H%>C$E#4Ax1dG1^7U`<hJ>kbyP)eNt<$z# zeKqf8_zvmg@OpT5%}K7@-KjUNJ3r7^Rf>FD;loeDy{U_?lNQ`5X<QbN-f@Dz4^)(> zXHyC%i3!D^8iGWLS`tcKhJXqJ60@d+&adg%I-N)y%VpG8B@euw1mA7gj8|K<pv(RP zzr(!V@!@B%_aIaJ0gjCz$_1)gI->2kPH>G~2^m))x1XKx$48W}sSyxP{S^wVRF|HV zSk#xKrLp;$DhJ9vDqaY%EILEM2Ie>ubBPA(l^rv|ENJbGe@9V+j@`0`*N(IrXNb+t z205{qs|n4g|1uYbn6-A<23RGq1$3<Li#1?IZ%?py?1U=8=!}ghoFojpLekGmVv^L? z;9I0*^B<W8o;Jo~+Os(vcn@t746WK=>V8EW-~7xP9?syH(BlAPhezomNa`j4br9Fz z)=~FT)xlItaCuX3-KK2-mJdlf2&(s_-7;NWiW66eC_FeWNyhAkMMLJM8Npo?+Ozl3 zBevk_Vd?ByzGrXwCsVhv6s(Tp+}Ppw3y4LwYlS3-2BbkP8R^(QNOla#O~s?%vbkoe zBg7QnQr#UJByEJVsd2iM+}^v!s~<Pki5#X^j#ewCz0)vEZtY&Pn~tBzj=p%fD;h7u zVz}Wn$~box>Q^P|b?a;Rxpn}(?tsFwEWKETpFp4?3BvCi5gy4)HQYE#UD<JtrVm2l z7*86KP&2s%1`Qu*dto@Bteu@9*C}Rs4Q&m38}p@MGGb$MhmYy{Rofnx)$v+NRHxH# zmZtydEWY5^0qr-x2S7QY+sNl{2){*j_rJ8-{^&15VW08l+uF;rQJi&wpzA)Q`H&r` zcL_D^?nl~clDwsB`1(M}Qm(;z7oBrU)G6><7N|{(C=aHd(2(eQrshhDxlelF8qM>` z?!0>eag8!)0GMz9P1*xxHa$t6>2EWBNqBCD`#9Y24Ad)Tu`6xK*_p{(M;4Dbj0LQy z%O9jFpEv&AJWr7I^R~32?HCc~v6<%wf!D(hX9T6A8GT&3cqG%Ov}t_I^NJRnkCk?) z40aie{3tP3S-krhh($@gBH7JJs$BGY!0`02RLo%7Lxm;5!mS%1%yUC9v`4f>ieE4H z#l!OqX^|s43*g(cuhNd>V;JW(jq>3?_#5Zu!R`cQIIF)&sZ$kIb0@Y*8LZGeMsTds znrK>jN8=W3HoVhJ8%0!N;w!@&QL5YHfg-HJ%tTy__Huju0)K2$Wl{|%)5`w*z1p=m zqk(I6-12zJ=u`GR8QMYSslPAtZ@0EflK#cS$XoUTvUzAD5C{~PM{Op$pD8|ftE~PX z{g+?P+@KCOnx(#?cP%8e!)k;X?=ysdA>^SgL=k26OVx%=wa~L|(d(mYv!{8dcze6j z_h|LI<1^Y<o?RX9oc9=~qD_4`-l$f50?vt6bw@wbFRJejZW_4kU{9-!eQ-}zkSTO- z4?q5eS;7iG<Q@IyV}E?JOaBYA^q;K0(SPN+|6`Kgf2p{t<}TQ#sNN#$BX<MgXC%(? zO45d!NrxD5KW-J8qtav8n-uqkhA3#HDncuimdNvCk((1}<;+%dEzMWifFWa0;`Hp* zx_WoHwqJ&_b22hgj=fBYC6`(lM2{yno~OLBpSO-_nO=uG`93jwe!kQCJEu_IA-?D> z5rl?QRzUbq<^7^<3Nrw4iZW@%LvB%uj&Gr+rJ~GIy%hkFrYABRAUnS$q%D0>;?e0F z*YC*NTZCx#;`B%J6dANYbnJuKuiyJ@rPo1!W(yoV9-N|E*bi?ZPSQpCp{sJ6NZ*CU zkKUycUA-@@e-CT-x2UC~bWalsYqBGg!6Ar<im54aw6HX_BZuxBSePpwH)Za=AL`76 z@ifC4okp;C^sJa@in0874j8WIrog-qd@d<#3=0@~b)qM}O_^R{|7b2QOH$gzeu%<t z?}j`U`z}eI-o7cHQVE~eaD~~eKx5x72c+)18DAAk^uvl6Zz_ydKixyREj26aNu59e zdFYZZqp1-jO4S;|Q=Y-Arf1j3PV%O;fO(#xgosF|5OkfsDGHZ7hB>FWmEw1t)0(NT zZ%ah9P*p#+ogxb4pG<{n=s1{w6yf)5Pnc7k->i4J$D=#<?M$I?U0K?hS7DJ{XmYL1 z$*JUANc5!G=*N2^dUlbO>oy!(LeDbH6emaBR=LFm?bmTzLCYIaUSX9i+(Np3Ech~* zZHTPZ`qMW7@!C0m)ySk|8>=iz9uk3a={c)1BmX_(iy>YbGwBzbB70ITRD;4)n5Re3 zv3feudeh@Wv$Z^3LRkfij>W8`O&Xe0Gm<P9kBEPZ6?L=1+A3nTS%Do>Itv={wt<V` zl9VjgxJc7Rs@2vI6jBy^6GX@Mo7DBpv^8NF%I4Es8Hd%1D4TSGS*bgvsf0_UefSUO zlhOpCjKz9kL+Dras$Sz`H{46fK)!Q*kFUEgzP`l_I}Oh2auXo8ocZOEi0?dqgdyha zlNHO&ThKff+&&cK=C9Kh9W|qHi<9BcG;o~1SX<G+Sa7?({@|=xQR+!ugb+(NKRxC8 zHC;9PU2b_`w};_T2Cj}792$9encork6mAWh`b?IT--Y^RZ<#>BH*eWd&MAov7wPat zRX+eoZInHV$FwzpEE#?ASl&^}UDi!0=un=cDFEG_WE^xJtRnhKeVAkBcPLe5t$F(B zdMxkAZQBM_DexyTjp?KgPItFnTep?d7nJi;%7+2_B3wz#V@$6<-6N=m@0Eb_ma<*2 ztl1m5s--y1ew_AvXWGOBMlS{P^oSw+WJ3-`l?LTUxly?Y@u^I6d#dM}QeckO61;u5 z*oLSY({aV(R;c;E4J-16B^vd3ZXp@#!TXInjaahq0>{!8;$%ZPqW!!dTfeZcQFyZ1 z>`NnKReAcFyh{VoCo(Ecg&r#L7$AT&J50!dWuZCSI$7O<R^@nZTC(dU*s~-ejq6b| z=7#&<8Lf_k9e&8qp3BkqB*I_sr_t!>;2*rs6tQS_bbKP5x$#Btj|uuR!tp8n*%I3T z#I*o#zgxZ75dLNmV{k-117H-Xi89zDKYCfrph%G{*9i8aW)#fi>{Od&bOn&EF~ftt z+7Pq>z)@g8x%{iNrNriHjL8#Tcz|$oqk6D3K2kKbzn0Hlx!8<i`tSJshb+icE8n|p z@)xG2Z!=;3@_!<)1YuqPB6(a<;dfaEZaBrUcB2H};q~)>MjN0IXyEo3x@M3g3*q)7 zf=$>mM3McVz#U|myVoDXx{f+xFGNmwCa95_dZ&z|Bvtyn?%{DPH&dD&SoE3s&_z0x z;~M43AnS-z%h+87s-#;(dqrM5{(uxI-x``q{p*WxUWkEWpcdlud)Nt*NWi7ZdDIrC z_*E;|%V30~wZFY1*p<%<Jk#jCx3s4uJ~7vKN9oQ>OpJEBchiO-F5;>!XwzZz1kddp zLZ#w8zx>=scB@Ztd0c#j?z|9PpBNz*-EK)g4%Ib=AD#i#u%c_fz|}vELP1yJH;%_G zBIz&kcdB@=G(LXklqV+FuusvJHyD%Dgh&vGat^kil{edhO2WkgZP$cFd57ALEfGEm zA{ooH`(!1zw_6z}?LjLUIq8nv7yXTl)rjW5#`YLa&C~01FLasqF-bD~i?@MUFJQU& zSK^=jJ}|QE;-6WsfAZ7xKB+J(n3l$B6d_yYh*tf=XlZKuwE1eZmsuk&H(f!fH*$*- z=8VRBrHYD*9hKoEhI<&FNX$4HtbcL+-fc8Vrj^C=axFkI+|CN6am>_(t&OL%n-LR| zXL0(#i=SzkCh-Z&b)93uyM`NMyhTR&m(~3<4n_DN8BWx=fa0lu|1Wo@HZ_;#WnRA` zFqhUtg=`xdz#g5)lATxmS6KhH?*TGIn9kY;$7<LVWZR956j=3fth1qe-()4}Zw$qa z;8yJPxinL7tqQSn6=zjLjQqO@7}}N)4z@~<GPN|c!IXsknq<)jo0s)p6bSoeBe6}? z)8gz9hYn98@<n3eF!cD9>BRg7*A5X&9B*MBPkOrMH%aA`I`Ybng+8#5_=~W4X{{&s zp|@|-*oP4uBv0IA7toH!!d(J7dy@Ny_DjwVaC~P;D|)N5{HHp?{K9H-kn(a+Nk${B z{~CaG+Xi)9`xa=0zdbJ0|5IlAA7J1gd)GgZAo4rry6_u?XS4cB)X(^@9Ed(@ps{>e z$;(f|5Hm3q2K9j6W_=e0u=dNMOQhZ68_T_L_>>Y5@dZ<#gj*R+J$2&S-1*dXk7=Ic zjqk;++de;1`r?`E$jeg1i2Mzpa9gs94gq1K#1G6!EvdaUQY3boUDqWoRNM3Rt;Ks? z|EIDufroPI<M>d>lu~1>khSb`Z}t=!`zW%eR6~<(n0XDNNTWf@b}bdxZX%T;np@o~ z(jpSKP@+_Hy(&v?mP+^bo{8~rj4|)&GoP_^zP~ePd(Lw_=l4G;fL^t`kw|tiVN}*L z&USsIm7Jk{c%)>R9*x(!@`lVOub%65yrN#sRP#t;S$u}Rid7@pCX|9Mh#q$0D>wVy z`ks^`e)vp6hryw}6~U=;H&Wd3y($#i=Gfb3f0I37m4Co6CP43!Z(x-N`X5osp1tms ze%c3}6kDxdVi;xvDg5Kk=TLkvqlYWfL@LvboWsVW+U`h~6rz383{`x@j1I34O>A9u z(OF!w(7xw%ab7W5$HpM}K%Mf9$YGm+jk=D;r>mTjH9CcgYjXwbLtab1OI>AUy5g{C zP<EL+S(2fy?AM3gen;uP$g=DpcOBb+jj3wGpPx*i$IF%EQIA~w2Yb~!ACk({bG)90 zbX7~HUIl^sVnHyzi+Njd8+yOE-5J5Yd}~r<Q<7xd(#%k4`zY~gjhI6I<L_&Sl+)5j zZTHHq=-iPMGZ?QL!aH=@=iHkHdo|sC(Rpc?5}(w#@rxc!y>+qH{X$!n|DOCvC7Z1h zLb#ijLmCEVe<tV+)Can0+8tPK-@)^|drMlkteoG(iKAxy6}b_=IDgp}rQ+e(VqvKM zpiXgQ;`5^Gk{$yz*Oq&v6GH_9!g1HKZYI5L?iRnhJXtP(T`l>mlBALG`lx+>j-CJM z{h@xv#Js&KqkRhBOy1ko*g1^9E1Qrp(!v^?%anZ^SMoN$#p>Wa#eciXlWFTD1ES($ zH&V4-ltR*P33%k}#G;=mJh;o#As5=>+aU21_EK|k|9@jb19hYPwg}y<lI{MK?5sg9 zbib|9+HP_6bxZlku^ud@Zcl2fp4{^=!JQxD;=e<Og7$>m-xdxYfL#h6fHhz<MgmE` z1kWID41cpzY<AQdi$pi`Eyjj#wYyW$U$Zz<BDhE1K3=szL1Nt0@U)hH?6O6I->qHN zYkcGRSE)zjf>t}WM{V$3mj0`ekRsBM<`vXf`EFyewPD2G@^lO3*a69qCC@P{(GljB zE`En-IER~AWiM9AR!j4{Uk=#yOt;C+#-Op<(;EA!y|FJxLO9WFXBeaS><3EcaP&*( zzo~{Dmbt3xpYxQDABzsC^mB-j_Y4fixsHDJ@(yo#wk?L1;9ELcW8OHntM9o~DYh@8 zuPLcd@fq&(3&k|dQ~tzN!->&}k}9$L;?Dn7wRQCA2?Hg$*v-@qnn$E{Tf&&2xYXs+ z_LD(>AN;Ua#b*3^n-u!hwIU%`r>>7{oU5eb3t#wbl-7!T;3rgjJ92pfS?_rEApy7Y zS9*>cy#}|gS#39hFKYTV!#^#)X~5`sPNONB&!GZCky=_LR?Jg)3KK5)P-{=pn-RD7 z|KV4UFm2h_XU&_LWA-qv&zCnd!%S81{Fg%;N=8@A{_{GzS<i^srr*Har$4t%;ZSrl zZigT{&g_(j)_06WVw&48`d?!_^=&hIp}h@bcQ;x*SxkJVrro=vnbIx4C}7sNZ0oXi ziCVg@CU(^ZAK?;{ySuV}{?z>aQPzz=BLBF>Q^P|%BeNnwjwq79i}r|@D4J&`6WOqN zeY4<!j<3najE8lWc^zKTUAUJkPaZJ{Oxrm`Ib~p~;<{=3-Ah?z$7<|zmv&b2Nf~;( zE&o{nFY~wx^TI-QHNX4d&DOORr$TP%I>?>G@M^Cmc%VrU_17)(9zUH(3Np8iJ<QNg zjtXO3WgK-qqNGeA<M!(kG|Cp+II9VLc61G`FE}|`opun*=a`2w<E2~VN#3=qa}lBT z@L2m__C9*G^!~a{`X&Rup{3UzmkE`&Q0{n-H41sPW)uVn>wT-!F6ng7(=exsw5C*3 z$^`UBU)w+AjcY3CzPctu1(Qyh&@|3*@)ERG>GdpMP7qb49B)w7x`l3AJg7h}x;0XH zOs6_OLo-O7?~z)8VTm_**C=p9U)bW;@Ae%!8vjrG)&fz`lo;@0df-oa--Bn=Is4xK z#g*H=;%p+BqtiVPugD@`558mx$YcUuh-p4BSDQ-0sDU59vNdxwQMcM|u4!j8JDY#` z79(TupPA21fk;WyiB1KNgrKIg*_v#(GB<N@)UY*&3Ct{@fB#6}p}wia6#f-_&2*gQ zlmoc!%*atam1DA2Ic8)wz+_@dy$4^;Ft?owMKA}DuGms^0}RO3V3O5j<p=L{sucJs z8^AUaDTo4G|H-y^p8#;|lIiu&vfqP0mJg5G#dTnXqW~I(8ElP}=u~+i$0dAn(F3Es z?f;D^0K6yQCC}o5cRDozv_2a&7Wgp`N%#Zvl~q~MQ%4W9Ry)|Dne020R63OmIu9ox zmT(XsOblWPfD4jWAb~=`fk@?q09GIbxctr6&|AboC&2;9O|!}`0Gx9<$pL<7m`QMu zH*k#h@kHEDV1*sox$ABN7DgI{lAWbM7UrnHzQV((xPp9uX#g*#oi!_g`T?V!LxH)g z4_W>2B@A%#i?(d?zypHcFT)lO%(98W6yOD8?n5M)czS{wx5WqGz2>X%<bIl37^v_V zP~o%tqSpqt0v3UI5C+u=xJz1+{0TS`$uF49zG^Z&b##kCClL}up;TA}2k&&MD)^R7 z)l8zNf~_&f5qs{}Zi(ItfYS+Ha<jN=K$l^|wPN)__B?%}NVhW>9Wh`BayD<VHhW$G zB?wO>&NpQEt}Go42UWTnwA<_|%>>Wwvn$^e4><WSxu)I(Pe1lWt@tKfMhCO6G2qI~ z`sjFLPH6VDkJScaBv8;zU@iikbvn_hrcP{WIFi@A9f=gMdL@Ggh1w6MFuiFMv$cm@ z*uv~U;1?4Lh2ZZ2qUtK(NS=5i7R(KSJ|4k{**iRXrL5b##lTdw8;oG)ZZRv-sS~>v zR$*TaG$<A@!gRv3Wx~s`S&@O^62p--5jx=@Tl!T02Maqm&L)h8BNrm*{XU$~v*Q@T zR5)l4Lj65(dKtqhgbxg40zfbOk(g@*R-#kaQsw~XU&(O7GGq2kCgwH%0Km=|X3S%O zaAr7y4=X#JnmRW#D~QVc%WfDCM`c0q(jjxo#=>)R%LWU<(G(D&=EHM@W|V)P*a|Qn z4hw+b3E`aZ&|L|Ph28KG?7aw1*qPfsFcbDhMwm-!oR~lMl;&Nk!8XJQb&MP8{HDZk z@nIuXL@4_N7sa1zs|pLiwv~uL@+mF^IG9+%O0bI^qVyq&3ni{R?O;vVhz!xpO5sA2 zlPwu61)H)UQWF_mNO7=eft6tY3q<K_78gpBqs4@+8wM-|y9^*w-*dT^0`m)V`kpo( zghk+^+la`DLas$7$LkDZ8(0NCBaEmlJIA%k<f%#a>jn5ACL*xp{QoJiP>sQd;1H>C zumXmzaWkg(sYz|Yx`GcxA$*%sF8G{}N5KsPpCLiSqRSQ*W8W6=(*p?eRqY(+kLsBF zECF0j_>T|>v%g_sCZ}r@ymgC^g`4J*x!=fzKLNa*i0Hg+o}&Y=W@mJx1uo<878fG( z+vDkl-FzEfaG9BzS*t|m?iMT2se)iLW5(_odEUJ)I~zW5%Y{PefPe47&D?g75rz66 D613UA diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index da9702f9e7..e411586a54 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,111 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,87 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a141f..6689b85bee 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,10 +25,14 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/postman/RpCollection.postman_collection.json b/postman/RpCollection.postman_collection.json index 5023bf3054..6c93e416ec 100644 --- a/postman/RpCollection.postman_collection.json +++ b/postman/RpCollection.postman_collection.json @@ -1,403 +1,403 @@ { - "info": { - "_postman_id": "318614d6-a5b9-4a7a-b040-e35f253ba572", - "name": "RpCollection", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "API Info", - "event": [ - { - "listen": "test", - "script": { - "id": "2464c641-2864-4fb4-a92b-4744f3b77617", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate Build Version\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.build.version).to.eql(pm.environment.get(\"build\"))", - "});", - "", - "pm.test(\"Validate Metadate Activity Action\", function(){", - " var jsonData = pm.response.json();", - " var activityActions = [\"createDashboard\",", - " \"updateDashboard\",", - " \"deleteDashboard\",", - " \"createWidget\",", - " \"updateWidget\",", - " \"deleteWidget\",", - " \"createFilter\",", - " \"updateFilter\",", - " \"deleteFilter\",", - " \"analyzeItem\",", - " \"createDefect\",", - " \"updateDefect\",", - " \"deleteDefect\",", - " \"createIntegration\",", - " \"updateIntegration\",", - " \"deleteIntegration\",", - " \"startLaunch\",", - " \"finishLaunch\",", - " \"deleteLaunch\",", - " \"updateProject\",", - " \"updateAnalyzer\",", - " \"postIssue\",", - " \"linkIssue\",", - " \"linkIssueAa\",", - " \"unlinkIssue\",", - " \"updateItem\",", - " \"createUser\",", - " \"deleteIndex\",", - " \"generateIndex\",", - " \"startImport\",", - " \"finishImport\",", - " \"createPattern\",", - " \"updatePattern\",", - " \"deletePattern\",", - " \"patternMatched\"];", - " pm.expect(jsonData.metadata.activityAction.length).to.eql(activityActions.length);", - "", - "});", - "", - "pm.test(\"Validate Activity Entity Type\", function(){", - " var jsonData = pm.response.json();", - " var activityActions = [\"launch\",", - " \"item\",", - " \"dashboard\",", - " \"defectType\",", - " \"emailConfig\",", - " \"filter\",", - " \"import\",", - " \"integration\",", - " \"itemIssue\",", - " \"project\",", - " \"sharing\",", - " \"ticket\",", - " \"user\",", - " \"widget\",", - " \"pattern\"];", - " pm.expect(jsonData.metadata.activityEntityType.length).to.eql(activityActions.length);", - "", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Authorization", - "value": "bearer 78afb592-b4e3-401c-8097-f45d7489898f", - "type": "text", - "disabled": true - }, - { - "key": "Accept", - "value": "application/json", - "type": "text", - "disabled": true - } - ], - "url": { - "raw": "{{host}}/api/info", - "host": [ - "{{host}}" - ], - "path": [ - "api", - "info" - ] - } - }, - "response": [] - }, - { - "name": "API Health", - "event": [ - { - "listen": "test", - "script": { - "id": "fe96f91f-1539-45a0-8e08-c11dc784ad65", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate Health\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.status).to.eql(\"UP\")", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{host}}/api/health", - "host": [ - "{{host}}" - ], - "path": [ - "api", - "health" - ] - } - }, - "response": [] - }, - { - "name": "UAT Info", - "event": [ - { - "listen": "test", - "script": { - "id": "b1730e92-c7c7-4e73-8fe4-b3fbc92b2f9c", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate Build Version\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.build.version).to.eql(\"5.0\")", - "});", - "", - "pm.test(\"Validate Project Roles\", function(){", - " var jsonData = pm.response.json();", - " var prRoles = [\"OPERATOR\", \"CUSTOMER\", \"MEMBER\", \"PROJECT_MANAGER\"];", - " pm.expect(jsonData.metadata.project_roles.length).to.eql(prRoles.length);", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{host}}/uat/info", - "host": [ - "{{host}}" - ], - "path": [ - "uat", - "info" - ] - } - }, - "response": [] - }, - { - "name": "UAT Health", - "event": [ - { - "listen": "test", - "script": { - "id": "d6803e52-8276-423b-941f-e0334b6364c8", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate Health\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.status).to.eql(\"UP\")", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{host}}/uat/health", - "host": [ - "{{host}}" - ], - "path": [ - "uat", - "health" - ] - } - }, - "response": [] - }, - { - "name": "{{host}}/uat/sso/oauth/token", - "event": [ - { - "listen": "test", - "script": { - "id": "d338cddf-0851-4d2b-b414-9147a109cf31", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate Access Token Value\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.access_token).not.eql(\"\")", - "});", - "", - "pm.test(\"Validate Token Type\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.token_type).to.eql(\"bearer\")", - "});", - "", - "pm.test(\"Validate Refresh Token Value\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.refresh_token).not.eql(\"\")", - "});", - "", - "pm.test(\"Validate Refresh Token Value\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.refresh_token).not.eql(\"\")", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "noauth" - }, - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "{{Authorization}}", - "type": "text" - } - ], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "grant_type", - "value": "{{grant_type}}", - "type": "text" - }, - { - "key": "username", - "value": "{{username}}", - "type": "text" - }, - { - "key": "password", - "value": "{{password}}", - "type": "text" - } - ] - }, - "url": { - "raw": "{{host}}/uat/sso/oauth/token", - "host": [ - "{{host}}" - ], - "path": [ - "uat", - "sso", - "oauth", - "token" - ] - } - }, - "response": [] - }, - { - "name": "{{host}}/user/default", - "event": [ - { - "listen": "prerequest", - "script": { - "id": "a1315561-d45a-4879-b0a2-6cc2f07bb86a", - "exec": [ - "pm.sendRequest({\r", - " url: pm.environment.get(\"host\") + '/uat/sso/oauth/token',\r", - " method: 'POST',\r", - " header: {\r", - " 'Authorization': pm.environment.get(\"Authorization\"),\r", - " 'Content-Type': 'multpart/form-data'\r", - " },\r", - " body: {\r", - " mode: 'formdata',\r", - " formdata: [\r", - " {key: \"grant_type\", value:pm.environment.get(\"grant_type\")},\r", - " {key: \"username\", value:pm.environment.get(\"username\")},\r", - " {key: \"password\", value:pm.environment.get(\"password\")}\r", - " ]\r", - " }\r", - "},\r", - "function (err, res) {\r", - " pm.environment.set(\"token\", res.json().access_token);\r", - "});" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "id": "f2a5311a-87cb-4b81-bb35-379713824833", - "exec": [ - "pm.test(\"Validate Status\", function (){", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Validate UserId\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.userId).to.eql(\"default\")", - "});", - "", - "pm.test(\"Validate Assigned Project: default_personal\", function(){", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.assignedProjects.default_personal).not.eql(\"\")", - "});" - ], - "type": "text/javascript" - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{token}}", - "type": "string" - } - ] - }, - "method": "GET", - "header": [], - "url": { - "raw": "{{host}}/api/v1/user/default", - "host": [ - "{{host}}" - ], - "path": [ - "api", - "v1", - "user", - "default" - ] - } - }, - "response": [] - } - ] + "info": { + "_postman_id": "318614d6-a5b9-4a7a-b040-e35f253ba572", + "name": "RpCollection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "API Info", + "event": [ + { + "listen": "test", + "script": { + "id": "2464c641-2864-4fb4-a92b-4744f3b77617", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate Build Version\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.build.version).to.eql(pm.environment.get(\"build\"))", + "});", + "", + "pm.test(\"Validate Metadate Activity Action\", function(){", + " var jsonData = pm.response.json();", + " var activityActions = [\"createDashboard\",", + " \"updateDashboard\",", + " \"deleteDashboard\",", + " \"createWidget\",", + " \"updateWidget\",", + " \"deleteWidget\",", + " \"createFilter\",", + " \"updateFilter\",", + " \"deleteFilter\",", + " \"analyzeItem\",", + " \"createDefect\",", + " \"updateDefect\",", + " \"deleteDefect\",", + " \"createIntegration\",", + " \"updateIntegration\",", + " \"deleteIntegration\",", + " \"startLaunch\",", + " \"finishLaunch\",", + " \"deleteLaunch\",", + " \"updateProject\",", + " \"updateAnalyzer\",", + " \"postIssue\",", + " \"linkIssue\",", + " \"linkIssueAa\",", + " \"unlinkIssue\",", + " \"updateItem\",", + " \"createUser\",", + " \"deleteIndex\",", + " \"generateIndex\",", + " \"startImport\",", + " \"finishImport\",", + " \"createPattern\",", + " \"updatePattern\",", + " \"deletePattern\",", + " \"patternMatched\"];", + " pm.expect(jsonData.metadata.activityAction.length).to.eql(activityActions.length);", + "", + "});", + "", + "pm.test(\"Validate Activity Entity Type\", function(){", + " var jsonData = pm.response.json();", + " var activityActions = [\"launch\",", + " \"item\",", + " \"dashboard\",", + " \"defectType\",", + " \"emailConfig\",", + " \"filter\",", + " \"import\",", + " \"integration\",", + " \"itemIssue\",", + " \"project\",", + " \"sharing\",", + " \"ticket\",", + " \"user\",", + " \"widget\",", + " \"pattern\"];", + " pm.expect(jsonData.metadata.activityEntityType.length).to.eql(activityActions.length);", + "", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "bearer 78afb592-b4e3-401c-8097-f45d7489898f", + "type": "text", + "disabled": true + }, + { + "key": "Accept", + "value": "application/json", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{host}}/api/info", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "info" + ] + } + }, + "response": [] + }, + { + "name": "API Health", + "event": [ + { + "listen": "test", + "script": { + "id": "fe96f91f-1539-45a0-8e08-c11dc784ad65", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate Health\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"UP\")", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/api/health", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "health" + ] + } + }, + "response": [] + }, + { + "name": "UAT Info", + "event": [ + { + "listen": "test", + "script": { + "id": "b1730e92-c7c7-4e73-8fe4-b3fbc92b2f9c", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate Build Version\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.build.version).to.eql(\"5.0\")", + "});", + "", + "pm.test(\"Validate Project Roles\", function(){", + " var jsonData = pm.response.json();", + " var prRoles = [\"OPERATOR\", \"CUSTOMER\", \"MEMBER\", \"PROJECT_MANAGER\"];", + " pm.expect(jsonData.metadata.project_roles.length).to.eql(prRoles.length);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/uat/info", + "host": [ + "{{host}}" + ], + "path": [ + "uat", + "info" + ] + } + }, + "response": [] + }, + { + "name": "UAT Health", + "event": [ + { + "listen": "test", + "script": { + "id": "d6803e52-8276-423b-941f-e0334b6364c8", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate Health\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"UP\")", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/uat/health", + "host": [ + "{{host}}" + ], + "path": [ + "uat", + "health" + ] + } + }, + "response": [] + }, + { + "name": "{{host}}/uat/sso/oauth/token", + "event": [ + { + "listen": "test", + "script": { + "id": "d338cddf-0851-4d2b-b414-9147a109cf31", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate Access Token Value\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.access_token).not.eql(\"\")", + "});", + "", + "pm.test(\"Validate Token Type\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.token_type).to.eql(\"bearer\")", + "});", + "", + "pm.test(\"Validate Refresh Token Value\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.refresh_token).not.eql(\"\")", + "});", + "", + "pm.test(\"Validate Refresh Token Value\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.refresh_token).not.eql(\"\")", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "{{Authorization}}", + "type": "text" + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "grant_type", + "value": "{{grant_type}}", + "type": "text" + }, + { + "key": "username", + "value": "{{username}}", + "type": "text" + }, + { + "key": "password", + "value": "{{password}}", + "type": "text" + } + ] + }, + "url": { + "raw": "{{host}}/uat/sso/oauth/token", + "host": [ + "{{host}}" + ], + "path": [ + "uat", + "sso", + "oauth", + "token" + ] + } + }, + "response": [] + }, + { + "name": "{{host}}/user/default", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "a1315561-d45a-4879-b0a2-6cc2f07bb86a", + "exec": [ + "pm.sendRequest({\r", + " url: pm.environment.get(\"host\") + '/uat/sso/oauth/token',\r", + " method: 'POST',\r", + " header: {\r", + " 'Authorization': pm.environment.get(\"Authorization\"),\r", + " 'Content-Type': 'multpart/form-data'\r", + " },\r", + " body: {\r", + " mode: 'formdata',\r", + " formdata: [\r", + " {key: \"grant_type\", value:pm.environment.get(\"grant_type\")},\r", + " {key: \"username\", value:pm.environment.get(\"username\")},\r", + " {key: \"password\", value:pm.environment.get(\"password\")}\r", + " ]\r", + " }\r", + "},\r", + "function (err, res) {\r", + " pm.environment.set(\"token\", res.json().access_token);\r", + "});" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "id": "f2a5311a-87cb-4b81-bb35-379713824833", + "exec": [ + "pm.test(\"Validate Status\", function (){", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Validate UserId\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.userId).to.eql(\"default\")", + "});", + "", + "pm.test(\"Validate Assigned Project: default_personal\", function(){", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.assignedProjects.default_personal).not.eql(\"\")", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{token}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{host}}/api/v1/user/default", + "host": [ + "{{host}}" + ], + "path": [ + "api", + "v1", + "user", + "default" + ] + } + }, + "response": [] + } + ] } \ No newline at end of file diff --git a/postman/service-api.postman_collection.json b/postman/service-api.postman_collection.json index cc37003226..4ab47860a8 100644 --- a/postman/service-api.postman_collection.json +++ b/postman/service-api.postman_collection.json @@ -1,48 +1,48 @@ { - "info": { - "_postman_id": "1c81a0f3-8beb-4317-8749-0d506c95eac8", - "name": "service-api", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "GET Info", - "event": [ - { - "listen": "test", - "script": { - "id": "3e2613e1-567b-46da-a520-f54f5a7936f7", - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Build Version is Present\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.build.version).to.not.eq(undefined);", - "});", - "", - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{rp_url}}/api/info", - "host": [ - "{{rp_url}}" - ], - "path": [ - "api", - "info" - ] - } - }, - "response": [] - } - ] + "info": { + "_postman_id": "1c81a0f3-8beb-4317-8749-0d506c95eac8", + "name": "service-api", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "GET Info", + "event": [ + { + "listen": "test", + "script": { + "id": "3e2613e1-567b-46da-a520-f54f5a7936f7", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Build Version is Present\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.build.version).to.not.eq(undefined);", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{rp_url}}/api/info", + "host": [ + "{{rp_url}}" + ], + "path": [ + "api", + "info" + ] + } + }, + "response": [] + } + ] } \ No newline at end of file diff --git a/project-properties.gradle b/project-properties.gradle index 78d8cc2981..5aa0e51a56 100755 --- a/project-properties.gradle +++ b/project-properties.gradle @@ -1,5 +1,3 @@ -sourceCompatibility = JavaVersion.VERSION_11 -targetCompatibility = JavaVersion.VERSION_11 def commonScriptsUrl = 'https://raw.githubusercontent.com/reportportal/gradle-scripts/' def migrationsScriptsUrl = 'https://raw.githubusercontent.com/reportportal/migrations/' @@ -17,8 +15,8 @@ project.ext { ] isDebugMode = System.getProperty("DEBUG", "false") == "true" releaseMode = project.hasProperty("releaseMode") - scriptsUrl = commonScriptsUrl + (releaseMode ? '5.10.0' : 'develop') - migrationsUrl = migrationsScriptsUrl + (releaseMode ? '5.10.0' : 'develop') + scriptsUrl = commonScriptsUrl + (releaseMode ? '5.11.0' : 'develop') + migrationsUrl = migrationsScriptsUrl + (releaseMode ? '5.11.0' : 'feature/settings') //TODO refactor with archive download testScriptsSrc = [ (migrationsUrl + '/migrations/0_extensions.up.sql') : 'V001__extensions.sql', @@ -65,6 +63,10 @@ project.ext { (migrationsUrl + '/migrations/69_replace_activity_table.up.sql') : 'V069__replace_activity_table.sql', (migrationsUrl + '/migrations/71_user_bid_inviting_user_id.up.sql') : 'V071__user_bid_inviting_user_id.sql', (migrationsUrl + '/migrations/72_add_attachment_name.up.sql') : 'V072__add_attachment_name.sql', + (migrationsUrl + '/migrations/73_sender_case_rule_name.up.sql') : 'V073__sender_case_rule_name.sql', + (migrationsUrl + '/migrations/76_user_bid_extension.up.sql') : 'V076__user_bid_extension.sql', + (migrationsUrl + '/migrations/77_email_server_documentation_link.up.sql') : 'V077__email_server_documentation_link.sql', + (migrationsUrl + '/migrations/78_drop_redundant_index.up.sql') : 'V078__drop_redundant_index.sql', ] excludeTests = ['**/entity/**', '**/aop/**', @@ -80,5 +82,5 @@ project.ext { } wrapper { - gradleVersion = '6.8' + gradleVersion = '8.4' } diff --git a/sealights.gradle b/sealights.gradle deleted file mode 100755 index f196ae9ea4..0000000000 --- a/sealights.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'io.sealights.on-premise.agents.plugin:sealights-gradle-plugin:latest.release' - } -} - -apply plugin: io.sealights.onpremise.agents.plugin.SealightsPlugin - -sealights { - buildSessionId = project.properties['sealightsSession'] - token = project.properties['sealightsToken'] - createBuildSessionId = false - - filesStorage = "/tmp" - - logEnabled = false - logLevel = "off" - logToFile = false - logToConsole = true - - includeResources = true - - runTestOnly = false - testTasks = ["test", "junitPlatformTest", "integrationTest"] - sealightsJvmParams = ["sl.junitVersion": "5"] -} \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/ApiKeyUtils.java b/src/main/java/com/epam/ta/reportportal/auth/ApiKeyUtils.java index 225f42f7a4..e1b7a73918 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/ApiKeyUtils.java +++ b/src/main/java/com/epam/ta/reportportal/auth/ApiKeyUtils.java @@ -34,6 +34,9 @@ private ApiKeyUtils() { /** * Validate token sign + * + * @param apiKey User's Api token + * @return true if apiKey valid */ public static boolean validateToken(String apiKey) { if (isUUID(apiKey) || (apiKey.length() == 27 && Base64.getUrlDecoder().decode(apiKey.getBytes( diff --git a/src/main/java/com/epam/ta/reportportal/auth/PermissionsRegisterBean.java b/src/main/java/com/epam/ta/reportportal/auth/PermissionsRegisterBean.java index 731970dd0f..1792d1f368 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/PermissionsRegisterBean.java +++ b/src/main/java/com/epam/ta/reportportal/auth/PermissionsRegisterBean.java @@ -18,39 +18,42 @@ import com.epam.ta.reportportal.auth.permissions.LookupPermission; import com.epam.ta.reportportal.auth.permissions.Permission; +import java.util.Arrays; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import java.util.Arrays; -import java.util.Map; - public class PermissionsRegisterBean implements BeanDefinitionRegistryPostProcessor { - @SuppressWarnings("unchecked") - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - Map<String, Permission> permissionsMap = beanFactory.getBean("permissionsMap", Map.class); - beanFactory.getBeansOfType(Permission.class).entrySet().forEach(permission -> { - /* - * There will be no NPE since we asked bean factory to get beans - * with this annotation - */ - Arrays.stream(permission.getValue().getClass().getAnnotation(LookupPermission.class).value()).forEach(permissionName -> { - /* - * TODO add check for type before doing this - */ - Permission permissionBean = permission.getValue(); - beanFactory.autowireBeanProperties(permissionBean, AutowireCapableBeanFactory.AUTOWIRE_NO, true); - permissionsMap.put(permissionName, permissionBean); - }); - }); - } + @SuppressWarnings("unchecked") + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { + Map<String, Permission> permissionsMap = beanFactory.getBean("permissionsMap", Map.class); + beanFactory.getBeansOfType(Permission.class).entrySet().forEach(permission -> { + /* + * There will be no NPE since we asked bean factory to get beans + * with this annotation + */ + Arrays.stream(permission.getValue().getClass().getAnnotation(LookupPermission.class).value()) + .forEach(permissionName -> { + /* + * TODO add check for type before doing this + */ + Permission permissionBean = permission.getValue(); + beanFactory.autowireBeanProperties(permissionBean, + AutowireCapableBeanFactory.AUTOWIRE_NO, true); + permissionsMap.put(permissionName, permissionBean); + }); + }); + } - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - //nothing to do - } + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) + throws BeansException { + //nothing to do + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/ReportPortalClient.java b/src/main/java/com/epam/ta/reportportal/auth/ReportPortalClient.java index f29eb8640c..e87f65b3c0 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/ReportPortalClient.java +++ b/src/main/java/com/epam/ta/reportportal/auth/ReportPortalClient.java @@ -21,7 +21,7 @@ * @author <a href="mailto:andrei_varabyeu@epam.com">Andrei Varabyeu</a> */ public enum ReportPortalClient { - ui, - api, - internal + ui, + api, + internal } diff --git a/src/main/java/com/epam/ta/reportportal/auth/UserRoleHierarchy.java b/src/main/java/com/epam/ta/reportportal/auth/UserRoleHierarchy.java index 003dfa81dc..7b3b3f0aa2 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/UserRoleHierarchy.java +++ b/src/main/java/com/epam/ta/reportportal/auth/UserRoleHierarchy.java @@ -18,6 +18,13 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.ImmutableSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; @@ -25,71 +32,70 @@ import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import java.util.*; -import java.util.stream.Collectors; - /** - * UserRoleHierarchy processor. Actually, hierarchy is pretty simple: role in - * {@link UserRole} has more - * rights than the following one. So, Administrator is more privileged than - * User. + * UserRoleHierarchy processor. Actually, hierarchy is pretty simple: role in {@link UserRole} has + * more rights than the following one. So, Administrator is more privileged than User. * * @author Andrei Varabyeu */ public class UserRoleHierarchy implements RoleHierarchy { - public static final String ROLE_REGISTERED = "ROLE_REGISTERED"; - - /** - * Special additional role for other microservices - */ - public static final String ROLE_COMPONENT = "ROLE_COMPONENT"; - - private static final Logger logger = LoggerFactory.getLogger(UserRoleHierarchy.class); - - private Map<GrantedAuthority, Set<GrantedAuthority>> authoritiesMap; - - public UserRoleHierarchy() { - authoritiesMap = Arrays.stream(UserRole.values()).collect(Collectors.toMap(this::asAuthority, this::findReachableRoles)); - /* - * Specify authorities explicitly. It additionally has USER role to allow other services to pass login check - */ - GrantedAuthority component = new SimpleGrantedAuthority(ROLE_COMPONENT); - authoritiesMap.put(component, ImmutableSet.<GrantedAuthority>builder().add(component).build()); - } - - @Override - public Collection<? extends GrantedAuthority> getReachableGrantedAuthorities(Collection<? extends GrantedAuthority> authorities) { - - if ((authorities == null) || (authorities.isEmpty())) { - return AuthorityUtils.NO_AUTHORITIES; - } - - List<GrantedAuthority> reachableRoles = authorities.stream() - .filter(authority -> authoritiesMap.containsKey(authority)) - .flatMap(authority -> authoritiesMap.get(authority).stream()) - .collect(Collectors.toList()); - - if (logger.isDebugEnabled()) { - logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities + " one can reach " + reachableRoles - + " in zero or more steps."); - } - - return reachableRoles; - } - - private Set<GrantedAuthority> findReachableRoles(UserRole authority) { - Set<GrantedAuthority> reachableRoles = new HashSet<>(); - UserRole[] roles = UserRole.values(); - int startIndex = Arrays.binarySearch(UserRole.values(), authority); - for (int i = 0; i <= startIndex; i++) { - reachableRoles.add(asAuthority(roles[i])); - } - return reachableRoles; - } - - private GrantedAuthority asAuthority(UserRole userRole) { - return new SimpleGrantedAuthority(userRole.getAuthority()); - } + public static final String ROLE_REGISTERED = "ROLE_REGISTERED"; + + /** + * Special additional role for other microservices + */ + public static final String ROLE_COMPONENT = "ROLE_COMPONENT"; + + private static final Logger logger = LoggerFactory.getLogger(UserRoleHierarchy.class); + + private Map<GrantedAuthority, Set<GrantedAuthority>> authoritiesMap; + + public UserRoleHierarchy() { + authoritiesMap = Arrays.stream(UserRole.values()) + .collect(Collectors.toMap(this::asAuthority, this::findReachableRoles)); + /* + * Specify authorities explicitly. It additionally has USER role to allow other services to pass login check + */ + GrantedAuthority component = new SimpleGrantedAuthority(ROLE_COMPONENT); + authoritiesMap.put(component, ImmutableSet.<GrantedAuthority>builder().add(component).build()); + } + + @Override + public Collection<? extends GrantedAuthority> getReachableGrantedAuthorities( + Collection<? extends GrantedAuthority> authorities) { + + if ((authorities == null) || (authorities.isEmpty())) { + return AuthorityUtils.NO_AUTHORITIES; + } + + List<GrantedAuthority> reachableRoles = authorities.stream() + .filter(authority -> authoritiesMap.containsKey(authority)) + .flatMap(authority -> authoritiesMap.get(authority).stream()) + .collect(Collectors.toList()); + + if (logger.isDebugEnabled()) { + logger.debug( + "getReachableGrantedAuthorities() - From the roles " + authorities + " one can reach " + + reachableRoles + + " in zero or more steps."); + } + + return reachableRoles; + } + + private Set<GrantedAuthority> findReachableRoles(UserRole authority) { + Set<GrantedAuthority> reachableRoles = new HashSet<>(); + UserRole[] roles = UserRole.values(); + int startIndex = Arrays.binarySearch(UserRole.values(), authority); + for (int i = 0; i <= startIndex; i++) { + reachableRoles.add(asAuthority(roles[i])); + } + return reachableRoles; + } + + private GrantedAuthority asAuthority(UserRole userRole) { + return new SimpleGrantedAuthority(userRole.getAuthority()); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/acl/ReportPortalAclAuthorizationStrategyImpl.java b/src/main/java/com/epam/ta/reportportal/auth/acl/ReportPortalAclAuthorizationStrategyImpl.java index ffa21bfd4c..81cdec8fe5 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/acl/ReportPortalAclAuthorizationStrategyImpl.java +++ b/src/main/java/com/epam/ta/reportportal/auth/acl/ReportPortalAclAuthorizationStrategyImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.auth.acl; +import static com.epam.ta.reportportal.auth.UserRoleHierarchy.ROLE_REGISTERED; + import org.springframework.security.access.AccessDeniedException; import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl; import org.springframework.security.acls.model.Acl; @@ -23,32 +25,33 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import static com.epam.ta.reportportal.auth.UserRoleHierarchy.ROLE_REGISTERED; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class ReportPortalAclAuthorizationStrategyImpl extends AclAuthorizationStrategyImpl { - public ReportPortalAclAuthorizationStrategyImpl(GrantedAuthority... auths) { - super(auths); - } + public ReportPortalAclAuthorizationStrategyImpl(GrantedAuthority... auths) { + super(auths); + } - @Override - public void securityCheck(Acl acl, int changeType) { + @Override + public void securityCheck(Acl acl, int changeType) { - if ((SecurityContextHolder.getContext() == null) || (SecurityContextHolder.getContext().getAuthentication() == null) || !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) { - throw new AccessDeniedException("Authenticated principal required to operate with ACLs"); - } + if ((SecurityContextHolder.getContext() == null) || ( + SecurityContextHolder.getContext().getAuthentication() == null) + || !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) { + throw new AccessDeniedException("Authenticated principal required to operate with ACLs"); + } - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (!authentication.isAuthenticated() || !isJustRegistered(authentication)) { - super.securityCheck(acl, changeType); - } - } + if (!authentication.isAuthenticated() || !isJustRegistered(authentication)) { + super.securityCheck(acl, changeType); + } + } - private boolean isJustRegistered(Authentication authentication) { - return authentication.getAuthorities().stream().anyMatch(authority -> ROLE_REGISTERED.equals(authority.getAuthority())); - } + private boolean isJustRegistered(Authentication authentication) { + return authentication.getAuthorities().stream() + .anyMatch(authority -> ROLE_REGISTERED.equals(authority.getAuthority())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/auth/authenticator/RegisteredUserAuthenticator.java b/src/main/java/com/epam/ta/reportportal/auth/authenticator/RegisteredUserAuthenticator.java index 5b79021bbe..d15f7c7bac 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/authenticator/RegisteredUserAuthenticator.java +++ b/src/main/java/com/epam/ta/reportportal/auth/authenticator/RegisteredUserAuthenticator.java @@ -1,5 +1,7 @@ package com.epam.ta.reportportal.auth.authenticator; +import static com.epam.ta.reportportal.auth.UserRoleHierarchy.ROLE_REGISTERED; + import com.epam.ta.reportportal.entity.user.User; import com.google.common.collect.Sets; import org.springframework.security.acls.model.Acl; @@ -9,25 +11,27 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.auth.UserRoleHierarchy.ROLE_REGISTERED; - @Service public class RegisteredUserAuthenticator implements UserAuthenticator { - /** - * Required for {@link org.springframework.security.acls.domain.AclAuthorizationStrategy#securityCheck(Acl, int)} with custom implementation - * {@link com.epam.ta.reportportal.auth.acl.ReportPortalAclAuthorizationStrategyImpl} to permit shared objects to the newly created user - * - * @param user {@link User} - * @return {@link Authentication} with authenticated user with the role {@link com.epam.ta.reportportal.auth.UserRoleHierarchy#ROLE_REGISTERED} - */ - @Override - public Authentication authenticate(User user) { - final Authentication authentication = new UsernamePasswordAuthenticationToken(user.getLogin(), - user.getPassword(), - Sets.newHashSet(new SimpleGrantedAuthority(ROLE_REGISTERED)) - ); - SecurityContextHolder.getContext().setAuthentication(authentication); - return authentication; - } + /** + * Required for + * {@link org.springframework.security.acls.domain.AclAuthorizationStrategy#securityCheck(Acl, + * int)} with custom implementation + * {@link com.epam.ta.reportportal.auth.acl.ReportPortalAclAuthorizationStrategyImpl} to permit + * shared objects to the newly created user + * + * @param user {@link User} + * @return {@link Authentication} with authenticated user with the role + * {@link com.epam.ta.reportportal.auth.UserRoleHierarchy#ROLE_REGISTERED} + */ + @Override + public Authentication authenticate(User user) { + final Authentication authentication = new UsernamePasswordAuthenticationToken(user.getLogin(), + user.getPassword(), + Sets.newHashSet(new SimpleGrantedAuthority(ROLE_REGISTERED)) + ); + SecurityContextHolder.getContext().setAuthentication(authentication); + return authentication; + } } diff --git a/src/main/java/com/epam/ta/reportportal/auth/authenticator/UserAuthenticator.java b/src/main/java/com/epam/ta/reportportal/auth/authenticator/UserAuthenticator.java index cd85ebe1cd..b59d4cb17e 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/authenticator/UserAuthenticator.java +++ b/src/main/java/com/epam/ta/reportportal/auth/authenticator/UserAuthenticator.java @@ -5,5 +5,5 @@ public interface UserAuthenticator { - Authentication authenticate(User user); + Authentication authenticate(User user); } diff --git a/src/main/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsService.java b/src/main/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsService.java index 1d9c319a34..1eab301d76 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsService.java +++ b/src/main/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsService.java @@ -15,6 +15,8 @@ */ package com.epam.ta.reportportal.auth.basic; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; + import com.epam.ta.reportportal.auth.util.AuthUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.UserRepository; @@ -27,43 +29,41 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; - /** - * Spring's {@link UserDetailsService} implementation. Uses {@link User} entity - * from ReportPortal database + * Spring's {@link UserDetailsService} implementation. Uses {@link User} entity from ReportPortal + * database * * @author <a href="mailto:andrei_varabyeu@epam.com">Andrei Varabyeu</a> */ @Service public class DatabaseUserDetailsService implements UserDetailsService { - private UserRepository userRepository; + private UserRepository userRepository; - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } - @Override - @Transactional(readOnly = true) - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - ReportPortalUser user = userRepository.findReportPortalUser(normalizeId(username)) - .orElseThrow(() -> new UsernameNotFoundException("User not found")); + @Override + @Transactional(readOnly = true) + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + ReportPortalUser user = userRepository.findReportPortalUser(normalizeId(username)) + .orElseThrow(() -> new UsernameNotFoundException("User not found")); - UserDetails userDetails = User.builder() - .username(user.getUsername()) - .password(user.getPassword() == null ? "" : user.getPassword()) - .authorities(AuthUtils.AS_AUTHORITIES.apply(user.getUserRole())) - .build(); + UserDetails userDetails = User.builder() + .username(user.getUsername()) + .password(user.getPassword() == null ? "" : user.getPassword()) + .authorities(AuthUtils.AS_AUTHORITIES.apply(user.getUserRole())) + .build(); - return ReportPortalUser.userBuilder() - .withUserDetails(userDetails) - .withUserId(user.getUserId()) - .withUserRole(user.getUserRole()) - .withProjectDetails(Maps.newHashMapWithExpectedSize(1)) - .withEmail(user.getEmail()) - .build(); - } + return ReportPortalUser.userBuilder() + .withUserDetails(userDetails) + .withUserId(user.getUserId()) + .withUserRole(user.getUserRole()) + .withProjectDetails(Maps.newHashMapWithExpectedSize(1)) + .withEmail(user.getEmail()) + .build(); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationFailureEventHandler.java b/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationFailureEventHandler.java index e2015660f3..073f1e3fa3 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationFailureEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationFailureEventHandler.java @@ -19,68 +19,70 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.net.HttpHeaders; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.inject.Inject; +import javax.inject.Provider; +import javax.servlet.http.HttpServletRequest; import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; import org.springframework.stereotype.Component; -import javax.inject.Inject; -import javax.inject.Provider; -import javax.servlet.http.HttpServletRequest; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - /** * Initial implementation of authentication failures handler * * @author Andrei_Ramanchuk */ @Component -public class UiAuthenticationFailureEventHandler implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> { +public class UiAuthenticationFailureEventHandler implements + ApplicationListener<AuthenticationFailureBadCredentialsEvent> { - private static final long MAXIMUM_SIZE = 5000; - private static final long EXPIRATION_SECONDS = 30; - private static final int MAX_ATTEMPTS = 3; - private static final RequestHeaderRequestMatcher AJAX_REQUEST_MATCHER = new RequestHeaderRequestMatcher(HttpHeaders.X_REQUESTED_WITH, - "XMLHttpRequest"); + private static final long MAXIMUM_SIZE = 5000; + private static final long EXPIRATION_SECONDS = 30; + private static final int MAX_ATTEMPTS = 3; + private static final RequestHeaderRequestMatcher AJAX_REQUEST_MATCHER = new RequestHeaderRequestMatcher( + HttpHeaders.X_REQUESTED_WITH, + "XMLHttpRequest"); - @Inject - private Provider<HttpServletRequest> request; + @Inject + private Provider<HttpServletRequest> request; - private LoadingCache<String, AtomicInteger> failures; + private LoadingCache<String, AtomicInteger> failures; - public UiAuthenticationFailureEventHandler() { - super(); - failures = CacheBuilder.newBuilder().maximumSize(MAXIMUM_SIZE).expireAfterWrite(EXPIRATION_SECONDS, TimeUnit.SECONDS) - .build(new CacheLoader<String, AtomicInteger>() { - @Override - public AtomicInteger load(String key) { - return new AtomicInteger(0); - } - }); - } + public UiAuthenticationFailureEventHandler() { + super(); + failures = CacheBuilder.newBuilder().maximumSize(MAXIMUM_SIZE) + .expireAfterWrite(EXPIRATION_SECONDS, TimeUnit.SECONDS) + .build(new CacheLoader<String, AtomicInteger>() { + @Override + public AtomicInteger load(String key) { + return new AtomicInteger(0); + } + }); + } - public boolean isBlocked(HttpServletRequest request) { - AtomicInteger attempts = failures.getIfPresent(getClientIP(request)); - return null != attempts && attempts.get() > MAX_ATTEMPTS; - } + public boolean isBlocked(HttpServletRequest request) { + AtomicInteger attempts = failures.getIfPresent(getClientIP(request)); + return null != attempts && attempts.get() > MAX_ATTEMPTS; + } - private void onAjaxFailure(HttpServletRequest request) { - String clientIP = getClientIP(request); - failures.getUnchecked(clientIP).incrementAndGet(); + private void onAjaxFailure(HttpServletRequest request) { + String clientIP = getClientIP(request); + failures.getUnchecked(clientIP).incrementAndGet(); - } + } - private String getClientIP(HttpServletRequest request) { - String xfHeader = request.getHeader(HttpHeaders.X_FORWARDED_FOR); - if (xfHeader == null) { - return request.getRemoteAddr(); - } - return xfHeader.split(",")[0]; - } + private String getClientIP(HttpServletRequest request) { + String xfHeader = request.getHeader(HttpHeaders.X_FORWARDED_FOR); + if (xfHeader == null) { + return request.getRemoteAddr(); + } + return xfHeader.split(",")[0]; + } - @Override - public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) { - onAjaxFailure(request.get()); - } + @Override + public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) { + onAjaxFailure(request.get()); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationSuccessEventHandler.java b/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationSuccessEventHandler.java index 1b8bd39e57..d2c4ebe3d5 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationSuccessEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/auth/event/UiAuthenticationSuccessEventHandler.java @@ -24,16 +24,17 @@ * @author Andrei Varabyeu */ @Component -public class UiAuthenticationSuccessEventHandler implements ApplicationListener<UiUserSignedInEvent> { +public class UiAuthenticationSuccessEventHandler implements + ApplicationListener<UiUserSignedInEvent> { - // @Autowired - // private UserRepository userRepository; - // @Autowired - // private DSLContext dsl; + // @Autowired + // private UserRepository userRepository; + // @Autowired + // private DSLContext dsl; - @Override - public void onApplicationEvent(UiUserSignedInEvent event) { - // dsl.update(Users.USERS).set(Users.USERS.) - // userRepository.updateLastLoginDate(event.getAuthentication().getName(), new Date(event.getTimestamp())); - } + @Override + public void onApplicationEvent(UiUserSignedInEvent event) { + // dsl.update(Users.USERS).set(Users.USERS.) + // userRepository.updateLastLoginDate(event.getAuthentication().getName(), new Date(event.getTimestamp())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/auth/event/UiUserSignedInEvent.java b/src/main/java/com/epam/ta/reportportal/auth/event/UiUserSignedInEvent.java index 21add2235e..ed8b65ffe0 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/event/UiUserSignedInEvent.java +++ b/src/main/java/com/epam/ta/reportportal/auth/event/UiUserSignedInEvent.java @@ -20,16 +20,15 @@ /** * UI user has signed in - * + * * @author Andrei Varabyeu - * */ public class UiUserSignedInEvent extends AuthenticationSuccessEvent { - private static final long serialVersionUID = -6746135168882975399L; + private static final long serialVersionUID = -6746135168882975399L; - public UiUserSignedInEvent(Authentication authentication) { - super(authentication); - } + public UiUserSignedInEvent(Authentication authentication) { + super(authentication); + } } diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/BaseProjectPermission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/BaseProjectPermission.java index 1a5d329ec3..372b7be071 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/BaseProjectPermission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/BaseProjectPermission.java @@ -23,62 +23,64 @@ import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Maps; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.provider.OAuth2Authentication; - import java.util.Map; import java.util.Objects; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.provider.OAuth2Authentication; /** - * Base logic for project-related permissions. Validates project exists and - * there is provided in {@link Authentication} user assigned to this project + * Base logic for project-related permissions. Validates project exists and there is provided in + * {@link Authentication} user assigned to this project * * @author Andrei Varabyeu */ abstract class BaseProjectPermission implements Permission { - private final ProjectExtractor projectExtractor; + private final ProjectExtractor projectExtractor; - protected BaseProjectPermission(ProjectExtractor projectExtractor) { - this.projectExtractor = projectExtractor; - } + protected BaseProjectPermission(ProjectExtractor projectExtractor) { + this.projectExtractor = projectExtractor; + } - /** - * Validates project exists and user assigned to project. After that - * delegates permission check to subclass - */ - @Override - public boolean isAllowed(Authentication authentication, Object projectName) { - if (!authentication.isAuthenticated()) { - return false; - } + /** + * Validates project exists and user assigned to project. After that delegates permission check to + * subclass + */ + @Override + public boolean isAllowed(Authentication authentication, Object projectName) { + if (!authentication.isAuthenticated()) { + return false; + } - OAuth2Authentication oauth = (OAuth2Authentication) authentication; - ReportPortalUser rpUser = (ReportPortalUser) oauth.getUserAuthentication().getPrincipal(); - BusinessRule.expect(rpUser, Objects::nonNull).verify(ErrorType.ACCESS_DENIED); + OAuth2Authentication oauth = (OAuth2Authentication) authentication; + ReportPortalUser rpUser = (ReportPortalUser) oauth.getUserAuthentication().getPrincipal(); + BusinessRule.expect(rpUser, Objects::nonNull).verify(ErrorType.ACCESS_DENIED); - final String resolvedProjectName = String.valueOf(projectName); - final ReportPortalUser.ProjectDetails projectDetails = projectExtractor.findProjectDetails(rpUser, resolvedProjectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.ACCESS_DENIED)); - fillProjectDetails(rpUser, resolvedProjectName, projectDetails); + final String resolvedProjectName = String.valueOf(projectName); + final ReportPortalUser.ProjectDetails projectDetails = projectExtractor.findProjectDetails( + rpUser, resolvedProjectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.ACCESS_DENIED)); + fillProjectDetails(rpUser, resolvedProjectName, projectDetails); - ProjectRole role = projectDetails.getProjectRole(); - return checkAllowed(rpUser, projectName.toString(), role); - } + ProjectRole role = projectDetails.getProjectRole(); + return checkAllowed(rpUser, projectName.toString(), role); + } - private void fillProjectDetails(ReportPortalUser rpUser, String resolvedProjectName, ReportPortalUser.ProjectDetails projectDetails) { - final Map<String, ReportPortalUser.ProjectDetails> projectDetailsMapping = Maps.newHashMapWithExpectedSize(1); - projectDetailsMapping.put(resolvedProjectName, projectDetails); - rpUser.setProjectDetails(projectDetailsMapping); - } + private void fillProjectDetails(ReportPortalUser rpUser, String resolvedProjectName, + ReportPortalUser.ProjectDetails projectDetails) { + final Map<String, ReportPortalUser.ProjectDetails> projectDetailsMapping = Maps.newHashMapWithExpectedSize( + 1); + projectDetailsMapping.put(resolvedProjectName, projectDetails); + rpUser.setProjectDetails(projectDetailsMapping); + } - /** - * Validates permission - * - * @param user ReportPortal user object - * @param project ReportPortal's Project name - * @param role User role - * @return TRUE if access allowed - */ - abstract protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role); + /** + * Validates permission + * + * @param user ReportPortal user object + * @param project ReportPortal's Project name + * @param role User role + * @return TRUE if access allowed + */ + abstract protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/LookupPermission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/LookupPermission.java index 21512ac856..5aaa0f3cf0 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/LookupPermission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/LookupPermission.java @@ -16,20 +16,20 @@ package com.epam.ta.reportportal.auth.permissions; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - /** * * Specifies list of permission names to be assigned to some * {@link com.epam.ta.reportportal.auth.permissions.Permission} implementation<br> * <b>BE AWARE</b> that each permissions should be marked with - * {@link com.epam.ta.reportportal.auth.permissions.LookupPermission} annotation - * to be assigned to some permission name. Without this permission will be - * ignored by {@link org.springframework.security.access.PermissionEvaluator} + * {@link com.epam.ta.reportportal.auth.permissions.LookupPermission} annotation to be assigned to + * some permission name. Without this permission will be ignored by + * {@link org.springframework.security.access.PermissionEvaluator} * * @author Andrei Varabyeu */ @@ -37,5 +37,6 @@ @Retention(RUNTIME) @Documented public @interface LookupPermission { - String[] value(); + + String[] value(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/NotCustomerPermission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/NotCustomerPermission.java index e2e60cc68b..5f63552beb 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/NotCustomerPermission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/NotCustomerPermission.java @@ -23,27 +23,26 @@ import org.springframework.stereotype.Component; /** - * Validates this is {@link ProjectRole#MEMBER} or higher authority in the - * authentication context + * Validates this is {@link ProjectRole#MEMBER} or higher authority in the authentication context * * @author Andrei Varabyeu */ @Component -@LookupPermission({ "notCustomerPermission" }) +@LookupPermission({"notCustomerPermission"}) public class NotCustomerPermission extends BaseProjectPermission { - @Autowired - public NotCustomerPermission(ProjectExtractor projectExtractor) { - super(projectExtractor); - } + @Autowired + public NotCustomerPermission(ProjectExtractor projectExtractor) { + super(projectExtractor); + } - /** - * Validates this is not a {@link ProjectRole#CUSTOMER} or higher authority in the - * authentication context - */ - @Override - protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { - return (null != role) && role.compareTo(ProjectRole.CUSTOMER) != 0; - } + /** + * Validates this is not a {@link ProjectRole#CUSTOMER} or higher authority in the authentication + * context + */ + @Override + protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { + return (null != role) && role.compareTo(ProjectRole.CUSTOMER) != 0; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/Permission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/Permission.java index 5ca4f014e2..e16f0a866e 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/Permission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/Permission.java @@ -21,20 +21,20 @@ /** * Report Portal Permission representation<br> * <b>BE AWARE</b> that each permissions should be marked with - * {@link com.epam.ta.reportportal.auth.permissions.LookupPermission} annotation - * to be assigned to some permission name. Without this permission will be - * ignored by {@link org.springframework.security.access.PermissionEvaluator} + * {@link com.epam.ta.reportportal.auth.permissions.LookupPermission} annotation to be assigned to + * some permission name. Without this permission will be ignored by + * {@link org.springframework.security.access.PermissionEvaluator} * * @author Andrei Varabyeu */ public interface Permission { - /** - * Is action allowed for user with {@link Authentication} for target object - * - * @param authentication - * @param targetDomainObject - * @return - */ - boolean isAllowed(Authentication authentication, Object targetDomainObject); + /** + * Is action allowed for user with {@link Authentication} for target object + * + * @param authentication {@link Authentication} + * @param targetDomainObject target domain object + * @return true if access is allowed + */ + boolean isAllowed(Authentication authentication, Object targetDomainObject); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/PermissionEvaluatorFactoryBean.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/PermissionEvaluatorFactoryBean.java index 54f71340d9..aeb9ee767f 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/PermissionEvaluatorFactoryBean.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/PermissionEvaluatorFactoryBean.java @@ -17,50 +17,51 @@ package com.epam.ta.reportportal.auth.permissions; import com.epam.ta.reportportal.util.ApplicationContextAwareFactoryBean; -import org.springframework.security.access.PermissionEvaluator; - import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import org.springframework.security.access.PermissionEvaluator; /** - * Factory bean for providing permissions marked with {@link LookupPermission} - * annotation + * Factory bean for providing permissions marked with {@link LookupPermission} annotation * * @author Andrei Varabyeu */ -public class PermissionEvaluatorFactoryBean extends ApplicationContextAwareFactoryBean<PermissionEvaluator> { +public class PermissionEvaluatorFactoryBean extends + ApplicationContextAwareFactoryBean<PermissionEvaluator> { - @Override - public Class<?> getObjectType() { - return PermissionEvaluator.class; - } + @Override + public Class<?> getObjectType() { + return PermissionEvaluator.class; + } - @Override - protected PermissionEvaluator createInstance() { + @Override + protected PermissionEvaluator createInstance() { - /* - * Find all beans in context marked with - * com.epam.ta.reportportal.auth.permissions.LookupPermission annotation - */ - Map<String, Object> permissionBeans = getApplicationContext().getBeansWithAnnotation(LookupPermission.class); - Map<String, Permission> permissionsMap = new HashMap<>(); - for (Entry<String, Object> permission : permissionBeans.entrySet()) { - /* - * There will be no NPE since we asked bean factory to get beans - * with this annotation - */ - for (String permissionName : permission.getValue().getClass().getAnnotation(LookupPermission.class).value()) { - if (Permission.class.isAssignableFrom(permission.getValue().getClass())) { - /* - * Assign permission name from LookupPermission annotation - * to it's value - */ - permissionsMap.put(permissionName, (Permission) permission.getValue()); - } - } - } + /* + * Find all beans in context marked with + * com.epam.ta.reportportal.auth.permissions.LookupPermission annotation + */ + Map<String, Object> permissionBeans = getApplicationContext().getBeansWithAnnotation( + LookupPermission.class); + Map<String, Permission> permissionsMap = new HashMap<>(); + for (Entry<String, Object> permission : permissionBeans.entrySet()) { + /* + * There will be no NPE since we asked bean factory to get beans + * with this annotation + */ + for (String permissionName : permission.getValue().getClass() + .getAnnotation(LookupPermission.class).value()) { + if (Permission.class.isAssignableFrom(permission.getValue().getClass())) { + /* + * Assign permission name from LookupPermission annotation + * to it's value + */ + permissionsMap.put(permissionName, (Permission) permission.getValue()); + } + } + } - return new ReportPortalPermissionEvaluator(permissionsMap); - } + return new ReportPortalPermissionEvaluator(permissionsMap); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectAuthority.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectAuthority.java index 7a66191913..da8f39c0cc 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectAuthority.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectAuthority.java @@ -15,9 +15,8 @@ */ package com.epam.ta.reportportal.auth.permissions; -import org.springframework.security.core.GrantedAuthority; - import java.util.Objects; +import org.springframework.security.core.GrantedAuthority; /** * Project authority @@ -26,41 +25,41 @@ */ public class ProjectAuthority implements GrantedAuthority { - private final String project; - private final String projectRole; + private final String project; + private final String projectRole; - public ProjectAuthority(String project, String projectRole) { - this.project = project; - this.projectRole = projectRole; - } + public ProjectAuthority(String project, String projectRole) { + this.project = project; + this.projectRole = projectRole; + } - public String getProject() { - return project; - } + public String getProject() { + return project; + } - public String getProjectRole() { - return projectRole; - } + public String getProjectRole() { + return projectRole; + } - @Override - public String getAuthority() { - return "PROJECT_" + project + "_" + projectRole; - } + @Override + public String getAuthority() { + return "PROJECT_" + project + "_" + projectRole; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ProjectAuthority that = (ProjectAuthority) o; - return Objects.equals(project, that.project) && Objects.equals(projectRole, that.projectRole); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ProjectAuthority that = (ProjectAuthority) o; + return Objects.equals(project, that.project) && Objects.equals(projectRole, that.projectRole); + } - @Override - public int hashCode() { - return Objects.hash(project, projectRole); - } + @Override + public int hashCode() { + return Objects.hash(project, projectRole); + } } diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectManagerPermission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectManagerPermission.java index 054ff48d81..af3e5a1669 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectManagerPermission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/ProjectManagerPermission.java @@ -23,26 +23,26 @@ import org.springframework.stereotype.Component; /** - * Validates this is {@link ProjectRole#PROJECT_MANAGER} or higher authority in the - * authentication context + * Validates this is {@link ProjectRole#PROJECT_MANAGER} or higher authority in the authentication + * context * * @author Andrei Varabyeu */ @Component -@LookupPermission({ "projectManagerPermission" }) +@LookupPermission({"projectManagerPermission"}) public class ProjectManagerPermission extends BaseProjectPermission { - @Autowired - public ProjectManagerPermission(ProjectExtractor projectExtractor) { - super(projectExtractor); - } + @Autowired + public ProjectManagerPermission(ProjectExtractor projectExtractor) { + super(projectExtractor); + } - /** - * Validates this is {@link ProjectRole#PROJECT_MANAGER} or higher authority in the - * authentication context - */ - @Override - protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { - return role.sameOrHigherThan(ProjectRole.PROJECT_MANAGER); - } + /** + * Validates this is {@link ProjectRole#PROJECT_MANAGER} or higher authority in the authentication + * context + */ + @Override + protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { + return role.sameOrHigherThan(ProjectRole.PROJECT_MANAGER); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/ReportPortalPermissionEvaluator.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/ReportPortalPermissionEvaluator.java index fe1a429caa..daaa26b327 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/ReportPortalPermissionEvaluator.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/ReportPortalPermissionEvaluator.java @@ -19,14 +19,13 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.PermissionNotDefinedException; import com.google.common.base.Preconditions; +import java.io.Serializable; +import java.util.Map; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import java.io.Serializable; -import java.util.Map; - /** * ReportPortal permission evaluator * @@ -35,56 +34,66 @@ // TODO add custom exception handling class ReportPortalPermissionEvaluator implements PermissionEvaluator { - private static final GrantedAuthority ADMIN_AUTHORITY = new SimpleGrantedAuthority(UserRole.ADMINISTRATOR.getAuthority()); + private static final GrantedAuthority ADMIN_AUTHORITY = new SimpleGrantedAuthority( + UserRole.ADMINISTRATOR.getAuthority()); - /** - * Mapping between permission names and permissions - */ - private Map<String, Permission> permissionNameToPermissionMap; + /** + * Mapping between permission names and permissions + */ + private Map<String, Permission> permissionNameToPermissionMap; - private boolean allowAllToAdmin; + private boolean allowAllToAdmin; - public ReportPortalPermissionEvaluator(Map<String, Permission> permissionNameToPermissionMap) { - this(permissionNameToPermissionMap, true); + public ReportPortalPermissionEvaluator(Map<String, Permission> permissionNameToPermissionMap) { + this(permissionNameToPermissionMap, true); - } + } - public ReportPortalPermissionEvaluator(Map<String, Permission> permissionNameToPermissionMap, boolean allowAllToAdmin) { - this.permissionNameToPermissionMap = Preconditions.checkNotNull(permissionNameToPermissionMap); - this.allowAllToAdmin = allowAllToAdmin; - } + public ReportPortalPermissionEvaluator(Map<String, Permission> permissionNameToPermissionMap, + boolean allowAllToAdmin) { + this.permissionNameToPermissionMap = Preconditions.checkNotNull(permissionNameToPermissionMap); + this.allowAllToAdmin = allowAllToAdmin; + } - @Override - public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { - boolean hasPermission = false; - if (canHandle(authentication, targetDomainObject, permission)) { - hasPermission = checkPermission(authentication, targetDomainObject, (String) permission); - } - return hasPermission; - } + @Override + public boolean hasPermission(Authentication authentication, Object targetDomainObject, + Object permission) { + boolean hasPermission = false; + if (canHandle(authentication, targetDomainObject, permission)) { + hasPermission = checkPermission(authentication, targetDomainObject, (String) permission); + } + return hasPermission; + } - private boolean canHandle(Authentication authentication, Object targetDomainObject, Object permission) { - return targetDomainObject != null && authentication != null && String.class.equals(permission.getClass()); - } + private boolean canHandle(Authentication authentication, Object targetDomainObject, + Object permission) { + return targetDomainObject != null && authentication != null && String.class.equals( + permission.getClass()); + } - private boolean checkPermission(Authentication authentication, Object targetDomainObject, String permissionKey) { - verifyPermissionIsDefined(permissionKey); - if (allowAllToAdmin && authentication.isAuthenticated() && authentication.getAuthorities().contains(ADMIN_AUTHORITY)) { - return true; - } - Permission permission = permissionNameToPermissionMap.get(permissionKey); - return permission.isAllowed(authentication, targetDomainObject); - } + private boolean checkPermission(Authentication authentication, Object targetDomainObject, + String permissionKey) { + verifyPermissionIsDefined(permissionKey); + if (allowAllToAdmin && authentication.isAuthenticated() && authentication.getAuthorities() + .contains(ADMIN_AUTHORITY)) { + return true; + } + Permission permission = permissionNameToPermissionMap.get(permissionKey); + return permission.isAllowed(authentication, targetDomainObject); + } - private void verifyPermissionIsDefined(String permissionKey) { - if (!permissionNameToPermissionMap.containsKey(permissionKey)) { - throw new PermissionNotDefinedException( - "No permission with key " + permissionKey + " is defined in " + this.getClass().toString()); - } - } + private void verifyPermissionIsDefined(String permissionKey) { + if (!permissionNameToPermissionMap.containsKey(permissionKey)) { + throw new PermissionNotDefinedException( + "No permission with key " + permissionKey + " is defined in " + this.getClass() + .toString()); + } + } - @Override - public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { - throw new PermissionNotDefinedException("Id and Class permissions are not supperted by " + this.getClass().toString()); - } + @Override + public boolean hasPermission(Authentication authentication, Serializable targetId, + String targetType, Object permission) { + throw new PermissionNotDefinedException( + "Id and Class permissions are not supperted by " + this.getClass().toString()); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/permissions/ReporterPermission.java b/src/main/java/com/epam/ta/reportportal/auth/permissions/ReporterPermission.java index 8a20c19836..fd7a98efc0 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/permissions/ReporterPermission.java +++ b/src/main/java/com/epam/ta/reportportal/auth/permissions/ReporterPermission.java @@ -28,19 +28,19 @@ * @author Andrei Varabyeu */ @Component -@LookupPermission({ "reporterPermission" }) +@LookupPermission({"reporterPermission"}) public class ReporterPermission extends BaseProjectPermission { - @Autowired - public ReporterPermission(ProjectExtractor projectExtractor) { - super(projectExtractor); - } + @Autowired + public ReporterPermission(ProjectExtractor projectExtractor) { + super(projectExtractor); + } - /** - * Validates that user is allowed to report (start/finish, launch, start/finish item, log) - */ - @Override - protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { - return role.sameOrHigherThan(ProjectRole.CUSTOMER); - } + /** + * Validates that user is allowed to report (start/finish, launch, start/finish item, log) + */ + @Override + protected boolean checkAllowed(ReportPortalUser user, String project, ProjectRole role) { + return role.sameOrHigherThan(ProjectRole.CUSTOMER); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/auth/util/AuthUtils.java b/src/main/java/com/epam/ta/reportportal/auth/util/AuthUtils.java index bf93c89df4..6e7dc8a246 100644 --- a/src/main/java/com/epam/ta/reportportal/auth/util/AuthUtils.java +++ b/src/main/java/com/epam/ta/reportportal/auth/util/AuthUtils.java @@ -16,19 +16,23 @@ package com.epam.ta.reportportal.auth.util; import com.epam.ta.reportportal.entity.user.UserRole; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.common.util.SerializationUtils; -import javax.annotation.Nullable; -import java.io.*; -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; - /** * Authentication utils * @@ -36,79 +40,12 @@ */ public final class AuthUtils { - private AuthUtils() { - //statics only - } - - public static final Function<UserRole, List<GrantedAuthority>> AS_AUTHORITIES = userRole -> Collections.singletonList(new SimpleGrantedAuthority( - userRole.getAuthority())); - - /** - * Dirty hack to fix <a href="https://github.com/spring-projects/spring-security-oauth/issues/665">Spring Security Issue</a> - * If there is serialUid mismatch, replaces Uuid and tries de-serialize object again - * Introduces mismatchCallback function to handle successful recovery of Uuid mismatch - * - * @param data Data to de-serialize - * @param mismatchCallback Mismatch callback. Executed in case of successful recovery - * @param <T> Type of Object - * @return De-serialized object - */ - @SuppressWarnings("unchecked") - public static <T> T deserializeSafely(byte[] data, @Nullable Consumer<T> mismatchCallback) { - try { - return SerializationUtils.deserialize(data); - } catch (IllegalArgumentException e) { - boolean serialUidMismatch = java.io.InvalidClassException.class.equals(e.getCause().getClass()); - if (!serialUidMismatch) { - throw e; - } - - try { - //TODO investigate stream closing requirement - ObjectInputStream is = new SerialUidReplacingInputStream(new ByteArrayInputStream(data)); - T t = (T) is.readObject(); - if (null != mismatchCallback) { - mismatchCallback.accept(t); - } - return t; - } catch (IOException | ClassNotFoundException e1) { - throw new IllegalArgumentException("Unable to serialize object", e1); - } - } - } - - public static class SerialUidReplacingInputStream extends ObjectInputStream { - - private static Logger logger = LoggerFactory.getLogger(SerialUidReplacingInputStream.class); - - public SerialUidReplacingInputStream(InputStream in) throws IOException { - super(in); - } + private AuthUtils() { + //statics only + } - protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { - ObjectStreamClass resultClassDescriptor = super.readClassDescriptor(); // initially streams descriptor - Class localClass; // the class in the local JVM that this descriptor represents. - try { - localClass = Class.forName(resultClassDescriptor.getName()); - } catch (ClassNotFoundException e) { - logger.error("No local class for " + resultClassDescriptor.getName(), e); - return resultClassDescriptor; - } - ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass); - if (localClassDescriptor != null) { // only if class implements serializable - final long localSUID = localClassDescriptor.getSerialVersionUID(); - final long streamSUID = resultClassDescriptor.getSerialVersionUID(); - if (streamSUID != localSUID) { // check for serialVersionUID mismatch. - final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: "); - s.append("local serialVersionUID = ").append(localSUID); - s.append(" stream serialVersionUID = ").append(streamSUID); - Exception e = new InvalidClassException(s.toString()); - logger.error("Potentially Fatal Deserialization Operation.", e); - resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization - } - } - return resultClassDescriptor; - } - } + public static final Function<UserRole, List<GrantedAuthority>> AS_AUTHORITIES = userRole -> Collections.singletonList( + new SimpleGrantedAuthority( + userRole.getAuthority())); } diff --git a/src/main/java/com/epam/ta/reportportal/auth/util/Encryptor.java b/src/main/java/com/epam/ta/reportportal/auth/util/Encryptor.java deleted file mode 100644 index 028a21cd7c..0000000000 --- a/src/main/java/com/epam/ta/reportportal/auth/util/Encryptor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.auth.util; - -import org.jasypt.util.text.BasicTextEncryptor; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * @author Andrei Varabyeu - */ -@Component -public class Encryptor implements InitializingBean { - - @Value("${rp.auth.encryptor.password:reportportal}") - private String password; - - private BasicTextEncryptor textEncryptor; - - /** - * Encrypts string - * - * @param str String to be encrypted - * @return Encrypted string - */ - public String encrypt(String str) { - return this.textEncryptor.encrypt(str); - } - - /** - * Decrypts string - * - * @param str String to be decrypted - * @return Decrypted string - */ - public String decrypt(String str) { - return this.textEncryptor.decrypt(str); - } - - @Override - public void afterPropertiesSet() throws Exception { - textEncryptor = new BasicTextEncryptor(); - textEncryptor.setPassword(password); - } -} diff --git a/src/main/java/com/epam/ta/reportportal/core/ElementsCounterService.java b/src/main/java/com/epam/ta/reportportal/core/ElementsCounterService.java new file mode 100644 index 0000000000..0868ec7572 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/ElementsCounterService.java @@ -0,0 +1,92 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ +package com.epam.ta.reportportal.core; + +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.google.common.collect.Lists; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Service +public class ElementsCounterService { + + private final Integer batchSize; + + private final TestItemRepository testItemRepository; + + private final LogRepository logRepository; + + @Autowired + public ElementsCounterService( + @Value("${rp.environment.variable.elements-counter.batch-size}") Integer batchSize, + TestItemRepository testItemRepository, LogRepository logRepository) { + this.batchSize = batchSize; + this.testItemRepository = testItemRepository; + this.logRepository = logRepository; + } + + public Long countNumberOfLaunchElements(Long launchId) { + final AtomicLong resultedNumber = new AtomicLong(1L); + final List<Long> testItemIdsByLaunchId = testItemRepository.findIdsByLaunchId(launchId); + resultedNumber.addAndGet(testItemIdsByLaunchId.size()); + resultedNumber.addAndGet(logRepository.countLogsByLaunchId(launchId)); + Lists.partition(testItemIdsByLaunchId, batchSize) + .forEach( + batch -> resultedNumber.addAndGet(logRepository.countLogsByTestItemItemIdIn(batch))); + return resultedNumber.longValue(); + } + + public Long countNumberOfItemElements(TestItem item) { + if (item != null) { + final AtomicLong resultedNumber; + final List<Long> itemIds = testItemRepository.selectAllDescendantsIds(item.getPath()); + resultedNumber = new AtomicLong(itemIds.size()); + resultedNumber.addAndGet(logRepository.countLogsByTestItemItemIdIn(itemIds)); + + if (item.isHasRetries()) { + final List<Long> retryIds = testItemRepository.findIdsByRetryOf(item.getItemId()); + final List<String> nestedPaths = testItemRepository.findPathsByParentIds( + retryIds.toArray(new Long[0])); + nestedPaths.forEach(path -> { + final List<Long> nestedChild = testItemRepository.selectAllDescendantsIds(path); + resultedNumber.addAndGet(nestedChild.size()); + resultedNumber.addAndGet(logRepository.countLogsByTestItemItemIdIn(nestedChild)); + }); + } + return resultedNumber.longValue(); + } + return 0L; + } + + public Long countNumberOfItemElements(List<TestItem> items) { + if (!CollectionUtils.isEmpty(items)) { + final AtomicLong resultedNumber = new AtomicLong(0L); + items.forEach(item -> resultedNumber.addAndGet(countNumberOfItemElements(item))); + return resultedNumber.get(); + } + return 0L; + } + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/activity/ActivityHandler.java b/src/main/java/com/epam/ta/reportportal/core/activity/ActivityHandler.java index eece781574..e795b03a7b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/activity/ActivityHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/activity/ActivityHandler.java @@ -19,6 +19,7 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.ws.model.ActivityEventResource; import com.epam.ta.reportportal.ws.model.ActivityResource; import org.springframework.data.domain.Pageable; @@ -27,51 +28,55 @@ */ public interface ActivityHandler { - /** - * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityResource} - * for specified - * {@link com.epam.ta.reportportal.entity.item.TestItem} - * - * @param projectDetails Details of project {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param filter Filter - * @param pageable Page Details - * @return Found activities - */ - Iterable<ActivityResource> getActivitiesHistory(ReportPortalUser.ProjectDetails projectDetails, Filter filter, - Queryable predefinedFilter, Pageable pageable); + /** + * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityResource} for specified + * {@link com.epam.ta.reportportal.entity.item.TestItem} + * + * @param projectDetails Details of project + * {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param filter Filter + * @param pageable Page Details + * @param predefinedFilter Additional filter + * @return Found activities + */ + Iterable<ActivityResource> getActivitiesHistory(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, + Queryable predefinedFilter, Pageable pageable); - /** - * Load {@link com.epam.ta.reportportal.ws.model.ActivityResource} - * - * @param projectDetails Details of project {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param activityId ID of activity - * @return Found Activity or NOT FOUND exception - */ - ActivityResource getActivity(ReportPortalUser.ProjectDetails projectDetails, Long activityId); + /** + * Load {@link com.epam.ta.reportportal.ws.model.ActivityResource} + * + * @param projectDetails Details of project + * {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param activityId ID of activity + * @return Found Activity or NOT FOUND exception + */ + ActivityResource getActivity(ReportPortalUser.ProjectDetails projectDetails, Long activityId); /** - * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityResource} - * for specified + * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityEventResource} for specified * {@link com.epam.ta.reportportal.entity.item.TestItem} * - * @param projectDetails Details of project {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param projectDetails Details of project + * {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} * @param itemId ID of test item * @param filter Filter * @param pageable Page Details * @return Found activities */ - Iterable<ActivityResource> getItemActivities(ReportPortalUser.ProjectDetails projectDetails, Long itemId, Filter filter, + Iterable<ActivityEventResource> getItemActivities(ReportPortalUser.ProjectDetails projectDetails, + Long itemId, Filter filter, Pageable pageable); - /** - * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityResource} - * for specified - * {@link com.epam.ta.reportportal.entity.project.Project} - * - * @param projectDetails Details of project {@link ReportPortalUser.ProjectDetails} - * @param filter Filter - * @param pageable Page Details - * @return Found activities - */ - Iterable<ActivityResource> getItemActivities(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable); + /** + * Load list of {@link com.epam.ta.reportportal.ws.model.ActivityResource} for specified + * {@link com.epam.ta.reportportal.entity.project.Project} + * + * @param projectDetails Details of project {@link ReportPortalUser.ProjectDetails} + * @param filter Filter + * @param pageable Page Details + * @return Found activities + */ + Iterable<ActivityResource> getItemActivities(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable); } diff --git a/src/main/java/com/epam/ta/reportportal/core/activity/impl/ActivityHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/activity/impl/ActivityHandlerImpl.java index 5343695c19..a14b93f9d9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/activity/impl/ActivityHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/activity/impl/ActivityHandlerImpl.java @@ -48,6 +48,8 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.converter.PagedResourcesAssembler; import com.epam.ta.reportportal.ws.converter.converters.ActivityConverter; +import com.epam.ta.reportportal.ws.converter.converters.ActivityEventConverter; +import com.epam.ta.reportportal.ws.model.ActivityEventResource; import com.epam.ta.reportportal.ws.model.ActivityResource; import com.epam.ta.reportportal.ws.model.ErrorType; import java.util.function.Predicate; @@ -111,7 +113,8 @@ public ActivityResource getActivity(ReportPortalUser.ProjectDetails projectDetai } @Override - public Iterable<ActivityResource> getItemActivities(ReportPortalUser.ProjectDetails projectDetails, Long itemId, Filter filter, + public Iterable<ActivityEventResource> getItemActivities( + ReportPortalUser.ProjectDetails projectDetails, Long itemId, Filter filter, Pageable pageable) { TestItem testItem = testItemRepository.findById(itemId).orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, itemId)); Launch launch = launchRepository.findById(testItem.getLaunchId()) @@ -141,7 +144,7 @@ public Iterable<ActivityResource> getItemActivities(ReportPortalUser.ProjectDeta new CompositeFilter(Operator.OR, filter, patternActivityFilter), PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sortByCreationDateDesc) ); - return PagedResourcesAssembler.pageConverter(ActivityConverter.TO_RESOURCE).apply(page); + return PagedResourcesAssembler.pageConverter(ActivityEventConverter.TO_RESOURCE).apply(page); } @Override diff --git a/src/main/java/com/epam/ta/reportportal/core/activityevent/ActivityEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/activityevent/ActivityEventHandler.java index f3d79611cd..398e503048 100644 --- a/src/main/java/com/epam/ta/reportportal/core/activityevent/ActivityEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/activityevent/ActivityEventHandler.java @@ -16,9 +16,11 @@ package com.epam.ta.reportportal.core.activityevent; +import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.ws.model.ActivityEventResource; import com.epam.ta.reportportal.ws.model.PagedResponse; +import java.util.List; import org.springframework.data.domain.Pageable; @@ -39,4 +41,13 @@ public interface ActivityEventHandler { PagedResponse<ActivityEventResource> getActivityEventsHistory(Queryable filter, Pageable pageable); + /** + * Get list of specified subjectName in project activities. + * + * @param projectDetails Project name + * @param value Filter value + * @return List of found user logins + */ + List<String> getSubjectNames(ReportPortalUser.ProjectDetails projectDetails, String value); + } diff --git a/src/main/java/com/epam/ta/reportportal/core/activityevent/impl/ActivityEventHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/activityevent/impl/ActivityEventHandlerImpl.java index 11b40b91d7..bb1db79398 100644 --- a/src/main/java/com/epam/ta/reportportal/core/activityevent/impl/ActivityEventHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/activityevent/impl/ActivityEventHandlerImpl.java @@ -16,14 +16,20 @@ package com.epam.ta.reportportal.core.activityevent.impl; +import com.epam.ta.reportportal.commons.Predicates; +import com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails; import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.commons.validation.BusinessRule; +import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.activityevent.ActivityEventHandler; import com.epam.ta.reportportal.dao.ActivityRepository; import com.epam.ta.reportportal.entity.activity.Activity; import com.epam.ta.reportportal.ws.converter.PagedResourcesAssembler; import com.epam.ta.reportportal.ws.converter.converters.ActivityEventConverter; import com.epam.ta.reportportal.ws.model.ActivityEventResource; +import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.PagedResponse; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -36,6 +42,9 @@ @Service public class ActivityEventHandlerImpl implements ActivityEventHandler { + private static final String LENGTH_LESS_THAN_1_SYMBOL_MSG = "Length of the filtering string " + + "'{}' is less than 1 symbol"; + private final ActivityRepository activityRepository; public ActivityEventHandlerImpl(ActivityRepository activityRepository) { @@ -51,4 +60,16 @@ public PagedResponse<ActivityEventResource> getActivityEventsHistory(Queryable f .apply(activityPage); } + @Override + public List<String> getSubjectNames(ProjectDetails projectDetails, String value) { + checkBusinessRuleLessThan1Symbol(value); + return activityRepository.findSubjectNameByProjectIdAndSubjectName( + projectDetails.getProjectId(), value.toLowerCase()); + } + + private void checkBusinessRuleLessThan1Symbol(String value) { + BusinessRule.expect(value.length() >= 1, Predicates.equalTo(true)) + .verify(ErrorType.INCORRECT_FILTER_PARAMETERS, + Suppliers.formattedSupplier(LENGTH_LESS_THAN_1_SYMBOL_MSG, value)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandler.java b/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandler.java index 47d74f76cb..591afac049 100644 --- a/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandler.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.settings.AnalyticsResource; import com.epam.ta.reportportal.ws.model.settings.ServerSettingsResource; - import java.util.Map; /** @@ -29,18 +28,18 @@ */ public interface ServerAdminHandler { - /** - * Get all server settings - * - * @return {@link ServerSettingsResource} - */ - Map<String, String> getServerSettings(); + /** + * Get all server settings + * + * @return {@link ServerSettingsResource} + */ + Map<String, String> getServerSettings(); - /** - * Update analytics settings - * - * @param analyticsResource {@link AnalyticsResource} - * @return Operation results - */ - OperationCompletionRS saveAnalyticsSettings(AnalyticsResource analyticsResource); + /** + * Update analytics settings + * + * @param analyticsResource {@link AnalyticsResource} + * @return Operation results + */ + OperationCompletionRS saveAnalyticsSettings(AnalyticsResource analyticsResource); } diff --git a/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandlerImpl.java index 255d32bce0..feb792b1d6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/admin/ServerAdminHandlerImpl.java @@ -16,65 +16,66 @@ package com.epam.ta.reportportal.core.admin; +import static com.epam.ta.reportportal.entity.ServerSettingsConstants.ANALYTICS_CONFIG_PREFIX; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toMap; + import com.epam.ta.reportportal.dao.ServerSettingsRepository; import com.epam.ta.reportportal.entity.ServerSettings; import com.epam.ta.reportportal.ws.converter.converters.ServerSettingsConverter; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.settings.AnalyticsResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.entity.ServerSettingsConstants.ANALYTICS_CONFIG_PREFIX; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** - * Basic implementation of server administration interface - * {@link ServerAdminHandler} + * Basic implementation of server administration interface {@link ServerAdminHandler} * * @author Andrei_Ramanchuk */ @Service public class ServerAdminHandlerImpl implements ServerAdminHandler { - private final ServerSettingsRepository serverSettingsRepository; + private final ServerSettingsRepository serverSettingsRepository; - @Autowired - public ServerAdminHandlerImpl(ServerSettingsRepository serverSettingsRepository) { - this.serverSettingsRepository = serverSettingsRepository; - } + @Autowired + public ServerAdminHandlerImpl(ServerSettingsRepository serverSettingsRepository) { + this.serverSettingsRepository = serverSettingsRepository; + } - @Override - public Map<String, String> getServerSettings() { - return ServerSettingsConverter.TO_RESOURCE.apply(serverSettingsRepository.selectServerSettings()); - } + @Override + public Map<String, String> getServerSettings() { + return ServerSettingsConverter.TO_RESOURCE.apply( + serverSettingsRepository.selectServerSettings()); + } - @Override - public OperationCompletionRS saveAnalyticsSettings(AnalyticsResource analyticsResource) { - String analyticsType = analyticsResource.getType(); - Map<String, ServerSettings> serverAnalyticsDetails = findServerSettings().entrySet() - .stream() - .filter(entry -> entry.getKey().startsWith(ANALYTICS_CONFIG_PREFIX)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + @Override + public OperationCompletionRS saveAnalyticsSettings(AnalyticsResource analyticsResource) { + String analyticsType = analyticsResource.getType(); + Map<String, ServerSettings> serverAnalyticsDetails = findServerSettings().entrySet() + .stream() + .filter(entry -> entry.getKey().startsWith(ANALYTICS_CONFIG_PREFIX)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - String formattedAnalyticsType = analyticsType.startsWith(ANALYTICS_CONFIG_PREFIX) ? - analyticsType : - ANALYTICS_CONFIG_PREFIX + analyticsType; + String formattedAnalyticsType = analyticsType.startsWith(ANALYTICS_CONFIG_PREFIX) ? + analyticsType : + ANALYTICS_CONFIG_PREFIX + analyticsType; - ServerSettings analyticsDetails = ofNullable(serverAnalyticsDetails.get(formattedAnalyticsType)).orElseGet(ServerSettings::new); - analyticsDetails.setKey(formattedAnalyticsType); - analyticsDetails.setValue(String.valueOf((ofNullable(analyticsResource.getEnabled()).orElse(false)))); + ServerSettings analyticsDetails = ofNullable( + serverAnalyticsDetails.get(formattedAnalyticsType)).orElseGet(ServerSettings::new); + analyticsDetails.setKey(formattedAnalyticsType); + analyticsDetails.setValue( + String.valueOf((ofNullable(analyticsResource.getEnabled()).orElse(false)))); - serverSettingsRepository.save(analyticsDetails); - return new OperationCompletionRS("Server Settings were successfully updated."); - } + serverSettingsRepository.save(analyticsDetails); + return new OperationCompletionRS("Server Settings were successfully updated."); + } - private Map<String, ServerSettings> findServerSettings() { - return serverSettingsRepository.selectServerSettings() - .stream() - .collect(toMap(ServerSettings::getKey, s -> s, (prev, curr) -> prev)); - } + private Map<String, ServerSettings> findServerSettings() { + return serverSettingsRepository.selectServerSettings() + .stream() + .collect(toMap(ServerSettings::getKey, s -> s, (prev, curr) -> prev)); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerService.java index 1cd5f8080f..e951489e27 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerService.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.List; /** @@ -29,19 +28,19 @@ */ public interface AnalyzerService { - /** - * Run analyzers for provided launch with concrete config - * - * @param launch Launch - * @param testItemIds Ids of items to be analyzed - * @param analyzerConfig Analyzer Configuration - */ - void runAnalyzers(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig); + /** + * Run analyzers for provided launch with concrete config + * + * @param launch Launch + * @param testItemIds Ids of items to be analyzed + * @param analyzerConfig Analyzer Configuration + */ + void runAnalyzers(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig); - /** - * Checks if any analyzer is available - * - * @return <code>true</code> if some exists - */ - boolean hasAnalyzers(); + /** + * Checks if any analyzer is available + * + * @return <code>true</code> if some exists + */ + boolean hasAnalyzers(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerServiceAsync.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerServiceAsync.java index af4e631c89..41252d8f4c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerServiceAsync.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/AnalyzerServiceAsync.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.List; import java.util.concurrent.CompletableFuture; @@ -27,21 +26,23 @@ */ public interface AnalyzerServiceAsync { - /** - * Analyze history to find similar issues and updates items if some were found - * Indexes investigated issues as well. - * - * @param launch - Initial launch for history - * @param testItemIds - Prepared ids of test item for analyzing - * @param analyzerConfig - Analyze mode - */ - CompletableFuture<Void> analyze(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig); + /** + * Analyze history to find similar issues and updates items if some were found Indexes + * investigated issues as well. + * + * @param launch - Initial launch for history + * @param testItemIds - Prepared ids of test item for analyzing + * @param analyzerConfig - Analyze mode + * @return {@link CompletableFuture} + */ + CompletableFuture<Void> analyze(Launch launch, List<Long> testItemIds, + AnalyzerConfig analyzerConfig); - /** - * Checks if any analyzer is available - * - * @return <code>true</code> if some exists - */ - boolean hasAnalyzers(); + /** + * Checks if any analyzer is available + * + * @return <code>true</code> if some exists + */ + boolean hasAnalyzers(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/LogIndexer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/LogIndexer.java index f95404d982..5efbd2efdf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/LogIndexer.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/LogIndexer.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -31,69 +30,70 @@ */ public interface LogIndexer { - /** - * Index logs with it's level greater than - * {@link com.epam.ta.reportportal.entity.enums.LogLevel#ERROR} - * for all given test items within launch - * - * @param projectId - project id - * @param analyzerConfig - anlayzer config - * @return The count of indexed test items - */ - CompletableFuture<Long> index(Long projectId, AnalyzerConfig analyzerConfig); + /** + * Index logs with it's level greater than + * {@link com.epam.ta.reportportal.entity.enums.LogLevel#ERROR} for all given test items within + * launch + * + * @param projectId - project id + * @param analyzerConfig - anlayzer config + * @return The count of indexed test items + */ + CompletableFuture<Long> index(Long projectId, AnalyzerConfig analyzerConfig); - Long indexLaunchLogs(Launch launch, AnalyzerConfig analyzerConfig); + Long indexLaunchLogs(Launch launch, AnalyzerConfig analyzerConfig); - Long indexItemsLogs(Long projectId, Long launchId, List<Long> itemIds, AnalyzerConfig analyzerConfig); + Long indexItemsLogs(Long projectId, Long launchId, List<Long> itemIds, + AnalyzerConfig analyzerConfig); - /** - * Delete index of specified project - * - * @param project Project/index - */ - void deleteIndex(Long project); + /** + * Delete index of specified project + * + * @param project Project/index + */ + void deleteIndex(Long project); - /** - * Remove documents with specified ids from index - * - * @param index Index to to be cleaned - * @param ids The {@link List} of the {@link com.epam.ta.reportportal.entity.log.Log#id} - * @return Amount of deleted logs - */ - CompletableFuture<Long> cleanIndex(Long index, List<Long> ids); + /** + * Remove documents with specified ids from index + * + * @param index Index to to be cleaned + * @param ids The {@link List} of the {@link com.epam.ta.reportportal.entity.log.Log#id} + * @return Amount of deleted logs + */ + CompletableFuture<Long> cleanIndex(Long index, List<Long> ids); - /** - * Async handle of updated items for indexing. - * - * @param projectId Project id - * @param analyzerConfig Analyzer config for indexing - * @param testItems Test items must be updated - */ - void indexDefectsUpdate(Long projectId, AnalyzerConfig analyzerConfig, List<TestItem> testItems); + /** + * Async handle of updated items for indexing. + * + * @param projectId Project id + * @param analyzerConfig Analyzer config for indexing + * @param testItems Test items must be updated + */ + void indexDefectsUpdate(Long projectId, AnalyzerConfig analyzerConfig, List<TestItem> testItems); - /** - * Handle of items that should be removed from index. - * - * @param projectId Project id - * @param itemsForIndexRemove Ids of items - * @return number of removed items - */ - int indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove); + /** + * Handle of items that should be removed from index. + * + * @param projectId Project id + * @param itemsForIndexRemove Ids of items + * @return number of removed items + */ + int indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove); - /** - * Async handle of items that should be removed from index. - * - * @param projectId Project id - * @param itemsForIndexRemove Ids of items - */ - void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove); + /** + * Async handle of items that should be removed from index. + * + * @param projectId Project id + * @param itemsForIndexRemove Ids of items + */ + void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove); - /** - * Async handle of launches that should be removed from index. - * - * @param projectId Project id - * @param launchesForIndexRemove Ids of launches - */ - void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove); + /** + * Async handle of launches that should be removed from index. + * + * @param projectId Project id + * @param launchesForIndexRemove Ids of launches + */ + void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/SearchLogService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/SearchLogService.java index 259dbe5cea..e6913b8035 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/SearchLogService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/SearchLogService.java @@ -25,5 +25,6 @@ */ public interface SearchLogService { - Iterable<SearchLogRs> search(Long itemId, SearchLogRq request, ReportPortalUser.ProjectDetails projectDetails); + Iterable<SearchLogRs> search(Long itemId, SearchLogRq request, + ReportPortalUser.ProjectDetails projectDetails); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/AnalyzerServiceClient.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/AnalyzerServiceClient.java index 4beb8d69cd..f6fdd5b19e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/AnalyzerServiceClient.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/AnalyzerServiceClient.java @@ -17,82 +17,79 @@ package com.epam.ta.reportportal.core.analyzer.auto.client; import com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils; +import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; +import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestRq; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; -import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestRq; -import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; import com.epam.ta.reportportal.ws.model.analyzer.AnalyzedItemRs; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.analyzer.SearchRq; import com.epam.ta.reportportal.ws.model.analyzer.SearchRs; - import java.util.List; import java.util.Map; /** - * Rabbit client for all log indexing/analysis services. Such services are those that have - * tag {@link AnalyzerUtils#ANALYZER_KEY} - * in service's metadata. + * Rabbit client for all log indexing/analysis services. Such services are those that have tag + * {@link AnalyzerUtils#ANALYZER_KEY} in service's metadata. * <p> * To define that service indexes/collecting data it should be indicated by tag - * {@link AnalyzerUtils#ANALYZER_INDEX} - * with <code>true</code> in metadata. If tag is not provided it is <code>false</code> by default + * {@link AnalyzerUtils#ANALYZER_INDEX} with <code>true</code> in metadata. If tag is not provided + * it is <code>false</code> by default * <p> - * Items are analyzed in order of priority specified in tag - * * {@link AnalyzerUtils#ANALYZER_PRIORITY} in metadata. - * If priority is not provided service gets the lowest one. If several analyzers provided different - * issues for one item, it would be overwritten with results of more priority - * service. + * Items are analyzed in order of priority specified in tag * + * {@link AnalyzerUtils#ANALYZER_PRIORITY} in metadata. If priority is not provided service gets the + * lowest one. If several analyzers provided different issues for one item, it would be overwritten + * with results of more priority service. * * @author Ivan Sharamet * @author Pavel Bortnik */ public interface AnalyzerServiceClient { - /** - * Checks if any client is available - * - * @return <code>true</code> if some exists - */ - boolean hasClients(); + /** + * Checks if any client is available + * + * @return <code>true</code> if some exists + */ + boolean hasClients(); - /** - * Analyze launch - * - * @param rq Launch - * @return Analyzed Launch - */ - Map<String, List<AnalyzedItemRs>> analyze(IndexLaunch rq); + /** + * Analyze launch + * + * @param rq Launch + * @return Analyzed Launch + */ + Map<String, List<AnalyzedItemRs>> analyze(IndexLaunch rq); - /** - * Searches logs with similar log message - * - * @param rq {@link SearchRq} request - * @return {@link List<SearchRs>} of log ids - */ - List<SearchRs> searchLogs(SearchRq rq); + /** + * Searches logs with similar log message + * + * @param rq {@link SearchRq} request + * @return {@link List} of {@link SearchRs} of log ids + */ + List<SearchRs> searchLogs(SearchRq rq); - /** - * Removes suggest index - * - * @param projectId Project/index id - */ - void removeSuggest(Long projectId); + /** + * Removes suggest index + * + * @param projectId Project/index id + */ + void removeSuggest(Long projectId); - /** - * Searches suggests in analyzer for provided item - * - * @param rq {@link SuggestRq} request - * @return {@link List<SuggestInfo>} list of founded suggests - */ - List<SuggestInfo> searchSuggests(SuggestRq rq); + /** + * Searches suggests in analyzer for provided item + * + * @param rq {@link SuggestRq} request + * @return {@link List} of {@link SuggestInfo} - list of founded suggests + */ + List<SuggestInfo> searchSuggests(SuggestRq rq); - /** - * Sends to analyzer info about user choice from suggests - * - * @param suggestInfos Info about user suggests - */ - void handleSuggestChoice(List<SuggestInfo> suggestInfos); + /** + * Sends to analyzer info about user choice from suggests + * + * @param suggestInfos Info about user suggests + */ + void handleSuggestChoice(List<SuggestInfo> suggestInfos); - ClusterData generateClusters(GenerateClustersRq generateClustersRq); + ClusterData generateClusters(GenerateClustersRq generateClustersRq); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/IndexerServiceClient.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/IndexerServiceClient.java index f79f938fc3..5a31fdde23 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/IndexerServiceClient.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/IndexerServiceClient.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; - import java.util.Collection; import java.util.List; import java.util.Map; @@ -27,59 +26,62 @@ */ public interface IndexerServiceClient { - /** - * Remove documents with specified ids from index - * - * @param index Index to to be cleaned - * @param ids Document ids to be deleted from index - * @return Amount of deleted logs - */ - Long cleanIndex(Long index, List<Long> ids); + /** + * Remove documents with specified ids from index + * + * @param index Index to to be cleaned + * @param ids Document ids to be deleted from index + * @return Amount of deleted logs + */ + Long cleanIndex(Long index, List<Long> ids); - /** - * Delete index - * - * @param index Index to be deleted - */ - void deleteIndex(Long index); + /** + * Delete index + * + * @param index Index to be deleted + */ + void deleteIndex(Long index); - /** - * Index list of launches - * - * @param rq Launches - * @return Count of indexed test items - */ - Long index(List<IndexLaunch> rq); + /** + * Index list of launches + * + * @param rq Launches + */ + void index(List<IndexLaunch> rq); - /** - * Sends a message to the queue with a map of items which must be updated with a new issue type - * - * @param itemsForIndexUpdate Pair of itemId - issue type - * @return List of missed items in analyzer - */ - List<Long> indexDefectsUpdate(Long projectId, Map<Long, String> itemsForIndexUpdate); + /** + * Sends a message to the queue with a map of items which must be updated with a new issue type + * + * @param projectId Project id + * @param itemsForIndexUpdate Pair of itemId - issue type + * @return List of missed items in analyzer + */ + List<Long> indexDefectsUpdate(Long projectId, Map<Long, String> itemsForIndexUpdate); - /** - * Sends a message to the queue with a list of items which must be removed from index - * and receive number of removed objects as a response. - * - * @param itemsForIndexRemove List of item ids - * @return number of removed objects - */ - Integer indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove); + /** + * Sends a message to the queue with a list of items which must be removed from index and receive + * number of removed objects as a response. + * + * @param projectId Project id + * @param itemsForIndexRemove List of item ids + * @return number of removed objects + */ + Integer indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove); - /** - * Sends a message to the queue with a list of items which must be removed from index - * - * @param itemsForIndexRemove List of item ids - */ - void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove); + /** + * Sends a message to the queue with a list of items which must be removed from index + * + * @param projectId Project id + * @param itemsForIndexRemove List of item ids + */ + void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove); - /** - * Sends a message to the queue with a list of launches which must be removed from index - * - * @param launchesForIndexRemove List of launhces ids - */ - void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove); + /** + * Sends a message to the queue with a list of launches which must be removed from index + * + * @param projectId Project id + * @param launchesForIndexRemove List of launhces ids + */ + void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/RabbitMqManagementClient.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/RabbitMqManagementClient.java index db429a7c3c..81e02ec7c7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/RabbitMqManagementClient.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/RabbitMqManagementClient.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client; import com.rabbitmq.http.client.domain.ExchangeInfo; - import java.util.List; /** @@ -25,6 +24,6 @@ */ public interface RabbitMqManagementClient { - List<ExchangeInfo> getAnalyzerExchangesInfo(); + List<ExchangeInfo> getAnalyzerExchangesInfo(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerServiceClientImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerServiceClientImpl.java index c44afe47e4..69de662e08 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerServiceClientImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerServiceClientImpl.java @@ -16,12 +16,18 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_CLUSTER; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_SEARCH; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_SUGGEST; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.EXCHANGE_PRIORITY; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.RabbitMqManagementClient; -import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; -import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestRq; +import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; +import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.analyzer.AnalyzedItemRs; @@ -29,6 +35,13 @@ import com.epam.ta.reportportal.ws.model.analyzer.SearchRq; import com.epam.ta.reportportal.ws.model.analyzer.SearchRs; import com.rabbitmq.http.client.domain.ExchangeInfo; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Predicate; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -37,122 +50,126 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.*; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.*; -import static java.util.stream.Collectors.toList; - @Service public class AnalyzerServiceClientImpl implements AnalyzerServiceClient { - private static final String ANALYZE_ROUTE = "analyze"; - private static final String SEARCH_ROUTE = "search"; - private static final String SUGGEST_ROUTE = "suggest"; - private static final String SUGGEST_INFO_ROUTE = "index_suggest_info"; - private static final String REMOVE_SUGGEST_ROUTE = "remove_suggest_info"; - private static final String CLUSTER_ROUTE = "cluster"; - - private final RabbitMqManagementClient rabbitMqManagementClient; - - private final RabbitTemplate rabbitTemplate; - - private String virtualHost; - - @Autowired - public AnalyzerServiceClientImpl(RabbitMqManagementClient rabbitMqManagementClient, - @Qualifier("analyzerRabbitTemplate") RabbitTemplate rabbitTemplate, @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { - this.rabbitMqManagementClient = rabbitMqManagementClient; - this.rabbitTemplate = rabbitTemplate; - this.virtualHost = virtualHost; - } - - @Override - public boolean hasClients() { - return rabbitMqManagementClient.getAnalyzerExchangesInfo().size() != 0; - } - - @Override - public Map<String, List<AnalyzedItemRs>> analyze(IndexLaunch rq) { - List<ExchangeInfo> analyzerExchanges = rabbitMqManagementClient.getAnalyzerExchangesInfo(); - Map<String, List<AnalyzedItemRs>> resultMap = new HashMap<>(analyzerExchanges.size()); - analyzerExchanges.forEach(exchange -> analyze(rq, resultMap, exchange)); - return resultMap; - } - - @Override - public List<SearchRs> searchLogs(SearchRq rq) { - String exchangeName = resolveExchangeName(DOES_SUPPORT_SEARCH) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer services with search logs support deployed." - )); - return rabbitTemplate.convertSendAndReceiveAsType(exchangeName, SEARCH_ROUTE, rq, new ParameterizedTypeReference<>() { - }); - } - - @Override - public void removeSuggest(Long projectId) { - resolveExchangeName(DOES_SUPPORT_SUGGEST) - .ifPresent(suggestExchange -> rabbitTemplate.convertAndSend(suggestExchange, REMOVE_SUGGEST_ROUTE, projectId)); - } - - @Override - public List<SuggestInfo> searchSuggests(SuggestRq rq) { - return rabbitTemplate.convertSendAndReceiveAsType(getSuggestExchangeName(), SUGGEST_ROUTE, rq, new ParameterizedTypeReference<>() { - }); - } - - @Override - public void handleSuggestChoice(List<SuggestInfo> suggestInfos) { - rabbitTemplate.convertAndSend(getSuggestExchangeName(), SUGGEST_INFO_ROUTE, suggestInfos); - } - - @Override - public ClusterData generateClusters(GenerateClustersRq generateClustersRq) { - final String exchangeName = resolveExchangeName(DOES_SUPPORT_CLUSTER).orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer services with clusters creation support deployed." - )); - return rabbitTemplate.convertSendAndReceiveAsType(exchangeName, CLUSTER_ROUTE, generateClustersRq, new ParameterizedTypeReference<>() { - }); - } - - private Optional<String> resolveExchangeName(Predicate<ExchangeInfo> supportCondition) { - return rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .filter(supportCondition) - .min(Comparator.comparingInt(EXCHANGE_PRIORITY)) - .map(ExchangeInfo::getName); - } - - private String getSuggestExchangeName() { - return resolveExchangeName(DOES_SUPPORT_SUGGEST) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer services with suggest items support deployed." - )); - } - - private void analyze(IndexLaunch rq, Map<String, List<AnalyzedItemRs>> resultMap, ExchangeInfo exchangeInfo) { - List<AnalyzedItemRs> result = rabbitTemplate.convertSendAndReceiveAsType(exchangeInfo.getName(), - ANALYZE_ROUTE, - Collections.singletonList(rq), - new ParameterizedTypeReference<>() { - } - ); - if (!CollectionUtils.isEmpty(result)) { - resultMap.put((String) exchangeInfo.getArguments().getOrDefault(virtualHost, exchangeInfo.getName()), result); - removeAnalyzedFromRq(rq, result); - } - } - - /** - * Removes form rq analyzed items to make rq for the next analyzer. - * - * @param rq Request - * @param analyzed List of analyzer items - */ - private void removeAnalyzedFromRq(IndexLaunch rq, List<AnalyzedItemRs> analyzed) { - List<Long> analyzedItemIds = analyzed.stream().map(AnalyzedItemRs::getItemId).collect(toList()); - rq.getTestItems().removeIf(it -> analyzedItemIds.contains(it.getTestItemId())); - } + private static final String ANALYZE_ROUTE = "analyze"; + private static final String SEARCH_ROUTE = "search"; + private static final String SUGGEST_ROUTE = "suggest"; + private static final String SUGGEST_INFO_ROUTE = "index_suggest_info"; + private static final String REMOVE_SUGGEST_ROUTE = "remove_suggest_info"; + private static final String CLUSTER_ROUTE = "cluster"; + + private final RabbitMqManagementClient rabbitMqManagementClient; + + private final RabbitTemplate rabbitTemplate; + + private String virtualHost; + + @Autowired + public AnalyzerServiceClientImpl(RabbitMqManagementClient rabbitMqManagementClient, + @Qualifier("analyzerRabbitTemplate") RabbitTemplate rabbitTemplate, + @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { + this.rabbitMqManagementClient = rabbitMqManagementClient; + this.rabbitTemplate = rabbitTemplate; + this.virtualHost = virtualHost; + } + + @Override + public boolean hasClients() { + return rabbitMqManagementClient.getAnalyzerExchangesInfo().size() != 0; + } + + @Override + public Map<String, List<AnalyzedItemRs>> analyze(IndexLaunch rq) { + List<ExchangeInfo> analyzerExchanges = rabbitMqManagementClient.getAnalyzerExchangesInfo(); + Map<String, List<AnalyzedItemRs>> resultMap = new HashMap<>(analyzerExchanges.size()); + analyzerExchanges.forEach(exchange -> analyze(rq, resultMap, exchange)); + return resultMap; + } + + @Override + public List<SearchRs> searchLogs(SearchRq rq) { + String exchangeName = resolveExchangeName(DOES_SUPPORT_SEARCH) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "There are no analyzer services with search logs support deployed." + )); + return rabbitTemplate.convertSendAndReceiveAsType(exchangeName, SEARCH_ROUTE, rq, + new ParameterizedTypeReference<>() { + }); + } + + @Override + public void removeSuggest(Long projectId) { + resolveExchangeName(DOES_SUPPORT_SUGGEST) + .ifPresent( + suggestExchange -> rabbitTemplate.convertAndSend(suggestExchange, REMOVE_SUGGEST_ROUTE, + projectId)); + } + + @Override + public List<SuggestInfo> searchSuggests(SuggestRq rq) { + return rabbitTemplate.convertSendAndReceiveAsType(getSuggestExchangeName(), SUGGEST_ROUTE, rq, + new ParameterizedTypeReference<>() { + }); + } + + @Override + public void handleSuggestChoice(List<SuggestInfo> suggestInfos) { + rabbitTemplate.convertAndSend(getSuggestExchangeName(), SUGGEST_INFO_ROUTE, suggestInfos); + } + + @Override + public ClusterData generateClusters(GenerateClustersRq generateClustersRq) { + final String exchangeName = resolveExchangeName(DOES_SUPPORT_CLUSTER).orElseThrow( + () -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "There are no analyzer services with clusters creation support deployed." + )); + return rabbitTemplate.convertSendAndReceiveAsType(exchangeName, CLUSTER_ROUTE, + generateClustersRq, new ParameterizedTypeReference<>() { + }); + } + + private Optional<String> resolveExchangeName(Predicate<ExchangeInfo> supportCondition) { + return rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .filter(supportCondition) + .min(Comparator.comparingInt(EXCHANGE_PRIORITY)) + .map(ExchangeInfo::getName); + } + + private String getSuggestExchangeName() { + return resolveExchangeName(DOES_SUPPORT_SUGGEST) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "There are no analyzer services with suggest items support deployed." + )); + } + + private void analyze(IndexLaunch rq, Map<String, List<AnalyzedItemRs>> resultMap, + ExchangeInfo exchangeInfo) { + List<AnalyzedItemRs> result = rabbitTemplate.convertSendAndReceiveAsType(exchangeInfo.getName(), + ANALYZE_ROUTE, + Collections.singletonList(rq), + new ParameterizedTypeReference<>() { + } + ); + if (!CollectionUtils.isEmpty(result)) { + resultMap.put( + (String) exchangeInfo.getArguments().getOrDefault(virtualHost, exchangeInfo.getName()), + result); + removeAnalyzedFromRq(rq, result); + } + } + + /** + * Removes form rq analyzed items to make rq for the next analyzer. + * + * @param rq Request + * @param analyzed List of analyzer items + */ + private void removeAnalyzedFromRq(IndexLaunch rq, List<AnalyzedItemRs> analyzed) { + List<Long> analyzedItemIds = analyzed.stream().map(AnalyzedItemRs::getItemId).collect(toList()); + rq.getTestItems().removeIf(it -> analyzedItemIds.contains(it.getTestItemId())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtils.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtils.java index 98ace65552..744e235deb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtils.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtils.java @@ -16,59 +16,55 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; -import com.rabbitmq.http.client.domain.ExchangeInfo; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.math.NumberUtils; +import static java.util.Optional.ofNullable; +import com.rabbitmq.http.client.domain.ExchangeInfo; import java.util.function.Predicate; import java.util.function.ToIntFunction; - -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.math.NumberUtils; /** * @author Pavel Bortnik */ public final class AnalyzerUtils { - static final String ANALYZER_KEY = "analyzer"; - static final String ANALYZER_PRIORITY = "analyzer_priority"; - static final String ANALYZER_INDEX = "analyzer_index"; - static final String ANALYZER_LOG_SEARCH = "analyzer_log_search"; - static final String ANALYZER_SUGGEST = "analyzer_suggest"; - static final String ANALYZER_CLUSTER = "analyzer_cluster"; + static final String ANALYZER_KEY = "analyzer"; + static final String ANALYZER_PRIORITY = "analyzer_priority"; + static final String ANALYZER_INDEX = "analyzer_index"; + static final String ANALYZER_LOG_SEARCH = "analyzer_log_search"; + static final String ANALYZER_SUGGEST = "analyzer_suggest"; + static final String ANALYZER_CLUSTER = "analyzer_cluster"; - /** - * Comparing by client service priority - */ - static final ToIntFunction<ExchangeInfo> EXCHANGE_PRIORITY = it -> ofNullable(it.getArguments() - .get(ANALYZER_PRIORITY)).map(val -> NumberUtils.toInt(val.toString(), Integer.MAX_VALUE)).orElse(Integer.MAX_VALUE); + /** + * Comparing by client service priority + */ + static final ToIntFunction<ExchangeInfo> EXCHANGE_PRIORITY = it -> ofNullable(it.getArguments() + .get(ANALYZER_PRIORITY)).map(val -> NumberUtils.toInt(val.toString(), Integer.MAX_VALUE)) + .orElse(Integer.MAX_VALUE); - /** - * Checks if service support items indexing. <code>false</code> - * by default - */ - static final Predicate<ExchangeInfo> DOES_SUPPORT_INDEX = it -> ofNullable(it.getArguments() - .get(ANALYZER_INDEX)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); + /** + * Checks if service support items indexing. <code>false</code> by default + */ + static final Predicate<ExchangeInfo> DOES_SUPPORT_INDEX = it -> ofNullable(it.getArguments() + .get(ANALYZER_INDEX)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); - /** - * Checks if service support logs searching. <code>false</code> - * by default - */ - static final Predicate<ExchangeInfo> DOES_SUPPORT_SEARCH = it -> ofNullable(it.getArguments() - .get(ANALYZER_LOG_SEARCH)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); + /** + * Checks if service support logs searching. <code>false</code> by default + */ + static final Predicate<ExchangeInfo> DOES_SUPPORT_SEARCH = it -> ofNullable(it.getArguments() + .get(ANALYZER_LOG_SEARCH)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); - /** - * Checks if service support logs searching. <code>false</code> - * by default - */ - static final Predicate<ExchangeInfo> DOES_SUPPORT_SUGGEST = it -> ofNullable(it.getArguments() - .get(ANALYZER_SUGGEST)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); + /** + * Checks if service support logs searching. <code>false</code> by default + */ + static final Predicate<ExchangeInfo> DOES_SUPPORT_SUGGEST = it -> ofNullable(it.getArguments() + .get(ANALYZER_SUGGEST)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); - /** - * Checks if service support logs cluster creation. <code>false</code> - * by default - */ - static final Predicate<ExchangeInfo> DOES_SUPPORT_CLUSTER = it -> ofNullable(it.getArguments() - .get(ANALYZER_CLUSTER)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); + /** + * Checks if service support logs cluster creation. <code>false</code> by default + */ + static final Predicate<ExchangeInfo> DOES_SUPPORT_CLUSTER = it -> ofNullable(it.getArguments() + .get(ANALYZER_CLUSTER)).map(val -> BooleanUtils.toBoolean(val.toString())).orElse(false); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImpl.java index ccc3501e40..6f5450f6e2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImpl.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_INDEX; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.EXCHANGE_PRIORITY; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.core.analyzer.auto.client.IndexerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.RabbitMqManagementClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.IndexDefectsUpdate; @@ -24,6 +29,13 @@ import com.epam.ta.reportportal.ws.model.analyzer.CleanIndexRq; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.analyzer.IndexRs; +import java.util.AbstractMap; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -31,144 +43,128 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Service; -import java.util.*; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_INDEX; -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.EXCHANGE_PRIORITY; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Service public class IndexerServiceClientImpl implements IndexerServiceClient { - private static final Logger LOGGER = LoggerFactory.getLogger(IndexerServiceClient.class); - private static final String INDEX_ROUTE = "index"; - static final String DEFECT_UPDATE_ROUTE = "defect_update"; - static final String ITEM_REMOVE_ROUTE = "item_remove"; - static final String LAUNCH_REMOVE_ROUTE = "launch_remove"; - private static final String NAMESPACE_FINDER_ROUTE = "namespace_finder"; - static final String DELETE_ROUTE = "delete"; - private static final String CLEAN_ROUTE = "clean"; - private static final Integer DELETE_INDEX_SUCCESS_CODE = 1; - - private final RabbitMqManagementClient rabbitMqManagementClient; - - private final RabbitTemplate rabbitTemplate; - - public IndexerServiceClientImpl(RabbitMqManagementClient rabbitMqManagementClient, - @Qualifier("analyzerRabbitTemplate") RabbitTemplate rabbitTemplate) { - this.rabbitMqManagementClient = rabbitMqManagementClient; - this.rabbitTemplate = rabbitTemplate; - } - - @Override - public Long index(List<IndexLaunch> rq) { - return rabbitMqManagementClient.getAnalyzerExchangesInfo().stream().filter(DOES_SUPPORT_INDEX).map(exchange -> { - rabbitTemplate.convertAndSend(exchange.getName(), NAMESPACE_FINDER_ROUTE, rq); - return rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), - INDEX_ROUTE, - rq, - new ParameterizedTypeReference<IndexRs>() { - } - ); - }).mapToLong(it -> { - if (Objects.nonNull(it)) { - return it.getTook(); - } - return 0; - }).sum(); - } - - @Override - public List<Long> indexDefectsUpdate(Long projectId, Map<Long, String> itemsForIndexUpdate) { - return rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .filter(DOES_SUPPORT_INDEX) - .flatMap(exchange -> ofNullable(rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), - DEFECT_UPDATE_ROUTE, - new IndexDefectsUpdate(projectId, itemsForIndexUpdate), - new ParameterizedTypeReference<List<Long>>() { - } - )).orElse(Collections.emptyList()).stream()) - .collect(toList()); - } - - @Override - public Integer indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove) { - return rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .filter(DOES_SUPPORT_INDEX) - .map(exchange -> ofNullable(rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), - ITEM_REMOVE_ROUTE, - new IndexItemsRemove(projectId, itemsForIndexRemove), - new ParameterizedTypeReference<Integer>() { - } - )).orElse(0)) - .mapToInt(Integer::intValue) - .sum(); - } - - @Override - public void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove) { - rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .filter(DOES_SUPPORT_INDEX) - .forEach(exchange -> rabbitTemplate.convertAndSend(exchange.getName(), - ITEM_REMOVE_ROUTE, - new IndexItemsRemove(projectId, itemsForIndexRemove) - )); - } - - @Override - public void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove) { - rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .filter(DOES_SUPPORT_INDEX) - .forEach(exchange -> rabbitTemplate.convertAndSend(exchange.getName(), - LAUNCH_REMOVE_ROUTE, - new IndexLaunchRemove(projectId, launchesForIndexRemove) - )); - } - - @Override - public Long cleanIndex(Long index, List<Long> ids) { - Map<Integer, Long> priorityToCleanedLogsCountMapping = rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .collect(Collectors.toMap(EXCHANGE_PRIORITY::applyAsInt, - exchange -> rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), - CLEAN_ROUTE, - new CleanIndexRq(index, ids), - new ParameterizedTypeReference<>() { - } - ) - )); - return priorityToCleanedLogsCountMapping.entrySet() - .stream() - .min(Map.Entry.comparingByKey()) - .orElseGet(() -> new AbstractMap.SimpleEntry<>(0, 0L)) - .getValue(); - } - - @Override - public void deleteIndex(Long index) { - rabbitMqManagementClient.getAnalyzerExchangesInfo() - .stream() - .map(exchange -> rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), - DELETE_ROUTE, - index, - new ParameterizedTypeReference<Integer>() { - } - )) - .forEach(it -> { - if (DELETE_INDEX_SUCCESS_CODE.equals(it)) { - LOGGER.info("Successfully deleted index '{}'", index); - } else { - LOGGER.error("Error deleting index '{}'", index); - } - }); - } + private static final Logger LOGGER = LoggerFactory.getLogger(IndexerServiceClient.class); + private static final String INDEX_ROUTE = "index"; + static final String DEFECT_UPDATE_ROUTE = "defect_update"; + static final String ITEM_REMOVE_ROUTE = "item_remove"; + static final String LAUNCH_REMOVE_ROUTE = "launch_remove"; + private static final String NAMESPACE_FINDER_ROUTE = "namespace_finder"; + static final String DELETE_ROUTE = "delete"; + private static final String CLEAN_ROUTE = "clean"; + private static final Integer DELETE_INDEX_SUCCESS_CODE = 1; + + private final RabbitMqManagementClient rabbitMqManagementClient; + + private final RabbitTemplate rabbitTemplate; + + public IndexerServiceClientImpl(RabbitMqManagementClient rabbitMqManagementClient, + @Qualifier("analyzerRabbitTemplate") RabbitTemplate rabbitTemplate) { + this.rabbitMqManagementClient = rabbitMqManagementClient; + this.rabbitTemplate = rabbitTemplate; + } + + @Override + public void index(List<IndexLaunch> rq) { + rabbitMqManagementClient.getAnalyzerExchangesInfo().stream().filter(DOES_SUPPORT_INDEX) + .forEach(exchange -> { + rabbitTemplate.convertAndSend(exchange.getName(), NAMESPACE_FINDER_ROUTE, rq); + rabbitTemplate.convertAndSend(exchange.getName(), INDEX_ROUTE, rq); + }); + } + + @Override + public List<Long> indexDefectsUpdate(Long projectId, Map<Long, String> itemsForIndexUpdate) { + return rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .filter(DOES_SUPPORT_INDEX) + .flatMap( + exchange -> ofNullable(rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), + DEFECT_UPDATE_ROUTE, + new IndexDefectsUpdate(projectId, itemsForIndexUpdate), + new ParameterizedTypeReference<List<Long>>() { + } + )).orElse(Collections.emptyList()).stream()) + .collect(toList()); + } + + @Override + public Integer indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove) { + return rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .filter(DOES_SUPPORT_INDEX) + .map(exchange -> ofNullable(rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), + ITEM_REMOVE_ROUTE, + new IndexItemsRemove(projectId, itemsForIndexRemove), + new ParameterizedTypeReference<Integer>() { + } + )).orElse(0)) + .mapToInt(Integer::intValue) + .sum(); + } + + @Override + public void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove) { + rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .filter(DOES_SUPPORT_INDEX) + .forEach(exchange -> rabbitTemplate.convertAndSend(exchange.getName(), + ITEM_REMOVE_ROUTE, + new IndexItemsRemove(projectId, itemsForIndexRemove) + )); + } + + @Override + public void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove) { + rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .filter(DOES_SUPPORT_INDEX) + .forEach(exchange -> rabbitTemplate.convertAndSend(exchange.getName(), + LAUNCH_REMOVE_ROUTE, + new IndexLaunchRemove(projectId, launchesForIndexRemove) + )); + } + + @Override + public Long cleanIndex(Long index, List<Long> ids) { + Map<Integer, Long> priorityToCleanedLogsCountMapping = rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .collect(Collectors.toMap(EXCHANGE_PRIORITY::applyAsInt, + exchange -> rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), + CLEAN_ROUTE, + new CleanIndexRq(index, ids), + new ParameterizedTypeReference<>() { + } + ) + )); + return priorityToCleanedLogsCountMapping.entrySet() + .stream() + .min(Map.Entry.comparingByKey()) + .orElseGet(() -> new AbstractMap.SimpleEntry<>(0, 0L)) + .getValue(); + } + + @Override + public void deleteIndex(Long index) { + rabbitMqManagementClient.getAnalyzerExchangesInfo() + .stream() + .map(exchange -> rabbitTemplate.convertSendAndReceiveAsType(exchange.getName(), + DELETE_ROUTE, + index, + new ParameterizedTypeReference<Integer>() { + } + )) + .forEach(it -> { + if (DELETE_INDEX_SUCCESS_CODE.equals(it)) { + LOGGER.info("Successfully deleted index '{}'", index); + } else { + LOGGER.error("Error deleting index '{}'", index); + } + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplate.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplate.java index e74dc83f00..4ff216f06c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplate.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplate.java @@ -16,47 +16,47 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_KEY; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.EXCHANGE_PRIORITY; +import static java.util.Comparator.comparingInt; + import com.epam.ta.reportportal.core.analyzer.auto.client.RabbitMqManagementClient; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.fasterxml.jackson.core.JsonProcessingException; import com.rabbitmq.http.client.Client; import com.rabbitmq.http.client.domain.ExchangeInfo; - import java.util.List; import java.util.stream.Collectors; -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_KEY; -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.EXCHANGE_PRIORITY; -import static java.util.Comparator.comparingInt; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public class RabbitMqManagementClientTemplate implements RabbitMqManagementClient { - private final Client rabbitClient; - - private final String virtualHost; - - public RabbitMqManagementClientTemplate(Client rabbitClient, String virtualHost) { - this.rabbitClient = rabbitClient; - this.virtualHost = virtualHost; - try { - rabbitClient.createVhost(virtualHost); - } catch (JsonProcessingException e) { - throw new ReportPortalException(ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, "Unable to create RabbitMq virtual host"); - } - } - - public List<ExchangeInfo> getAnalyzerExchangesInfo() { - List<ExchangeInfo> client = rabbitClient.getExchanges(virtualHost); - if (client == null) { - throw new ReportPortalException(ErrorType.ANALYZER_NOT_FOUND, virtualHost); - } - return client.stream() - .filter(it -> it.getArguments().get(ANALYZER_KEY) != null) - .sorted(comparingInt(EXCHANGE_PRIORITY)) - .collect(Collectors.toList()); + private final Client rabbitClient; + + private final String virtualHost; + + public RabbitMqManagementClientTemplate(Client rabbitClient, String virtualHost) { + this.rabbitClient = rabbitClient; + this.virtualHost = virtualHost; + try { + rabbitClient.createVhost(virtualHost); + } catch (Exception e) { + throw new ReportPortalException(ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, + "Unable to create RabbitMq virtual host"); + } + } + + public List<ExchangeInfo> getAnalyzerExchangesInfo() { + List<ExchangeInfo> client = rabbitClient.getExchanges(virtualHost); + if (client == null) { + throw new ReportPortalException(ErrorType.ANALYZER_NOT_FOUND, virtualHost); } + return client.stream() + .filter(it -> it.getArguments().get(ANALYZER_KEY) != null) + .sorted(comparingInt(EXCHANGE_PRIORITY)) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexDefectsUpdate.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexDefectsUpdate.java index 33898c85b9..9107ee7cd6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexDefectsUpdate.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexDefectsUpdate.java @@ -16,7 +16,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.model; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.Map; import java.util.Objects; @@ -25,47 +24,48 @@ */ public class IndexDefectsUpdate { - @JsonProperty("project") - private Long projectId; + @JsonProperty("project") + private Long projectId; - @JsonProperty("itemsToUpdate") - private Map<Long, String> itemsToUpdate; + @JsonProperty("itemsToUpdate") + private Map<Long, String> itemsToUpdate; - public IndexDefectsUpdate(Long projectId, Map<Long, String> itemsToUpdate) { - this.projectId = projectId; - this.itemsToUpdate = itemsToUpdate; - } + public IndexDefectsUpdate(Long projectId, Map<Long, String> itemsToUpdate) { + this.projectId = projectId; + this.itemsToUpdate = itemsToUpdate; + } - public Long getProjectId() { - return projectId; - } + public Long getProjectId() { + return projectId; + } - public void setProjectId(Long projectId) { - this.projectId = projectId; - } + public void setProjectId(Long projectId) { + this.projectId = projectId; + } - public Map<Long, String> getItemsToUpdate() { - return itemsToUpdate; - } + public Map<Long, String> getItemsToUpdate() { + return itemsToUpdate; + } - public void setItemsToUpdate(Map<Long, String> itemsToUpdate) { - this.itemsToUpdate = itemsToUpdate; - } + public void setItemsToUpdate(Map<Long, String> itemsToUpdate) { + this.itemsToUpdate = itemsToUpdate; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IndexDefectsUpdate that = (IndexDefectsUpdate) o; - return Objects.equals(projectId, that.projectId) && Objects.equals(itemsToUpdate, that.itemsToUpdate); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IndexDefectsUpdate that = (IndexDefectsUpdate) o; + return Objects.equals(projectId, that.projectId) && Objects.equals(itemsToUpdate, + that.itemsToUpdate); + } - @Override - public int hashCode() { - return Objects.hash(projectId, itemsToUpdate); - } + @Override + public int hashCode() { + return Objects.hash(projectId, itemsToUpdate); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexItemsRemove.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexItemsRemove.java index 10ab6a0460..2b8aed48b6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexItemsRemove.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexItemsRemove.java @@ -16,7 +16,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.model; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.Collection; import java.util.Objects; @@ -25,47 +24,48 @@ */ public class IndexItemsRemove { - @JsonProperty("project") - private Long projectId; + @JsonProperty("project") + private Long projectId; - @JsonProperty("itemsToDelete") - private Collection<Long> itemsToDelete; + @JsonProperty("itemsToDelete") + private Collection<Long> itemsToDelete; - public IndexItemsRemove(Long projectId, Collection<Long> itemsToDelete) { - this.projectId = projectId; - this.itemsToDelete = itemsToDelete; - } + public IndexItemsRemove(Long projectId, Collection<Long> itemsToDelete) { + this.projectId = projectId; + this.itemsToDelete = itemsToDelete; + } - public Long getProjectId() { - return projectId; - } + public Long getProjectId() { + return projectId; + } - public void setProjectId(Long projectId) { - this.projectId = projectId; - } + public void setProjectId(Long projectId) { + this.projectId = projectId; + } - public Collection<Long> getItemsToDelete() { - return itemsToDelete; - } + public Collection<Long> getItemsToDelete() { + return itemsToDelete; + } - public void setItemsToDelete(Collection<Long> itemsToDelete) { - this.itemsToDelete = itemsToDelete; - } + public void setItemsToDelete(Collection<Long> itemsToDelete) { + this.itemsToDelete = itemsToDelete; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IndexItemsRemove that = (IndexItemsRemove) o; - return Objects.equals(projectId, that.projectId) && Objects.equals(itemsToDelete, that.itemsToDelete); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IndexItemsRemove that = (IndexItemsRemove) o; + return Objects.equals(projectId, that.projectId) && Objects.equals(itemsToDelete, + that.itemsToDelete); + } - @Override - public int hashCode() { - return Objects.hash(projectId, itemsToDelete); - } + @Override + public int hashCode() { + return Objects.hash(projectId, itemsToDelete); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexLaunchRemove.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexLaunchRemove.java index 24f2048605..e098714326 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexLaunchRemove.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/IndexLaunchRemove.java @@ -16,7 +16,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.model; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.Collection; import java.util.Objects; @@ -25,47 +24,47 @@ */ public class IndexLaunchRemove { - @JsonProperty("project") - private Long projectId; + @JsonProperty("project") + private Long projectId; - @JsonProperty("launch_ids") - private Collection<Long> launchIds; + @JsonProperty("launch_ids") + private Collection<Long> launchIds; - public IndexLaunchRemove(Long projectId, Collection<Long> launchIds) { - this.projectId = projectId; - this.launchIds = launchIds; - } + public IndexLaunchRemove(Long projectId, Collection<Long> launchIds) { + this.projectId = projectId; + this.launchIds = launchIds; + } - public Long getProjectId() { - return projectId; - } + public Long getProjectId() { + return projectId; + } - public void setProjectId(Long projectId) { - this.projectId = projectId; - } + public void setProjectId(Long projectId) { + this.projectId = projectId; + } - public Collection<Long> getLaunchIds() { - return launchIds; - } + public Collection<Long> getLaunchIds() { + return launchIds; + } - public void setLaunchIds(Collection<Long> launchIds) { - this.launchIds = launchIds; - } + public void setLaunchIds(Collection<Long> launchIds) { + this.launchIds = launchIds; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IndexLaunchRemove that = (IndexLaunchRemove) o; - return Objects.equals(projectId, that.projectId) && Objects.equals(launchIds, that.launchIds); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + IndexLaunchRemove that = (IndexLaunchRemove) o; + return Objects.equals(projectId, that.projectId) && Objects.equals(launchIds, that.launchIds); + } - @Override - public int hashCode() { - return Objects.hash(projectId, launchIds); - } + @Override + public int hashCode() { + return Objects.hash(projectId, launchIds); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestInfo.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestInfo.java index 1a73313741..355b491798 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestInfo.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestInfo.java @@ -23,223 +23,233 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class SuggestInfo { - private Long project; + private Long project; - private Long testItem; + private Long testItem; - private Long testItemLogId; + private Long testItemLogId; - private Long launchId; + private Long launchId; - private String launchName; + private String launchName; - private String issueType; + private Long launchNumber; - private Long relevantItem; + private String issueType; - private Long relevantLogId; + private Long relevantItem; - private boolean isMergedLog; + private Long relevantLogId; - private float matchScore; + private boolean isMergedLog; - private int resultPosition; + private float matchScore; - private float esScore; + private int resultPosition; - private int esPosition; + private float esScore; - private String modelFeatureNames; + private int esPosition; - private String modelFeatureValues; + private String modelFeatureNames; - private String modelInfo; + private String modelFeatureValues; - private int usedLogLines; + private String modelInfo; - private int minShouldMatch; + private int usedLogLines; - private float processedTime; + private int minShouldMatch; - private int userChoice; + private float processedTime; - private String methodName; + private int userChoice; - private Long clusterId; + private String methodName; - public Long getProject() { - return project; - } + private Long clusterId; - public void setProject(Long project) { - this.project = project; - } + public Long getProject() { + return project; + } - public Long getTestItem() { - return testItem; - } + public void setProject(Long project) { + this.project = project; + } - public void setTestItem(Long testItem) { - this.testItem = testItem; - } + public Long getTestItem() { + return testItem; + } - public Long getTestItemLogId() { - return testItemLogId; - } + public void setTestItem(Long testItem) { + this.testItem = testItem; + } - public void setTestItemLogId(Long testItemLogId) { - this.testItemLogId = testItemLogId; - } + public Long getTestItemLogId() { + return testItemLogId; + } - public Long getLaunchId() { - return launchId; - } + public void setTestItemLogId(Long testItemLogId) { + this.testItemLogId = testItemLogId; + } - public void setLaunchId(Long launchId) { - this.launchId = launchId; - } + public Long getLaunchId() { + return launchId; + } - public String getLaunchName() { - return launchName; - } + public void setLaunchId(Long launchId) { + this.launchId = launchId; + } - public void setLaunchName(String launchName) { - this.launchName = launchName; - } + public String getLaunchName() { + return launchName; + } - public String getIssueType() { - return issueType; - } + public void setLaunchName(String launchName) { + this.launchName = launchName; + } - public void setIssueType(String issueType) { - this.issueType = issueType; - } + public String getIssueType() { + return issueType; + } - public Long getRelevantItem() { - return relevantItem; - } + public void setIssueType(String issueType) { + this.issueType = issueType; + } - public void setRelevantItem(Long relevantItem) { - this.relevantItem = relevantItem; - } + public Long getRelevantItem() { + return relevantItem; + } - public Long getRelevantLogId() { - return relevantLogId; - } + public void setRelevantItem(Long relevantItem) { + this.relevantItem = relevantItem; + } - public void setRelevantLogId(Long relevantLogId) { - this.relevantLogId = relevantLogId; - } + public Long getRelevantLogId() { + return relevantLogId; + } - public boolean getIsMergedLog() { - return isMergedLog; - } + public void setRelevantLogId(Long relevantLogId) { + this.relevantLogId = relevantLogId; + } - public void setIsMergedLog(boolean isMergedLog) { - this.isMergedLog = isMergedLog; - } + public boolean getIsMergedLog() { + return isMergedLog; + } - public float getMatchScore() { - return matchScore; - } + public void setIsMergedLog(boolean isMergedLog) { + this.isMergedLog = isMergedLog; + } - public void setMatchScore(float matchScore) { - this.matchScore = matchScore; - } + public float getMatchScore() { + return matchScore; + } - public int getResultPosition() { - return resultPosition; - } + public void setMatchScore(float matchScore) { + this.matchScore = matchScore; + } - public void setResultPosition(int resultPosition) { - this.resultPosition = resultPosition; - } + public int getResultPosition() { + return resultPosition; + } - public float getEsScore() { - return esScore; - } + public void setResultPosition(int resultPosition) { + this.resultPosition = resultPosition; + } - public void setEsScore(float esScore) { - this.esScore = esScore; - } + public float getEsScore() { + return esScore; + } - public int getEsPosition() { - return esPosition; - } + public void setEsScore(float esScore) { + this.esScore = esScore; + } - public void setEsPosition(int esPosition) { - this.esPosition = esPosition; - } + public int getEsPosition() { + return esPosition; + } - public String getModelFeatureNames() { - return modelFeatureNames; - } + public void setEsPosition(int esPosition) { + this.esPosition = esPosition; + } - public void setModelFeatureNames(String modelFeatureNames) { - this.modelFeatureNames = modelFeatureNames; - } + public String getModelFeatureNames() { + return modelFeatureNames; + } - public String getModelFeatureValues() { - return modelFeatureValues; - } + public void setModelFeatureNames(String modelFeatureNames) { + this.modelFeatureNames = modelFeatureNames; + } - public void setModelFeatureValues(String modelFeatureValues) { - this.modelFeatureValues = modelFeatureValues; - } + public String getModelFeatureValues() { + return modelFeatureValues; + } - public String getModelInfo() { - return modelInfo; - } + public void setModelFeatureValues(String modelFeatureValues) { + this.modelFeatureValues = modelFeatureValues; + } - public void setModelInfo(String modelInfo) { - this.modelInfo = modelInfo; - } + public String getModelInfo() { + return modelInfo; + } - public int getUsedLogLines() { - return usedLogLines; - } + public void setModelInfo(String modelInfo) { + this.modelInfo = modelInfo; + } - public void setUsedLogLines(int usedLogLines) { - this.usedLogLines = usedLogLines; - } + public int getUsedLogLines() { + return usedLogLines; + } - public int getMinShouldMatch() { - return minShouldMatch; - } + public void setUsedLogLines(int usedLogLines) { + this.usedLogLines = usedLogLines; + } - public void setMinShouldMatch(int minShouldMatch) { - this.minShouldMatch = minShouldMatch; - } + public int getMinShouldMatch() { + return minShouldMatch; + } - public float getProcessedTime() { - return processedTime; - } + public void setMinShouldMatch(int minShouldMatch) { + this.minShouldMatch = minShouldMatch; + } - public void setProcessedTime(float processedTime) { - this.processedTime = processedTime; - } + public float getProcessedTime() { + return processedTime; + } - public int getUserChoice() { - return userChoice; - } + public void setProcessedTime(float processedTime) { + this.processedTime = processedTime; + } - public void setUserChoice(int userChoice) { - this.userChoice = userChoice; - } + public int getUserChoice() { + return userChoice; + } - public String getMethodName() { - return methodName; - } + public void setUserChoice(int userChoice) { + this.userChoice = userChoice; + } - public void setMethodName(String methodName) { - this.methodName = methodName; - } + public String getMethodName() { + return methodName; + } - public Long getClusterId() { - return clusterId; - } + public void setMethodName(String methodName) { + this.methodName = methodName; + } - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } + public Long getClusterId() { + return clusterId; + } + + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } + + public Long getLaunchNumber() { + return launchNumber; + } + + public void setLaunchNumber(Long launchNumber) { + this.launchNumber = launchNumber; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestRq.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestRq.java index 693da7f4ed..c8576dc275 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestRq.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/SuggestRq.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.fasterxml.jackson.annotation.JsonInclude; - import java.util.Set; /** @@ -27,96 +26,106 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class SuggestRq { - private Long testItemId; + private Long testItemId; + + private String uniqueId; + + private Integer testCaseHash; + + private Long clusterId; - private String uniqueId; + private Long launchId; - private Integer testCaseHash; + private String launchName; - private Long clusterId; + private Long launchNumber; - private Long launchId; + private Long project; - private String launchName; + private AnalyzerConfig analyzerConfig; - private Long project; + private Set<IndexLog> logs; - private AnalyzerConfig analyzerConfig; + public SuggestRq() { + } - private Set<IndexLog> logs; + public Long getTestItemId() { + return testItemId; + } - public SuggestRq() { - } + public void setTestItemId(Long testItemId) { + this.testItemId = testItemId; + } - public Long getTestItemId() { - return testItemId; - } + public String getUniqueId() { + return uniqueId; + } - public void setTestItemId(Long testItemId) { - this.testItemId = testItemId; - } + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } - public String getUniqueId() { - return uniqueId; - } + public Integer getTestCaseHash() { + return testCaseHash; + } - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } + public void setTestCaseHash(Integer testCaseHash) { + this.testCaseHash = testCaseHash; + } - public Integer getTestCaseHash() { - return testCaseHash; - } + public Long getClusterId() { + return clusterId; + } - public void setTestCaseHash(Integer testCaseHash) { - this.testCaseHash = testCaseHash; - } + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } - public Long getClusterId() { - return clusterId; - } + public Long getLaunchId() { + return launchId; + } - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } + public void setLaunchId(Long launchId) { + this.launchId = launchId; + } - public Long getLaunchId() { - return launchId; - } + public String getLaunchName() { + return launchName; + } - public void setLaunchId(Long launchId) { - this.launchId = launchId; - } + public void setLaunchName(String launchName) { + this.launchName = launchName; + } - public String getLaunchName() { - return launchName; - } + public Long getProject() { + return project; + } - public void setLaunchName(String launchName) { - this.launchName = launchName; - } + public void setProject(Long project) { + this.project = project; + } - public Long getProject() { - return project; - } + public AnalyzerConfig getAnalyzerConfig() { + return analyzerConfig; + } - public void setProject(Long project) { - this.project = project; - } + public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { + this.analyzerConfig = analyzerConfig; + } - public AnalyzerConfig getAnalyzerConfig() { - return analyzerConfig; - } + public Set<IndexLog> getLogs() { + return logs; + } - public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { - this.analyzerConfig = analyzerConfig; - } + public void setLogs(Set<IndexLog> logs) { + this.logs = logs; + } - public Set<IndexLog> getLogs() { - return logs; - } + public Long getLaunchNumber() { + return launchNumber; + } - public void setLogs(Set<IndexLog> logs) { - this.logs = logs; - } + public void setLaunchNumber(Long launchNumber) { + this.launchNumber = launchNumber; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterData.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterData.java index f0ecdad316..0f76548529 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterData.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterData.java @@ -23,34 +23,34 @@ */ public class ClusterData { - private Long project; - private Long launchId; - private List<ClusterInfoRs> clusters; + private Long project; + private Long launchId; + private List<ClusterInfoRs> clusters; - public ClusterData() { - } + public ClusterData() { + } - public Long getProject() { - return project; - } + public Long getProject() { + return project; + } - public void setProject(Long project) { - this.project = project; - } + public void setProject(Long project) { + this.project = project; + } - public Long getLaunchId() { - return launchId; - } + public Long getLaunchId() { + return launchId; + } - public void setLaunchId(Long launchId) { - this.launchId = launchId; - } + public void setLaunchId(Long launchId) { + this.launchId = launchId; + } - public List<ClusterInfoRs> getClusters() { - return clusters; - } + public List<ClusterInfoRs> getClusters() { + return clusters; + } - public void setClusters(List<ClusterInfoRs> clusters) { - this.clusters = clusters; - } + public void setClusters(List<ClusterInfoRs> clusters) { + this.clusters = clusters; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterInfoRs.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterInfoRs.java index e0a3f1d23b..49f60938aa 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterInfoRs.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/ClusterInfoRs.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - import java.util.LinkedHashSet; import java.util.Set; @@ -26,47 +25,47 @@ */ public class ClusterInfoRs { - private Long clusterId; - private String clusterMessage; + private Long clusterId; + private String clusterMessage; - @JsonDeserialize(as = LinkedHashSet.class) - private Set<Long> itemIds; + @JsonDeserialize(as = LinkedHashSet.class) + private Set<Long> itemIds; - @JsonDeserialize(as = LinkedHashSet.class) - private Set<Long> logIds; + @JsonDeserialize(as = LinkedHashSet.class) + private Set<Long> logIds; - public ClusterInfoRs() { - } + public ClusterInfoRs() { + } - public Long getClusterId() { - return clusterId; - } + public Long getClusterId() { + return clusterId; + } - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } + public void setClusterId(Long clusterId) { + this.clusterId = clusterId; + } - public String getClusterMessage() { - return clusterMessage; - } + public String getClusterMessage() { + return clusterMessage; + } - public void setClusterMessage(String clusterMessage) { - this.clusterMessage = clusterMessage; - } + public void setClusterMessage(String clusterMessage) { + this.clusterMessage = clusterMessage; + } - public Set<Long> getItemIds() { - return itemIds; - } + public Set<Long> getItemIds() { + return itemIds; + } - public void setItemIds(Set<Long> itemIds) { - this.itemIds = itemIds; - } + public void setItemIds(Set<Long> itemIds) { + this.itemIds = itemIds; + } - public Set<Long> getLogIds() { - return logIds; - } + public Set<Long> getLogIds() { + return logIds; + } - public void setLogIds(Set<Long> logIds) { - this.logIds = logIds; - } + public void setLogIds(Set<Long> logIds) { + this.logIds = logIds; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/GenerateClustersRq.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/GenerateClustersRq.java index 328e44fea1..f76557a178 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/GenerateClustersRq.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/client/model/cluster/GenerateClustersRq.java @@ -23,55 +23,55 @@ */ public class GenerateClustersRq { - private IndexLaunch launch; + private IndexLaunch launch; - private Long project; + private Long project; - private int numberOfLogLines; + private int numberOfLogLines; - private boolean forUpdate; - private boolean cleanNumbers; + private boolean forUpdate; + private boolean cleanNumbers; - public GenerateClustersRq() { - } + public GenerateClustersRq() { + } - public IndexLaunch getLaunch() { - return launch; - } + public IndexLaunch getLaunch() { + return launch; + } - public void setLaunch(IndexLaunch launch) { - this.launch = launch; - } + public void setLaunch(IndexLaunch launch) { + this.launch = launch; + } - public Long getProject() { - return project; - } + public Long getProject() { + return project; + } - public void setProject(Long project) { - this.project = project; - } + public void setProject(Long project) { + this.project = project; + } - public int getNumberOfLogLines() { - return numberOfLogLines; - } + public int getNumberOfLogLines() { + return numberOfLogLines; + } - public void setNumberOfLogLines(int numberOfLogLines) { - this.numberOfLogLines = numberOfLogLines; - } + public void setNumberOfLogLines(int numberOfLogLines) { + this.numberOfLogLines = numberOfLogLines; + } - public boolean isForUpdate() { - return forUpdate; - } + public boolean isForUpdate() { + return forUpdate; + } - public void setForUpdate(boolean forUpdate) { - this.forUpdate = forUpdate; - } + public void setForUpdate(boolean forUpdate) { + this.forUpdate = forUpdate; + } - public boolean isCleanNumbers() { - return cleanNumbers; - } + public boolean isCleanNumbers() { + return cleanNumbers; + } - public void setCleanNumbers(boolean cleanNumbers) { - this.cleanNumbers = cleanNumbers; - } + public void setCleanNumbers(boolean cleanNumbers) { + this.cleanNumbers = cleanNumbers; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceAsyncImpl.java index aa3aa3363c..4473a46b19 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceAsyncImpl.java @@ -20,11 +20,10 @@ import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerServiceAsync; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.concurrent.CompletableFuture; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -32,21 +31,23 @@ @Service public class AnalyzerServiceAsyncImpl implements AnalyzerServiceAsync { - private final AnalyzerService analyzerService; + private final AnalyzerService analyzerService; - @Autowired - public AnalyzerServiceAsyncImpl(AnalyzerService analyzerService) { - this.analyzerService = analyzerService; - } + @Autowired + public AnalyzerServiceAsyncImpl(AnalyzerService analyzerService) { + this.analyzerService = analyzerService; + } - @Override - public CompletableFuture<Void> analyze(Launch launch, List<Long> itemIds, AnalyzerConfig analyzerConfig) { - return CompletableFuture.runAsync(() -> analyzerService.runAnalyzers(launch, itemIds, analyzerConfig)); - } + @Override + public CompletableFuture<Void> analyze(Launch launch, List<Long> itemIds, + AnalyzerConfig analyzerConfig) { + return CompletableFuture.runAsync( + () -> analyzerService.runAnalyzers(launch, itemIds, analyzerConfig)); + } - @Override - public boolean hasAnalyzers() { - return analyzerService.hasAnalyzers(); - } + @Override + public boolean hasAnalyzers() { + return analyzerService.hasAnalyzers(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceImpl.java index 3a0b4de2c7..48e3aa4577 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceImpl.java @@ -28,7 +28,9 @@ import com.epam.ta.reportportal.core.events.activity.ItemIssueTypeDefinedEvent; import com.epam.ta.reportportal.core.events.activity.LinkTicketEvent; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; +import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.AnalyzeMode; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueType; @@ -63,80 +65,93 @@ @Transactional public class AnalyzerServiceImpl implements AnalyzerService { - private static final Logger LOGGER = LogManager.getLogger(AnalyzerServiceImpl.class.getName()); - - private final AnalyzerStatusCache analyzerStatusCache; - - private final LaunchPreparerService launchPreparerService; - - private final AnalyzerServiceClient analyzerServicesClient; - - private final IssueTypeHandler issueTypeHandler; - - private final TestItemRepository testItemRepository; - - private final MessageBus messageBus; - - private final Integer itemsBatchSize; - - @Autowired - public AnalyzerServiceImpl(@Value("${rp.environment.variable.item-analyze.batch-size}") Integer itemsBatchSize, - AnalyzerStatusCache analyzerStatusCache, LaunchPreparerService launchPreparerService, - AnalyzerServiceClient analyzerServicesClient, IssueTypeHandler issueTypeHandler, TestItemRepository testItemRepository, - MessageBus messageBus) { - this.itemsBatchSize = itemsBatchSize; - this.analyzerStatusCache = analyzerStatusCache; - this.launchPreparerService = launchPreparerService; - this.analyzerServicesClient = analyzerServicesClient; - this.issueTypeHandler = issueTypeHandler; - this.testItemRepository = testItemRepository; - this.messageBus = messageBus; - } - - @Override - public boolean hasAnalyzers() { - return analyzerServicesClient.hasClients(); - } - - @Override - public void runAnalyzers(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig) { - try { - analyzerStatusCache.analyzeStarted(AUTO_ANALYZER_KEY, launch.getId(), launch.getProjectId()); - Iterables.partition(testItemIds, itemsBatchSize).forEach(partition -> analyzeItemsPartition(launch, partition, analyzerConfig)); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } finally { - analyzerStatusCache.analyzeFinished(AUTO_ANALYZER_KEY, launch.getId()); - } - } - - /** - * Prepare and analyze the number of provided test item ids. - * - * @param launch Launch - * @param testItemIds Item ids for analyzing - * @param analyzerConfig Analyzer config - */ - private void analyzeItemsPartition(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig) { - LOGGER.info("Start analysis of '{}' items for launch with id '{}'", testItemIds.size(), launch.getId()); - List<TestItem> toAnalyze = testItemRepository.findAllById(testItemIds); - Optional<IndexLaunch> rqLaunch = launchPreparerService.prepare(launch, toAnalyze, analyzerConfig); - rqLaunch.ifPresent(rq -> { - Map<String, List<AnalyzedItemRs>> analyzedMap = analyzerServicesClient.analyze(rq); - if (!MapUtils.isEmpty(analyzedMap)) { - analyzedMap.forEach((key, value) -> updateTestItems(key, value, toAnalyze, launch.getProjectId())); - } - }); - } - - /** - * Update issue types for analyzed items and posted events for updated - * - * @param rs Results of analyzing - * @param testItems items to be updated - * @return List of updated items - */ - private List<TestItem> updateTestItems(String analyzerInstance, List<AnalyzedItemRs> rs, List<TestItem> testItems, Long projectId) { + private static final Logger LOGGER = LogManager.getLogger(AnalyzerServiceImpl.class.getName()); + + private final AnalyzerStatusCache analyzerStatusCache; + + private final LaunchPreparerService launchPreparerService; + + private final AnalyzerServiceClient analyzerServicesClient; + + private final IssueTypeHandler issueTypeHandler; + + private final TestItemRepository testItemRepository; + + private final LaunchRepository launchRepository; + + private final MessageBus messageBus; + + private final Integer itemsBatchSize; + + @Autowired + public AnalyzerServiceImpl( + @Value("${rp.environment.variable.item-analyze.batch-size}") Integer itemsBatchSize, + AnalyzerStatusCache analyzerStatusCache, LaunchPreparerService launchPreparerService, + AnalyzerServiceClient analyzerServicesClient, IssueTypeHandler issueTypeHandler, + TestItemRepository testItemRepository, + MessageBus messageBus, LaunchRepository launchRepository) { + this.itemsBatchSize = itemsBatchSize; + this.analyzerStatusCache = analyzerStatusCache; + this.launchPreparerService = launchPreparerService; + this.analyzerServicesClient = analyzerServicesClient; + this.issueTypeHandler = issueTypeHandler; + this.testItemRepository = testItemRepository; + this.messageBus = messageBus; + this.launchRepository = launchRepository; + } + + @Override + public boolean hasAnalyzers() { + return analyzerServicesClient.hasClients(); + } + + @Override + public void runAnalyzers(Launch launch, List<Long> testItemIds, AnalyzerConfig analyzerConfig) { + try { + analyzerStatusCache.analyzeStarted(AUTO_ANALYZER_KEY, launch.getId(), launch.getProjectId()); + Optional<Long> previousLaunchId = findPreviousLaunchId(launch, analyzerConfig); + Iterables.partition(testItemIds, itemsBatchSize) + .forEach(partition -> analyzeItemsPartition(launch, partition, analyzerConfig, previousLaunchId)); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + analyzerStatusCache.analyzeFinished(AUTO_ANALYZER_KEY, launch.getId()); + } + } + + /** + * Prepare and analyze the number of provided test item ids. + * + * @param launch Launch + * @param testItemIds Item ids for analyzing + * @param analyzerConfig Analyzer config + */ + private void analyzeItemsPartition(Launch launch, List<Long> testItemIds, + AnalyzerConfig analyzerConfig, Optional<Long> previousLaunchId) { + LOGGER.info("Start analysis of '{}' items for launch with id '{}'", testItemIds.size(), + launch.getId()); + List<TestItem> toAnalyze = testItemRepository.findAllById(testItemIds); + Optional<IndexLaunch> rqLaunch = launchPreparerService.prepare(launch, toAnalyze, + analyzerConfig); + rqLaunch.ifPresent(rq -> { + previousLaunchId.ifPresent(rq::setPreviousLaunchId); + Map<String, List<AnalyzedItemRs>> analyzedMap = analyzerServicesClient.analyze(rq); + if (!MapUtils.isEmpty(analyzedMap)) { + analyzedMap.forEach( + (key, value) -> updateTestItems(key, value, toAnalyze, launch.getProjectId())); + } + }); + } + + /** + * Update issue types for analyzed items and posted events for updated + * + * @param rs Results of analyzing + * @param testItems items to be updated + * @return List of updated items + */ + private List<TestItem> updateTestItems(String analyzerInstance, List<AnalyzedItemRs> rs, + List<TestItem> testItems, Long projectId) { return rs.stream().map(analyzed -> { Optional<TestItem> toUpdate = testItems.stream() .filter(item -> item.getItemId().equals(analyzed.getItemId())).findAny(); @@ -164,50 +179,64 @@ private List<TestItem> updateTestItems(String analyzerInstance, List<AnalyzedIte }).filter(Optional::isPresent).map(Optional::get).collect(toList()); } - /** - * Updates issue for a specified test item - * - * @param projectId - Project id - * @param rs - Response from an analyzer - * @param testItem - Test item to be updated - * @return Updated issue entity - */ - private RelevantItemInfo updateTestItemIssue(Long projectId, AnalyzedItemRs rs, TestItem testItem) { - IssueType issueType = issueTypeHandler.defineIssueType(projectId, rs.getLocator()); - IssueEntity issueEntity = new IssueEntityBuilder(testItem.getItemResults().getIssue()).addIssueType(issueType) - .addIgnoreFlag(testItem.getItemResults().getIssue().getIgnoreAnalyzer()) - .addAutoAnalyzedFlag(true) - .get(); - issueEntity.setIssueId(testItem.getItemId()); - issueEntity.setTestItemResults(testItem.getItemResults()); - testItem.getItemResults().setIssue(issueEntity); - - RelevantItemInfo relevantItemInfo = null; - if (rs.getRelevantItemId() != null) { - Optional<TestItem> relevantItemOptional = testItemRepository.findById(rs.getRelevantItemId()); - if (relevantItemOptional.isPresent()) { - relevantItemInfo = updateIssueFromRelevantItem(issueEntity, relevantItemOptional.get()); - } else { - LOGGER.error(ErrorType.TEST_ITEM_NOT_FOUND.getDescription(), rs.getRelevantItemId()); - } - } - - return relevantItemInfo; - } - - /** - * Updates issue with values are taken from most relevant item - * - * @param issue Issue to update - * @param relevantItem Relevant item - */ - private RelevantItemInfo updateIssueFromRelevantItem(IssueEntity issue, TestItem relevantItem) { - ofNullable(relevantItem.getItemResults().getIssue()).ifPresent(relevantIssue -> { - issue.setIssueDescription(relevantIssue.getIssueDescription()); - issue.setTickets(Sets.newHashSet(relevantIssue.getTickets())); - }); - - return AnalyzerUtils.TO_RELEVANT_ITEM_INFO.apply(relevantItem); - } + /** + * Updates issue for a specified test item + * + * @param projectId - Project id + * @param rs - Response from an analyzer + * @param testItem - Test item to be updated + * @return Updated issue entity + */ + private RelevantItemInfo updateTestItemIssue(Long projectId, AnalyzedItemRs rs, + TestItem testItem) { + IssueType issueType = issueTypeHandler.defineIssueType(projectId, rs.getLocator()); + IssueEntity issueEntity = new IssueEntityBuilder( + testItem.getItemResults().getIssue()).addIssueType(issueType) + .addIgnoreFlag(testItem.getItemResults().getIssue().getIgnoreAnalyzer()) + .addAutoAnalyzedFlag(true) + .get(); + issueEntity.setIssueId(testItem.getItemId()); + issueEntity.setTestItemResults(testItem.getItemResults()); + testItem.getItemResults().setIssue(issueEntity); + + RelevantItemInfo relevantItemInfo = null; + if (rs.getRelevantItemId() != null) { + Optional<TestItem> relevantItemOptional = testItemRepository.findById(rs.getRelevantItemId()); + if (relevantItemOptional.isPresent()) { + relevantItemInfo = updateIssueFromRelevantItem(issueEntity, relevantItemOptional.get()); + } else { + LOGGER.error(ErrorType.TEST_ITEM_NOT_FOUND.getDescription(), rs.getRelevantItemId()); + } + } + + return relevantItemInfo; + } + /** + * Updates issue with values are taken from most relevant item + * + * @param issue Issue to update + * @param relevantItem Relevant item + */ + private RelevantItemInfo updateIssueFromRelevantItem(IssueEntity issue, TestItem relevantItem) { + ofNullable(relevantItem.getItemResults().getIssue()).ifPresent(relevantIssue -> { + issue.setIssueDescription(relevantIssue.getIssueDescription()); + issue.setTickets(Sets.newHashSet(relevantIssue.getTickets())); + }); + + return AnalyzerUtils.TO_RELEVANT_ITEM_INFO.apply(relevantItem); + } + + /** + * + * @param launch Analyzed launch + * @param analyzerConfig Current analyzer config + * @return Id of previous launch. Required only for PREVIOUS_LAUNCH option. + */ + private Optional<Long> findPreviousLaunchId(Launch launch, AnalyzerConfig analyzerConfig) { + if (analyzerConfig.getAnalyzerMode().equals(AnalyzeMode.PREVIOUS_LAUNCH.getValue())) { + return launchRepository.findPreviousLaunchId(launch); + } + return Optional.empty(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerStatusCache.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerStatusCache.java index 3d79905e3a..a54ac48809 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerStatusCache.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerStatusCache.java @@ -16,104 +16,106 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static java.util.Optional.ofNullable; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableMap; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - -import static java.util.Optional.ofNullable; +import org.springframework.stereotype.Service; /** * Contains caches for analyzing and indexing status * * @author Pavel Bortnik */ +@Deprecated(since = "This cache is not representable since api scaling") @Service public class AnalyzerStatusCache { - public static final String AUTO_ANALYZER_KEY = "autoAnalyzer"; - public static final String PATTERN_ANALYZER_KEY = "patternAnalyzer"; - public static final String CLUSTER_KEY = "cluster"; - - private static final int CACHE_ITEM_LIVE = 10; - private static final int MAXIMUM_SIZE = 50000; - - private static final int CLUSTER_ITEM_LIVE = 20; - - /** - * Contains cache of analyze running for concrete launch - * launchId - projectId - */ - private Map<String, Cache<Long, Long>> analyzeStatus; - - public AnalyzerStatusCache() { - Cache<Long, Long> autoAnalysisStatusCache = CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_SIZE) - .expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES) - .build(); - Cache<Long, Long> patternAnalysisCache = CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_SIZE) - .expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES) - .build(); - Cache<Long, Long> clusterCache = CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_SIZE) - .expireAfterWrite(CLUSTER_ITEM_LIVE, TimeUnit.MINUTES) - .build(); - analyzeStatus = ImmutableMap.<String, Cache<Long, Long>>builder().put(AUTO_ANALYZER_KEY, autoAnalysisStatusCache) - .put(PATTERN_ANALYZER_KEY, patternAnalysisCache) - .put(CLUSTER_KEY, clusterCache) - .build(); - } - - public AnalyzerStatusCache(Map<String, Cache<Long, Long>> analyzeStatus) { - this.analyzeStatus = analyzeStatus; - } - - public boolean analyzeStarted(String analyzerKey, Long launchId, Long projectId) { - Cache<Long, Long> analysisCache = analyzeStatus.get(analyzerKey); - if (analysisCache == null) { - return false; - } - analysisCache.put(launchId, projectId); - return true; - } - - public boolean analyzeFinished(String analyzerKey, Long launchId) { - Cache<Long, Long> analysisCache = analyzeStatus.get(analyzerKey); - if (analysisCache == null) { - return false; - } - analysisCache.invalidate(launchId); - return true; - } - - public Optional<Cache<Long, Long>> getAnalyzeStatus(String analyzerKey) { - return ofNullable(analyzeStatus.get(analyzerKey)); - } - - public boolean containsLaunchId(String analyzerKey, Long launchId) { - return ofNullable(analyzeStatus.get(analyzerKey)).map(cache -> cache.asMap().containsKey(launchId)).orElse(Boolean.FALSE); - } - - public boolean containsProjectId(String analyzerKey, Long projectId) { - return ofNullable(analyzeStatus.get(analyzerKey)).map(cache -> cache.asMap().containsValue(projectId)).orElse(Boolean.FALSE); - } - - public Set<String> getStartedAnalyzers(Long launchId) { - return analyzeStatus.entrySet() - .stream() - .filter(entry -> entry.getValue().asMap().containsKey(launchId)) - .map(Map.Entry::getKey) - .collect(Collectors.toSet()); - } - - public Set<String> getAnalyzers() { - return analyzeStatus.keySet(); - } + public static final String AUTO_ANALYZER_KEY = "autoAnalyzer"; + public static final String PATTERN_ANALYZER_KEY = "patternAnalyzer"; + public static final String CLUSTER_KEY = "cluster"; + + private static final int CACHE_ITEM_LIVE = 10; + private static final int MAXIMUM_SIZE = 50000; + + private static final int CLUSTER_ITEM_LIVE = 20; + + /** + * Contains cache of analyze running for concrete launch launchId - projectId + */ + private Map<String, Cache<Long, Long>> analyzeStatus; + + public AnalyzerStatusCache() { + Cache<Long, Long> autoAnalysisStatusCache = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_SIZE) + .expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES) + .build(); + Cache<Long, Long> patternAnalysisCache = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_SIZE) + .expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES) + .build(); + Cache<Long, Long> clusterCache = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_SIZE) + .expireAfterWrite(CLUSTER_ITEM_LIVE, TimeUnit.MINUTES) + .build(); + analyzeStatus = ImmutableMap.<String, Cache<Long, Long>>builder() + .put(AUTO_ANALYZER_KEY, autoAnalysisStatusCache) + .put(PATTERN_ANALYZER_KEY, patternAnalysisCache) + .put(CLUSTER_KEY, clusterCache) + .build(); + } + + public AnalyzerStatusCache(Map<String, Cache<Long, Long>> analyzeStatus) { + this.analyzeStatus = analyzeStatus; + } + + public boolean analyzeStarted(String analyzerKey, Long launchId, Long projectId) { + Cache<Long, Long> analysisCache = analyzeStatus.get(analyzerKey); + if (analysisCache == null) { + return false; + } + analysisCache.put(launchId, projectId); + return true; + } + + public boolean analyzeFinished(String analyzerKey, Long launchId) { + Cache<Long, Long> analysisCache = analyzeStatus.get(analyzerKey); + if (analysisCache == null) { + return false; + } + analysisCache.invalidate(launchId); + return true; + } + + public Optional<Cache<Long, Long>> getAnalyzeStatus(String analyzerKey) { + return ofNullable(analyzeStatus.get(analyzerKey)); + } + + public boolean containsLaunchId(String analyzerKey, Long launchId) { + return ofNullable(analyzeStatus.get(analyzerKey)).map( + cache -> cache.asMap().containsKey(launchId)).orElse(Boolean.FALSE); + } + + public boolean containsProjectId(String analyzerKey, Long projectId) { + return ofNullable(analyzeStatus.get(analyzerKey)).map( + cache -> cache.asMap().containsValue(projectId)).orElse(Boolean.FALSE); + } + + public Set<String> getStartedAnalyzers(Long launchId) { + return analyzeStatus.entrySet() + .stream() + .filter(entry -> entry.getValue().asMap().containsKey(launchId)) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + } + + public Set<String> getAnalyzers() { + return analyzeStatus.keySet(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtils.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtils.java index ae37a9f8c7..a3d048e25b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtils.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtils.java @@ -16,8 +16,19 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.ALL_MESSAGES_SHOULD_MATCH; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.AUTO_ANALYZER_ENABLED; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.AUTO_ANALYZER_MODE; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.INDEXING_RUNNING; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.MIN_SHOULD_MATCH; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.NUMBER_OF_LOG_LINES; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectUtils; import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; @@ -25,17 +36,13 @@ import com.epam.ta.reportportal.ws.model.analyzer.RelevantItemInfo; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.epam.ta.reportportal.ws.model.project.UniqueErrorConfig; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; - import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.*; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; /** * Useful utils methods for basic analyzer @@ -44,83 +51,92 @@ */ public class AnalyzerUtils { - private AnalyzerUtils() { - //static only - } + private AnalyzerUtils() { + //static only + } - /** - * Creates {@link IndexLog} model for log for further - * sending that into analyzer - */ - private final static Function<Log, IndexLog> TO_INDEX_LOG = log -> { - IndexLog indexLog = new IndexLog(); - indexLog.setLogId(log.getId()); - if (log.getLogLevel() != null) { - indexLog.setLogLevel(log.getLogLevel()); - } - indexLog.setMessage(log.getLogMessage()); - indexLog.setClusterId(log.getClusterId()); - return indexLog; - }; + /** + * Creates {@link IndexLog} model for log for further sending that into analyzer + */ + private final static Function<LogFull, IndexLog> TO_INDEX_LOG = log -> { + IndexLog indexLog = new IndexLog(); + indexLog.setLogId(log.getId()); + if (log.getLogLevel() != null) { + indexLog.setLogLevel(log.getLogLevel()); + } + indexLog.setMessage(log.getLogMessage()); + indexLog.setClusterId(log.getClusterId()); + return indexLog; + }; - /** - * Creates {@link IndexTestItem} model for test item and it's logs - * for further sending that into analyzer. - * - * @param testItem Test item to be created from - * @param logs Test item's logs - * @return {@link IndexTestItem} object - */ - public static IndexTestItem fromTestItem(TestItem testItem) { - IndexTestItem indexTestItem = new IndexTestItem(); - indexTestItem.setTestItemId(testItem.getItemId()); - indexTestItem.setTestItemName(testItem.getName()); - indexTestItem.setUniqueId(testItem.getUniqueId()); - indexTestItem.setStartTime(testItem.getStartTime()); - indexTestItem.setTestCaseHash(testItem.getTestCaseHash()); - if (testItem.getItemResults().getIssue() != null) { - indexTestItem.setIssueTypeLocator(testItem.getItemResults().getIssue().getIssueType().getLocator()); - indexTestItem.setAutoAnalyzed(testItem.getItemResults().getIssue().getAutoAnalyzed()); - } - return indexTestItem; - } + /** + * Creates {@link IndexTestItem} model for test item and it's logs for further sending that into + * analyzer. + * + * @param testItem Test item to be created from + * @return {@link IndexTestItem} object + */ + public static IndexTestItem fromTestItem(TestItem testItem) { + IndexTestItem indexTestItem = new IndexTestItem(); + indexTestItem.setTestItemId(testItem.getItemId()); + indexTestItem.setTestItemName(testItem.getName()); + indexTestItem.setUniqueId(testItem.getUniqueId()); + indexTestItem.setStartTime(testItem.getStartTime()); + indexTestItem.setTestCaseHash(testItem.getTestCaseHash()); + if (testItem.getItemResults().getIssue() != null) { + indexTestItem.setIssueTypeLocator( + testItem.getItemResults().getIssue().getIssueType().getLocator()); + indexTestItem.setAutoAnalyzed(testItem.getItemResults().getIssue().getAutoAnalyzed()); + } + return indexTestItem; + } - public static Set<IndexLog> fromLogs(List<Log> logs) { - return logs.stream().filter(it -> StringUtils.isNotEmpty(it.getLogMessage())).map(TO_INDEX_LOG).collect(Collectors.toSet()); - } + public static Set<IndexLog> fromLogs(List<LogFull> logs) { + return logs.stream().filter(it -> StringUtils.isNotEmpty(it.getLogMessage())).map(TO_INDEX_LOG) + .collect(Collectors.toSet()); + } - public static AnalyzerConfig getAnalyzerConfig(Project project) { - Map<String, String> configParameters = ProjectUtils.getConfigParameters(project.getProjectAttributes()); - return getAnalyzerConfig(configParameters); - } + public static AnalyzerConfig getAnalyzerConfig(Project project) { + Map<String, String> configParameters = ProjectUtils.getConfigParameters( + project.getProjectAttributes()); + return getAnalyzerConfig(configParameters); + } - public static AnalyzerConfig getAnalyzerConfig(Map<String, String> configParameters) { - AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setIsAutoAnalyzerEnabled(BooleanUtils.toBoolean(configParameters.get(AUTO_ANALYZER_ENABLED.getAttribute()))); - analyzerConfig.setMinShouldMatch(Integer.valueOf(ofNullable(configParameters.get(MIN_SHOULD_MATCH.getAttribute())).orElse( - MIN_SHOULD_MATCH.getDefaultValue()))); - analyzerConfig.setSearchLogsMinShouldMatch(Integer.valueOf(ofNullable(configParameters.get(SEARCH_LOGS_MIN_SHOULD_MATCH.getAttribute())).orElse( - SEARCH_LOGS_MIN_SHOULD_MATCH.getDefaultValue()))); - analyzerConfig.setNumberOfLogLines(Integer.valueOf(ofNullable(configParameters.get(NUMBER_OF_LOG_LINES.getAttribute())).orElse( - NUMBER_OF_LOG_LINES.getDefaultValue()))); - analyzerConfig.setIndexingRunning(BooleanUtils.toBoolean(configParameters.get(INDEXING_RUNNING.getAttribute()))); - analyzerConfig.setAnalyzerMode(configParameters.get(AUTO_ANALYZER_MODE.getAttribute())); - analyzerConfig.setAllMessagesShouldMatch(BooleanUtils.toBoolean(configParameters.get(ALL_MESSAGES_SHOULD_MATCH.getAttribute()))); - return analyzerConfig; - } + public static AnalyzerConfig getAnalyzerConfig(Map<String, String> configParameters) { + AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setIsAutoAnalyzerEnabled( + BooleanUtils.toBoolean(configParameters.get(AUTO_ANALYZER_ENABLED.getAttribute()))); + analyzerConfig.setMinShouldMatch( + Integer.valueOf(ofNullable(configParameters.get(MIN_SHOULD_MATCH.getAttribute())).orElse( + MIN_SHOULD_MATCH.getDefaultValue()))); + analyzerConfig.setSearchLogsMinShouldMatch(Integer.valueOf( + ofNullable(configParameters.get(SEARCH_LOGS_MIN_SHOULD_MATCH.getAttribute())).orElse( + SEARCH_LOGS_MIN_SHOULD_MATCH.getDefaultValue()))); + analyzerConfig.setNumberOfLogLines( + Integer.valueOf(ofNullable(configParameters.get(NUMBER_OF_LOG_LINES.getAttribute())).orElse( + NUMBER_OF_LOG_LINES.getDefaultValue()))); + analyzerConfig.setIndexingRunning( + BooleanUtils.toBoolean(configParameters.get(INDEXING_RUNNING.getAttribute()))); + analyzerConfig.setAnalyzerMode(configParameters.get(AUTO_ANALYZER_MODE.getAttribute())); + analyzerConfig.setAllMessagesShouldMatch( + BooleanUtils.toBoolean(configParameters.get(ALL_MESSAGES_SHOULD_MATCH.getAttribute()))); + return analyzerConfig; + } - public static UniqueErrorConfig getUniqueErrorConfig(Map<String, String> configParameters) { - final UniqueErrorConfig uniqueErrorConfig = new UniqueErrorConfig(); - uniqueErrorConfig.setEnabled(BooleanUtils.toBoolean(configParameters.get(AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute()))); - uniqueErrorConfig.setRemoveNumbers(BooleanUtils.toBoolean(configParameters.get(UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute()))); - return uniqueErrorConfig; - } + public static UniqueErrorConfig getUniqueErrorConfig(Map<String, String> configParameters) { + final UniqueErrorConfig uniqueErrorConfig = new UniqueErrorConfig(); + uniqueErrorConfig.setEnabled(BooleanUtils.toBoolean( + configParameters.get(AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute()))); + uniqueErrorConfig.setRemoveNumbers(BooleanUtils.toBoolean( + configParameters.get(UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute()))); + return uniqueErrorConfig; + } - public static final Function<TestItem, RelevantItemInfo> TO_RELEVANT_ITEM_INFO = item -> { - RelevantItemInfo relevantItemInfo = new RelevantItemInfo(); - relevantItemInfo.setItemId(String.valueOf(item.getItemId())); - relevantItemInfo.setPath(item.getPath()); - relevantItemInfo.setLaunchId(String.valueOf(item.getLaunchId())); - return relevantItemInfo; - }; + public static final Function<TestItem, RelevantItemInfo> TO_RELEVANT_ITEM_INFO = item -> { + RelevantItemInfo relevantItemInfo = new RelevantItemInfo(); + relevantItemInfo.setItemId(String.valueOf(item.getItemId())); + relevantItemInfo.setPath(item.getPath()); + relevantItemInfo.setLaunchId(String.valueOf(item.getLaunchId())); + return relevantItemInfo; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerService.java index d873b65edf..429225b290 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerService.java @@ -29,6 +29,12 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -37,142 +43,145 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Service public class LogIndexerService implements LogIndexer { - private static Logger LOGGER = LoggerFactory.getLogger(LogIndexerService.class); - - private final BatchLogIndexer batchLogIndexer; - - private final TaskExecutor taskExecutor; - - private final LaunchRepository launchRepository; - - private final TestItemRepository testItemRepository; - - private final IndexerServiceClient indexerServiceClient; - - private final LaunchPreparerService launchPreparerService; - - private final IndexerStatusCache indexerStatusCache; - - @Autowired - public LogIndexerService(BatchLogIndexer batchLogIndexer, @Qualifier("logIndexTaskExecutor") TaskExecutor taskExecutor, - LaunchRepository launchRepository, TestItemRepository testItemRepository, IndexerServiceClient indexerServiceClient, - LaunchPreparerService launchPreparerService, IndexerStatusCache indexerStatusCache) { - this.batchLogIndexer = batchLogIndexer; - this.taskExecutor = taskExecutor; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.indexerServiceClient = indexerServiceClient; - this.launchPreparerService = launchPreparerService; - this.indexerStatusCache = indexerStatusCache; - } - - @Override - public CompletableFuture<Long> index(Long projectId, AnalyzerConfig analyzerConfig) { - return CompletableFuture.supplyAsync(() -> { - try { - LOGGER.info("Start indexing for project: {}", projectId); - indexerStatusCache.indexingStarted(projectId); - final Long indexed = batchLogIndexer.index(projectId, analyzerConfig); - LOGGER.info("Indexing finished for project: {}. Logs indexed: {}", projectId, indexed); - return indexed; - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - throw new ReportPortalException(e.getMessage()); - } finally { - indexerStatusCache.indexingFinished(projectId); - } - }, taskExecutor); - } - - @Override - @Transactional(readOnly = true) - public Long indexLaunchLogs(Launch launch, AnalyzerConfig analyzerConfig) { - try { - indexerStatusCache.indexingStarted(launch.getProjectId()); - final List<Long> itemIds = testItemRepository.selectIdsWithIssueByLaunch(launch.getId()); - return batchLogIndexer.index(analyzerConfig, launch, itemIds); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - throw new ReportPortalException(e.getMessage()); - } finally { - indexerStatusCache.indexingFinished(launch.getProjectId()); - } - } - - @Override - @Transactional(readOnly = true) - public Long indexItemsLogs(Long projectId, Long launchId, List<Long> itemIds, AnalyzerConfig analyzerConfig) { - try { - indexerStatusCache.indexingStarted(projectId); - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); - return batchLogIndexer.index(analyzerConfig, launch, itemIds); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - throw new ReportPortalException(e.getMessage()); - } finally { - indexerStatusCache.indexingFinished(projectId); - } - } - - @Override - public void deleteIndex(Long project) { - indexerServiceClient.deleteIndex(project); - } - - @Override - public CompletableFuture<Long> cleanIndex(Long index, List<Long> ids) { - return CollectionUtils.isEmpty(ids) ? - CompletableFuture.completedFuture(0L) : - CompletableFuture.supplyAsync(() -> indexerServiceClient.cleanIndex(index, ids)); - } - - @Async - @Override - public void indexDefectsUpdate(Long projectId, AnalyzerConfig analyzerConfig, List<TestItem> testItems) { - if (CollectionUtils.isEmpty(testItems)) { - return; - } - - Map<Long, String> itemsForIndexUpdate = testItems.stream() - .collect(Collectors.toMap(TestItem::getItemId, it -> it.getItemResults().getIssue().getIssueType().getLocator())); - - List<Long> missedItemIds = indexerServiceClient.indexDefectsUpdate(projectId, itemsForIndexUpdate); - List<TestItem> missedItems = testItems.stream().filter(it -> missedItemIds.contains(it.getItemId())).collect(Collectors.toList()); - - List<IndexLaunch> indexLaunchList = launchPreparerService.prepare(analyzerConfig, missedItems); - - indexerServiceClient.index(indexLaunchList); - } - - @Override - public int indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove) { - return indexerServiceClient.indexItemsRemove(projectId, itemsForIndexRemove); - } - - @Async - @Override - public void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove) { - indexerServiceClient.indexItemsRemoveAsync(projectId, itemsForIndexRemove); - } - - @Async - @Override - public void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove) { - indexerServiceClient.indexLaunchesRemove(projectId, launchesForIndexRemove); - } + + private static Logger LOGGER = LoggerFactory.getLogger(LogIndexerService.class); + + private final BatchLogIndexer batchLogIndexer; + + private final TaskExecutor taskExecutor; + + private final LaunchRepository launchRepository; + + private final TestItemRepository testItemRepository; + + private final IndexerServiceClient indexerServiceClient; + + private final LaunchPreparerService launchPreparerService; + + private final IndexerStatusCache indexerStatusCache; + + @Autowired + public LogIndexerService(BatchLogIndexer batchLogIndexer, + @Qualifier("logIndexTaskExecutor") TaskExecutor taskExecutor, + LaunchRepository launchRepository, TestItemRepository testItemRepository, + IndexerServiceClient indexerServiceClient, + LaunchPreparerService launchPreparerService, IndexerStatusCache indexerStatusCache) { + this.batchLogIndexer = batchLogIndexer; + this.taskExecutor = taskExecutor; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.indexerServiceClient = indexerServiceClient; + this.launchPreparerService = launchPreparerService; + this.indexerStatusCache = indexerStatusCache; + } + + @Override + public CompletableFuture<Long> index(Long projectId, AnalyzerConfig analyzerConfig) { + return CompletableFuture.supplyAsync(() -> { + try { + LOGGER.info("Start indexing for project: {}", projectId); + indexerStatusCache.indexingStarted(projectId); + final Long indexed = batchLogIndexer.index(projectId, analyzerConfig); + LOGGER.info("Indexing finished for project: {}. Logs indexed: {}", projectId, indexed); + return indexed; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ReportPortalException(e.getMessage()); + } finally { + indexerStatusCache.indexingFinished(projectId); + } + }, taskExecutor); + } + + @Override + @Transactional(readOnly = true) + public Long indexLaunchLogs(Launch launch, AnalyzerConfig analyzerConfig) { + try { + indexerStatusCache.indexingStarted(launch.getProjectId()); + final List<Long> itemIds = testItemRepository.selectIdsWithIssueByLaunch(launch.getId()); + return batchLogIndexer.index(analyzerConfig, launch, itemIds); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ReportPortalException(e.getMessage()); + } finally { + indexerStatusCache.indexingFinished(launch.getProjectId()); + } + } + + @Override + @Transactional(readOnly = true) + public Long indexItemsLogs(Long projectId, Long launchId, List<Long> itemIds, + AnalyzerConfig analyzerConfig) { + try { + indexerStatusCache.indexingStarted(projectId); + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); + return batchLogIndexer.index(analyzerConfig, launch, itemIds); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ReportPortalException(e.getMessage()); + } finally { + indexerStatusCache.indexingFinished(projectId); + } + } + + @Override + public void deleteIndex(Long project) { + indexerServiceClient.deleteIndex(project); + } + + @Override + public CompletableFuture<Long> cleanIndex(Long index, List<Long> ids) { + return CollectionUtils.isEmpty(ids) ? + CompletableFuture.completedFuture(0L) : + CompletableFuture.supplyAsync(() -> indexerServiceClient.cleanIndex(index, ids)); + } + + @Async + @Override + public void indexDefectsUpdate(Long projectId, AnalyzerConfig analyzerConfig, + List<TestItem> testItems) { + if (CollectionUtils.isEmpty(testItems)) { + return; + } + + Map<Long, String> itemsForIndexUpdate = testItems.stream() + .collect(Collectors.toMap(TestItem::getItemId, + it -> it.getItemResults().getIssue().getIssueType().getLocator())); + + List<Long> missedItemIds = indexerServiceClient.indexDefectsUpdate(projectId, + itemsForIndexUpdate); + List<TestItem> missedItems = testItems.stream() + .filter(it -> missedItemIds.contains(it.getItemId())).collect(Collectors.toList()); + + if (CollectionUtils.isNotEmpty(missedItems)) { + List<IndexLaunch> indexLaunchList = launchPreparerService.prepare(analyzerConfig, + missedItems); + indexerServiceClient.index(indexLaunchList); + } + } + + @Override + public int indexItemsRemove(Long projectId, Collection<Long> itemsForIndexRemove) { + return indexerServiceClient.indexItemsRemove(projectId, itemsForIndexRemove); + } + + @Async + @Override + public void indexItemsRemoveAsync(Long projectId, Collection<Long> itemsForIndexRemove) { + indexerServiceClient.indexItemsRemoveAsync(projectId, itemsForIndexRemove); + } + + @Async + @Override + public void indexLaunchesRemove(Long projectId, Collection<Long> launchesForIndexRemove) { + indexerServiceClient.indexLaunchesRemove(projectId, launchesForIndexRemove); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImpl.java index 481c0a37dc..997f3f709c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImpl.java @@ -16,13 +16,22 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.TO_LOG_ENTRY; +import static java.util.Collections.singletonList; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.SearchLogService; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.strategy.search.SearchCollectorFactory; import com.epam.ta.reportportal.core.analyzer.auto.strategy.search.SearchLogsMode; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.LaunchRepository; -import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; @@ -30,7 +39,7 @@ import com.epam.ta.reportportal.entity.item.PathName; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.converter.converters.IssueConverter; @@ -43,23 +52,18 @@ import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import java.time.temporal.ChronoUnit; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.temporal.ChronoUnit; -import java.util.*; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.TO_LOG_ENTRY; -import static java.util.Collections.singletonList; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toMap; -import static java.util.stream.Collectors.toSet; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @@ -67,135 +71,154 @@ @Transactional public class SearchLogServiceImpl implements SearchLogService { - private final ProjectRepository projectRepository; - - private final LaunchRepository launchRepository; - - private final TestItemRepository testItemRepository; - - private final LogRepository logRepository; - - private final AnalyzerServiceClient analyzerServiceClient; - - private final SearchCollectorFactory searchCollectorFactory; - - @Autowired - public SearchLogServiceImpl(ProjectRepository projectRepository, LaunchRepository launchRepository, - TestItemRepository testItemRepository, LogRepository logRepository, AnalyzerServiceClient analyzerServiceClient, - SearchCollectorFactory searchCollectorFactory) { - this.projectRepository = projectRepository; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; - this.analyzerServiceClient = analyzerServiceClient; - this.searchCollectorFactory = searchCollectorFactory; - } - - @Override - public Iterable<SearchLogRs> search(Long itemId, SearchLogRq request, ReportPortalUser.ProjectDetails projectDetails) { - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectDetails.getProjectId())); - - TestItem item = testItemRepository.findById(itemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); - - Launch launch = launchRepository.findById(item.getLaunchId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, item.getLaunchId())); - - expect(item.getItemResults().getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify(ErrorType.TEST_ITEM_IS_NOT_FINISHED); - - return composeRequest(request, project, item, launch).map(searchRq -> processRequest(project.getId(), searchRq)) - .orElse(Collections.emptyList()); - } - - private Optional<SearchRq> composeRequest(SearchLogRq request, Project project, TestItem item, Launch launch) { - SearchLogsMode searchMode = SearchLogsMode.fromString(request.getSearchMode()) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, request.getSearchMode())); - - SearchRq searchRq = new SearchRq(); - - searchRq.setFilteredLaunchIds(searchCollectorFactory.getCollector(searchMode).collect(request.getFilterId(), launch)); - - //TODO fix query - select messages from `Nested Step` descendants too - List<String> logMessages = logRepository.findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(launch.getId(), - item.getItemId(), - item.getPath(), - LogLevel.ERROR_INT - ); - if (CollectionUtils.isEmpty(logMessages)) { - return Optional.empty(); - } - searchRq.setLogMessages(logMessages); - - final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(project); - searchRq.setAnalyzerConfig(analyzerConfig); - searchRq.setLogLines(analyzerConfig.getNumberOfLogLines()); - searchRq.setItemId(item.getItemId()); - searchRq.setLaunchId(launch.getId()); - searchRq.setLaunchName(launch.getName()); - searchRq.setProjectId(project.getId()); - return Optional.of(searchRq); - } - - private Collection<SearchLogRs> processRequest(Long projectId, SearchRq request) { - List<SearchRs> searchRs = analyzerServiceClient.searchLogs(request); - Map<Long, Long> logIdMapping = searchRs.stream() - .collect(HashMap::new, (m, rs) -> m.put(rs.getLogId(), rs.getTestItemId()), Map::putAll); - Map<Long, TestItem> testItemMapping = testItemRepository.findAllById(logIdMapping.values()) - .stream() - .collect(toMap(TestItem::getItemId, item -> item)); - List<Log> foundLogs = logRepository.findAllById(logIdMapping.keySet()); - Map<Long, SearchLogRs> foundLogsMap = Maps.newHashMap(); - - foundLogs.forEach(log -> ofNullable(logIdMapping.get(log.getId())).ifPresent(itemId -> { - foundLogsMap.computeIfPresent(itemId, (key, value) -> { - value.getLogs().add(TO_LOG_ENTRY.apply(log)); - return value; - }); - foundLogsMap.computeIfAbsent(itemId, key -> composeResponse(testItemMapping, projectId, itemId, log)); - })); - return foundLogsMap.values(); - } - - private SearchLogRs composeResponse(Map<Long, TestItem> testItemMapping, Long projectId, Long itemId, Log log) { - TestItem testItem = ofNullable(testItemMapping.get(itemId)).orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, - itemId - )); - Long launchId = ofNullable(testItem.getLaunchId()).orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, - testItem.getLaunchId() - )); - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); - - Map<Long, PathName> pathNameMapping = testItemRepository.selectPathNames(singletonList(testItem)); - - SearchLogRs response = new SearchLogRs(); - response.setLaunchId(launch.getId()); - ofNullable(pathNameMapping.get(testItem.getItemId())).ifPresent(pathName -> { - response.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE.apply(pathName)); - }); - response.setItemId(testItem.getItemId()); - response.setItemName(testItem.getName()); - response.setPath(testItem.getPath()); - response.setPatternTemplates(testItem.getPatternTemplateTestItems() - .stream() - .map(patternTemplateTestItem -> patternTemplateTestItem.getPatternTemplate().getName()) - .collect(toSet())); - response.setDuration(ofNullable(testItem.getItemResults().getDuration()).orElseGet(() -> getDuration(testItem))); - response.setStatus(testItem.getItemResults().getStatus().name()); - TestItem itemWithStats = testItem; - while (!itemWithStats.isHasStats()) { - final Long parentId = itemWithStats.getParentId(); - itemWithStats = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); - } - - response.setIssue(IssueConverter.TO_MODEL.apply(itemWithStats.getItemResults().getIssue())); - response.setLogs(Lists.newArrayList(TO_LOG_ENTRY.apply(log))); - return response; - } - - private double getDuration(TestItem testItem) { - return ChronoUnit.MILLIS.between(testItem.getStartTime(), testItem.getItemResults().getEndTime()) / 1000d; - } + private final ProjectRepository projectRepository; + + private final LaunchRepository launchRepository; + + private final TestItemRepository testItemRepository; + + private final LogService logService; + + private final AnalyzerServiceClient analyzerServiceClient; + + private final SearchCollectorFactory searchCollectorFactory; + + @Autowired + public SearchLogServiceImpl(ProjectRepository projectRepository, + LaunchRepository launchRepository, + TestItemRepository testItemRepository, LogService logService, + AnalyzerServiceClient analyzerServiceClient, + SearchCollectorFactory searchCollectorFactory) { + this.projectRepository = projectRepository; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.logService = logService; + this.analyzerServiceClient = analyzerServiceClient; + this.searchCollectorFactory = searchCollectorFactory; + } + + @Override + public Iterable<SearchLogRs> search(Long itemId, SearchLogRq request, + ReportPortalUser.ProjectDetails projectDetails) { + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, + projectDetails.getProjectId())); + + TestItem item = testItemRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); + + Launch launch = launchRepository.findById(item.getLaunchId()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, item.getLaunchId())); + + expect(item.getItemResults().getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify( + ErrorType.TEST_ITEM_IS_NOT_FINISHED); + + return composeRequest(request, project, item, launch).map( + searchRq -> processRequest(project.getId(), searchRq)) + .orElse(Collections.emptyList()); + } + + private Optional<SearchRq> composeRequest(SearchLogRq request, Project project, TestItem item, + Launch launch) { + SearchLogsMode searchMode = SearchLogsMode.fromString(request.getSearchMode()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, request.getSearchMode())); + + SearchRq searchRq = new SearchRq(); + + searchRq.setFilteredLaunchIds( + searchCollectorFactory.getCollector(searchMode).collect(request.getFilterId(), launch)); + + //TODO fix query - select messages from `Nested Step` descendants too + List<String> logMessages = logService.findMessagesByLaunchIdAndItemIdAndPathAndLevelGte( + launch.getId(), + item.getItemId(), + item.getPath(), + LogLevel.ERROR_INT + ); + if (CollectionUtils.isEmpty(logMessages)) { + return Optional.empty(); + } + searchRq.setLogMessages(logMessages); + + final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(project); + searchRq.setAnalyzerConfig(analyzerConfig); + searchRq.setLogLines(analyzerConfig.getNumberOfLogLines()); + searchRq.setItemId(item.getItemId()); + searchRq.setLaunchId(launch.getId()); + searchRq.setLaunchName(launch.getName()); + searchRq.setProjectId(project.getId()); + return Optional.of(searchRq); + } + + private Collection<SearchLogRs> processRequest(Long projectId, SearchRq request) { + List<SearchRs> searchRs = analyzerServiceClient.searchLogs(request); + Map<Long, Long> logIdMapping = searchRs.stream() + .collect(HashMap::new, (m, rs) -> m.put(rs.getLogId(), rs.getTestItemId()), Map::putAll); + Map<Long, TestItem> testItemMapping = testItemRepository.findAllById(logIdMapping.values()) + .stream() + .collect(toMap(TestItem::getItemId, item -> item)); + List<LogFull> foundLogs = logService.findAllById(logIdMapping.keySet()); + Map<Long, SearchLogRs> foundLogsMap = Maps.newHashMap(); + + foundLogs.forEach(log -> ofNullable(logIdMapping.get(log.getId())).ifPresent(itemId -> { + foundLogsMap.computeIfPresent(itemId, (key, value) -> { + value.getLogs().add(TO_LOG_ENTRY.apply(log)); + return value; + }); + foundLogsMap.computeIfAbsent(itemId, + key -> composeResponse(testItemMapping, projectId, itemId, log)); + })); + return foundLogsMap.values(); + } + + private SearchLogRs composeResponse(Map<Long, TestItem> testItemMapping, Long projectId, + Long itemId, LogFull log) { + TestItem testItem = ofNullable(testItemMapping.get(itemId)).orElseThrow( + () -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, + itemId + )); + Long launchId = ofNullable(testItem.getLaunchId()).orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, + testItem.getLaunchId() + )); + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); + + Map<Long, PathName> pathNameMapping = testItemRepository.selectPathNames( + singletonList(testItem)); + + SearchLogRs response = new SearchLogRs(); + response.setLaunchId(launch.getId()); + ofNullable(pathNameMapping.get(testItem.getItemId())).ifPresent(pathName -> { + response.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE.apply(pathName)); + }); + response.setItemId(testItem.getItemId()); + response.setItemName(testItem.getName()); + response.setPath(testItem.getPath()); + response.setPatternTemplates(testItem.getPatternTemplateTestItems() + .stream() + .map(patternTemplateTestItem -> patternTemplateTestItem.getPatternTemplate().getName()) + .collect(toSet())); + response.setDuration( + ofNullable(testItem.getItemResults().getDuration()).orElseGet(() -> getDuration(testItem))); + response.setStatus(testItem.getItemResults().getStatus().name()); + TestItem itemWithStats = testItem; + while (!itemWithStats.isHasStats()) { + final Long parentId = itemWithStats.getParentId(); + itemWithStats = testItemRepository.findById(parentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); + } + + response.setIssue(IssueConverter.TO_MODEL.apply(itemWithStats.getItemResults().getIssue())); + response.setLogs(Lists.newArrayList(TO_LOG_ENTRY.apply(log))); + return response; + } + + private double getDuration(TestItem testItem) { + return + ChronoUnit.MILLIS.between(testItem.getStartTime(), testItem.getItemResults().getEndTime()) + / 1000d; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemService.java index 47a0e95c57..5547e2e220 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemService.java @@ -15,6 +15,10 @@ */ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; +import static com.epam.ta.reportportal.entity.enums.LogLevel.ERROR_INT; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; @@ -23,8 +27,8 @@ import com.epam.ta.reportportal.core.item.validator.state.TestItemValidator; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.core.launch.cluster.GetClusterHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.core.project.GetProjectHandler; -import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; import com.epam.ta.reportportal.entity.item.TestItem; @@ -35,18 +39,13 @@ import com.epam.ta.reportportal.ws.converter.converters.TestItemConverter; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; -import static com.epam.ta.reportportal.entity.enums.LogLevel.ERROR_INT; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -54,127 +53,143 @@ @Service public class SuggestItemService { - private static final int SUGGESTED_ITEMS_LOGS_LIMIT = 5; - - private final AnalyzerServiceClient analyzerServiceClient; - - private final GetProjectHandler getProjectHandler; - private final GetLaunchHandler getLaunchHandler; - private final GetClusterHandler getClusterHandler; - - private final LaunchAccessValidator launchAccessValidator; - - private final TestItemRepository testItemRepository; - private final LogRepository logRepository; - - private final List<TestItemValidator> testItemValidators; - - @Autowired - public SuggestItemService(AnalyzerServiceClient analyzerServiceClient, GetProjectHandler getProjectHandler, - GetLaunchHandler getLaunchHandler, GetClusterHandler getClusterHandler, LaunchAccessValidator launchAccessValidator, - TestItemRepository testItemRepository, LogRepository logRepository, List<TestItemValidator> testItemValidators) { - this.analyzerServiceClient = analyzerServiceClient; - this.getProjectHandler = getProjectHandler; - this.getLaunchHandler = getLaunchHandler; - this.getClusterHandler = getClusterHandler; - this.launchAccessValidator = launchAccessValidator; - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; - this.testItemValidators = testItemValidators; - } - - @Transactional(readOnly = true) - public List<SuggestedItem> suggestItems(Long testItemId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - - TestItem testItem = testItemRepository.findById(testItemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, testItemId)); - - validateTestItem(testItem); - - Launch launch = getLaunch(testItem.getLaunchId(), projectDetails, user); - Project project = getProjectHandler.get(projectDetails); - - SuggestRq suggestRq = prepareSuggestRq(testItem, launch, project); - return getSuggestedItems(suggestRq); - } - - private void validateTestItem(TestItem testItem) { - testItemValidators.forEach(v -> { - if (!v.validate(testItem)) { - throw new ReportPortalException(BAD_REQUEST_ERROR, v.provide(testItem)); - } - }); - } - - @Transactional(readOnly = true) - public List<SuggestedItem> suggestClusterItems(Long clusterId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - final Cluster cluster = getClusterHandler.getById(clusterId); - final Launch launch = getLaunch(cluster.getLaunchId(), projectDetails, user); - final Project project = getProjectHandler.get(projectDetails); - final SuggestRq suggestRq = prepareSuggestRq(cluster, launch, project); - return getSuggestedItems(suggestRq); - } - - private Launch getLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - Launch launch = getLaunchHandler.get(launchId); - launchAccessValidator.validate(launch, projectDetails, user); - return launch; - } - - private SuggestRq prepareSuggestRq(TestItem testItem, Launch launch, Project project) { - SuggestRq suggestRq = prepareSuggestRq(launch, project); - suggestRq.setTestItemId(testItem.getItemId()); - suggestRq.setUniqueId(testItem.getUniqueId()); - suggestRq.setTestCaseHash(testItem.getTestCaseHash()); - suggestRq.setLogs(AnalyzerUtils.fromLogs(logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), - Collections.singletonList(testItem.getItemId()), - ERROR_INT - ))); - return suggestRq; - } - - private SuggestRq prepareSuggestRq(Cluster cluster, Launch launch, Project project) { - SuggestRq suggestRq = prepareSuggestRq(launch, project); - suggestRq.setClusterId(cluster.getIndexId()); - return suggestRq; - } - - private SuggestRq prepareSuggestRq(Launch launch, Project project) { - SuggestRq suggestRq = new SuggestRq(); - suggestRq.setLaunchId(launch.getId()); - suggestRq.setLaunchName(launch.getName()); - suggestRq.setProject(project.getId()); - suggestRq.setAnalyzerConfig(getAnalyzerConfig(project)); - return suggestRq; - } - - private List<SuggestedItem> getSuggestedItems(SuggestRq suggestRq) { - return analyzerServiceClient.searchSuggests(suggestRq) - .stream() - .map(this::prepareSuggestedItem) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - private SuggestedItem prepareSuggestedItem(SuggestInfo suggestInfo) { - TestItem relevantTestItem = testItemRepository.findById(suggestInfo.getRelevantItem()).orElse(null); - //TODO: EPMRPP-61038 temp fix for the case when item was removed from db but still exists in elastic - if (relevantTestItem == null) { - return null; - } - SuggestedItem suggestedItem = new SuggestedItem(); - suggestedItem.setSuggestRs(suggestInfo); - suggestedItem.setTestItemResource(TestItemConverter.TO_RESOURCE.apply(relevantTestItem)); - suggestedItem.setLogs(logRepository.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(relevantTestItem.getLaunchId(), - relevantTestItem.getItemId(), - ERROR_INT, - SUGGESTED_ITEMS_LOGS_LIMIT - ).stream().map(LogConverter.TO_RESOURCE).collect(Collectors.toSet())); - return suggestedItem; - } - - public OperationCompletionRS handleSuggestChoice(List<SuggestInfo> suggestInfos) { - analyzerServiceClient.handleSuggestChoice(suggestInfos); - return new OperationCompletionRS("User choice of suggested item was sent for handling to ML"); - } + private static final int SUGGESTED_ITEMS_LOGS_LIMIT = 5; + + private final AnalyzerServiceClient analyzerServiceClient; + + private final GetProjectHandler getProjectHandler; + private final GetLaunchHandler getLaunchHandler; + private final GetClusterHandler getClusterHandler; + + private final LaunchAccessValidator launchAccessValidator; + + private final TestItemRepository testItemRepository; + private final LogService logService; + + private final List<TestItemValidator> testItemValidators; + + @Autowired + public SuggestItemService(AnalyzerServiceClient analyzerServiceClient, + GetProjectHandler getProjectHandler, + GetLaunchHandler getLaunchHandler, GetClusterHandler getClusterHandler, + LaunchAccessValidator launchAccessValidator, + TestItemRepository testItemRepository, LogService logService, + List<TestItemValidator> testItemValidators) { + this.analyzerServiceClient = analyzerServiceClient; + this.getProjectHandler = getProjectHandler; + this.getLaunchHandler = getLaunchHandler; + this.getClusterHandler = getClusterHandler; + this.launchAccessValidator = launchAccessValidator; + this.testItemRepository = testItemRepository; + this.logService = logService; + this.testItemValidators = testItemValidators; + } + + @Transactional(readOnly = true) + public List<SuggestedItem> suggestItems(Long testItemId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + + TestItem testItem = testItemRepository.findById(testItemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, testItemId)); + + validateTestItem(testItem); + + Launch launch = getLaunch(testItem.getLaunchId(), projectDetails, user); + Project project = getProjectHandler.get(projectDetails); + + SuggestRq suggestRq = prepareSuggestRq(testItem, launch, project); + return getSuggestedItems(suggestRq); + } + + private void validateTestItem(TestItem testItem) { + testItemValidators.forEach(v -> { + if (!v.validate(testItem)) { + throw new ReportPortalException(BAD_REQUEST_ERROR, v.provide(testItem)); + } + }); + } + + @Transactional(readOnly = true) + public List<SuggestedItem> suggestClusterItems(Long clusterId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + final Cluster cluster = getClusterHandler.getById(clusterId); + final Launch launch = getLaunch(cluster.getLaunchId(), projectDetails, user); + final Project project = getProjectHandler.get(projectDetails); + final SuggestRq suggestRq = prepareSuggestRq(cluster, launch, project); + return getSuggestedItems(suggestRq); + } + + private Launch getLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + Launch launch = getLaunchHandler.get(launchId); + launchAccessValidator.validate(launch, projectDetails, user); + return launch; + } + + private SuggestRq prepareSuggestRq(TestItem testItem, Launch launch, Project project) { + SuggestRq suggestRq = prepareSuggestRq(launch, project); + suggestRq.setTestItemId(testItem.getItemId()); + suggestRq.setUniqueId(testItem.getUniqueId()); + suggestRq.setTestCaseHash(testItem.getTestCaseHash()); + suggestRq.setLogs(AnalyzerUtils.fromLogs( + logService.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), + Collections.singletonList(testItem.getItemId()), + ERROR_INT + ))); + return suggestRq; + } + + private SuggestRq prepareSuggestRq(Cluster cluster, Launch launch, Project project) { + SuggestRq suggestRq = prepareSuggestRq(launch, project); + suggestRq.setClusterId(cluster.getIndexId()); + return suggestRq; + } + + private SuggestRq prepareSuggestRq(Launch launch, Project project) { + SuggestRq suggestRq = new SuggestRq(); + suggestRq.setLaunchId(launch.getId()); + suggestRq.setLaunchName(launch.getName()); + suggestRq.setProject(project.getId()); + suggestRq.setAnalyzerConfig(getAnalyzerConfig(project)); + suggestRq.setLaunchNumber(launch.getNumber()); + return suggestRq; + } + + private List<SuggestedItem> getSuggestedItems(SuggestRq suggestRq) { + return analyzerServiceClient.searchSuggests(suggestRq) + .stream() + .map(this::prepareSuggestedItem) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private SuggestedItem prepareSuggestedItem(SuggestInfo suggestInfo) { + TestItem relevantTestItem = testItemRepository.findById(suggestInfo.getRelevantItem()) + .orElse(null); + //TODO: EPMRPP-61038 temp fix for the case when item was removed from db but still exists in elastic + if (relevantTestItem == null) { + return null; + } + SuggestedItem suggestedItem = new SuggestedItem(); + roundSuggestInfoMatchScore(suggestInfo); + suggestedItem.setSuggestRs(suggestInfo); + suggestedItem.setTestItemResource(TestItemConverter.TO_RESOURCE.apply(relevantTestItem)); + suggestedItem.setLogs(logService.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte( + relevantTestItem.getLaunchId(), + relevantTestItem.getItemId(), + ERROR_INT, + SUGGESTED_ITEMS_LOGS_LIMIT + ).stream().map(LogConverter.TO_RESOURCE).collect(Collectors.toSet())); + return suggestedItem; + } + + private void roundSuggestInfoMatchScore(SuggestInfo info) { + float roundedMatchScore = Math.round(info.getMatchScore()); + info.setMatchScore(roundedMatchScore); + } + + public OperationCompletionRS handleSuggestChoice(List<SuggestInfo> suggestInfos) { + analyzerServiceClient.handleSuggestChoice(suggestInfos); + return new OperationCompletionRS("User choice of suggested item was sent for handling to ML"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestedItem.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestedItem.java index 743fbac480..5d956d6055 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestedItem.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestedItem.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.ws.model.TestItemResource; import com.epam.ta.reportportal.ws.model.log.LogResource; import com.fasterxml.jackson.annotation.JsonInclude; - import java.util.Set; /** @@ -28,33 +27,33 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class SuggestedItem { - private TestItemResource testItemResource; + private TestItemResource testItemResource; - private Set<LogResource> logs; + private Set<LogResource> logs; - private SuggestInfo suggestInfo; + private SuggestInfo suggestInfo; - public Set<LogResource> getLogs() { - return logs; - } + public Set<LogResource> getLogs() { + return logs; + } - public void setLogs(Set<LogResource> logs) { - this.logs = logs; - } + public void setLogs(Set<LogResource> logs) { + this.logs = logs; + } - public TestItemResource getTestItemResource() { - return testItemResource; - } + public TestItemResource getTestItemResource() { + return testItemResource; + } - public void setTestItemResource(TestItemResource testItemResource) { - this.testItemResource = testItemResource; - } + public void setTestItemResource(TestItemResource testItemResource) { + this.testItemResource = testItemResource; + } - public SuggestInfo getSuggestRs() { - return suggestInfo; - } + public SuggestInfo getSuggestRs() { + return suggestInfo; + } - public void setSuggestRs(SuggestInfo suggestInfo) { - this.suggestInfo = suggestInfo; - } + public void setSuggestRs(SuggestInfo suggestInfo) { + this.suggestInfo = suggestInfo; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerService.java index 3327a35e0a..3a10aae3b2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerService.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.List; import java.util.Optional; @@ -29,12 +28,13 @@ */ public interface LaunchPreparerService { - Optional<IndexLaunch> prepare(Launch launch, List<TestItem> testItems, AnalyzerConfig analyzerConfig); + Optional<IndexLaunch> prepare(Launch launch, List<TestItem> testItems, + AnalyzerConfig analyzerConfig); - Optional<IndexLaunch> prepare(Long id, AnalyzerConfig analyzerConfig); + Optional<IndexLaunch> prepare(Long id, AnalyzerConfig analyzerConfig); - List<IndexLaunch> prepare(List<Long> ids, AnalyzerConfig analyzerConfig); + List<IndexLaunch> prepare(List<Long> ids, AnalyzerConfig analyzerConfig); - List<IndexLaunch> prepare(AnalyzerConfig analyzerConfig, List<TestItem> testItems); + List<IndexLaunch> prepare(AnalyzerConfig analyzerConfig, List<TestItem> testItems); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImpl.java index e8f2680795..665aa65692 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl.preparer; +import static com.epam.ta.reportportal.util.Predicates.LAUNCH_CAN_BE_INDEXED; + import com.epam.ta.reportportal.dao.ClusterRepository; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; @@ -26,17 +28,14 @@ import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.util.Predicates.LAUNCH_CAN_BE_INDEXED; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -44,93 +43,103 @@ @Service public class LaunchPreparerServiceImpl implements LaunchPreparerService { - private final LaunchRepository launchRepository; - private final ClusterRepository clusterRepository; - - private final TestItemPreparerService testItemPreparerService; - - @Autowired - public LaunchPreparerServiceImpl(LaunchRepository launchRepository, ClusterRepository clusterRepository, - TestItemPreparerService testItemPreparerService) { - this.launchRepository = launchRepository; - this.clusterRepository = clusterRepository; - this.testItemPreparerService = testItemPreparerService; - } - - @Override - public Optional<IndexLaunch> prepare(Launch launch, List<TestItem> testItems, AnalyzerConfig analyzerConfig) { - if (LAUNCH_CAN_BE_INDEXED.test(launch)) { - final List<IndexTestItem> preparedItems = testItemPreparerService.prepare(launch.getId(), testItems); - if (CollectionUtils.isNotEmpty(preparedItems)) { - return Optional.of(createIndexLaunch(launch.getProjectId(), - launch.getId(), - launch.getName(), - launch.getStartTime(), - analyzerConfig, - preparedItems - )); - } - } - return Optional.empty(); - } - - private IndexLaunch createIndexLaunch(Long projectId, Long launchId, String name, LocalDateTime startLaunchTime, AnalyzerConfig analyzerConfig, - List<IndexTestItem> rqTestItems) { - IndexLaunch rqLaunch = new IndexLaunch(); - rqLaunch.setLaunchId(launchId); - rqLaunch.setLaunchName(name); - rqLaunch.setLaunchStartTime(startLaunchTime); - rqLaunch.setProjectId(projectId); - rqLaunch.setAnalyzerConfig(analyzerConfig); - rqLaunch.setTestItems(rqTestItems); - setClusters(rqLaunch); - return rqLaunch; - } - - @Override - public Optional<IndexLaunch> prepare(Long id, AnalyzerConfig analyzerConfig) { - return prepare(List.of(id), analyzerConfig).stream().findFirst(); - } - - @Override - public List<IndexLaunch> prepare(List<Long> ids, AnalyzerConfig analyzerConfig) { - return launchRepository.findIndexLaunchByIds(ids) - .stream() - .peek(this::fill) - .filter(l -> CollectionUtils.isNotEmpty(l.getTestItems())) - .peek(l -> l.setAnalyzerConfig(analyzerConfig)) - .collect(Collectors.toList()); - } - - /** - * Update prepared launch with items for indexing - * - * @param indexLaunch - Launch to be updated - */ - private void fill(IndexLaunch indexLaunch) { - final List<IndexTestItem> preparedItems = testItemPreparerService.prepare(indexLaunch.getLaunchId()); - if (!preparedItems.isEmpty()) { - indexLaunch.setTestItems(preparedItems); - setClusters(indexLaunch); - } - } - - @Override - public List<IndexLaunch> prepare(AnalyzerConfig analyzerConfig, List<TestItem> testItems) { - return testItems.stream().collect(Collectors.groupingBy(TestItem::getLaunchId)).entrySet().stream().flatMap(entry -> { - Launch launch = launchRepository.findById(entry.getKey()) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, entry.getKey())); - return prepare(launch, entry.getValue(), analyzerConfig).stream(); - }).collect(Collectors.toList()); - } - - private void setClusters(IndexLaunch indexLaunch) { - final Map<Long, String> clusters = clusterRepository.findAllByLaunchId(indexLaunch.getLaunchId()) - .stream() - .collect(Collectors.toMap(Cluster::getIndexId, Cluster::getMessage)); - if (!clusters.isEmpty()) { - indexLaunch.setClusters(clusters); - } - } + private final LaunchRepository launchRepository; + private final ClusterRepository clusterRepository; + + private final TestItemPreparerService testItemPreparerService; + + @Autowired + public LaunchPreparerServiceImpl(LaunchRepository launchRepository, + ClusterRepository clusterRepository, + TestItemPreparerService testItemPreparerService) { + this.launchRepository = launchRepository; + this.clusterRepository = clusterRepository; + this.testItemPreparerService = testItemPreparerService; + } + + @Override + public Optional<IndexLaunch> prepare(Launch launch, List<TestItem> testItems, + AnalyzerConfig analyzerConfig) { + if (LAUNCH_CAN_BE_INDEXED.test(launch)) { + final List<IndexTestItem> preparedItems = testItemPreparerService.prepare(launch.getId(), + testItems); + if (CollectionUtils.isNotEmpty(preparedItems)) { + return Optional.of(createIndexLaunch(launch.getProjectId(), + launch.getId(), + launch.getName(), + launch.getStartTime(), + analyzerConfig, + preparedItems, + launch.getNumber() + )); + } + } + return Optional.empty(); + } + + private IndexLaunch createIndexLaunch(Long projectId, Long launchId, String name, + LocalDateTime startLaunchTime, AnalyzerConfig analyzerConfig, + List<IndexTestItem> rqTestItems, Long launchNumber) { + IndexLaunch rqLaunch = new IndexLaunch(); + rqLaunch.setLaunchId(launchId); + rqLaunch.setLaunchName(name); + rqLaunch.setLaunchStartTime(startLaunchTime); + rqLaunch.setProjectId(projectId); + rqLaunch.setAnalyzerConfig(analyzerConfig); + rqLaunch.setTestItems(rqTestItems); + rqLaunch.setLaunchNumber(launchNumber); + setClusters(rqLaunch); + return rqLaunch; + } + + @Override + public Optional<IndexLaunch> prepare(Long id, AnalyzerConfig analyzerConfig) { + return prepare(List.of(id), analyzerConfig).stream().findFirst(); + } + + @Override + public List<IndexLaunch> prepare(List<Long> ids, AnalyzerConfig analyzerConfig) { + return launchRepository.findIndexLaunchByIds(ids) + .stream() + .peek(this::fill) + .filter(l -> CollectionUtils.isNotEmpty(l.getTestItems())) + .peek(l -> l.setAnalyzerConfig(analyzerConfig)) + .collect(Collectors.toList()); + } + + /** + * Update prepared launch with items for indexing + * + * @param indexLaunch - Launch to be updated + */ + private void fill(IndexLaunch indexLaunch) { + final List<IndexTestItem> preparedItems = testItemPreparerService.prepare( + indexLaunch.getLaunchId()); + if (!preparedItems.isEmpty()) { + indexLaunch.setTestItems(preparedItems); + setClusters(indexLaunch); + } + } + + @Override + public List<IndexLaunch> prepare(AnalyzerConfig analyzerConfig, List<TestItem> testItems) { + return testItems.stream().collect(Collectors.groupingBy(TestItem::getLaunchId)).entrySet() + .stream().flatMap(entry -> { + Launch launch = launchRepository.findById(entry.getKey()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, entry.getKey())); + return prepare(launch, entry.getValue(), analyzerConfig).stream(); + }).collect(Collectors.toList()); + } + + private void setClusters(IndexLaunch indexLaunch) { + final Map<Long, String> clusters = clusterRepository.findAllByLaunchId( + indexLaunch.getLaunchId()) + .stream() + .collect(Collectors.toMap(Cluster::getIndexId, Cluster::getMessage)); + if (!clusters.isEmpty()) { + indexLaunch.setClusters(clusters); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerService.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerService.java index 5e11d3f7fd..4a2e09bc72 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerService.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerService.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; - import java.util.Collection; import java.util.List; @@ -27,15 +26,15 @@ */ public interface TestItemPreparerService { - /** - * Creates {@link IndexTestItem} from {@link TestItem} - * - * @param launchId {@link TestItem#getLaunchId()} - * @param testItems Test item for preparing - * @return Prepared list of {@link IndexTestItem} for indexing - */ - List<IndexTestItem> prepare(Long launchId, Collection<TestItem> testItems); + /** + * Creates {@link IndexTestItem} from {@link TestItem} + * + * @param launchId {@link TestItem#getLaunchId()} + * @param testItems Test item for preparing + * @return Prepared list of {@link IndexTestItem} for indexing + */ + List<IndexTestItem> prepare(Long launchId, Collection<TestItem> testItems); - List<IndexTestItem> prepare(Long launchId); + List<IndexTestItem> prepare(Long launchId); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerServiceImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerServiceImpl.java index 2bc532d1c9..a64e47597e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/TestItemPreparerServiceImpl.java @@ -16,7 +16,12 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl.preparer; +import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; @@ -24,17 +29,12 @@ import com.epam.ta.reportportal.jooq.enums.JTestItemTypeEnum; import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.stereotype.Service; - import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -42,46 +42,51 @@ @Service public class TestItemPreparerServiceImpl implements TestItemPreparerService { - private final TestItemRepository testItemRepository; - private final LogRepository logRepository; + private final TestItemRepository testItemRepository; + private final LogService logService; - public TestItemPreparerServiceImpl(TestItemRepository testItemRepository, LogRepository logRepository) { - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; - } + public TestItemPreparerServiceImpl(TestItemRepository testItemRepository, LogService logService, + LogRepository logRepository) { + this.testItemRepository = testItemRepository; + this.logService = logService; + } - @Override - public List<IndexTestItem> prepare(Long launchId, Collection<TestItem> testItems) { - final List<IndexTestItem> itemsForIndexing = testItems.stream() - .filter(ITEM_CAN_BE_INDEXED) - .map(AnalyzerUtils::fromTestItem) - .collect(toList()); - return prepare(launchId, itemsForIndexing); - } + @Override + public List<IndexTestItem> prepare(Long launchId, Collection<TestItem> testItems) { + final List<IndexTestItem> itemsForIndexing = testItems.stream() + .filter(ITEM_CAN_BE_INDEXED) + .map(AnalyzerUtils::fromTestItem) + .collect(toList()); + return prepare(launchId, itemsForIndexing); + } - @Override - public List<IndexTestItem> prepare(Long launchId) { - final List<IndexTestItem> indexTestItems = testItemRepository.findIndexTestItemByLaunchId(launchId, - List.of(JTestItemTypeEnum.STEP, JTestItemTypeEnum.BEFORE_METHOD, JTestItemTypeEnum.AFTER_METHOD) - ); - return prepare(launchId, indexTestItems); - } + @Override + public List<IndexTestItem> prepare(Long launchId) { + final List<IndexTestItem> indexTestItems = testItemRepository.findIndexTestItemByLaunchId( + launchId, + List.of(JTestItemTypeEnum.STEP, JTestItemTypeEnum.BEFORE_METHOD, + JTestItemTypeEnum.AFTER_METHOD) + ); + return prepare(launchId, indexTestItems); + } - private List<IndexTestItem> prepare(Long launchId, List<IndexTestItem> indexTestItemList) { - final Map<Long, List<IndexLog>> logsMapping = getLogsMapping(launchId, - indexTestItemList.stream().map(IndexTestItem::getTestItemId).collect(toList()) - ); + private List<IndexTestItem> prepare(Long launchId, List<IndexTestItem> indexTestItemList) { + final Map<Long, List<IndexLog>> logsMapping = getLogsMapping(launchId, + indexTestItemList.stream().map(IndexTestItem::getTestItemId).collect(toList()) + ); - return indexTestItemList.stream() - .peek(indexTestItem -> ofNullable(logsMapping.get(indexTestItem.getTestItemId())).filter(CollectionUtils::isNotEmpty) - .map(HashSet::new) - .ifPresent(indexTestItem::setLogs)) - .filter(it -> CollectionUtils.isNotEmpty(it.getLogs())) - .collect(toList()); - } + return indexTestItemList.stream() + .peek(indexTestItem -> ofNullable(logsMapping.get(indexTestItem.getTestItemId())).filter( + CollectionUtils::isNotEmpty) + .map(HashSet::new) + .ifPresent(indexTestItem::setLogs)) + .filter(it -> CollectionUtils.isNotEmpty(it.getLogs())) + .collect(toList()); + } - private Map<Long, List<IndexLog>> getLogsMapping(Long launchId, List<Long> itemIds) { - return logRepository.findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, itemIds, LogLevel.ERROR.toInt()); - } + private Map<Long, List<IndexLog>> getLogsMapping(Long launchId, List<Long> itemIds) { + return logService.findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, + itemIds, LogLevel.ERROR.toInt()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java index 9138bb4a86..7a98614b1d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java @@ -3,8 +3,8 @@ import com.epam.ta.reportportal.core.analyzer.auto.client.IndexerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.preparer.LaunchPreparerService; import com.epam.ta.reportportal.dao.LaunchRepository; -import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.jooq.enums.JLaunchModeEnum; import com.epam.ta.reportportal.jooq.enums.JStatusEnum; @@ -14,6 +14,11 @@ import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -21,124 +26,141 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class BatchLogIndexer { - private static final Logger LOGGER = LoggerFactory.getLogger(BatchLogIndexer.class); - - private final Integer launchBatchSize; - private final Integer itemsBatchSize; - private final LaunchRepository launchRepository; - private final TestItemRepository testItemRepository; - private final LaunchPreparerService launchPreparerService; - private final IndexerServiceClient indexerServiceClient; - - @Autowired - public BatchLogIndexer(@Value("${rp.environment.variable.log-index.batch-size}") Integer launchBatchSize, - @Value("${rp.environment.variable.item-analyze.batch-size}") Integer itemsBatchSize, LaunchRepository launchRepository, - TestItemRepository testItemRepository, LaunchPreparerService launchPreparerService, IndexerServiceClient indexerServiceClient) { - this.launchBatchSize = launchBatchSize; - this.itemsBatchSize = itemsBatchSize; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.launchPreparerService = launchPreparerService; - this.indexerServiceClient = indexerServiceClient; - } - - @Transactional(readOnly = true) - public Long index(Long projectId, AnalyzerConfig analyzerConfig) { - final AtomicLong totalIndexed = new AtomicLong(0L); - - List<Long> ids = getLaunchIds(projectId); - index(projectId, analyzerConfig, ids, totalIndexed); - - while (launchBatchSize == ids.size()) { - final Long lastLaunchId = Iterables.getLast(ids); - ids = getLaunchIds(projectId, lastLaunchId); - index(projectId, analyzerConfig, ids, totalIndexed); - } - - return totalIndexed.get(); - } - - @Transactional(readOnly = true) - public Long index(AnalyzerConfig analyzerConfig, Launch launch, List<Long> itemIds) { - AtomicLong indexedCount = new AtomicLong(0); - Iterables.partition(itemIds, itemsBatchSize) - .forEach(partition -> indexedCount.addAndGet(indexPartition(partition, analyzerConfig, launch))); - return indexedCount.get(); - } - - private Long indexPartition(List<Long> itemIds, AnalyzerConfig analyzerConfig, Launch launch) { - LOGGER.info("Indexing started for {} items.", itemIds.size()); - final Long indexedLogs = launchPreparerService.prepare(launch, testItemRepository.findAllById(itemIds), analyzerConfig) - .map(it -> indexerServiceClient.index(Lists.newArrayList(it))) - .orElse(0L); - LOGGER.info("Indexing of {} logs is finished for {} items.", indexedLogs, itemIds.size()); - return indexedLogs; - } - - private void index(Long projectId, AnalyzerConfig analyzerConfig, List<Long> launchIds, AtomicLong totalIndexed) { - if (launchIds.isEmpty()) { - return; - } - LOGGER.debug("Project {}. Found {} ids", projectId, launchIds.size()); - final List<Long> filteredIds = filterIds(launchIds); - if (filteredIds.isEmpty()) { - return; - } - LOGGER.debug("Project {}. Found {} filtered ids", projectId, filteredIds.size()); - final List<IndexLaunch> preparedLaunches = launchPreparerService.prepare(launchIds, analyzerConfig); - if (preparedLaunches.isEmpty()) { - return; - } - - LOGGER.debug("Project {}. Start indexing for {} launches", projectId, preparedLaunches.size()); - final long indexed = indexByPartition(preparedLaunches); - LOGGER.debug("Project {}. Indexed {} logs", projectId, indexed); - totalIndexed.addAndGet(indexed); - } - - private long indexByPartition(List<IndexLaunch> preparedLaunches) { - return preparedLaunches.stream().map(indexLaunch -> { - final Iterable<List<IndexTestItem>> lists = Iterables.partition(indexLaunch.getTestItems(), itemsBatchSize); - return StreamSupport.stream(lists.spliterator(), false).map(partition -> { - indexLaunch.setTestItems(partition); - final Long indexed = indexerServiceClient.index(Lists.newArrayList(indexLaunch)); - return indexed; - }).mapToLong(Long::longValue).sum(); - }).mapToLong(Long::longValue).sum(); - } - - private List<Long> filterIds(List<Long> launchIds) { - return launchIds.stream() - .filter(id -> launchRepository.hasItemsWithLogsWithLogLevel(id, List.of(JTestItemTypeEnum.STEP), LogLevel.ERROR_INT)) - .collect(Collectors.toList()); - } - - private List<Long> getLaunchIds(Long projectId) { - return launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(projectId, - JLaunchModeEnum.DEFAULT, - JStatusEnum.PASSED, - launchBatchSize - ); - } - - private List<Long> getLaunchIds(Long projectId, Long launchId) { - return launchRepository.findIdsByProjectIdAndModeAndStatusNotEqAfterId(projectId, - JLaunchModeEnum.DEFAULT, - JStatusEnum.PASSED, - launchId, - launchBatchSize - ); - } + private static final Logger LOGGER = LoggerFactory.getLogger(BatchLogIndexer.class); + + private final Integer launchBatchSize; + private final Integer itemsBatchSize; + private final LaunchRepository launchRepository; + private final TestItemRepository testItemRepository; + private final LaunchPreparerService launchPreparerService; + private final IndexerServiceClient indexerServiceClient; + + @Autowired + public BatchLogIndexer( + @Value("${rp.environment.variable.log-index.batch-size}") Integer launchBatchSize, + @Value("${rp.environment.variable.item-analyze.batch-size}") Integer itemsBatchSize, + LaunchRepository launchRepository, + TestItemRepository testItemRepository, LaunchPreparerService launchPreparerService, + IndexerServiceClient indexerServiceClient) { + this.launchBatchSize = launchBatchSize; + this.itemsBatchSize = itemsBatchSize; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.launchPreparerService = launchPreparerService; + this.indexerServiceClient = indexerServiceClient; + } + + @Transactional(readOnly = true) + public Long index(Long projectId, AnalyzerConfig analyzerConfig) { + final AtomicLong totalIndexed = new AtomicLong(0L); + + List<Long> ids = getLaunchIds(projectId); + index(projectId, analyzerConfig, ids, totalIndexed); + + while (launchBatchSize == ids.size()) { + final Long lastLaunchId = Iterables.getLast(ids); + ids = getLaunchIds(projectId, lastLaunchId); + index(projectId, analyzerConfig, ids, totalIndexed); + } + + return totalIndexed.get(); + } + + @Transactional(readOnly = true) + public Long index(AnalyzerConfig analyzerConfig, Launch launch, List<Long> itemIds) { + AtomicLong indexedCount = new AtomicLong(0); + Iterables.partition(itemIds, itemsBatchSize) + .forEach( + partition -> indexedCount.addAndGet(indexPartition(partition, analyzerConfig, launch))); + return indexedCount.get(); + } + + private Long indexPartition(List<Long> itemIds, AnalyzerConfig analyzerConfig, Launch launch) { + LOGGER.info("Indexing started for {} items.", itemIds.size()); + Optional<IndexLaunch> prepared = launchPreparerService.prepare(launch, + testItemRepository.findAllById(itemIds), analyzerConfig); + prepared.ifPresent(it -> indexerServiceClient.index(Lists.newArrayList(it))); + + Long indexedLogs = 0L; + if (prepared.isPresent()) { + indexedLogs = countLogs(Lists.newArrayList(prepared.get())); + } + + LOGGER.info("Indexing of {} logs is finished for {} items.", indexedLogs, itemIds.size()); + return indexedLogs; + } + + private Long countLogs(List<IndexLaunch> indexLaunch) { + return indexLaunch.stream() + .flatMap(launch -> launch.getTestItems().stream()) + .mapToLong(item -> item.getLogs().size()) + .sum(); + } + + private void index(Long projectId, AnalyzerConfig analyzerConfig, List<Long> launchIds, + AtomicLong totalIndexed) { + if (launchIds.isEmpty()) { + return; + } + LOGGER.debug("Project {}. Found {} ids", projectId, launchIds.size()); + final List<Long> filteredIds = filterIds(launchIds); + if (filteredIds.isEmpty()) { + return; + } + LOGGER.debug("Project {}. Found {} filtered ids", projectId, filteredIds.size()); + final List<IndexLaunch> preparedLaunches = launchPreparerService.prepare(launchIds, + analyzerConfig); + if (preparedLaunches.isEmpty()) { + return; + } + + LOGGER.debug("Project {}. Start indexing for {} launches", projectId, preparedLaunches.size()); + indexByPartition(preparedLaunches); + final long indexed = countLogs(preparedLaunches); + LOGGER.debug("Project {}. Indexed {} logs", projectId, indexed); + totalIndexed.addAndGet(indexed); + } + + private void indexByPartition(List<IndexLaunch> preparedLaunches) { + preparedLaunches.forEach(indexLaunch -> { + final Iterable<List<IndexTestItem>> lists = Iterables.partition(indexLaunch.getTestItems(), + itemsBatchSize); + StreamSupport.stream(lists.spliterator(), false).forEach(partition -> { + indexLaunch.setTestItems(partition); + indexerServiceClient.index(Lists.newArrayList(indexLaunch)); + }); + }); + } + + private List<Long> filterIds(List<Long> launchIds) { + return launchIds.stream() + .filter( + id -> launchRepository.hasItemsWithLogsWithLogLevel(id, List.of(JTestItemTypeEnum.STEP), + LogLevel.ERROR_INT)) + .collect(Collectors.toList()); + } + + private List<Long> getLaunchIds(Long projectId) { + return launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(projectId, + JLaunchModeEnum.DEFAULT, + JStatusEnum.IN_PROGRESS, + launchBatchSize + ); + } + + private List<Long> getLaunchIds(Long projectId, Long launchId) { + return launchRepository.findIdsByProjectIdAndModeAndStatusNotEqAfterId(projectId, + JLaunchModeEnum.DEFAULT, + JStatusEnum.IN_PROGRESS, + launchId, + launchBatchSize + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/IndexerStatusCache.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/IndexerStatusCache.java index 8531ada0c2..6048bcd8ef 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/IndexerStatusCache.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/IndexerStatusCache.java @@ -18,9 +18,8 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import org.springframework.stereotype.Service; - import java.util.concurrent.TimeUnit; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -28,28 +27,28 @@ @Service public class IndexerStatusCache { - private static final int CACHE_ITEM_LIVE = 10; - private static final int MAXIMUM_SIZE = 50000; + private static final int CACHE_ITEM_LIVE = 10; + private static final int MAXIMUM_SIZE = 50000; - /** - * Contains cache of indexing running for concrete project - * launchId - projectId - */ - private Cache<Long, Boolean> indexingStatus; + /** + * Contains cache of indexing running for concrete project launchId - projectId + */ + private Cache<Long, Boolean> indexingStatus; - public IndexerStatusCache() { - indexingStatus = CacheBuilder.newBuilder().maximumSize(MAXIMUM_SIZE).expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES).build(); - } + public IndexerStatusCache() { + indexingStatus = CacheBuilder.newBuilder().maximumSize(MAXIMUM_SIZE) + .expireAfterWrite(CACHE_ITEM_LIVE, TimeUnit.MINUTES).build(); + } - public void indexingStarted(Long projectId) { - indexingStatus.put(projectId, true); - } + public void indexingStarted(Long projectId) { + indexingStatus.put(projectId, true); + } - public void indexingFinished(Long projectId) { - indexingStatus.invalidate(projectId); - } + public void indexingFinished(Long projectId) { + indexingStatus.invalidate(projectId); + } - public Cache<Long, Boolean> getIndexingStatus() { - return indexingStatus; - } + public Cache<Long, Boolean> getIndexingStatus() { + return indexingStatus; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarter.java index 34e96ddd7a..71142b9da6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarter.java @@ -16,69 +16,73 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerService; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; -import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeCollectorFactory; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsCollector; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; +import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; +import java.util.List; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Set; - -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class CollectingAutoAnalysisStarter implements LaunchAutoAnalysisStarter { - private static final Logger LOGGER = LoggerFactory.getLogger(CollectingAutoAnalysisStarter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CollectingAutoAnalysisStarter.class); - private final GetLaunchHandler getLaunchHandler; - private final AnalyzeCollectorFactory analyzeCollectorFactory; - private final AnalyzerService analyzerService; - private final LogIndexer logIndexer; + private final GetLaunchHandler getLaunchHandler; + private final AnalyzeCollectorFactory analyzeCollectorFactory; + private final AnalyzerService analyzerService; + private final LogIndexer logIndexer; - public CollectingAutoAnalysisStarter(GetLaunchHandler getLaunchHandler, AnalyzeCollectorFactory analyzeCollectorFactory, - AnalyzerService analyzerService, LogIndexer logIndexer) { - this.getLaunchHandler = getLaunchHandler; - this.analyzeCollectorFactory = analyzeCollectorFactory; - this.analyzerService = analyzerService; - this.logIndexer = logIndexer; - } + public CollectingAutoAnalysisStarter(GetLaunchHandler getLaunchHandler, + AnalyzeCollectorFactory analyzeCollectorFactory, + AnalyzerService analyzerService, LogIndexer logIndexer) { + this.getLaunchHandler = getLaunchHandler; + this.analyzeCollectorFactory = analyzeCollectorFactory; + this.analyzerService = analyzerService; + this.logIndexer = logIndexer; + } - @Override - @Transactional - public void start(StartLaunchAutoAnalysisConfig config) { - final Launch launch = getLaunchHandler.get(config.getLaunchId()); + @Override + @Transactional + public void start(StartLaunchAutoAnalysisConfig config) { + final Launch launch = getLaunchHandler.get(config.getLaunchId()); - final List<Long> itemIds = collectItemsByModes(launch, config.getAnalyzeItemsModes(), config.getUser()); + final List<Long> itemIds = collectItemsByModes(launch, config.getAnalyzeItemsModes(), + config.getUser()); - analyzerService.runAnalyzers(launch, itemIds, config.getAnalyzerConfig()); - logIndexer.indexItemsLogs(launch.getProjectId(), launch.getId(), itemIds, config.getAnalyzerConfig()); - } + analyzerService.runAnalyzers(launch, itemIds, config.getAnalyzerConfig()); + logIndexer.indexItemsLogs(launch.getProjectId(), launch.getId(), itemIds, + config.getAnalyzerConfig()); + } - /** - * Collect item ids for analyzer according to provided analyzer configuration. - * - * @return List of {@link TestItem#getItemId()} to analyze - * @see AnalyzeItemsMode - * @see AnalyzeCollectorFactory - * @see AnalyzeItemsCollector - */ - private List<Long> collectItemsByModes(Launch launch, Set<AnalyzeItemsMode> analyzeItemsModes, ReportPortalUser user) { - return analyzeItemsModes.stream().flatMap(it -> { - List<Long> itemIds = analyzeCollectorFactory.getCollector(it).collectItems(launch.getProjectId(), launch.getId(), user); - LOGGER.debug("Item itemIds collected by '{}' mode: {}", it, itemIds); - return itemIds.stream(); - }).collect(toList()); - } + /** + * Collect item ids for analyzer according to provided analyzer configuration. + * + * @return List of {@link TestItem#getItemId()} to analyze + * @see AnalyzeItemsMode + * @see AnalyzeCollectorFactory + * @see AnalyzeItemsCollector + */ + private List<Long> collectItemsByModes(Launch launch, Set<AnalyzeItemsMode> analyzeItemsModes, + ReportPortalUser user) { + return analyzeItemsModes.stream().flatMap(it -> { + List<Long> itemIds = analyzeCollectorFactory.getCollector(it) + .collectItems(launch.getProjectId(), launch.getId(), user); + LOGGER.debug("Item itemIds collected by '{}' mode: {}", it, itemIds); + return itemIds.stream(); + }).distinct().collect(toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/LaunchAutoAnalysisStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/LaunchAutoAnalysisStarter.java index 70a6324d0d..6ba28449cb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/LaunchAutoAnalysisStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/LaunchAutoAnalysisStarter.java @@ -23,6 +23,6 @@ */ public interface LaunchAutoAnalysisStarter { - void start(StartLaunchAutoAnalysisConfig config); + void start(StartLaunchAutoAnalysisConfig config); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarter.java index 7a91584f7f..3ca452f784 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarter.java @@ -16,8 +16,8 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; -import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; +import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import org.springframework.core.task.TaskExecutor; /** @@ -25,16 +25,17 @@ */ public class AsyncAutoAnalysisStarter implements LaunchAutoAnalysisStarter { - private final TaskExecutor executor; - private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; + private final TaskExecutor executor; + private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; - public AsyncAutoAnalysisStarter(TaskExecutor executor, LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { - this.executor = executor; - this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; - } + public AsyncAutoAnalysisStarter(TaskExecutor executor, + LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { + this.executor = executor; + this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; + } - @Override - public void start(StartLaunchAutoAnalysisConfig config) { - executor.execute(() -> launchAutoAnalysisStarter.start(config)); - } + @Override + public void start(StartLaunchAutoAnalysisConfig config) { + executor.execute(() -> launchAutoAnalysisStarter.start(config)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarter.java index 58875ce9b9..1aa674dfa8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarter.java @@ -24,16 +24,16 @@ */ public class AutoAnalysisEnabledStarter implements LaunchAutoAnalysisStarter { - private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; + private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; - public AutoAnalysisEnabledStarter(LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { - this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; - } + public AutoAnalysisEnabledStarter(LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { + this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; + } - @Override - public void start(StartLaunchAutoAnalysisConfig config) { - if (config.getAnalyzerConfig().getIsAutoAnalyzerEnabled()) { - launchAutoAnalysisStarter.start(config); - } - } + @Override + public void start(StartLaunchAutoAnalysisConfig config) { + if (config.getAnalyzerConfig().getIsAutoAnalyzerEnabled()) { + launchAutoAnalysisStarter.start(config); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarter.java index ff29cac1cb..0e9cdd30ee 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarter.java @@ -16,33 +16,33 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerService; -import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; +import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.function.Predicate; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class ExistingAnalyzerStarter implements LaunchAutoAnalysisStarter { - - private final AnalyzerService analyzerService; - private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; - - public ExistingAnalyzerStarter(AnalyzerService analyzerService, LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { - this.analyzerService = analyzerService; - this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; - } - - @Override - public void start(StartLaunchAutoAnalysisConfig config) { - expect(analyzerService.hasAnalyzers(), Predicate.isEqual(true)).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer services are deployed." - ); - launchAutoAnalysisStarter.start(config); - } + private final AnalyzerService analyzerService; + private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; + + public ExistingAnalyzerStarter(AnalyzerService analyzerService, + LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { + this.analyzerService = analyzerService; + this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; + } + + @Override + public void start(StartLaunchAutoAnalysisConfig config) { + expect(analyzerService.hasAnalyzers(), Predicate.isEqual(true)).verify( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "There are no analyzer services are deployed." + ); + launchAutoAnalysisStarter.start(config); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarter.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarter.java index 71d2d2e6dc..4cfda33aaa 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarter.java @@ -28,22 +28,22 @@ */ public class IndexingAutoAnalysisStarter implements LaunchAutoAnalysisStarter { - private final GetLaunchHandler getLaunchHandler; - private final LogIndexer logIndexer; - private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; + private final GetLaunchHandler getLaunchHandler; + private final LogIndexer logIndexer; + private final LaunchAutoAnalysisStarter launchAutoAnalysisStarter; - public IndexingAutoAnalysisStarter(GetLaunchHandler getLaunchHandler, LogIndexer logIndexer, - LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { - this.getLaunchHandler = getLaunchHandler; - this.logIndexer = logIndexer; - this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; - } + public IndexingAutoAnalysisStarter(GetLaunchHandler getLaunchHandler, LogIndexer logIndexer, + LaunchAutoAnalysisStarter launchAutoAnalysisStarter) { + this.getLaunchHandler = getLaunchHandler; + this.logIndexer = logIndexer; + this.launchAutoAnalysisStarter = launchAutoAnalysisStarter; + } - @Override - @Transactional - public void start(StartLaunchAutoAnalysisConfig config) { - final Launch launch = getLaunchHandler.get(config.getLaunchId()); - logIndexer.indexLaunchLogs(launch, config.getAnalyzerConfig()); - launchAutoAnalysisStarter.start(config); - } + @Override + @Transactional + public void start(StartLaunchAutoAnalysisConfig config) { + final Launch launch = getLaunchHandler.get(config.getLaunchId()); + logIndexer.indexLaunchLogs(launch, config.getAnalyzerConfig()); + launchAutoAnalysisStarter.start(config); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorConfig.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorConfig.java index 93d3cfa467..223091585b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorConfig.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze; +import java.util.HashMap; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -23,33 +25,35 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.HashMap; -import java.util.Map; - /** * @author Pavel Bortnik */ @Configuration public class AnalyzeCollectorConfig implements ApplicationContextAware { - private ApplicationContext applicationContext; - - @Autowired - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Bean(name = "analyzerModeMapping") - public Map<AnalyzeItemsMode, AnalyzeItemsCollector> getAnalyzerModeMapping() { - Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping = new HashMap<>(); - mapping.put(AnalyzeItemsMode.TO_INVESTIGATE, applicationContext.getBean(ToInvestigateCollector.class)); - mapping.put(AnalyzeItemsMode.AUTO_ANALYZED, applicationContext.getBean(AutoAnalyzedCollector.class)); - mapping.put(AnalyzeItemsMode.MANUALLY_ANALYZED, applicationContext.getBean(ManuallyAnalyzedCollector.class)); - return mapping; - } - - @Bean - public AnalyzeCollectorFactory analyzeCollectorFactory() { - return new AnalyzeCollectorFactory(getAnalyzerModeMapping()); - } + private ApplicationContext applicationContext; + + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Bean(name = "analyzerModeMapping") + public Map<AnalyzeItemsMode, AnalyzeItemsCollector> getAnalyzerModeMapping() { + Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping = new HashMap<>(); + mapping.put(AnalyzeItemsMode.TO_INVESTIGATE, + applicationContext.getBean(ToInvestigateCollector.class)); + mapping.put(AnalyzeItemsMode.AUTO_ANALYZED, + applicationContext.getBean(AutoAnalyzedCollector.class)); + mapping.put(AnalyzeItemsMode.MANUALLY_ANALYZED, + applicationContext.getBean(ManuallyAnalyzedCollector.class)); + mapping.put(AnalyzeItemsMode.IGNORE_IMMEDIATE, + applicationContext.getBean(IgnoreImmediateCollector.class)); + return mapping; + } + + @Bean + public AnalyzeCollectorFactory analyzeCollectorFactory() { + return new AnalyzeCollectorFactory(getAnalyzerModeMapping()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorFactory.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorFactory.java index f06a6523e0..75890c04d9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeCollectorFactory.java @@ -25,13 +25,13 @@ */ public class AnalyzeCollectorFactory { - private Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping; + private Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping; - public AnalyzeCollectorFactory(Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping) { - this.mapping = mapping; - } + public AnalyzeCollectorFactory(Map<AnalyzeItemsMode, AnalyzeItemsCollector> mapping) { + this.mapping = mapping; + } - public AnalyzeItemsCollector getCollector(AnalyzeItemsMode type) { - return this.mapping.get(type); - } + public AnalyzeItemsCollector getCollector(AnalyzeItemsMode type) { + return this.mapping.get(type); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsCollector.java index 89ac60a170..e49c0ecd95 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsCollector.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze; import com.epam.ta.reportportal.commons.ReportPortalUser; - import java.util.List; /** @@ -28,15 +27,15 @@ @FunctionalInterface public interface AnalyzeItemsCollector { - /** - * Collects items for concrete project of concrete launch for following analyzing - * according to concrete {@link com.epam.ta.reportportal.entity.AnalyzeMode} - * - * @param projectId Project id - * @param launchId Launch id - * @param user User started analysis - * @return List of item ids - */ - List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user); + /** + * Collects items for concrete project of concrete launch for following analyzing according to + * concrete {@link com.epam.ta.reportportal.entity.AnalyzeMode} + * + * @param projectId Project id + * @param launchId Launch id + * @param user User started analysis + * @return List of item ids + */ + List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsMode.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsMode.java index 6f3b1ff644..5f4897cdf1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsMode.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AnalyzeItemsMode.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.Arrays; import java.util.stream.Collectors; @@ -27,30 +26,31 @@ */ public enum AnalyzeItemsMode { - TO_INVESTIGATE("TO_INVESTIGATE"), - AUTO_ANALYZED("AUTO_ANALYZED"), - MANUALLY_ANALYZED("MANUALLY_ANALYZED"); - - private String value; - - AnalyzeItemsMode(String value) { - this.value = value; - } - - public static AnalyzeItemsMode fromString(String mode) { - return Arrays.stream(AnalyzeItemsMode.values()) - .filter(it -> it.getValue().equalsIgnoreCase(mode)) - .findFirst() - .orElseThrow(() -> new ReportPortalException( - ErrorType.INCORRECT_REQUEST, - "Incorrect analyze items mode. Allowed are: " + Arrays.stream(AnalyzeItemsMode.values()) - .map(AnalyzeItemsMode::getValue) - .collect(Collectors.toList()) - )); - } - - public String getValue() { - return value; - } + TO_INVESTIGATE("TO_INVESTIGATE"), + AUTO_ANALYZED("AUTO_ANALYZED"), + MANUALLY_ANALYZED("MANUALLY_ANALYZED"), + IGNORE_IMMEDIATE("IGNORE_IMMEDIATE"); + + private String value; + + AnalyzeItemsMode(String value) { + this.value = value; + } + + public static AnalyzeItemsMode fromString(String mode) { + return Arrays.stream(AnalyzeItemsMode.values()) + .filter(it -> it.getValue().equalsIgnoreCase(mode)) + .findFirst() + .orElseThrow(() -> new ReportPortalException( + ErrorType.INCORRECT_REQUEST, + "Incorrect analyze items mode. Allowed are: " + Arrays.stream(AnalyzeItemsMode.values()) + .map(AnalyzeItemsMode::getValue) + .collect(Collectors.toList()) + )); + } + + public String getValue() { + return value; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AutoAnalyzedCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AutoAnalyzedCollector.java index 0a23507d01..8fc81e0483 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AutoAnalyzedCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/AutoAnalyzedCollector.java @@ -21,41 +21,46 @@ import com.epam.ta.reportportal.core.item.UpdateTestItemHandler; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; +import java.util.Collections; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component public class AutoAnalyzedCollector implements AnalyzeItemsCollector { - private static final Logger LOGGER = LoggerFactory.getLogger(AutoAnalyzedCollector.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AutoAnalyzedCollector.class); - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - private final UpdateTestItemHandler updateTestItemHandler; + private final UpdateTestItemHandler updateTestItemHandler; - @Autowired - public AutoAnalyzedCollector(TestItemRepository testItemRepository, LogIndexer logIndexer, - UpdateTestItemHandler updateTestItemHandler) { - this.testItemRepository = testItemRepository; - this.logIndexer = logIndexer; - this.updateTestItemHandler = updateTestItemHandler; - } + @Autowired + public AutoAnalyzedCollector(TestItemRepository testItemRepository, LogIndexer logIndexer, + UpdateTestItemHandler updateTestItemHandler) { + this.testItemRepository = testItemRepository; + this.logIndexer = logIndexer; + this.updateTestItemHandler = updateTestItemHandler; + } - @Override - public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { - List<Long> itemIds = testItemRepository.selectIdsByAnalyzedWithLevelGte(true, false, launchId, LogLevel.ERROR.toInt()); - int deletedLogsCount = logIndexer.indexItemsRemove(projectId, itemIds); - LOGGER.debug("{} logs deleted from analyzer", deletedLogsCount); - updateTestItemHandler.resetItemsIssue(itemIds, projectId, user); - return itemIds; - } + @Override + public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { + List<Long> itemIds = testItemRepository.selectIdsByAnalyzedWithLevelGteExcludingIssueTypes(true, + false, + launchId, + LogLevel.ERROR.toInt(), + Collections.emptyList() + ); + int deletedLogsCount = logIndexer.indexItemsRemove(projectId, itemIds); + LOGGER.debug("{} logs deleted from analyzer", deletedLogsCount); + updateTestItemHandler.resetItemsIssue(itemIds, projectId, user); + return itemIds; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/IgnoreImmediateCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/IgnoreImmediateCollector.java new file mode 100644 index 0000000000..6ab6fa5148 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/IgnoreImmediateCollector.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ +package com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze; + +import static java.util.stream.Collectors.toList; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.item.TestItem; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:andrei_piankouski@epam.com">Andrei Piankouski</a> + */ +@Service +public class IgnoreImmediateCollector implements AnalyzeItemsCollector { + + protected static final String IMMEDIATE_AUTO_ANALYSIS = "immediateAutoAnalysis"; + + private TestItemRepository testItemRepository; + + @Autowired + public IgnoreImmediateCollector(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } + + @Override + public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { + return testItemRepository.findItemsForAnalyze(launchId) + .stream() + .filter(ti -> !ti.getItemResults().getIssue().getIgnoreAnalyzer()) + .filter(this::skipImmediateAA) + .map(TestItem::getItemId) + .collect(toList()); + } + + private boolean skipImmediateAA(TestItem item) { + return item.getAttributes().stream() + .filter(at -> !at.getTestItem().getItemResults().getIssue().getIgnoreAnalyzer()) + .noneMatch(at -> IMMEDIATE_AUTO_ANALYSIS.equals(at.getKey()) && Boolean.parseBoolean( + at.getValue()) && at.isSystem()); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ManuallyAnalyzedCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ManuallyAnalyzedCollector.java index d02f8f74d6..c9f21ef029 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ManuallyAnalyzedCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ManuallyAnalyzedCollector.java @@ -19,44 +19,60 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.item.UpdateTestItemHandler; +import com.epam.ta.reportportal.dao.IssueTypeRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.item.issue.IssueType; +import java.util.Collections; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component public class ManuallyAnalyzedCollector implements AnalyzeItemsCollector { - private static final Logger LOGGER = LoggerFactory.getLogger(AnalyzeItemsCollector.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AnalyzeItemsCollector.class); - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; + private final IssueTypeRepository issueTypeRepository; - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - private final UpdateTestItemHandler updateTestItemHandler; + private final UpdateTestItemHandler updateTestItemHandler; - @Autowired - public ManuallyAnalyzedCollector(TestItemRepository testItemRepository, LogIndexer logIndexer, - UpdateTestItemHandler updateTestItemHandler) { - this.testItemRepository = testItemRepository; - this.logIndexer = logIndexer; - this.updateTestItemHandler = updateTestItemHandler; - } + @Autowired + public ManuallyAnalyzedCollector(TestItemRepository testItemRepository, + IssueTypeRepository issueTypeRepository, LogIndexer logIndexer, + UpdateTestItemHandler updateTestItemHandler) { + this.testItemRepository = testItemRepository; + this.issueTypeRepository = issueTypeRepository; + this.logIndexer = logIndexer; + this.updateTestItemHandler = updateTestItemHandler; + } - @Override - public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { - List<Long> itemIds = testItemRepository.selectIdsByAnalyzedWithLevelGte(false, false, launchId, LogLevel.ERROR.toInt()); - int deletedLogsCount = logIndexer.indexItemsRemove(projectId, itemIds); - LOGGER.debug("{} logs deleted from analyzer", deletedLogsCount); - updateTestItemHandler.resetItemsIssue(itemIds, projectId, user); - return itemIds; - } + @Override + public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { + final List<IssueType> excludedTypes = issueTypeRepository.findByLocator( + TestItemIssueGroup.TO_INVESTIGATE.getLocator()) + .map(List::of) + .orElseGet(Collections::emptyList); + List<Long> itemIds = testItemRepository.selectIdsByAnalyzedWithLevelGteExcludingIssueTypes( + false, + false, + launchId, + LogLevel.ERROR.toInt(), + excludedTypes + ); + int deletedLogsCount = logIndexer.indexItemsRemove(projectId, itemIds); + LOGGER.debug("{} logs deleted from analyzer", deletedLogsCount); + updateTestItemHandler.resetItemsIssue(itemIds, projectId, user); + return itemIds; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ToInvestigateCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ToInvestigateCollector.java index 27286e301f..c3521f92ff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ToInvestigateCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/analyze/ToInvestigateCollector.java @@ -16,36 +16,36 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.item.TestItem; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Service public class ToInvestigateCollector implements AnalyzeItemsCollector { - private TestItemRepository testItemRepository; - - @Autowired - public ToInvestigateCollector(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } - - @Override - public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { - return testItemRepository.findAllInIssueGroupByLaunch(launchId, TestItemIssueGroup.TO_INVESTIGATE) - .stream() - .filter(it -> !it.getItemResults().getIssue().getIgnoreAnalyzer()) - .map(TestItem::getItemId) - .collect(toList()); - } + private TestItemRepository testItemRepository; + + @Autowired + public ToInvestigateCollector(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } + + @Override + public List<Long> collectItems(Long projectId, Long launchId, ReportPortalUser user) { + return testItemRepository.findAllInIssueGroupByLaunch(launchId, + TestItemIssueGroup.TO_INVESTIGATE) + .stream() + .filter(it -> !it.getItemResults().getIssue().getIgnoreAnalyzer()) + .map(TestItem::getItemId) + .collect(toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/CurrentLaunchCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/CurrentLaunchCollector.java index e265b2faa7..c33391e830 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/CurrentLaunchCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/CurrentLaunchCollector.java @@ -17,10 +17,9 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.search; import com.epam.ta.reportportal.entity.launch.Launch; -import org.springframework.stereotype.Component; - import java.util.Collections; import java.util.List; +import org.springframework.stereotype.Component; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -28,8 +27,8 @@ @Component public class CurrentLaunchCollector implements SearchLaunchesCollector { - @Override - public List<Long> collect(Long filerId, Launch launch) { - return Collections.singletonList(launch.getId()); - } + @Override + public List<Long> collect(Long filerId, Launch launch) { + return Collections.singletonList(launch.getId()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/FilterCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/FilterCollector.java index 2b1262b3ee..f4dee7b67a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/FilterCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/FilterCollector.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.search; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static org.springframework.data.domain.Sort.Direction.DESC; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.ProjectFilter; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -26,49 +32,49 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Lists; +import java.util.List; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static org.springframework.data.domain.Sort.Direction.DESC; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Component public class FilterCollector implements SearchLaunchesCollector { - private LaunchRepository launchRepository; + private LaunchRepository launchRepository; - private UserFilterRepository userFilterRepository; + private UserFilterRepository userFilterRepository; - @Autowired - public FilterCollector(LaunchRepository launchRepository, UserFilterRepository userFilterRepository) { - this.launchRepository = launchRepository; - this.userFilterRepository = userFilterRepository; - } + @Autowired + public FilterCollector(LaunchRepository launchRepository, + UserFilterRepository userFilterRepository) { + this.launchRepository = launchRepository; + this.userFilterRepository = userFilterRepository; + } - @Override - public List<Long> collect(Long filerId, Launch launch) { - UserFilter userFilter = userFilterRepository.findByIdAndProjectId(filerId, launch.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_FILTER_NOT_FOUND_IN_PROJECT, filerId, launch.getProjectId())); - ObjectType targetClass = userFilter.getTargetClass(); - expect(targetClass, equalTo(ObjectType.Launch)).verify(ErrorType.INCORRECT_FILTER_PARAMETERS, - formattedSupplier("Filter type '{}' is not supported", targetClass) - ); + @Override + public List<Long> collect(Long filerId, Launch launch) { + UserFilter userFilter = userFilterRepository.findByIdAndProjectId(filerId, + launch.getProjectId()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.USER_FILTER_NOT_FOUND_IN_PROJECT, filerId, + launch.getProjectId())); + ObjectType targetClass = userFilter.getTargetClass(); + expect(targetClass, equalTo(ObjectType.Launch)).verify(ErrorType.INCORRECT_FILTER_PARAMETERS, + formattedSupplier("Filter type '{}' is not supported", targetClass) + ); - Filter filter = ProjectFilter.of( - new Filter(targetClass.getClassObject(), Lists.newArrayList(userFilter.getFilterCondition())), - launch.getProjectId()); - PageRequest pageable = PageRequest.of(0, LAUNCHES_FILTER_LIMIT, Sort.by(DESC, CRITERIA_START_TIME)); - return launchRepository.findByFilter(filter, pageable).stream().map(Launch::getId).collect(Collectors.toList()); - } + Filter filter = ProjectFilter.of( + new Filter(targetClass.getClassObject(), + Lists.newArrayList(userFilter.getFilterCondition())), + launch.getProjectId()); + PageRequest pageable = PageRequest.of(0, LAUNCHES_FILTER_LIMIT, + Sort.by(DESC, CRITERIA_START_TIME)); + return launchRepository.findByFilter(filter, pageable).stream().map(Launch::getId) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/LaunchNameCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/LaunchNameCollector.java index 5a9a5bc6ba..cd5d0900a8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/LaunchNameCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/LaunchNameCollector.java @@ -16,41 +16,42 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.search; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.commons.querygen.ProjectFilter; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.launch.Launch; +import java.util.List; +import java.util.stream.Collectors; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Component public class LaunchNameCollector implements SearchLaunchesCollector { - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - public LaunchNameCollector(LaunchRepository launchRepository) { - this.launchRepository = launchRepository; - } + public LaunchNameCollector(LaunchRepository launchRepository) { + this.launchRepository = launchRepository; + } - @Override - public List<Long> collect(Long filerId, Launch launch) { - Filter filter = ProjectFilter.of(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_NAME, launch.getName()).build()) - .build(), launch.getProjectId()); - PageRequest pageRequest = PageRequest.of(0, LAUNCHES_FILTER_LIMIT, Sort.by(Sort.Direction.DESC, CRITERIA_START_TIME)); + @Override + public List<Long> collect(Long filerId, Launch launch) { + Filter filter = ProjectFilter.of(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq(CRITERIA_NAME, launch.getName()).build()) + .build(), launch.getProjectId()); + PageRequest pageRequest = PageRequest.of(0, LAUNCHES_FILTER_LIMIT, + Sort.by(Sort.Direction.DESC, CRITERIA_START_TIME)); - return launchRepository.findByFilter(filter, pageRequest).stream().map(Launch::getId).collect(Collectors.toList()); - } + return launchRepository.findByFilter(filter, pageRequest).stream().map(Launch::getId) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorConfig.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorConfig.java index 667cb138ff..2c0da13d92 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorConfig.java @@ -17,36 +17,37 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.search; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Configuration public class SearchCollectorConfig { - private ApplicationContext applicationContext; - - public SearchCollectorConfig(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - @Bean("searchModeMapping") - public Map<SearchLogsMode, SearchLaunchesCollector> getSearchModeMapping() { - return ImmutableMap.<SearchLogsMode, SearchLaunchesCollector>builder().put(SearchLogsMode.BY_LAUNCH_NAME, - applicationContext.getBean(LaunchNameCollector.class) - ) - .put(SearchLogsMode.CURRENT_LAUNCH, applicationContext.getBean(CurrentLaunchCollector.class)) - .put(SearchLogsMode.FILTER, applicationContext.getBean(FilterCollector.class)) - .build(); - } - - @Bean - public SearchCollectorFactory searchCollectorFactory() { - return new SearchCollectorFactory(getSearchModeMapping()); - } + private ApplicationContext applicationContext; + + public SearchCollectorConfig(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Bean("searchModeMapping") + public Map<SearchLogsMode, SearchLaunchesCollector> getSearchModeMapping() { + return ImmutableMap.<SearchLogsMode, SearchLaunchesCollector>builder() + .put(SearchLogsMode.BY_LAUNCH_NAME, + applicationContext.getBean(LaunchNameCollector.class) + ) + .put(SearchLogsMode.CURRENT_LAUNCH, + applicationContext.getBean(CurrentLaunchCollector.class)) + .put(SearchLogsMode.FILTER, applicationContext.getBean(FilterCollector.class)) + .build(); + } + + @Bean + public SearchCollectorFactory searchCollectorFactory() { + return new SearchCollectorFactory(getSearchModeMapping()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorFactory.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorFactory.java index 01a09b7610..d3d82ab81e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchCollectorFactory.java @@ -23,13 +23,13 @@ */ public class SearchCollectorFactory { - private Map<SearchLogsMode, SearchLaunchesCollector> mapping; + private Map<SearchLogsMode, SearchLaunchesCollector> mapping; - public SearchCollectorFactory(Map<SearchLogsMode, SearchLaunchesCollector> mapping) { - this.mapping = mapping; - } + public SearchCollectorFactory(Map<SearchLogsMode, SearchLaunchesCollector> mapping) { + this.mapping = mapping; + } - public SearchLaunchesCollector getCollector(SearchLogsMode mode) { - return mapping.get(mode); - } + public SearchLaunchesCollector getCollector(SearchLogsMode mode) { + return mapping.get(mode); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLaunchesCollector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLaunchesCollector.java index b9fadf0a0d..dcd71d5194 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLaunchesCollector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLaunchesCollector.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.analyzer.auto.strategy.search; import com.epam.ta.reportportal.entity.launch.Launch; - import java.util.List; /** @@ -25,7 +24,7 @@ */ public interface SearchLaunchesCollector { - int LAUNCHES_FILTER_LIMIT = 10; + int LAUNCHES_FILTER_LIMIT = 10; - List<Long> collect(Long filerId, Launch launch); + List<Long> collect(Long filerId, Launch launch); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLogsMode.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLogsMode.java index 3eb67fcb15..21860a39ff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLogsMode.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/strategy/search/SearchLogsMode.java @@ -24,21 +24,21 @@ */ public enum SearchLogsMode { - BY_LAUNCH_NAME("launchName"), - CURRENT_LAUNCH("currentLaunch"), - FILTER("filter"); + BY_LAUNCH_NAME("launchName"), + CURRENT_LAUNCH("currentLaunch"), + FILTER("filter"); - private String value; + private String value; - SearchLogsMode(String value) { - this.value = value; - } + SearchLogsMode(String value) { + this.value = value; + } - public String getValue() { - return value; - } + public String getValue() { + return value; + } - public static Optional<SearchLogsMode> fromString(String mode) { - return Arrays.stream(values()).filter(it -> it.getValue().equalsIgnoreCase(mode)).findFirst(); - } + public static Optional<SearchLogsMode> fromString(String mode) { + return Arrays.stream(values()).filter(it -> it.getValue().equalsIgnoreCase(mode)).findFirst(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerType.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerType.java index 2c139a0a06..a1894293c7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerType.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerType.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.Arrays; import java.util.stream.Collectors; @@ -27,28 +26,28 @@ */ public enum AnalyzerType { - AUTO_ANALYZER("autoAnalyzer"), - PATTERN_ANALYZER("patternAnalyzer"); - - private final String name; - - AnalyzerType(String name) { - this.name = name; - } - - public static AnalyzerType fromString(String type) { - return Arrays.stream(AnalyzerType.values()) - .filter(it -> it.getName().equalsIgnoreCase(type)) - .findFirst() - .orElseThrow(() -> new ReportPortalException( - ErrorType.INCORRECT_REQUEST, - "Incorrect analyzer type. Allowed are: " + Arrays.stream(AnalyzerType.values()) - .map(AnalyzerType::getName) - .collect(Collectors.toList()) - )); - } - - public String getName() { - return name; - } + AUTO_ANALYZER("autoAnalyzer"), + PATTERN_ANALYZER("patternAnalyzer"); + + private final String name; + + AnalyzerType(String name) { + this.name = name; + } + + public static AnalyzerType fromString(String type) { + return Arrays.stream(AnalyzerType.values()) + .filter(it -> it.getName().equalsIgnoreCase(type)) + .findFirst() + .orElseThrow(() -> new ReportPortalException( + ErrorType.INCORRECT_REQUEST, + "Incorrect analyzer type. Allowed are: " + Arrays.stream(AnalyzerType.values()) + .map(AnalyzerType::getName) + .collect(Collectors.toList()) + )); + } + + public String getName() { + return name; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzersConfig.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzersConfig.java index cad826a04b..a7230759bb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzersConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzersConfig.java @@ -20,26 +20,27 @@ import com.epam.ta.reportportal.core.analyzer.strategy.LaunchAutoAnalysisStrategy; import com.epam.ta.reportportal.core.analyzer.strategy.LaunchPatternAnalysisStrategy; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class AnalyzersConfig { - @Autowired - private ApplicationContext applicationContext; + @Autowired + private ApplicationContext applicationContext; - @Bean - public Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping() { - return ImmutableMap.<AnalyzerType, LaunchAnalysisStrategy>builder().put(AnalyzerType.AUTO_ANALYZER, - applicationContext.getBean(LaunchAutoAnalysisStrategy.class) - ).put(AnalyzerType.PATTERN_ANALYZER, applicationContext.getBean(LaunchPatternAnalysisStrategy.class)).build(); - } + @Bean + public Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping() { + return ImmutableMap.<AnalyzerType, LaunchAnalysisStrategy>builder() + .put(AnalyzerType.AUTO_ANALYZER, + applicationContext.getBean(LaunchAutoAnalysisStrategy.class) + ).put(AnalyzerType.PATTERN_ANALYZER, + applicationContext.getBean(LaunchPatternAnalysisStrategy.class)).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisConfig.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisConfig.java index dc3e797aed..382d1562c4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisConfig.java @@ -16,49 +16,59 @@ package com.epam.ta.reportportal.core.analyzer.config; -import com.epam.ta.reportportal.core.analyzer.pattern.CreatePatternTemplateHandler; -import com.epam.ta.reportportal.core.analyzer.pattern.impl.CreatePatternTemplateHandlerImpl; -import com.epam.ta.reportportal.core.analyzer.pattern.impl.CreateRegexPatternTemplateHandler; import com.epam.ta.reportportal.core.analyzer.pattern.selector.PatternAnalysisSelector; import com.epam.ta.reportportal.core.analyzer.pattern.selector.impl.RegexPatternAnalysisSelector; import com.epam.ta.reportportal.core.analyzer.pattern.selector.impl.StringPartPatternAnalysisSelector; +import com.epam.ta.reportportal.core.analyzer.pattern.service.CreatePatternTemplateHandler; +import com.epam.ta.reportportal.core.analyzer.pattern.service.impl.CreatePatternTemplateHandlerImpl; +import com.epam.ta.reportportal.core.analyzer.pattern.service.impl.CreateRegexPatternTemplateHandler; import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; import com.google.common.collect.ImmutableMap; +import java.util.Map; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.QueueBuilder; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class PatternAnalysisConfig implements ApplicationContextAware { + private ApplicationContext applicationContext; - private ApplicationContext applicationContext; - - @Autowired - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + @Autowired + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @Bean("createPatternTemplateMapping") - public Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateHandlerMapping() { - return ImmutableMap.<PatternTemplateType, CreatePatternTemplateHandler>builder().put(PatternTemplateType.STRING, - applicationContext.getBean(CreatePatternTemplateHandlerImpl.class) - ).put(PatternTemplateType.REGEX, applicationContext.getBean(CreateRegexPatternTemplateHandler.class)).build(); - } + @Bean("createPatternTemplateMapping") + public Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateHandlerMapping() { + return ImmutableMap.<PatternTemplateType, CreatePatternTemplateHandler>builder() + .put(PatternTemplateType.STRING, + applicationContext.getBean(CreatePatternTemplateHandlerImpl.class) + ).put(PatternTemplateType.REGEX, + applicationContext.getBean(CreateRegexPatternTemplateHandler.class)).build(); + } - @Bean("patternAnalysisSelectorMapping") - public Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping() { - return ImmutableMap.<PatternTemplateType, PatternAnalysisSelector>builder().put(PatternTemplateType.STRING, - applicationContext.getBean(StringPartPatternAnalysisSelector.class) - ).put(PatternTemplateType.REGEX, applicationContext.getBean(RegexPatternAnalysisSelector.class)).build(); - } + @Bean("patternAnalysisSelectorMapping") + public Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping() { + return ImmutableMap.<PatternTemplateType, PatternAnalysisSelector>builder() + .put(PatternTemplateType.STRING, + applicationContext.getBean(StringPartPatternAnalysisSelector.class) + ).put(PatternTemplateType.REGEX, + applicationContext.getBean(RegexPatternAnalysisSelector.class)).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisRabbitConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisRabbitConfiguration.java new file mode 100644 index 0000000000..d4dbc28ca5 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/PatternAnalysisRabbitConfiguration.java @@ -0,0 +1,87 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.config; + +import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Exchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.QueueBuilder; +import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Configuration +public class PatternAnalysisRabbitConfiguration { + + public static final String PATTERN_ANALYSIS = "pattern.analysis"; + public static final String PATTERN_ANALYSIS_STRING = "analysis.pattern.string"; + public static final String PATTERN_ANALYSIS_REGEX = "analysis.pattern.regex"; + + @Bean + public Exchange patternAnalysisExchange() { + return new DirectExchange(PATTERN_ANALYSIS); + } + + @Bean + public Queue patternAnalysisStringQueue() { + return QueueBuilder.durable(PATTERN_ANALYSIS_STRING).build(); + } + + @Bean + public Queue patternAnalysisRegexQueue() { + return QueueBuilder.durable(PATTERN_ANALYSIS_REGEX).build(); + } + + @Bean + public Binding stringQueueBinding() { + return BindingBuilder.bind(patternAnalysisStringQueue()).to(patternAnalysisExchange()).with( + PatternTemplateType.STRING.toString()).noargs(); + } + + @Bean + public Binding regexQueueBinding() { + return BindingBuilder.bind(patternAnalysisRegexQueue()).to(patternAnalysisExchange()).with( + PatternTemplateType.REGEX.toString()).noargs(); + } + + @Bean + public RabbitListenerContainerFactory<SimpleMessageListenerContainer> patternAnalysisContainerFactory( + ConnectionFactory connectionFactory, + SimpleRabbitListenerContainerFactoryConfigurer configurer, + @Value("${rp.environment.variable.pattern-analysis.consumers-count:1}") int consumersCount, + @Value("${rp.environment.variable.pattern-analysis.prefetch-count:0}") int prefetchCount) { + SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); + factory.setConcurrentConsumers(consumersCount); + factory.setPrefetchCount(prefetchCount); + factory.setDefaultRequeueRejected(false); + configurer.configure(factory, connectionFactory); + return factory; + } + + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/StartLaunchAutoAnalysisConfig.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/StartLaunchAutoAnalysisConfig.java index c1dba2da57..5e423855ca 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/config/StartLaunchAutoAnalysisConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/config/StartLaunchAutoAnalysisConfig.java @@ -19,44 +19,46 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.Set; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class StartLaunchAutoAnalysisConfig { - private final Long launchId; - private final AnalyzerConfig analyzerConfig; - private final Set<AnalyzeItemsMode> analyzeItemsModes; - private final ReportPortalUser user; - - private StartLaunchAutoAnalysisConfig(Long launchId, AnalyzerConfig analyzerConfig, Set<AnalyzeItemsMode> analyzeItemsModes, - ReportPortalUser user) { - this.launchId = launchId; - this.analyzerConfig = analyzerConfig; - this.analyzeItemsModes = analyzeItemsModes; - this.user = user; - } - - public static StartLaunchAutoAnalysisConfig of(Long launchId, AnalyzerConfig analyzerConfig, Set<AnalyzeItemsMode> analyzeItemsModes, - ReportPortalUser user) { - return new StartLaunchAutoAnalysisConfig(launchId, analyzerConfig, analyzeItemsModes, user); - } - - public Long getLaunchId() { - return launchId; - } - - public AnalyzerConfig getAnalyzerConfig() { - return analyzerConfig; - } - - public Set<AnalyzeItemsMode> getAnalyzeItemsModes() { - return analyzeItemsModes; - } - - public ReportPortalUser getUser() { - return user; - } + + private final Long launchId; + private final AnalyzerConfig analyzerConfig; + private final Set<AnalyzeItemsMode> analyzeItemsModes; + private final ReportPortalUser user; + + private StartLaunchAutoAnalysisConfig(Long launchId, AnalyzerConfig analyzerConfig, + Set<AnalyzeItemsMode> analyzeItemsModes, + ReportPortalUser user) { + this.launchId = launchId; + this.analyzerConfig = analyzerConfig; + this.analyzeItemsModes = analyzeItemsModes; + this.user = user; + } + + public static StartLaunchAutoAnalysisConfig of(Long launchId, AnalyzerConfig analyzerConfig, + Set<AnalyzeItemsMode> analyzeItemsModes, + ReportPortalUser user) { + return new StartLaunchAutoAnalysisConfig(launchId, analyzerConfig, analyzeItemsModes, user); + } + + public Long getLaunchId() { + return launchId; + } + + public AnalyzerConfig getAnalyzerConfig() { + return analyzerConfig; + } + + public Set<AnalyzeItemsMode> getAnalyzeItemsModes() { + return analyzeItemsModes; + } + + public ReportPortalUser getUser() { + return user; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzer.java deleted file mode 100644 index 06caee84f7..0000000000 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.analyzer.pattern; - -import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; -import com.epam.ta.reportportal.entity.launch.Launch; - -import java.util.Set; - -/** - * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> - */ -public interface PatternAnalyzer { - - /** - * Analyze by {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate#value} - * all {@link com.epam.ta.reportportal.entity.log.Log#logMessage} of {@link com.epam.ta.reportportal.entity.item.TestItem} - * with {@link TestItemIssueGroup#TO_INVESTIGATE} for {@link com.epam.ta.reportportal.entity.launch.Launch} with provided ID. - * Every matched {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} will be attached - * to the {@link com.epam.ta.reportportal.entity.item.TestItem} - * using {@link com.epam.ta.reportportal.entity.pattern.PatternTemplateTestItem} relation - * - * @param launch {@link com.epam.ta.reportportal.entity.launch.Launch}, which {@link com.epam.ta.reportportal.entity.item.TestItem} - * should be analyzed - * @param analyzeModes {@link AnalyzeItemsMode} to modify {@link com.epam.ta.reportportal.entity.item.TestItem} query conditions - */ - void analyzeTestItems(Launch launch, Set<AnalyzeItemsMode> analyzeModes); -} diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/Builder.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/ItemsPatternsAnalyzer.java similarity index 53% rename from src/main/java/com/epam/ta/reportportal/ws/converter/builders/Builder.java rename to src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/ItemsPatternsAnalyzer.java index f2a4f39f31..ca0139a41d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/Builder.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/ItemsPatternsAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 EPAM Systems + * Copyright 2023 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,37 +14,16 @@ * limitations under the License. */ -package com.epam.ta.reportportal.ws.converter.builders; +package com.epam.ta.reportportal.core.analyzer.pattern.handler; + +import java.util.List; /** - * Generic builder holder - * - * @param <T> - * @author Andrei Varabyeu + * Analyse list of items by project patterns + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ -@Deprecated -public abstract class Builder<T> { - - private T object; - - public Builder() { - object = initObject(); - } - - /** - * Builds object - * - * @return Built object - */ - public T build() { - T toReturn = object; - object = initObject(); - return toReturn; - } +public interface ItemsPatternsAnalyzer { - protected abstract T initObject(); + void analyze(long projectId, long launchId, List<Long> itemIds); - protected T getObject() { - return object; - } -} \ No newline at end of file +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/impl/ItemsPatternAnalyzerImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/impl/ItemsPatternAnalyzerImpl.java new file mode 100644 index 0000000000..7f8b78d5ef --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/impl/ItemsPatternAnalyzerImpl.java @@ -0,0 +1,110 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.handler.impl; + +import com.epam.ta.reportportal.core.analyzer.pattern.selector.PatternAnalysisSelector; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.PatternMatchedEvent; +import com.epam.ta.reportportal.dao.PatternTemplateRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.pattern.PatternTemplate; +import com.epam.ta.reportportal.entity.pattern.PatternTemplateTestItemPojo; +import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; +import com.epam.ta.reportportal.ws.converter.converters.PatternTemplateConverter; +import com.epam.ta.reportportal.ws.model.activity.PatternTemplateActivityResource; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Service +public class ItemsPatternAnalyzerImpl { + + private final PatternTemplateRepository patternTemplateRepository; + + private final Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping; + + private final TestItemRepository testItemRepository; + + private final MessageBus messageBus; + + public ItemsPatternAnalyzerImpl(PatternTemplateRepository patternTemplateRepository, + Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping, + TestItemRepository testItemRepository, MessageBus messageBus) { + this.patternTemplateRepository = patternTemplateRepository; + this.patternAnalysisSelectorMapping = patternAnalysisSelectorMapping; + this.testItemRepository = testItemRepository; + this.messageBus = messageBus; + } + + public void analyzeByPattern(PatternTemplate pattern, Long launchId, List<Long> itemIds) { + List<Long> filtered = filterAlreadyMatched(pattern, itemIds); + PatternAnalysisSelector patternAnalysisSelector = patternAnalysisSelectorMapping.get( + pattern.getTemplateType()); + List<Long> matchedIds = patternAnalysisSelector.selectItemsByPattern(launchId, filtered, + pattern.getValue()); + if (!CollectionUtils.isEmpty(matchedIds)) { + List<PatternTemplateTestItemPojo> patternTemplateTestItems = saveMatches(pattern, matchedIds); + publishEvents(pattern, patternTemplateTestItems); + } + } + + private List<Long> filterAlreadyMatched(PatternTemplate pattern, List<Long> itemIds) { + List<Long> alreadyMatched = patternTemplateRepository.findMatchedItemIdsIn(pattern.getId(), + itemIds); + return itemIds.stream().filter(id -> !alreadyMatched.contains(id)) + .collect(Collectors.toList()); + } + + private List<PatternTemplateTestItemPojo> saveMatches(PatternTemplate pattern, + List<Long> matchedIds) { + List<PatternTemplateTestItemPojo> patternTemplateTestItemPojos = convertToPojo(pattern, + matchedIds); + patternTemplateRepository.saveInBatch(patternTemplateTestItemPojos); + return patternTemplateTestItemPojos; + } + + private List<PatternTemplateTestItemPojo> convertToPojo(PatternTemplate patternTemplate, + List<Long> itemIds) { + return itemIds.stream() + .map(itemId -> new PatternTemplateTestItemPojo(patternTemplate.getId(), itemId)) + .collect(Collectors.toList()); + } + + private void publishEvents(PatternTemplate patternTemplate, + List<PatternTemplateTestItemPojo> patternTemplateTestItems) { + final PatternTemplateActivityResource patternTemplateActivityResource = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply( + patternTemplate); + patternTemplateTestItems.forEach(patternItem -> { + Long testItemId = patternItem.getTestItemId(); + Optional<String> itemNameByItemId = testItemRepository.findItemNameByItemId(testItemId); + PatternMatchedEvent patternMatchedEvent = new PatternMatchedEvent( + itemNameByItemId.orElse(StringUtils.EMPTY), + testItemId, + patternTemplateActivityResource + ); + messageBus.publishActivity(patternMatchedEvent); + }); + } + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeConsumer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeConsumer.java new file mode 100644 index 0000000000..4bfd5990d4 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeConsumer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.handler.proxy; + +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.PATTERN_ANALYZER_KEY; +import static com.epam.ta.reportportal.core.analyzer.config.PatternAnalysisRabbitConfiguration.PATTERN_ANALYSIS_REGEX; +import static com.epam.ta.reportportal.core.analyzer.config.PatternAnalysisRabbitConfiguration.PATTERN_ANALYSIS_STRING; + +import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; +import com.epam.ta.reportportal.core.analyzer.pattern.handler.impl.ItemsPatternAnalyzerImpl; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +/** + * Consumes items for pattern analysis from the queue + * + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Component +public class ItemsPatternAnalyzeConsumer { + + private final ItemsPatternAnalyzerImpl itemsPatternsAnalyzer; + + private final AnalyzerStatusCache analyzerStatusCache; + + public ItemsPatternAnalyzeConsumer(ItemsPatternAnalyzerImpl itemsPatternsAnalyzer, + AnalyzerStatusCache analyzerStatusCache) { + this.itemsPatternsAnalyzer = itemsPatternsAnalyzer; + this.analyzerStatusCache = analyzerStatusCache; + } + + @RabbitListener(queues = {PATTERN_ANALYSIS_REGEX, + PATTERN_ANALYSIS_STRING}, containerFactory = "patternAnalysisContainerFactory") + public void handleEvent(ItemsPatternAnalyzeDto event) { + if (event.isLastItem()) { + analyzerStatusCache.analyzeFinished(PATTERN_ANALYZER_KEY, event.getLaunchId()); + } else { + itemsPatternsAnalyzer.analyzeByPattern(event.getPatternTemplate(), event.getLaunchId(), + event.getItemIds()); + } + } + + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeDto.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeDto.java new file mode 100644 index 0000000000..c960eb009e --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeDto.java @@ -0,0 +1,103 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.handler.proxy; + +import com.epam.ta.reportportal.entity.pattern.PatternTemplate; +import java.util.List; + +/** + * Dto of item analysis event + * + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +public class ItemsPatternAnalyzeDto { + + private PatternTemplate patternTemplate; + private long projectId; + private long launchId; + private List<Long> itemIds; + private boolean isLastItem; + + public ItemsPatternAnalyzeDto() { + } + + public ItemsPatternAnalyzeDto(long projectId, long launchId, List<Long> itemIds, + PatternTemplate patternTemplate) { + this.projectId = projectId; + this.launchId = launchId; + this.itemIds = itemIds; + this.patternTemplate = patternTemplate; + } + + public ItemsPatternAnalyzeDto(long projectId, long launchId, List<Long> itemIds, + boolean isLastItem) { + this.projectId = projectId; + this.launchId = launchId; + this.itemIds = itemIds; + this.isLastItem = isLastItem; + } + + public PatternTemplate getPatternTemplate() { + return patternTemplate; + } + + public void setPatternTemplate(PatternTemplate patternTemplate) { + this.patternTemplate = patternTemplate; + } + + public long getProjectId() { + return projectId; + } + + public long getLaunchId() { + return launchId; + } + + public List<Long> getItemIds() { + return itemIds; + } + + public void setProjectId(long projectId) { + this.projectId = projectId; + } + + public void setLaunchId(long launchId) { + this.launchId = launchId; + } + + public void setItemIds(List<Long> itemIds) { + this.itemIds = itemIds; + } + + public boolean isLastItem() { + return isLastItem; + } + + public void setLastItem(boolean lastItem) { + isLastItem = lastItem; + } + + @Override + public String toString() { + return "ItemsPatternMessage{" + + "projectId=" + projectId + + ", launchId=" + launchId + + ", itemIds=" + itemIds + + ", isLastItem=" + isLastItem + + '}'; + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeProducer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeProducer.java new file mode 100644 index 0000000000..c65c4f0a81 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/handler/proxy/ItemsPatternAnalyzeProducer.java @@ -0,0 +1,80 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.handler.proxy; + + +import static com.epam.ta.reportportal.core.analyzer.config.PatternAnalysisRabbitConfiguration.PATTERN_ANALYSIS; + +import com.epam.ta.reportportal.core.analyzer.pattern.handler.ItemsPatternsAnalyzer; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.dao.PatternTemplateRepository; +import com.epam.ta.reportportal.entity.pattern.PatternTemplate; +import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; +import java.util.Collections; +import java.util.List; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +/** + * Sends items for pattern analysis queue + * + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Primary +@Component +public class ItemsPatternAnalyzeProducer implements ItemsPatternsAnalyzer { + + private final PatternTemplateRepository patternTemplateRepository; + private final boolean isSingleItem; + private final MessageBus messageBus; + + public ItemsPatternAnalyzeProducer( + @Value("${rp.environment.variable.pattern-analysis.single-item:true}") boolean isSingleItem, + MessageBus messageBus, PatternTemplateRepository patternTemplateRepository) { + this.isSingleItem = isSingleItem; + this.messageBus = messageBus; + this.patternTemplateRepository = patternTemplateRepository; + } + + @Override + public void analyze(long projectId, long launchId, List<Long> itemIds) { + List<PatternTemplate> patternTemplates = patternTemplateRepository.findAllByProjectIdAndEnabled( + projectId, true); + patternTemplates.forEach(pattern -> publishMessage(pattern, projectId, launchId, itemIds)); + if (CollectionUtils.isEmpty(itemIds)) { + sendFinishedEvent(projectId, launchId); + } + } + + private void publishMessage(PatternTemplate pattern, long projectId, long launchId, + List<Long> itemIds) { + if (isSingleItem) { + itemIds.forEach(id -> messageBus.publish(PATTERN_ANALYSIS, pattern.getTemplateType().name(), + new ItemsPatternAnalyzeDto(projectId, launchId, Collections.singletonList(id), pattern))); + } else { + messageBus.publish(PATTERN_ANALYSIS, pattern.getTemplateType().name(), + new ItemsPatternAnalyzeDto(projectId, launchId, itemIds, pattern)); + } + } + + public void sendFinishedEvent(long projectId, long launchId) { + messageBus.publish(PATTERN_ANALYSIS, PatternTemplateType.REGEX.name(), + new ItemsPatternAnalyzeDto(projectId, launchId, Collections.emptyList(), true)); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/PatternAnalyzerImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/PatternAnalyzerImpl.java deleted file mode 100644 index 537b2c6900..0000000000 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/PatternAnalyzerImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.analyzer.pattern.impl; - -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATTERN_TEMPLATE_NAME; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.PATTERN_ANALYZER_KEY; - -import com.epam.ta.reportportal.commons.querygen.Condition; -import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; -import com.epam.ta.reportportal.commons.querygen.Filter; -import com.epam.ta.reportportal.commons.querygen.FilterCondition; -import com.epam.ta.reportportal.commons.validation.BusinessRule; -import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; -import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.core.analyzer.pattern.PatternAnalyzer; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.PatternAnalysisSelector; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.PatternConditionProviderChain; -import com.epam.ta.reportportal.core.events.MessageBus; -import com.epam.ta.reportportal.core.events.activity.PatternMatchedEvent; -import com.epam.ta.reportportal.dao.PatternTemplateRepository; -import com.epam.ta.reportportal.dao.TestItemRepository; -import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.pattern.PatternTemplate; -import com.epam.ta.reportportal.entity.pattern.PatternTemplateTestItemPojo; -import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.converter.converters.PatternTemplateConverter; -import com.epam.ta.reportportal.ws.model.ErrorType; -import com.epam.ta.reportportal.ws.model.activity.PatternTemplateActivityResource; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.task.TaskExecutor; -import org.springframework.stereotype.Service; - -/** - * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> - */ -@Service -public class PatternAnalyzerImpl implements PatternAnalyzer { - - public static final Logger LOGGER = LoggerFactory.getLogger(PatternAnalyzerImpl.class); - - private final Integer batchSize; - - private final TestItemRepository testItemRepository; - private final PatternTemplateRepository patternTemplateRepository; - private final PatternConditionProviderChain patternConditionProviderChain; - - private final Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping; - - private final TaskExecutor patternAnalysisTaskExecutor; - - private final AnalyzerStatusCache analyzerStatusCache; - - private final MessageBus messageBus; - - @Autowired - public PatternAnalyzerImpl(@Value("${rp.environment.variable.pattern-analysis.batch-size}") Integer batchSize, - TestItemRepository testItemRepository, PatternTemplateRepository patternTemplateRepository, - @Qualifier("patternAnalysisSelectorMapping") Map<PatternTemplateType, PatternAnalysisSelector> patternAnalysisSelectorMapping, - TaskExecutor patternAnalysisTaskExecutor, PatternConditionProviderChain patternConditionProviderChain, - AnalyzerStatusCache analyzerStatusCache, MessageBus messageBus) { - this.batchSize = batchSize; - this.testItemRepository = testItemRepository; - this.patternTemplateRepository = patternTemplateRepository; - this.patternAnalysisSelectorMapping = patternAnalysisSelectorMapping; - this.patternAnalysisTaskExecutor = patternAnalysisTaskExecutor; - this.patternConditionProviderChain = patternConditionProviderChain; - this.analyzerStatusCache = analyzerStatusCache; - this.messageBus = messageBus; - } - - @Override - public void analyzeTestItems(Launch launch, Set<AnalyzeItemsMode> analyzeModes) { - BusinessRule.expect(analyzerStatusCache.getStartedAnalyzers(launch.getId()), not(started -> started.contains(PATTERN_ANALYZER_KEY))) - .verify(ErrorType.PATTERN_ANALYSIS_ERROR, "Pattern analysis is still in progress."); - - analyzerStatusCache.analyzeStarted(PATTERN_ANALYZER_KEY, launch.getId(), launch.getProjectId()); - patternAnalysisTaskExecutor.execute(() -> { - try { - final ConvertibleCondition itemCondition = getItemCondition(analyzeModes); - patternTemplateRepository.findAllByProjectIdAndEnabled(launch.getProjectId(), true) - .forEach(patternTemplate -> analyze(launch, itemCondition, patternTemplate)); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } finally { - analyzerStatusCache.analyzeFinished(PATTERN_ANALYZER_KEY, launch.getId()); - } - }); - - } - - private ConvertibleCondition getItemCondition(Set<AnalyzeItemsMode> analyzeModes) { - return patternConditionProviderChain.provideCondition(analyzeModes) - .orElseThrow(() -> new ReportPortalException(ErrorType.PATTERN_ANALYSIS_ERROR, "Unable to resolve item search condition")); - } - - private void analyze(Launch launch, ConvertibleCondition itemCondition, PatternTemplate patternTemplate) { - final Filter filter = createItemFilter(itemCondition, patternTemplate.getName()); - int offset = 0; - List<Long> itemIds = testItemRepository.selectIdsByFilter(launch.getId(), filter, batchSize, offset); - while (CollectionUtils.isNotEmpty(itemIds)) { - final List<Long> matchedIds = attachToPatternTemplate(launch, patternTemplate, itemIds); - offset += itemIds.size() - matchedIds.size(); - itemIds = testItemRepository.selectIdsByFilter(launch.getId(), filter, batchSize, offset); - } - - } - - private List<Long> attachToPatternTemplate(Launch launch, PatternTemplate patternTemplate, List<Long> itemIds) { - final List<Long> matchedIds = filterItems(launch, patternTemplate, itemIds); - final List<PatternTemplateTestItemPojo> patternTemplateTestItems = convertToPojo(patternTemplate, matchedIds); - patternTemplateRepository.saveInBatch(patternTemplateTestItems); - publishEvents(patternTemplate, patternTemplateTestItems); - return matchedIds; - } - - private List<Long> filterItems(Launch launch, PatternTemplate patternTemplate, List<Long> itemIds) { - final PatternAnalysisSelector patternAnalysisSelector = patternAnalysisSelectorMapping.get(patternTemplate.getTemplateType()); - return patternAnalysisSelector.selectItemsByPattern(launch.getId(), itemIds, patternTemplate.getValue()); - } - - private Filter createItemFilter(ConvertibleCondition commonItemCondition, String patternTemplateName) { - return Filter.builder() - .withTarget(TestItem.class) - .withCondition(commonItemCondition) - .withCondition(FilterCondition.builder() - .withCondition(Condition.ANY) - .withNegative(true) - .withSearchCriteria(CRITERIA_PATTERN_TEMPLATE_NAME) - .withValue(patternTemplateName) - .build()) - .build(); - } - - private List<PatternTemplateTestItemPojo> convertToPojo(PatternTemplate patternTemplate, List<Long> itemIds) { - return itemIds.stream() - .map(itemId -> new PatternTemplateTestItemPojo(patternTemplate.getId(), itemId)) - .collect(Collectors.toList()); - } - - private void publishEvents(PatternTemplate patternTemplate, List<PatternTemplateTestItemPojo> patternTemplateTestItems) { - final PatternTemplateActivityResource patternTemplateActivityResource = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply( - patternTemplate); - patternTemplateTestItems.forEach(patternItem -> { - Long testItemId = patternItem.getTestItemId(); - Optional<String> itemNameByItemId = testItemRepository.findItemNameByItemId(testItemId); - PatternMatchedEvent patternMatchedEvent = new PatternMatchedEvent( - itemNameByItemId.orElse(StringUtils.EMPTY), - testItemId, - patternTemplateActivityResource - ); - messageBus.publishActivity(patternMatchedEvent); - }); - } - -} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/PatternAnalysisSelector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/PatternAnalysisSelector.java index 27b0686e4d..3f1dbab7c0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/PatternAnalysisSelector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/PatternAnalysisSelector.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.pattern.PatternTemplate; - import java.util.Collection; import java.util.List; @@ -28,13 +27,13 @@ */ public interface PatternAnalysisSelector { - /** - * Select {@link TestItem#getItemId()} with logs matched by pattern value - * - * @param launchId {@link Launch#getId()} - * @param itemIds {@link Collection} with {@link TestItem#getItemId()} - * @param pattern {@link PatternTemplate#getValue()} - * @return {@link List} of {@link TestItem#getItemId()} - */ - List<Long> selectItemsByPattern(Long launchId, Collection<Long> itemIds, String pattern); + /** + * Select {@link TestItem#getItemId()} with logs matched by pattern value + * + * @param launchId {@link Launch#getId()} + * @param itemIds {@link Collection} with {@link TestItem#getItemId()} + * @param pattern {@link PatternTemplate#getValue()} + * @return {@link List} of {@link TestItem#getItemId()} + */ + List<Long> selectItemsByPattern(Long launchId, Collection<Long> itemIds, String pattern); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProvider.java index ceefbde798..4022989675 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProvider.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; - import java.util.Optional; import java.util.Set; @@ -28,5 +27,5 @@ //TODO should be updated according to the nested steps' logs retrieving logic public interface PatternConditionProvider { - Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes); + Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProviderChain.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProviderChain.java index 79e4bf4811..798b7b980d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProviderChain.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/PatternConditionProviderChain.java @@ -20,21 +20,21 @@ import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl.AutoAnalyzedPatternConditionProvider; +import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl.IgnoreImmediatePatternAnalysisConditionProvider; import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl.ManualPatternConditionProvider; import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl.ToInvestigatePatternConditionProvider; import com.epam.ta.reportportal.dao.IssueGroupRepository; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.google.common.collect.Sets; -import org.jooq.Operator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; +import org.jooq.Operator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -42,28 +42,31 @@ @Component public class PatternConditionProviderChain { - private final Set<PatternConditionProvider> patternConditionProviders; + private final Set<PatternConditionProvider> patternConditionProviders; - @Autowired - public PatternConditionProviderChain(IssueGroupRepository issueGroupRepository) { - Supplier<IssueGroup> issueGroupSupplier = () -> issueGroupRepository.findByTestItemIssueGroup(TestItemIssueGroup.TO_INVESTIGATE); - this.patternConditionProviders = Sets.newHashSet(new AutoAnalyzedPatternConditionProvider(AnalyzeItemsMode.AUTO_ANALYZED), - new ManualPatternConditionProvider(AnalyzeItemsMode.MANUALLY_ANALYZED, issueGroupSupplier), - new ToInvestigatePatternConditionProvider(AnalyzeItemsMode.TO_INVESTIGATE, - issueGroupSupplier - ) - ); - } + @Autowired + public PatternConditionProviderChain(IssueGroupRepository issueGroupRepository) { + Supplier<IssueGroup> issueGroupSupplier = () -> issueGroupRepository.findByTestItemIssueGroup( + TestItemIssueGroup.TO_INVESTIGATE); + this.patternConditionProviders = Sets.newHashSet( + new AutoAnalyzedPatternConditionProvider(AnalyzeItemsMode.AUTO_ANALYZED), + new ManualPatternConditionProvider(AnalyzeItemsMode.MANUALLY_ANALYZED, issueGroupSupplier), + new ToInvestigatePatternConditionProvider(AnalyzeItemsMode.TO_INVESTIGATE, + issueGroupSupplier + ), + new IgnoreImmediatePatternAnalysisConditionProvider(AnalyzeItemsMode.IGNORE_IMMEDIATE) + ); + } - public Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes) { - List<ConvertibleCondition> convertibleConditions = patternConditionProviders.stream() - .map(provider -> provider.provideCondition(analyzeItemsModes)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); + public Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes) { + List<ConvertibleCondition> convertibleConditions = patternConditionProviders.stream() + .map(provider -> provider.provideCondition(analyzeItemsModes)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); - return convertibleConditions.isEmpty() ? - Optional.empty() : - Optional.of(new CompositeFilterCondition(convertibleConditions, Operator.AND)); - } + return convertibleConditions.isEmpty() ? + Optional.empty() : + Optional.of(new CompositeFilterCondition(convertibleConditions, Operator.AND)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AbstractPatternConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AbstractPatternConditionProvider.java index 3019f97266..a1de62a364 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AbstractPatternConditionProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AbstractPatternConditionProvider.java @@ -19,33 +19,33 @@ import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.PatternConditionProvider; -import org.apache.commons.collections4.CollectionUtils; - import java.util.Optional; import java.util.Set; +import org.apache.commons.collections4.CollectionUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractPatternConditionProvider implements PatternConditionProvider { - private final AnalyzeItemsMode analyzeItemsMode; + private final AnalyzeItemsMode analyzeItemsMode; - public AbstractPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode) { - this.analyzeItemsMode = analyzeItemsMode; - } + public AbstractPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode) { + this.analyzeItemsMode = analyzeItemsMode; + } - @Override - public Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes) { - if (isModificationRequired(analyzeItemsModes)) { - return Optional.of(provideCondition()); - } - return Optional.empty(); - } + @Override + public Optional<ConvertibleCondition> provideCondition(Set<AnalyzeItemsMode> analyzeItemsModes) { + if (isModificationRequired(analyzeItemsModes)) { + return Optional.of(provideCondition()); + } + return Optional.empty(); + } - protected boolean isModificationRequired(Set<AnalyzeItemsMode> analyzeItemsModes) { - return CollectionUtils.isNotEmpty(analyzeItemsModes) && analyzeItemsModes.contains(analyzeItemsMode); - } + protected boolean isModificationRequired(Set<AnalyzeItemsMode> analyzeItemsModes) { + return CollectionUtils.isNotEmpty(analyzeItemsModes) && analyzeItemsModes.contains( + analyzeItemsMode); + } - protected abstract ConvertibleCondition provideCondition(); + protected abstract ConvertibleCondition provideCondition(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AutoAnalyzedPatternConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AutoAnalyzedPatternConditionProvider.java index 2a55ac4221..b977dc9c3d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AutoAnalyzedPatternConditionProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/AutoAnalyzedPatternConditionProvider.java @@ -16,25 +16,26 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.IssueCriteriaConstant.CRITERIA_ISSUE_AUTO_ANALYZED; + import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import org.jooq.Operator; -import static com.epam.ta.reportportal.commons.querygen.constant.IssueCriteriaConstant.CRITERIA_ISSUE_AUTO_ANALYZED; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class AutoAnalyzedPatternConditionProvider extends AbstractPatternConditionProvider { - public AutoAnalyzedPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode) { - super(analyzeItemsMode); - } + public AutoAnalyzedPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode) { + super(analyzeItemsMode); + } - @Override - protected ConvertibleCondition provideCondition() { - return FilterCondition.builder().eq(CRITERIA_ISSUE_AUTO_ANALYZED, Boolean.TRUE.toString()).withOperator(Operator.OR).build(); - } + @Override + protected ConvertibleCondition provideCondition() { + return FilterCondition.builder().eq(CRITERIA_ISSUE_AUTO_ANALYZED, Boolean.TRUE.toString()) + .withOperator(Operator.OR).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/IgnoreImmediatePatternAnalysisConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/IgnoreImmediatePatternAnalysisConditionProvider.java new file mode 100644 index 0000000000..a4be042d64 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/IgnoreImmediatePatternAnalysisConditionProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl; + +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_COMPOSITE_SYSTEM_ATTRIBUTE; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.KEY_VALUE_SEPARATOR; + +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +public class IgnoreImmediatePatternAnalysisConditionProvider extends + AbstractPatternConditionProvider { + + private static final String IMMEDIATE_PATTERN_ANALYSIS = "immediatePatternAnalysis"; + + public IgnoreImmediatePatternAnalysisConditionProvider(AnalyzeItemsMode analyzeItemsMode) { + super(analyzeItemsMode); + } + + @Override + protected ConvertibleCondition provideCondition() { + return FilterCondition.builder() + .withCondition(Condition.HAS) + .withNegative(true) + .withSearchCriteria(CRITERIA_COMPOSITE_SYSTEM_ATTRIBUTE) + .withValue(IMMEDIATE_PATTERN_ANALYSIS + KEY_VALUE_SEPARATOR + Boolean.TRUE) + .build(); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ManualPatternConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ManualPatternConditionProvider.java index 2a30426a1c..f6e41bc039 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ManualPatternConditionProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ManualPatternConditionProvider.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.IssueCriteriaConstant.CRITERIA_ISSUE_AUTO_ANALYZED; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_GROUP_ID; + import com.epam.ta.reportportal.commons.querygen.CompositeFilterCondition; import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; @@ -23,33 +26,32 @@ import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.google.common.collect.Lists; -import org.jooq.Operator; - import java.util.function.Supplier; - -import static com.epam.ta.reportportal.commons.querygen.constant.IssueCriteriaConstant.CRITERIA_ISSUE_AUTO_ANALYZED; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_GROUP_ID; +import org.jooq.Operator; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class ManualPatternConditionProvider extends AbstractPatternConditionProvider { - private final Supplier<IssueGroup> issueGroupSupplier; - - public ManualPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode, Supplier<IssueGroup> issueGroupSupplier) { - super(analyzeItemsMode); - this.issueGroupSupplier = issueGroupSupplier; - } - - @Override - protected ConvertibleCondition provideCondition() { - - return new CompositeFilterCondition(Lists.newArrayList(FilterCondition.builder() - .withCondition(Condition.NOT_EQUALS) - .withSearchCriteria(CRITERIA_ISSUE_GROUP_ID) - .withValue(String.valueOf(issueGroupSupplier.get().getId())) - .build(), FilterCondition.builder().eq(CRITERIA_ISSUE_AUTO_ANALYZED, Boolean.FALSE.toString()).build()), Operator.OR); - } + private final Supplier<IssueGroup> issueGroupSupplier; + + public ManualPatternConditionProvider(AnalyzeItemsMode analyzeItemsMode, + Supplier<IssueGroup> issueGroupSupplier) { + super(analyzeItemsMode); + this.issueGroupSupplier = issueGroupSupplier; + } + + @Override + protected ConvertibleCondition provideCondition() { + + return new CompositeFilterCondition(Lists.newArrayList(FilterCondition.builder() + .withCondition(Condition.NOT_EQUALS) + .withSearchCriteria(CRITERIA_ISSUE_GROUP_ID) + .withValue(String.valueOf(issueGroupSupplier.get().getId())) + .build(), + FilterCondition.builder().eq(CRITERIA_ISSUE_AUTO_ANALYZED, Boolean.FALSE.toString()) + .build()), Operator.OR); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ToInvestigatePatternConditionProvider.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ToInvestigatePatternConditionProvider.java index 338932859e..a01a5222b1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ToInvestigatePatternConditionProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/condition/impl/ToInvestigatePatternConditionProvider.java @@ -16,37 +16,37 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_GROUP_ID; + import com.epam.ta.reportportal.commons.querygen.CompositeFilterCondition; import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.google.common.collect.Lists; -import org.jooq.Operator; - import java.util.function.Supplier; - -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_GROUP_ID; +import org.jooq.Operator; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class ToInvestigatePatternConditionProvider extends AbstractPatternConditionProvider { - //TODO ADD OPTIONAL<ISSUEGROUP> - private final Supplier<IssueGroup> issueGroupSupplier; + //TODO ADD OPTIONAL<ISSUEGROUP> + private final Supplier<IssueGroup> issueGroupSupplier; - public ToInvestigatePatternConditionProvider(AnalyzeItemsMode analyzeItemsMode, Supplier<IssueGroup> issueGroupSupplier) { - super(analyzeItemsMode); - this.issueGroupSupplier = issueGroupSupplier; - } + public ToInvestigatePatternConditionProvider(AnalyzeItemsMode analyzeItemsMode, + Supplier<IssueGroup> issueGroupSupplier) { + super(analyzeItemsMode); + this.issueGroupSupplier = issueGroupSupplier; + } - @Override - protected ConvertibleCondition provideCondition() { - return new CompositeFilterCondition(Lists.newArrayList(FilterCondition.builder() - .eq(CRITERIA_ISSUE_GROUP_ID, String.valueOf(issueGroupSupplier.get().getId())) - .build()), Operator.OR); + @Override + protected ConvertibleCondition provideCondition() { + return new CompositeFilterCondition(Lists.newArrayList(FilterCondition.builder() + .eq(CRITERIA_ISSUE_GROUP_ID, String.valueOf(issueGroupSupplier.get().getId())) + .build()), Operator.OR); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/AbstractPatternAnalysisSelector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/AbstractPatternAnalysisSelector.java index 941c153794..3bedcb1756 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/AbstractPatternAnalysisSelector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/AbstractPatternAnalysisSelector.java @@ -1,43 +1,50 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.impl; import com.epam.ta.reportportal.core.analyzer.pattern.selector.PatternAnalysisSelector; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.TestItemRepository; import com.google.common.collect.Sets; -import org.apache.commons.collections4.CollectionUtils; - import java.util.Collection; import java.util.List; import java.util.Set; +import org.apache.commons.collections4.CollectionUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractPatternAnalysisSelector implements PatternAnalysisSelector { - protected final TestItemRepository testItemRepository; + protected final TestItemRepository testItemRepository; + protected final LogService logService; + + public AbstractPatternAnalysisSelector(TestItemRepository testItemRepository, + LogService logService) { + this.testItemRepository = testItemRepository; + this.logService = logService; + } - public AbstractPatternAnalysisSelector(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } + protected abstract List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds); - protected abstract List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds); - protected abstract List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, List<Long> itemsWithNestedSteps); + protected abstract List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, + List<Long> itemsWithNestedSteps); - @Override - public List<Long> selectItemsByPattern(Long launchId, Collection<Long> itemIds, String pattern) { - final Set<Long> sourceIds = Sets.newHashSet(itemIds); - final List<Long> itemsWithMatchedLogs = getItemsWithMatches(pattern, sourceIds); + @Override + public List<Long> selectItemsByPattern(Long launchId, Collection<Long> itemIds, String pattern) { + final Set<Long> sourceIds = Sets.newHashSet(itemIds); + final List<Long> itemsWithMatchedLogs = getItemsWithMatches(pattern, sourceIds); - sourceIds.removeAll(itemsWithMatchedLogs); + itemsWithMatchedLogs.forEach(sourceIds::remove); - if (CollectionUtils.isNotEmpty(sourceIds)) { - final List<Long> itemsWithNestedSteps = testItemRepository.selectIdsByHasDescendants(sourceIds); - if (CollectionUtils.isNotEmpty(itemsWithNestedSteps)) { - final List<Long> nestedStepsMatches = getItemsWithNestedStepsMatches(launchId, pattern, itemsWithNestedSteps); - itemsWithMatchedLogs.addAll(nestedStepsMatches); - } - } + if (CollectionUtils.isNotEmpty(sourceIds)) { + final List<Long> itemsWithNestedSteps = testItemRepository.selectIdsByHasDescendants( + sourceIds); + if (CollectionUtils.isNotEmpty(itemsWithNestedSteps)) { + final List<Long> nestedStepsMatches = getItemsWithNestedStepsMatches(launchId, pattern, + itemsWithNestedSteps); + itemsWithMatchedLogs.addAll(nestedStepsMatches); + } + } - return itemsWithMatchedLogs; - } + return itemsWithMatchedLogs; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/RegexPatternAnalysisSelector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/RegexPatternAnalysisSelector.java index de2d1e0ef8..e8df7b1e5e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/RegexPatternAnalysisSelector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/RegexPatternAnalysisSelector.java @@ -16,13 +16,13 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.impl; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -30,22 +30,24 @@ @Service public class RegexPatternAnalysisSelector extends AbstractPatternAnalysisSelector { - @Autowired - public RegexPatternAnalysisSelector(TestItemRepository testItemRepository) { - super(testItemRepository); - } + @Autowired + public RegexPatternAnalysisSelector(TestItemRepository testItemRepository, + LogService logService) { + super(testItemRepository, logService); + } - @Override - protected List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds) { - return testItemRepository.selectIdsByRegexLogMessage(itemIds, LogLevel.ERROR_INT, pattern); - } + @Override + protected List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds) { + return logService.selectTestItemIdsByRegexLogMessage(itemIds, LogLevel.ERROR_INT, pattern); + } - @Override - protected List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, List<Long> itemsWithNestedSteps) { - return testItemRepository.selectIdsUnderByRegexLogMessage(launchId, - itemsWithNestedSteps, - LogLevel.ERROR_INT, - pattern - ); - } + @Override + protected List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, + List<Long> itemsWithNestedSteps) { + return logService.selectTestItemIdsUnderByRegexLogMessage(launchId, + itemsWithNestedSteps, + LogLevel.ERROR_INT, + pattern + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/StringPartPatternAnalysisSelector.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/StringPartPatternAnalysisSelector.java index 89cee55275..88067b6c1e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/StringPartPatternAnalysisSelector.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/selector/impl/StringPartPatternAnalysisSelector.java @@ -16,13 +16,13 @@ package com.epam.ta.reportportal.core.analyzer.pattern.selector.impl; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -30,25 +30,27 @@ @Service public class StringPartPatternAnalysisSelector extends AbstractPatternAnalysisSelector { - @Autowired - public StringPartPatternAnalysisSelector(TestItemRepository testItemRepository) { - super(testItemRepository); - } + @Autowired + public StringPartPatternAnalysisSelector(TestItemRepository testItemRepository, + LogService logService) { + super(testItemRepository, logService); + } - @Override - protected List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds) { - return testItemRepository.selectIdsByStringLogMessage(itemIds, - LogLevel.ERROR_INT, - pattern - ); - } + @Override + protected List<Long> getItemsWithMatches(String pattern, Set<Long> itemIds) { + return logService.selectTestItemIdsByStringLogMessage(itemIds, + LogLevel.ERROR_INT, + pattern + ); + } - @Override - protected List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, List<Long> itemsWithNestedSteps) { - return testItemRepository.selectIdsUnderByStringLogMessage(launchId, - itemsWithNestedSteps, - LogLevel.ERROR_INT, - pattern - ); - } + @Override + protected List<Long> getItemsWithNestedStepsMatches(Long launchId, String pattern, + List<Long> itemsWithNestedSteps) { + return logService.selectTestItemIdsUnderByStringLogMessage(launchId, + itemsWithNestedSteps, + LogLevel.ERROR_INT, + pattern + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/CreatePatternTemplateHandler.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/CreatePatternTemplateHandler.java similarity index 58% rename from src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/CreatePatternTemplateHandler.java rename to src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/CreatePatternTemplateHandler.java index 488e273e89..340e80c187 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/CreatePatternTemplateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/CreatePatternTemplateHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 EPAM Systems + * Copyright 2023 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.epam.ta.reportportal.core.analyzer.pattern; +package com.epam.ta.reportportal.core.analyzer.pattern.service; import com.epam.ta.reportportal.entity.pattern.PatternTemplate; import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; @@ -24,12 +24,14 @@ */ public interface CreatePatternTemplateHandler { - /** - * Create {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} entity for specified {@link com.epam.ta.reportportal.entity.project.Project} - * - * @param projectId {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate#projectId} - * @param createPatternTemplateRQ {@link CreatePatternTemplateRQ} - * @return {@link java.util.regex.Pattern} - */ - PatternTemplate createPatternTemplate(Long projectId, CreatePatternTemplateRQ createPatternTemplateRQ); + /** + * Create {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} entity for specified + * {@link com.epam.ta.reportportal.entity.project.Project} + * + * @param projectId {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} + * @param createPatternTemplateRQ {@link CreatePatternTemplateRQ} + * @return {@link java.util.regex.Pattern} + */ + PatternTemplate createPatternTemplate(Long projectId, + CreatePatternTemplateRQ createPatternTemplateRQ); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/LaunchPatternAnalyzer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/LaunchPatternAnalyzer.java new file mode 100644 index 0000000000..a0751a0d8d --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/LaunchPatternAnalyzer.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.service; + +import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.launch.Launch; +import java.util.Set; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +public interface LaunchPatternAnalyzer { + + /** + * Analyze by {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} all + * {@link com.epam.ta.reportportal.entity.log.Log} of + * {@link com.epam.ta.reportportal.entity.item.TestItem} with + * {@link TestItemIssueGroup#TO_INVESTIGATE} for + * {@link com.epam.ta.reportportal.entity.launch.Launch} with provided ID. Every matched + * {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} will be attached to the + * {@link com.epam.ta.reportportal.entity.item.TestItem} using + * {@link com.epam.ta.reportportal.entity.pattern.PatternTemplateTestItem} relation + * + * @param launch {@link com.epam.ta.reportportal.entity.launch.Launch}, which + * {@link com.epam.ta.reportportal.entity.item.TestItem} should be analyzed + * @param analyzeModes {@link AnalyzeItemsMode} to modify + * {@link com.epam.ta.reportportal.entity.item.TestItem} query conditions + */ + void analyzeLaunch(Launch launch, Set<AnalyzeItemsMode> analyzeModes); +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreatePatternTemplateHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreatePatternTemplateHandlerImpl.java similarity index 54% rename from src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreatePatternTemplateHandlerImpl.java rename to src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreatePatternTemplateHandlerImpl.java index e95f0dc070..ccac8df33b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreatePatternTemplateHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreatePatternTemplateHandlerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 EPAM Systems + * Copyright 2023 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.epam.ta.reportportal.core.analyzer.pattern.impl; +package com.epam.ta.reportportal.core.analyzer.pattern.service.impl; + +import static com.epam.ta.reportportal.commons.Predicates.equalTo; import com.epam.ta.reportportal.commons.validation.BusinessRule; -import com.epam.ta.reportportal.core.analyzer.pattern.CreatePatternTemplateHandler; +import com.epam.ta.reportportal.core.analyzer.pattern.service.CreatePatternTemplateHandler; import com.epam.ta.reportportal.dao.PatternTemplateRepository; import com.epam.ta.reportportal.entity.pattern.PatternTemplate; import com.epam.ta.reportportal.ws.converter.builders.PatternTemplateBuilder; @@ -25,29 +27,31 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public class CreatePatternTemplateHandlerImpl implements CreatePatternTemplateHandler { - protected final PatternTemplateRepository patternTemplateRepository; + protected final PatternTemplateRepository patternTemplateRepository; - @Autowired - public CreatePatternTemplateHandlerImpl(PatternTemplateRepository patternTemplateRepository) { - this.patternTemplateRepository = patternTemplateRepository; - } + @Autowired + public CreatePatternTemplateHandlerImpl(PatternTemplateRepository patternTemplateRepository) { + this.patternTemplateRepository = patternTemplateRepository; + } - @Override - public PatternTemplate createPatternTemplate(Long projectId, CreatePatternTemplateRQ createPatternTemplateRQ) { - final String name = StringUtils.trim(createPatternTemplateRQ.getName()); - BusinessRule.expect(patternTemplateRepository.existsByProjectIdAndNameIgnoreCase(projectId, name), equalTo(false)) - .verify(ErrorType.RESOURCE_ALREADY_EXISTS, name); - PatternTemplate patternTemplate = new PatternTemplateBuilder().withCreateRequest(createPatternTemplateRQ) - .withName(name) - .withProjectId(projectId) - .get(); - return patternTemplateRepository.save(patternTemplate); - } + @Override + public PatternTemplate createPatternTemplate(Long projectId, + CreatePatternTemplateRQ createPatternTemplateRQ) { + final String name = StringUtils.trim(createPatternTemplateRQ.getName()); + BusinessRule.expect( + patternTemplateRepository.existsByProjectIdAndNameIgnoreCase(projectId, name), + equalTo(false)) + .verify(ErrorType.RESOURCE_ALREADY_EXISTS, name); + PatternTemplate patternTemplate = new PatternTemplateBuilder().withCreateRequest( + createPatternTemplateRQ) + .withName(name) + .withProjectId(projectId) + .get(); + return patternTemplateRepository.save(patternTemplate); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreateRegexPatternTemplateHandler.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreateRegexPatternTemplateHandler.java similarity index 61% rename from src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreateRegexPatternTemplateHandler.java rename to src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreateRegexPatternTemplateHandler.java index 938bf3a3f8..6474044932 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/impl/CreateRegexPatternTemplateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/CreateRegexPatternTemplateHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 EPAM Systems + * Copyright 2023 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.epam.ta.reportportal.core.analyzer.pattern.impl; +package com.epam.ta.reportportal.core.analyzer.pattern.service.impl; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.dao.PatternTemplateRepository; @@ -22,31 +22,32 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; +import javax.persistence.PersistenceException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.persistence.PersistenceException; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class CreateRegexPatternTemplateHandler extends CreatePatternTemplateHandlerImpl { - @Autowired - public CreateRegexPatternTemplateHandler(PatternTemplateRepository patternTemplateRepository) { - super(patternTemplateRepository); - } + @Autowired + public CreateRegexPatternTemplateHandler(PatternTemplateRepository patternTemplateRepository) { + super(patternTemplateRepository); + } - @Override - public PatternTemplate createPatternTemplate(Long projectId, CreatePatternTemplateRQ createPatternTemplateRQ) { - try { - patternTemplateRepository.validateRegex(createPatternTemplateRQ.getValue()); - } catch (PersistenceException ex) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Provided regex pattern - '{}' is invalid", createPatternTemplateRQ.getValue()).get() - ); - } - return super.createPatternTemplate(projectId, createPatternTemplateRQ); - } + @Override + public PatternTemplate createPatternTemplate(Long projectId, + CreatePatternTemplateRQ createPatternTemplateRQ) { + try { + patternTemplateRepository.validateRegex(createPatternTemplateRQ.getValue()); + } catch (PersistenceException ex) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Provided regex pattern - '{}' is invalid", + createPatternTemplateRQ.getValue()).get() + ); + } + return super.createPatternTemplate(projectId, createPatternTemplateRQ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/LaunchPatternAnalyzerImpl.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/LaunchPatternAnalyzerImpl.java new file mode 100644 index 0000000000..c4bb9a1643 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/pattern/service/impl/LaunchPatternAnalyzerImpl.java @@ -0,0 +1,119 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.analyzer.pattern.service.impl; + +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.PATTERN_ANALYZER_KEY; + +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.validation.BusinessRule; +import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; +import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; +import com.epam.ta.reportportal.core.analyzer.pattern.handler.ItemsPatternsAnalyzer; +import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.PatternConditionProviderChain; +import com.epam.ta.reportportal.core.analyzer.pattern.service.LaunchPatternAnalyzer; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.epam.ta.reportportal.entity.launch.Launch; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import org.apache.commons.collections4.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +@Service +public class LaunchPatternAnalyzerImpl implements LaunchPatternAnalyzer { + + public static final Logger LOGGER = LoggerFactory.getLogger(LaunchPatternAnalyzerImpl.class); + + private final Integer batchSize; + + private final TestItemRepository testItemRepository; + private final PatternConditionProviderChain patternConditionProviderChain; + + private final AnalyzerStatusCache analyzerStatusCache; + + private final ItemsPatternsAnalyzer itemsPatternsAnalyzer; + + @Autowired + public LaunchPatternAnalyzerImpl( + @Value("${rp.environment.variable.pattern-analysis.batch-size}") Integer batchSize, + TestItemRepository testItemRepository, + PatternConditionProviderChain patternConditionProviderChain, + AnalyzerStatusCache analyzerStatusCache, ItemsPatternsAnalyzer itemsPatternsAnalyzer) { + this.batchSize = batchSize; + this.testItemRepository = testItemRepository; + this.patternConditionProviderChain = patternConditionProviderChain; + this.analyzerStatusCache = analyzerStatusCache; + this.itemsPatternsAnalyzer = itemsPatternsAnalyzer; + } + + @Override + public void analyzeLaunch(Launch launch, Set<AnalyzeItemsMode> analyzeModes) { + BusinessRule.expect(analyzerStatusCache.getStartedAnalyzers(launch.getId()), + not(started -> started.contains(PATTERN_ANALYZER_KEY))) + .verify(ErrorType.PATTERN_ANALYSIS_ERROR, "Pattern analysis is still in progress."); + analyzerStatusCache.analyzeStarted(PATTERN_ANALYZER_KEY, launch.getId(), launch.getProjectId()); + try { + analyze(launch, buildItemsCondition(analyzeModes)); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + analyzerStatusCache.analyzeFinished(PATTERN_ANALYZER_KEY, launch.getId()); + } + } + + private void analyze(Launch launch, ConvertibleCondition itemCondition) { + final Filter filter = createItemFilter(itemCondition); + int offset = 0; + List<Long> itemIds = testItemRepository.selectIdsByFilter(launch.getId(), filter, batchSize, + offset); + while (CollectionUtils.isNotEmpty(itemIds)) { + itemsPatternsAnalyzer.analyze(launch.getProjectId(), launch.getId(), itemIds); + offset += itemIds.size(); + itemIds = testItemRepository.selectIdsByFilter(launch.getId(), filter, batchSize, offset); + } + notifyAnalysisFinished(launch.getProjectId(), launch.getId()); + } + + private void notifyAnalysisFinished(long projectId, long launchId) { + itemsPatternsAnalyzer.analyze(projectId, launchId, Collections.emptyList()); + } + + private ConvertibleCondition buildItemsCondition(Set<AnalyzeItemsMode> analyzeModes) { + return patternConditionProviderChain.provideCondition(analyzeModes) + .orElseThrow(() -> new ReportPortalException(ErrorType.PATTERN_ANALYSIS_ERROR, + "Unable to resolve item search condition")); + } + + private Filter createItemFilter(ConvertibleCondition commonItemCondition) { + return Filter.builder() + .withTarget(TestItem.class) + .withCondition(commonItemCondition) + .build(); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/AbstractLaunchAnalysisStrategy.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/AbstractLaunchAnalysisStrategy.java index d7ea28bfc6..4a58a81262 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/AbstractLaunchAnalysisStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/AbstractLaunchAnalysisStrategy.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.analyzer.strategy; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -23,35 +28,33 @@ import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.launch.Launch; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractLaunchAnalysisStrategy implements LaunchAnalysisStrategy { - protected final ProjectRepository projectRepository; - protected final LaunchRepository launchRepository; + protected final ProjectRepository projectRepository; + protected final LaunchRepository launchRepository; - protected AbstractLaunchAnalysisStrategy(ProjectRepository projectRepository, LaunchRepository launchRepository) { - this.projectRepository = projectRepository; - this.launchRepository = launchRepository; - } + protected AbstractLaunchAnalysisStrategy(ProjectRepository projectRepository, + LaunchRepository launchRepository) { + this.projectRepository = projectRepository; + this.launchRepository = launchRepository; + } - protected void validateLaunch(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { + protected void validateLaunch(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - Suppliers.formattedSupplier("Launch with ID '{}' is not under '{}' project.", - launch.getId(), - projectDetails.getProjectName() - ) - ); + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + Suppliers.formattedSupplier("Launch with ID '{}' is not under '{}' project.", + launch.getId(), + projectDetails.getProjectName() + ) + ); - /* Do not process debug launches */ - expect(launch.getMode(), equalTo(LaunchModeEnum.DEFAULT)).verify(INCORRECT_REQUEST, "Cannot analyze launches in debug mode."); + /* Do not process debug launches */ + expect(launch.getMode(), equalTo(LaunchModeEnum.DEFAULT)).verify(INCORRECT_REQUEST, + "Cannot analyze launches in debug mode."); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAnalysisStrategy.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAnalysisStrategy.java index 4a2b54ce4a..38dec9a63a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAnalysisStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAnalysisStrategy.java @@ -24,5 +24,6 @@ */ public interface LaunchAnalysisStrategy { - void analyze(AnalyzeLaunchRQ analyzeLaunchRequest, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + void analyze(AnalyzeLaunchRQ analyzeLaunchRequest, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategy.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategy.java index 87bce46178..55213d6bbc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategy.java @@ -16,10 +16,15 @@ package com.epam.ta.reportportal.core.analyzer.strategy; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; +import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.AnalyzeMode; @@ -28,15 +33,11 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -44,50 +45,54 @@ @Service public class LaunchAutoAnalysisStrategy extends AbstractLaunchAnalysisStrategy { - private final LaunchAutoAnalysisStarter manualAnalysisStarter; - - @Autowired - public LaunchAutoAnalysisStrategy(ProjectRepository projectRepository, LaunchRepository launchRepository, - LaunchAutoAnalysisStarter manualAnalysisStarter) { - super(projectRepository, launchRepository); - this.manualAnalysisStarter = manualAnalysisStarter; - } - - public void analyze(AnalyzeLaunchRQ analyzeRQ, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - - final AnalyzeMode analyzeMode = AnalyzeMode.fromString(analyzeRQ.getAnalyzerHistoryMode()) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, analyzeRQ.getAnalyzerHistoryMode())); - final Set<AnalyzeItemsMode> analyzeItemsModes = getAnalyzeItemsModes(analyzeRQ); - - if (analyzeItemsModes.isEmpty()) { - return; - } - - Launch launch = launchRepository.findById(analyzeRQ.getLaunchId()) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, analyzeRQ.getLaunchId())); - validateLaunch(launch, projectDetails); - - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectId())); - - AnalyzerConfig analyzerConfig = getAnalyzerConfig(project); - analyzerConfig.setAnalyzerMode(analyzeMode.getValue()); - - final StartLaunchAutoAnalysisConfig autoAnalysisConfig = StartLaunchAutoAnalysisConfig.of( - launch.getId(), - analyzerConfig, - analyzeItemsModes, - user - ); - - manualAnalysisStarter.start(autoAnalysisConfig); - } - - private LinkedHashSet<AnalyzeItemsMode> getAnalyzeItemsModes(AnalyzeLaunchRQ analyzeRQ) { - return analyzeRQ.getAnalyzeItemsModes() - .stream() - .map(AnalyzeItemsMode::fromString) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } + private final LaunchAutoAnalysisStarter manualAnalysisStarter; + + @Autowired + public LaunchAutoAnalysisStrategy(ProjectRepository projectRepository, + LaunchRepository launchRepository, + LaunchAutoAnalysisStarter manualAnalysisStarter) { + super(projectRepository, launchRepository); + this.manualAnalysisStarter = manualAnalysisStarter; + } + + public void analyze(AnalyzeLaunchRQ analyzeRQ, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + + final AnalyzeMode analyzeMode = AnalyzeMode.fromString(analyzeRQ.getAnalyzerHistoryMode()) + .orElseThrow( + () -> new ReportPortalException(BAD_REQUEST_ERROR, analyzeRQ.getAnalyzerHistoryMode())); + final Set<AnalyzeItemsMode> analyzeItemsModes = getAnalyzeItemsModes(analyzeRQ); + + if (analyzeItemsModes.isEmpty()) { + return; + } + + Launch launch = launchRepository.findById(analyzeRQ.getLaunchId()) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, analyzeRQ.getLaunchId())); + validateLaunch(launch, projectDetails); + + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow( + () -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectId())); + + AnalyzerConfig analyzerConfig = getAnalyzerConfig(project); + analyzerConfig.setAnalyzerMode(analyzeMode.getValue()); + + final StartLaunchAutoAnalysisConfig autoAnalysisConfig = StartLaunchAutoAnalysisConfig.of( + launch.getId(), + analyzerConfig, + analyzeItemsModes, + user + ); + + manualAnalysisStarter.start(autoAnalysisConfig); + } + + private LinkedHashSet<AnalyzeItemsMode> getAnalyzeItemsModes(AnalyzeLaunchRQ analyzeRQ) { + return analyzeRQ.getAnalyzeItemsModes() + .stream() + .map(AnalyzeItemsMode::fromString) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategy.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategy.java index e65263b392..91ecb49023 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategy.java @@ -16,54 +16,56 @@ package com.epam.ta.reportportal.core.analyzer.strategy; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.core.analyzer.pattern.PatternAnalyzer; +import com.epam.ta.reportportal.core.analyzer.pattern.service.LaunchPatternAnalyzer; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; +import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Set; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; -import static java.util.stream.Collectors.toSet; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class LaunchPatternAnalysisStrategy extends AbstractLaunchAnalysisStrategy { - private final PatternAnalyzer patternAnalyzer; + private final LaunchPatternAnalyzer launchPatternAnalyzer; - @Autowired - public LaunchPatternAnalysisStrategy(ProjectRepository projectRepository, LaunchRepository launchRepository, - PatternAnalyzer patternAnalyzer) { - super(projectRepository, launchRepository); - this.patternAnalyzer = patternAnalyzer; - } + @Autowired + public LaunchPatternAnalysisStrategy(ProjectRepository projectRepository, + LaunchRepository launchRepository, + LaunchPatternAnalyzer launchPatternAnalyzer) { + super(projectRepository, launchRepository); + this.launchPatternAnalyzer = launchPatternAnalyzer; + } - public void analyze(AnalyzeLaunchRQ analyzeRQ, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + public void analyze(AnalyzeLaunchRQ analyzeRQ, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { - Set<AnalyzeItemsMode> analyzeItemsModes = analyzeRQ.getAnalyzeItemsModes() - .stream() - .map(AnalyzeItemsMode::fromString) - .collect(toSet()); + Set<AnalyzeItemsMode> analyzeItemsModes = analyzeRQ.getAnalyzeItemsModes() + .stream() + .map(AnalyzeItemsMode::fromString) + .collect(toSet()); - expect(analyzeItemsModes, CollectionUtils::isNotEmpty).verify(ErrorType.PATTERN_ANALYSIS_ERROR, "No analyze item mode specified."); + expect(analyzeItemsModes, CollectionUtils::isNotEmpty).verify(ErrorType.PATTERN_ANALYSIS_ERROR, + "No analyze item mode specified."); - Launch launch = launchRepository.findById(analyzeRQ.getLaunchId()) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, analyzeRQ.getLaunchId())); - validateLaunch(launch, projectDetails); + Launch launch = launchRepository.findById(analyzeRQ.getLaunchId()) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, analyzeRQ.getLaunchId())); + validateLaunch(launch, projectDetails); - patternAnalyzer.analyzeTestItems(launch, analyzeItemsModes); + launchPatternAnalyzer.analyzeLaunch(launch, analyzeItemsModes); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/annotation/Datastore.java b/src/main/java/com/epam/ta/reportportal/core/annotation/Datastore.java index 6805bcae9a..f51801cfb3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/annotation/Datastore.java +++ b/src/main/java/com/epam/ta/reportportal/core/annotation/Datastore.java @@ -16,15 +16,16 @@ package com.epam.ta.reportportal.core.annotation; -import javax.inject.Qualifier; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.inject.Qualifier; @Target({ElementType.FIELD, ElementType.METHOD, - ElementType.TYPE, ElementType.PARAMETER}) + ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Datastore { + } diff --git a/src/main/java/com/epam/ta/reportportal/core/annotation/Regular.java b/src/main/java/com/epam/ta/reportportal/core/annotation/Regular.java index cbeb7e3810..c67a5fda38 100644 --- a/src/main/java/com/epam/ta/reportportal/core/annotation/Regular.java +++ b/src/main/java/com/epam/ta/reportportal/core/annotation/Regular.java @@ -16,15 +16,16 @@ package com.epam.ta.reportportal.core.annotation; -import javax.inject.Qualifier; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import javax.inject.Qualifier; @Target({ElementType.FIELD, ElementType.METHOD, - ElementType.TYPE, ElementType.PARAMETER}) + ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Qualifier public @interface Regular { + } diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/CreateTicketHandler.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/CreateTicketHandler.java index e41470bb4d..04aae849fb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/CreateTicketHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/CreateTicketHandler.java @@ -28,15 +28,16 @@ public interface CreateTicketHandler { - /** - * Post ticket to external system. - * - * @param postTicketRQ Request Data - * @param integrationId Integration id - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user User - * @return Found Ticket - */ - Ticket createIssue(PostTicketRQ postTicketRQ, Long integrationId, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Post ticket to external system. + * + * @param postTicketRQ Request Data + * @param integrationId Integration id + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user User + * @return Found Ticket + */ + Ticket createIssue(PostTicketRQ postTicketRQ, Long integrationId, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetBugTrackingSystemHandler.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetBugTrackingSystemHandler.java index edd11ced22..3221010040 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetBugTrackingSystemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetBugTrackingSystemHandler.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.integration.Integration; - import java.util.Optional; /** @@ -26,11 +25,13 @@ */ public interface GetBugTrackingSystemHandler { - Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, String url, String btsProject); + Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, + String url, String btsProject); - Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, Long integrationId); + Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, + Long integrationId); - Optional<Integration> getEnabledGlobalIntegration(String url, String btsProject); + Optional<Integration> getEnabledGlobalIntegration(String url, String btsProject); - Optional<Integration> getEnabledGlobalIntegration(Long integrationId); + Optional<Integration> getEnabledGlobalIntegration(Long integrationId); } diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetTicketHandler.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetTicketHandler.java index 3c21fe5f2d..bec0596295 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetTicketHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/GetTicketHandler.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.ws.model.externalsystem.PostFormField; import com.epam.ta.reportportal.ws.model.externalsystem.Ticket; - import java.util.List; /** @@ -29,38 +28,41 @@ */ public interface GetTicketHandler { - /** - * Get ticket from specified external system by id.<br> - * <b>Note: resulting object returned from cache.</b> - * - * @param ticketId Ticket ID - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param btsUrl URL of the bug tracking system to get ticket from - * @param btsProject Project in the bug tracking system to get ticket from - * @return Ticket - */ - Ticket getTicket(String ticketId, String btsUrl, String btsProject, ReportPortalUser.ProjectDetails projectDetails); + /** + * Get ticket from specified external system by id.<br> + * <b>Note: resulting object returned from cache.</b> + * + * @param ticketId Ticket ID + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param btsUrl URL of the bug tracking system to get ticket from + * @param btsProject Project in the bug tracking system to get ticket from + * @return Ticket + */ + Ticket getTicket(String ticketId, String btsUrl, String btsProject, + ReportPortalUser.ProjectDetails projectDetails); - /** - * Get set of fields of external system to submit a ticket - * - * @param ticketType Ticket Type - * @param integrationId Integration id - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @return Found fields - */ - List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId, ReportPortalUser.ProjectDetails projectDetails); + /** + * Get set of fields of external system to submit a ticket + * + * @param ticketType Ticket Type + * @param integrationId Integration id + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @return Found fields + */ + List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId, + ReportPortalUser.ProjectDetails projectDetails); - List<PostFormField> getSubmitTicketFields(String issueType, Long integrationId); + List<PostFormField> getSubmitTicketFields(String issueType, Long integrationId); - /** - * Get allowable issue types - * - * @param integrationId Integration id - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @return Fields - */ - List<String> getAllowableIssueTypes(Long integrationId, ReportPortalUser.ProjectDetails projectDetails); + /** + * Get allowable issue types + * + * @param integrationId Integration id + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @return Fields + */ + List<String> getAllowableIssueTypes(Long integrationId, + ReportPortalUser.ProjectDetails projectDetails); - List<String> getAllowableIssueTypes(Long integrationId); + List<String> getAllowableIssueTypes(Long integrationId); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/CreateTicketHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/CreateTicketHandlerImpl.java index f8e9b8bb7e..ac925d43f3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/CreateTicketHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/CreateTicketHandlerImpl.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.bts.handler.impl; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_POST_TICKET; +import static java.util.Optional.ofNullable; + import com.epam.reportportal.extension.bugtracking.BtsConstants; import com.epam.reportportal.extension.bugtracking.BtsExtension; import com.epam.ta.reportportal.commons.ReportPortalUser; @@ -32,19 +39,11 @@ import com.epam.ta.reportportal.ws.model.activity.TestItemActivityResource; import com.epam.ta.reportportal.ws.model.externalsystem.PostTicketRQ; import com.epam.ta.reportportal.ws.model.externalsystem.Ticket; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.List; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.notNull; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; -import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_POST_TICKET; -import static java.util.Optional.ofNullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * Default implementation of {@link CreateTicketHandler} @@ -55,60 +54,67 @@ @Service public class CreateTicketHandlerImpl implements CreateTicketHandler { - private final TestItemRepository testItemRepository; - private final MessageBus messageBus; - private final PluginBox pluginBox; - private final GetIntegrationHandler getIntegrationHandler; + private final TestItemRepository testItemRepository; + private final MessageBus messageBus; + private final PluginBox pluginBox; + private final GetIntegrationHandler getIntegrationHandler; - @Autowired - public CreateTicketHandlerImpl(TestItemRepository testItemRepository, PluginBox pluginBox, MessageBus messageBus, - GetIntegrationHandler getIntegrationHandler) { - this.testItemRepository = testItemRepository; - this.pluginBox = pluginBox; - this.messageBus = messageBus; - this.getIntegrationHandler = getIntegrationHandler; - } + @Autowired + public CreateTicketHandlerImpl(TestItemRepository testItemRepository, PluginBox pluginBox, + MessageBus messageBus, + GetIntegrationHandler getIntegrationHandler) { + this.testItemRepository = testItemRepository; + this.pluginBox = pluginBox; + this.messageBus = messageBus; + this.getIntegrationHandler = getIntegrationHandler; + } - @Override - public Ticket createIssue(PostTicketRQ postTicketRQ, Long integrationId, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - validatePostTicketRQ(postTicketRQ); + @Override + public Ticket createIssue(PostTicketRQ postTicketRQ, Long integrationId, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + validatePostTicketRQ(postTicketRQ); - List<TestItem> testItems = ofNullable(postTicketRQ.getBackLinks()).map(links -> testItemRepository.findAllById(links.keySet())) - .orElseGet(Collections::emptyList); - List<TestItemActivityResource> before = testItems.stream() - .map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) - .collect(Collectors.toList()); + List<TestItem> testItems = ofNullable(postTicketRQ.getBackLinks()).map( + links -> testItemRepository.findAllById(links.keySet())) + .orElseGet(Collections::emptyList); + List<TestItemActivityResource> before = testItems.stream() + .map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) + .collect(Collectors.toList()); - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, integrationId); + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, + integrationId); - expect(BtsConstants.DEFECT_FORM_FIELDS.getParam(integration.getParams()), notNull()).verify(BAD_REQUEST_ERROR, - "There aren't any submitted BTS fields!" - ); + expect(BtsConstants.DEFECT_FORM_FIELDS.getParam(integration.getParams()), notNull()).verify( + BAD_REQUEST_ERROR, + "There aren't any submitted BTS fields!" + ); - BtsExtension btsExtension = pluginBox.getInstance(integration.getType().getName(), BtsExtension.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("BugTracking plugin for {} isn't installed", - BtsConstants.PROJECT.getParam(integration.getParams()) - ).get() - )); + BtsExtension btsExtension = pluginBox.getInstance(integration.getType().getName(), + BtsExtension.class) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("BugTracking plugin for {} isn't installed", + BtsConstants.PROJECT.getParam(integration.getParams()) + ).get() + )); - Ticket ticket = btsExtension.submitTicket(postTicketRQ, integration); + Ticket ticket = btsExtension.submitTicket(postTicketRQ, integration); - before.forEach(it -> messageBus.publishActivity(new TicketPostedEvent(ticket, user.getUserId(), user.getUsername(), it))); - return ticket; - } + before.forEach(it -> messageBus.publishActivity( + new TicketPostedEvent(ticket, user.getUserId(), user.getUsername(), it))); + return ticket; + } - /** - * Additional validations to {@link PostTicketRQ}. - * - * @param postTicketRQ - */ - private void validatePostTicketRQ(PostTicketRQ postTicketRQ) { - if (postTicketRQ.getIsIncludeLogs() || postTicketRQ.getIsIncludeScreenshots()) { - expect(postTicketRQ.getBackLinks(), notNull()).verify(UNABLE_POST_TICKET, - "Test item id should be specified, when logs required in ticket description." - ); - } - } + /** + * Additional validations to {@link PostTicketRQ}. + * + * @param postTicketRQ + */ + private void validatePostTicketRQ(PostTicketRQ postTicketRQ) { + if (postTicketRQ.getIsIncludeLogs() || postTicketRQ.getIsIncludeScreenshots()) { + expect(postTicketRQ.getBackLinks(), notNull()).verify(UNABLE_POST_TICKET, + "Test item id should be specified, when logs required in ticket description." + ); + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetBugTrackingSystemHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetBugTrackingSystemHandlerImpl.java index 8ca31f18fd..8557f75b7f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetBugTrackingSystemHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetBugTrackingSystemHandlerImpl.java @@ -24,67 +24,72 @@ import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Optional; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class GetBugTrackingSystemHandlerImpl implements GetBugTrackingSystemHandler { - private final IntegrationRepository integrationRepository; - - @Autowired - public GetBugTrackingSystemHandlerImpl(IntegrationRepository integrationRepository) { - this.integrationRepository = integrationRepository; - } - - @Override - public Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, String url, - String btsProject) { - - Optional<Integration> integration = integrationRepository.findProjectBtsByUrlAndLinkedProject(url, - btsProject, - projectDetails.getProjectId() - ); - integration.ifPresent(this::validateBtsIntegration); - return integration; - } - - @Override - public Optional<Integration> getEnabledProjectIntegration(ReportPortalUser.ProjectDetails projectDetails, Long integrationId) { - - Optional<Integration> integration = integrationRepository.findByIdAndProjectId(integrationId, projectDetails.getProjectId()); - integration.ifPresent(this::validateBtsIntegration); - return integration; - } - - @Override - public Optional<Integration> getEnabledGlobalIntegration(String url, String btsProject) { - - Optional<Integration> integration = integrationRepository.findGlobalBtsByUrlAndLinkedProject(url, btsProject); - integration.ifPresent(this::validateBtsIntegration); - return integration; - } - - @Override - public Optional<Integration> getEnabledGlobalIntegration(Long integrationId) { - - Optional<Integration> integration = integrationRepository.findGlobalById(integrationId); - integration.ifPresent(this::validateBtsIntegration); - return integration; - } - - private void validateBtsIntegration(Integration integration) { - - BusinessRule.expect(integration, it -> IntegrationGroupEnum.BTS == it.getType().getIntegrationGroup()) - .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, Suppliers.formattedSupplier( - "Unable to test connection to the integration with type - '{}', Allowed type(es): '{}'", - integration.getType().getIntegrationGroup(), - IntegrationGroupEnum.BTS - )); - } + private final IntegrationRepository integrationRepository; + + @Autowired + public GetBugTrackingSystemHandlerImpl(IntegrationRepository integrationRepository) { + this.integrationRepository = integrationRepository; + } + + @Override + public Optional<Integration> getEnabledProjectIntegration( + ReportPortalUser.ProjectDetails projectDetails, String url, + String btsProject) { + + Optional<Integration> integration = integrationRepository.findProjectBtsByUrlAndLinkedProject( + url, + btsProject, + projectDetails.getProjectId() + ); + integration.ifPresent(this::validateBtsIntegration); + return integration; + } + + @Override + public Optional<Integration> getEnabledProjectIntegration( + ReportPortalUser.ProjectDetails projectDetails, Long integrationId) { + + Optional<Integration> integration = integrationRepository.findByIdAndProjectId(integrationId, + projectDetails.getProjectId()); + integration.ifPresent(this::validateBtsIntegration); + return integration; + } + + @Override + public Optional<Integration> getEnabledGlobalIntegration(String url, String btsProject) { + + Optional<Integration> integration = integrationRepository.findGlobalBtsByUrlAndLinkedProject( + url, btsProject); + integration.ifPresent(this::validateBtsIntegration); + return integration; + } + + @Override + public Optional<Integration> getEnabledGlobalIntegration(Long integrationId) { + + Optional<Integration> integration = integrationRepository.findGlobalById(integrationId); + integration.ifPresent(this::validateBtsIntegration); + return integration; + } + + private void validateBtsIntegration(Integration integration) { + + BusinessRule.expect(integration, + it -> IntegrationGroupEnum.BTS == it.getType().getIntegrationGroup()) + .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, Suppliers.formattedSupplier( + "Unable to test connection to the integration with type - '{}', Allowed type(es): '{}'", + integration.getType().getIntegrationGroup(), + IntegrationGroupEnum.BTS + )); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetTicketHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetTicketHandlerImpl.java index 2f38119c94..fa6ea54a0b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetTicketHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/bts/handler/impl/GetTicketHandlerImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.bts.handler.impl; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + import com.epam.reportportal.extension.bugtracking.BtsExtension; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -27,13 +29,10 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.externalsystem.PostFormField; import com.epam.ta.reportportal.ws.model.externalsystem.Ticket; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; - /** * Default implementation of {@link GetTicketHandler} * @@ -43,52 +42,58 @@ @Service public class GetTicketHandlerImpl implements GetTicketHandler { - private final PluginBox pluginBox; - private final GetIntegrationHandler getIntegrationHandler; + private final PluginBox pluginBox; + private final GetIntegrationHandler getIntegrationHandler; - @Autowired - public GetTicketHandlerImpl(PluginBox pluginBox, GetIntegrationHandler getIntegrationHandler) { - this.pluginBox = pluginBox; - this.getIntegrationHandler = getIntegrationHandler; - } + @Autowired + public GetTicketHandlerImpl(PluginBox pluginBox, GetIntegrationHandler getIntegrationHandler) { + this.pluginBox = pluginBox; + this.getIntegrationHandler = getIntegrationHandler; + } - @Override - public Ticket getTicket(String ticketId, String url, String btsProject, ReportPortalUser.ProjectDetails projectDetails) { - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, url, btsProject); - return getBtsExtension(integration).getTicket(ticketId, integration) - .orElseThrow(() -> new ReportPortalException(ErrorType.TICKET_NOT_FOUND, ticketId)); - } + @Override + public Ticket getTicket(String ticketId, String url, String btsProject, + ReportPortalUser.ProjectDetails projectDetails) { + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, url, + btsProject); + return getBtsExtension(integration).getTicket(ticketId, integration) + .orElseThrow(() -> new ReportPortalException(ErrorType.TICKET_NOT_FOUND, ticketId)); + } - @Override - public List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId, - ReportPortalUser.ProjectDetails projectDetails) { - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, integrationId); - return getBtsExtension(integration).getTicketFields(ticketType, integration); - } + @Override + public List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId, + ReportPortalUser.ProjectDetails projectDetails) { + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, + integrationId); + return getBtsExtension(integration).getTicketFields(ticketType, integration); + } - @Override - public List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId) { - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(integrationId); - return getBtsExtension(integration).getTicketFields(ticketType, integration); - } + @Override + public List<PostFormField> getSubmitTicketFields(String ticketType, Long integrationId) { + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(integrationId); + return getBtsExtension(integration).getTicketFields(ticketType, integration); + } - @Override - public List<String> getAllowableIssueTypes(Long integrationId, ReportPortalUser.ProjectDetails projectDetails) { - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, integrationId); - return getBtsExtension(integration).getIssueTypes(integration); - } + @Override + public List<String> getAllowableIssueTypes(Long integrationId, + ReportPortalUser.ProjectDetails projectDetails) { + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(projectDetails, + integrationId); + return getBtsExtension(integration).getIssueTypes(integration); + } - @Override - public List<String> getAllowableIssueTypes(Long integrationId) { - Integration integration = getIntegrationHandler.getEnabledBtsIntegration(integrationId); - return getBtsExtension(integration).getIssueTypes(integration); - } + @Override + public List<String> getAllowableIssueTypes(Long integrationId) { + Integration integration = getIntegrationHandler.getEnabledBtsIntegration(integrationId); + return getBtsExtension(integration).getIssueTypes(integration); + } - private BtsExtension getBtsExtension(Integration integration) { - return pluginBox.getInstance(integration.getType().getName(), BtsExtension.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("BugTracking plugin for {} isn't installed", integration.getType().getName()).get() - )); - } + private BtsExtension getBtsExtension(Integration integration) { + return pluginBox.getInstance(integration.getType().getName(), BtsExtension.class) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("BugTracking plugin for {} isn't installed", + integration.getType().getName()).get() + )); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/AspectConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/AspectConfig.java index a3e46a4c2a..96d39b693c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/AspectConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/AspectConfig.java @@ -28,15 +28,15 @@ @Configuration public class AspectConfig { - @Bean - @ConditionalOnProperty(name = "rp.requestLogging", havingValue = "true") - HttpLoggingAspect httpLoggingAspect() { - return new HttpLoggingAspect(); - } + @Bean + @ConditionalOnProperty(name = "rp.requestLogging", havingValue = "true") + HttpLoggingAspect httpLoggingAspect() { + return new HttpLoggingAspect(); + } - @Bean - @ConditionalOnProperty(name = "rp.requestLogging", havingValue = "true") - RabbitMessageLoggingAspect rabbitMessageLoggingAspect() { - return new RabbitMessageLoggingAspect(); - } + @Bean + @ConditionalOnProperty(name = "rp.requestLogging", havingValue = "true") + RabbitMessageLoggingAspect rabbitMessageLoggingAspect() { + return new RabbitMessageLoggingAspect(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/AttachmentSizeConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/AttachmentSizeConfig.java index 91a11e44c5..5d62eb685a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/AttachmentSizeConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/AttachmentSizeConfig.java @@ -20,6 +20,9 @@ import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.attachment.Attachment; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.io.InputStream; +import java.util.Optional; +import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.Step; @@ -35,10 +38,6 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.StreamUtils; -import javax.sql.DataSource; -import java.io.InputStream; -import java.util.Optional; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @@ -46,72 +45,75 @@ @ConditionalOnProperty(name = "rp.attachments.recalculate", havingValue = "true") public class AttachmentSizeConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentSizeConfig.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentSizeConfig.class); - private static final int CHUNK_SIZE = 10; + private static final int CHUNK_SIZE = 10; - @Autowired - private StepBuilderFactory stepBuilderFactory; + @Autowired + private StepBuilderFactory stepBuilderFactory; - @Autowired - private DataSource dataSource; + @Autowired + private DataSource dataSource; - @Autowired - @Qualifier("attachmentDataStoreService") - private DataStoreService dataStoreService; + @Autowired + @Qualifier("attachmentDataStoreService") + private DataStoreService dataStoreService; - @Autowired - private JdbcTemplate jdbcTemplate; + @Autowired + private JdbcTemplate jdbcTemplate; - @Bean - public JdbcCursorItemReader<Attachment> reader() throws Exception { - String query = "SELECT * from attachment order by id"; - JdbcCursorItemReader<Attachment> reader = new JdbcCursorItemReader<>(); - reader.setSql(query); - reader.setDataSource(dataSource); - reader.setRowMapper((rs, rowNum) -> { - Attachment attachment = new Attachment(); - attachment.setId(rs.getLong("id")); - attachment.setFileId(rs.getString("file_id")); - return attachment; - }); - reader.afterPropertiesSet(); - return reader; - } + @Bean + public JdbcCursorItemReader<Attachment> reader() throws Exception { + String query = "SELECT * from attachment order by id"; + JdbcCursorItemReader<Attachment> reader = new JdbcCursorItemReader<>(); + reader.setSql(query); + reader.setDataSource(dataSource); + reader.setRowMapper((rs, rowNum) -> { + Attachment attachment = new Attachment(); + attachment.setId(rs.getLong("id")); + attachment.setFileId(rs.getString("file_id")); + return attachment; + }); + reader.afterPropertiesSet(); + return reader; + } - @Bean - public ItemProcessor<Attachment, Attachment> processor() { - return item -> { - try { - Optional<InputStream> file = dataStoreService.load(item.getFileId()); - try (final InputStream inputStream = file.get()) { - item.setFileSize(StreamUtils.copyToByteArray(inputStream).length); - return item; - } - } catch (ReportPortalException e) { - LOGGER.debug(Suppliers.formattedSupplier("File with id {} is not presented at the file system. Removing from the database.", - item.getId() - ).get()); - jdbcTemplate.update("DELETE FROM attachment WHERE id = ?", item.getId()); - return null; - } - }; - } + @Bean + public ItemProcessor<Attachment, Attachment> processor() { + return item -> { + try { + Optional<InputStream> file = dataStoreService.load(item.getFileId()); + try (final InputStream inputStream = file.get()) { + item.setFileSize(StreamUtils.copyToByteArray(inputStream).length); + return item; + } + } catch (ReportPortalException e) { + LOGGER.debug(Suppliers.formattedSupplier( + "File with id {} is not presented at the file system. Removing from the database.", + item.getId() + ).get()); + jdbcTemplate.update("DELETE FROM attachment WHERE id = ?", item.getId()); + return null; + } + }; + } - @Bean - public ItemWriter<Attachment> writer() { - return items -> items.forEach(item -> { - jdbcTemplate.update("UPDATE attachment SET file_size = ? WHERE id = ?", item.getFileSize(), item.getId()); - }); - } + @Bean + public ItemWriter<Attachment> writer() { + return items -> items.forEach(item -> { + jdbcTemplate.update("UPDATE attachment SET file_size = ? WHERE id = ?", item.getFileSize(), + item.getId()); + }); + } - @Bean - public Step attachmentSizeStep() throws Exception { - return stepBuilderFactory.get("attachment").<Attachment, Attachment>chunk(CHUNK_SIZE).reader(reader()) - .processor(processor()) - .writer(writer()) - .allowStartIfComplete(true) - .build(); - } + @Bean + public Step attachmentSizeStep() throws Exception { + return stepBuilderFactory.get("attachment").<Attachment, Attachment>chunk(CHUNK_SIZE) + .reader(reader()) + .processor(processor()) + .writer(writer()) + .allowStartIfComplete(true) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/BatchJobConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/BatchJobConfiguration.java index 9396f0d904..9b861329fc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/BatchJobConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/BatchJobConfiguration.java @@ -38,37 +38,37 @@ @ConditionalOnBean(name = "attachmentSizeConfig") public class BatchJobConfiguration { - @Autowired - private JobBuilderFactory jobBuilderFactory; + @Autowired + private JobBuilderFactory jobBuilderFactory; - @Autowired - private Step attachmentSizeStep; + @Autowired + private Step attachmentSizeStep; - @Autowired - private JdbcTemplate jdbcTemplate; + @Autowired + private JdbcTemplate jdbcTemplate; - @Bean - public JobExecutionListener jobExecutionListener() { - return new JobExecutionListener() { - @Override - public void beforeJob(JobExecution jobExecution) { + @Bean + public JobExecutionListener jobExecutionListener() { + return new JobExecutionListener() { + @Override + public void beforeJob(JobExecution jobExecution) { - } + } - @Override - public void afterJob(JobExecution jobExecution) { - jdbcTemplate.update( - "UPDATE project AS prj SET allocated_storage = (SELECT coalesce(sum(attachment.file_size), 0) FROM attachment WHERE project_id = prj.id)"); - } - }; - } + @Override + public void afterJob(JobExecution jobExecution) { + jdbcTemplate.update( + "UPDATE project AS prj SET allocated_storage = (SELECT coalesce(sum(attachment.file_size), 0) FROM attachment WHERE project_id = prj.id)"); + } + }; + } - @Bean - public Job job() { - SimpleJobBuilder job = jobBuilderFactory.get("attachmentSize") - .incrementer(new RunIdIncrementer()) - .listener(jobExecutionListener()) - .start(attachmentSizeStep); - return job.build(); - } + @Bean + public Job job() { + SimpleJobBuilder job = jobBuilderFactory.get("attachmentSize") + .incrementer(new RunIdIncrementer()) + .listener(jobExecutionListener()) + .start(attachmentSizeStep); + return job.build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/Conditions.java b/src/main/java/com/epam/ta/reportportal/core/configs/Conditions.java index 516dcac044..7cf34b2b78 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/Conditions.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/Conditions.java @@ -15,12 +15,11 @@ */ package com.epam.ta.reportportal.core.configs; +import java.util.Arrays; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.ConfigurationCondition; import org.springframework.core.type.AnnotatedTypeMetadata; -import java.util.Arrays; - /** * Configuration conditions * @@ -28,17 +27,18 @@ */ public class Conditions { - public static class NotTestCondition implements ConfigurationCondition { + public static class NotTestCondition implements ConfigurationCondition { - @Override - public ConfigurationCondition.ConfigurationPhase getConfigurationPhase() { - return ConfigurationCondition.ConfigurationPhase.PARSE_CONFIGURATION; - } + @Override + public ConfigurationCondition.ConfigurationPhase getConfigurationPhase() { + return ConfigurationCondition.ConfigurationPhase.PARSE_CONFIGURATION; + } - @Override - public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { - return Arrays.stream(context.getEnvironment().getActiveProfiles()).noneMatch(profile -> profile.equals("unittest")); - } - } + @Override + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { + return Arrays.stream(context.getEnvironment().getActiveProfiles()) + .noneMatch(profile -> profile.equals("unittest")); + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/DemoDataConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/DemoDataConfig.java index 92b7dab06e..eb51f16f11 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/DemoDataConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/DemoDataConfig.java @@ -5,35 +5,35 @@ import com.epam.ta.reportportal.demodata.service.generator.SuiteWithNestedStepsGenerator; import com.epam.ta.reportportal.demodata.service.generator.SuiteWithRetriesGenerator; import com.epam.ta.reportportal.demodata.service.generator.model.SuiteGeneratorType; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - @Configuration public class DemoDataConfig { - private final DefaultSuiteGenerator defaultSuiteGenerator; - private final SuiteWithRetriesGenerator suiteWithRetriesGenerator; - private final SuiteWithNestedStepsGenerator suiteWithNestedStepsGenerator; + private final DefaultSuiteGenerator defaultSuiteGenerator; + private final SuiteWithRetriesGenerator suiteWithRetriesGenerator; + private final SuiteWithNestedStepsGenerator suiteWithNestedStepsGenerator; - @Autowired - public DemoDataConfig(DefaultSuiteGenerator defaultSuiteGenerator, SuiteWithRetriesGenerator suiteWithRetriesGenerator, - SuiteWithNestedStepsGenerator suiteWithNestedStepsGenerator) { - this.defaultSuiteGenerator = defaultSuiteGenerator; - this.suiteWithRetriesGenerator = suiteWithRetriesGenerator; - this.suiteWithNestedStepsGenerator = suiteWithNestedStepsGenerator; - } + @Autowired + public DemoDataConfig(DefaultSuiteGenerator defaultSuiteGenerator, + SuiteWithRetriesGenerator suiteWithRetriesGenerator, + SuiteWithNestedStepsGenerator suiteWithNestedStepsGenerator) { + this.defaultSuiteGenerator = defaultSuiteGenerator; + this.suiteWithRetriesGenerator = suiteWithRetriesGenerator; + this.suiteWithNestedStepsGenerator = suiteWithNestedStepsGenerator; + } - @Bean - public SuiteGeneratorResolver suiteGeneratorResolver() { - return new SuiteGeneratorResolver(Map.of(SuiteGeneratorType.DEFAULT, - defaultSuiteGenerator, - SuiteGeneratorType.RETRY, - suiteWithRetriesGenerator, - SuiteGeneratorType.NESTED, - suiteWithNestedStepsGenerator - )); - } + @Bean + public SuiteGeneratorResolver suiteGeneratorResolver() { + return new SuiteGeneratorResolver(Map.of(SuiteGeneratorType.DEFAULT, + defaultSuiteGenerator, + SuiteGeneratorType.RETRY, + suiteWithRetriesGenerator, + SuiteGeneratorType.NESTED, + suiteWithNestedStepsGenerator + )); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/EmailConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/EmailConfiguration.java index 3e969afd82..5a9d443795 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/EmailConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/EmailConfiguration.java @@ -18,7 +18,6 @@ import com.epam.reportportal.commons.template.TemplateEngine; import com.epam.reportportal.commons.template.TemplateEngineProvider; -import com.epam.ta.reportportal.core.analyzer.strategy.LaunchAnalysisStrategy; import com.epam.ta.reportportal.util.email.strategy.EmailNotificationStrategy; import com.epam.ta.reportportal.util.email.strategy.EmailTemplate; import com.epam.ta.reportportal.util.email.strategy.UserDeletionNotificationStrategy; @@ -27,6 +26,7 @@ import com.google.common.collect.ImmutableMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,7 +34,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** - * Global Email Configuration<br> Probably will be replaces by configuration per project. + * Global Email Configuration<br> Probably will be replaced by configuration per project. * * @author Andrei_Ramanchuk */ @@ -45,11 +45,14 @@ public class EmailConfiguration { private ApplicationContext applicationContext; @Bean - public ThreadPoolTaskExecutor emailExecutorService() { + public ThreadPoolTaskExecutor emailExecutorService( + @Value("${rp.environment.variable.executor.pool.user-email.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.user-email.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.user-email.queue}") Integer queueCapacity) { ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(5); - threadPoolTaskExecutor.setMaxPoolSize(20); - threadPoolTaskExecutor.setQueueCapacity(50); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); threadPoolTaskExecutor.setAwaitTerminationSeconds(20); threadPoolTaskExecutor.setThreadNamePrefix("email-sending-exec"); diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/ExecutorConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/ExecutorConfiguration.java index 79719e0a63..5145ac242c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/ExecutorConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/ExecutorConfiguration.java @@ -16,7 +16,6 @@ package com.epam.ta.reportportal.core.configs; -import com.epam.ta.reportportal.core.log.impl.SaveLogBinaryDataTask; import com.epam.ta.reportportal.core.log.impl.SaveLogBinaryDataTaskAsync; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -31,8 +30,6 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import java.util.concurrent.ThreadPoolExecutor; - /** * Configs for beans related to job execution * @@ -42,138 +39,129 @@ @EnableAsync public class ExecutorConfiguration { - @Bean - @Primary - public TaskScheduler taskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(5); - scheduler.setThreadNamePrefix("default-task-sched"); - scheduler.setWaitForTasksToCompleteOnShutdown(true); - return scheduler; - } - - @Bean(name = "saveLogsTaskExecutor") - public TaskExecutor saveLogsTaskExecutor(@Value("${rp.environment.variable.executor.pool.save-logs.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.save-logs.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.save-logs.queue}") Integer queueCapacity) { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(corePoolSize); - executor.setMaxPoolSize(maxPoolSize); - executor.setQueueCapacity(queueCapacity); - executor.setAllowCoreThreadTimeOut(true); - executor.setThreadNamePrefix("logs-task-exec"); - executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); - return executor; - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public SaveLogBinaryDataTask saveLogBinaryDataTask() { - return new SaveLogBinaryDataTask(); - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public SaveLogBinaryDataTaskAsync saveLogBinaryDataTaskAsync() { - return new SaveLogBinaryDataTaskAsync(); - } - - @EnableScheduling - public static class SchedulingConfiguration { - } - - @Bean(name = "logIndexTaskExecutor") - public TaskExecutor logIndexTaskExecutor(@Value("${rp.environment.variable.executor.pool.log-index.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.log-index.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.log-index.queue}") Integer queueCapacity) { - final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(corePoolSize); - threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); - threadPoolTaskExecutor.setQueueCapacity(queueCapacity); - threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); - threadPoolTaskExecutor.setThreadNamePrefix("log-index-exec"); - return threadPoolTaskExecutor; - } - - @Bean(name = "autoAnalyzeTaskExecutor") - public TaskExecutor autoAnalyzeTaskExecutor(@Value("${rp.environment.variable.executor.pool.auto-analyze.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.auto-analyze.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.auto-analyze.queue}") Integer queueCapacity) { - final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(corePoolSize); - threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); - threadPoolTaskExecutor.setQueueCapacity(queueCapacity); - threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); - threadPoolTaskExecutor.setThreadNamePrefix("auto-analyze-exec"); - return threadPoolTaskExecutor; - } - - @Bean("patternAnalysisTaskExecutor") - public TaskExecutor patternAnalysisTaskExecutor(@Value("${rp.environment.variable.executor.pool.pattern-analyze.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.pattern-analyze.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.pattern-analyze.queue}") Integer queueCapacity) { - ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); - taskExecutor.setCorePoolSize(corePoolSize); - taskExecutor.setMaxPoolSize(maxPoolSize); - taskExecutor.setQueueCapacity(queueCapacity); - taskExecutor.setThreadNamePrefix("pattern-analysis-task-exec"); - taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - return taskExecutor; - } - - @Bean(name = "demoDataTaskExecutor") - public TaskExecutor demoDataTaskExecutor(@Value("${rp.environment.variable.executor.pool.demo-data.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.demo-data.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.demo-data.queue}") Integer queueCapacity) { - ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(corePoolSize); - threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); - threadPoolTaskExecutor.setQueueCapacity(queueCapacity); - threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); - threadPoolTaskExecutor.setAwaitTerminationSeconds(60); - threadPoolTaskExecutor.setThreadNamePrefix("demo-data-exec"); - return threadPoolTaskExecutor; - } - - @Bean(name = "widgetViewExecutor") - public TaskExecutor healthCheckTableExecutor( - @Value("${rp.environment.variable.executor.pool.widget-view.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.widget-view.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.widget-view.queue}") Integer queueCapacity) { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(corePoolSize); - executor.setMaxPoolSize(maxPoolSize); - executor.setQueueCapacity(queueCapacity); - executor.setAllowCoreThreadTimeOut(true); - executor.setThreadNamePrefix("generate-widget-view-task"); - executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); - return executor; - } - - @Bean(name = "logClusterExecutor") - public TaskExecutor logClusterExecutor(@Value("${rp.environment.variable.executor.pool.log-cluster.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.log-cluster.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.log-cluster.queue}") Integer queueCapacity) { - final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(corePoolSize); - threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); - threadPoolTaskExecutor.setQueueCapacity(queueCapacity); - threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); - threadPoolTaskExecutor.setThreadNamePrefix("log-cluster-exec"); - return threadPoolTaskExecutor; - } - - @Bean(name = "eventListenerExecutor") - public TaskExecutor eventListenerExecutor(@Value("${rp.environment.variable.executor.pool.event-listener.core}") Integer corePoolSize, - @Value("${rp.environment.variable.executor.pool.event-listener.max}") Integer maxPoolSize, - @Value("${rp.environment.variable.executor.pool.event-listener.queue}") Integer queueCapacity) { - final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); - threadPoolTaskExecutor.setCorePoolSize(corePoolSize); - threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); - threadPoolTaskExecutor.setQueueCapacity(queueCapacity); - threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); - threadPoolTaskExecutor.setThreadNamePrefix("event-listener-exec"); - return threadPoolTaskExecutor; - } + @Bean + @Primary + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(5); + scheduler.setThreadNamePrefix("default-task-sched"); + scheduler.setWaitForTasksToCompleteOnShutdown(true); + return scheduler; + } + + @Bean(name = "saveLogsTaskExecutor") + public TaskExecutor saveLogsTaskExecutor( + @Value("${rp.environment.variable.executor.pool.save-logs.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.save-logs.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.save-logs.queue}") Integer queueCapacity) { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setAllowCoreThreadTimeOut(true); + executor.setThreadNamePrefix("logs-task-exec"); + executor.setRejectedExecutionHandler( + new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public SaveLogBinaryDataTaskAsync saveLogBinaryDataTaskAsync() { + return new SaveLogBinaryDataTaskAsync(); + } + + @EnableScheduling + public static class SchedulingConfiguration { + + } + + @Bean(name = "logIndexTaskExecutor") + public TaskExecutor logIndexTaskExecutor( + @Value("${rp.environment.variable.executor.pool.log-index.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.log-index.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.log-index.queue}") Integer queueCapacity) { + final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); + threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); + threadPoolTaskExecutor.setThreadNamePrefix("log-index-exec"); + return threadPoolTaskExecutor; + } + + @Bean(name = "autoAnalyzeTaskExecutor") + public TaskExecutor autoAnalyzeTaskExecutor( + @Value("${rp.environment.variable.executor.pool.auto-analyze.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.auto-analyze.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.auto-analyze.queue}") Integer queueCapacity) { + final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); + threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); + threadPoolTaskExecutor.setThreadNamePrefix("auto-analyze-exec"); + return threadPoolTaskExecutor; + } + + @Bean(name = "demoDataTaskExecutor") + public TaskExecutor demoDataTaskExecutor( + @Value("${rp.environment.variable.executor.pool.demo-data.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.demo-data.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.demo-data.queue}") Integer queueCapacity) { + ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); + threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); + threadPoolTaskExecutor.setAwaitTerminationSeconds(60); + threadPoolTaskExecutor.setThreadNamePrefix("demo-data-exec"); + return threadPoolTaskExecutor; + } + + @Bean(name = "widgetViewExecutor") + public TaskExecutor healthCheckTableExecutor( + @Value("${rp.environment.variable.executor.pool.widget-view.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.widget-view.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.widget-view.queue}") Integer queueCapacity) { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setAllowCoreThreadTimeOut(true); + executor.setThreadNamePrefix("generate-widget-view-task"); + executor.setRejectedExecutionHandler( + new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + @Bean(name = "logClusterExecutor") + public TaskExecutor logClusterExecutor( + @Value("${rp.environment.variable.executor.pool.log-cluster.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.log-cluster.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.log-cluster.queue}") Integer queueCapacity) { + final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); + threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); + threadPoolTaskExecutor.setThreadNamePrefix("log-cluster-exec"); + return threadPoolTaskExecutor; + } + + @Bean(name = "eventListenerExecutor") + public TaskExecutor eventListenerExecutor( + @Value("${rp.environment.variable.executor.pool.event-listener.core}") Integer corePoolSize, + @Value("${rp.environment.variable.executor.pool.event-listener.max}") Integer maxPoolSize, + @Value("${rp.environment.variable.executor.pool.event-listener.queue}") + Integer queueCapacity) { + final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + threadPoolTaskExecutor.setCorePoolSize(corePoolSize); + threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize); + threadPoolTaskExecutor.setQueueCapacity(queueCapacity); + threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true); + threadPoolTaskExecutor.setThreadNamePrefix("event-listener-exec"); + return threadPoolTaskExecutor; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/IntegrationConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/IntegrationConfig.java index 10ede48abe..b8bbe50fb9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/IntegrationConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/IntegrationConfig.java @@ -16,37 +16,41 @@ package com.epam.ta.reportportal.core.configs; -import com.epam.ta.reportportal.core.integration.util.*; +import com.epam.ta.reportportal.core.integration.util.AzureIntegrationService; +import com.epam.ta.reportportal.core.integration.util.BtsIntegrationService; +import com.epam.ta.reportportal.core.integration.util.EmailServerIntegrationService; +import com.epam.ta.reportportal.core.integration.util.IntegrationService; +import com.epam.ta.reportportal.core.integration.util.SauceLabsIntegrationService; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class IntegrationConfig implements ApplicationContextAware { - private ApplicationContext applicationContext; + private ApplicationContext applicationContext; - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @Bean - public Map<String, IntegrationService> integrationServiceMapping() { - return ImmutableMap.<String, IntegrationService>builder().put("jira", applicationContext.getBean(BtsIntegrationService.class)) - .put("rally", applicationContext.getBean(BtsIntegrationService.class)) - .put("Azure DevOps", applicationContext.getBean(AzureIntegrationService.class)) - .put("email", applicationContext.getBean(EmailServerIntegrationService.class)) - .put("saucelabs", applicationContext.getBean(SauceLabsIntegrationService.class)) - .build(); + @Bean + public Map<String, IntegrationService> integrationServiceMapping() { + return ImmutableMap.<String, IntegrationService>builder() + .put("jira", applicationContext.getBean(BtsIntegrationService.class)) + .put("rally", applicationContext.getBean(BtsIntegrationService.class)) + .put("Azure DevOps", applicationContext.getBean(AzureIntegrationService.class)) + .put("email", applicationContext.getBean(EmailServerIntegrationService.class)) + .put("saucelabs", applicationContext.getBean(SauceLabsIntegrationService.class)) + .build(); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/ItemStatusChangingStrategyConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/ItemStatusChangingStrategyConfig.java index 3b53225357..2970c4339d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/ItemStatusChangingStrategyConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/ItemStatusChangingStrategyConfig.java @@ -22,40 +22,41 @@ import com.epam.ta.reportportal.core.item.impl.status.ToSkippedStatusChangingStrategy; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Configuration public class ItemStatusChangingStrategyConfig { - private final ToFailedStatusChangingStrategy toFailedStatusChangingStrategy; - - private final ToPassedStatusChangingStrategy toPassedStatusChangingStrategy; - - private final ToSkippedStatusChangingStrategy toSkippedStatusChangingStrategy; - - @Autowired - public ItemStatusChangingStrategyConfig(ToFailedStatusChangingStrategy toFailedStatusChangingStrategy, - ToPassedStatusChangingStrategy toPassedStatusChangingStrategy, - ToSkippedStatusChangingStrategy toSkippedStatusChangingStrategy) { - this.toFailedStatusChangingStrategy = toFailedStatusChangingStrategy; - this.toPassedStatusChangingStrategy = toPassedStatusChangingStrategy; - this.toSkippedStatusChangingStrategy = toSkippedStatusChangingStrategy; - } - - @Bean - public Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping() { - return ImmutableMap.<StatusEnum, StatusChangingStrategy>builder().put(StatusEnum.PASSED, toPassedStatusChangingStrategy) - .put(StatusEnum.INFO, toPassedStatusChangingStrategy) - .put(StatusEnum.WARN, toPassedStatusChangingStrategy) - .put(StatusEnum.FAILED, toFailedStatusChangingStrategy) - .put(StatusEnum.SKIPPED, toSkippedStatusChangingStrategy) - .build(); - } + private final ToFailedStatusChangingStrategy toFailedStatusChangingStrategy; + + private final ToPassedStatusChangingStrategy toPassedStatusChangingStrategy; + + private final ToSkippedStatusChangingStrategy toSkippedStatusChangingStrategy; + + @Autowired + public ItemStatusChangingStrategyConfig( + ToFailedStatusChangingStrategy toFailedStatusChangingStrategy, + ToPassedStatusChangingStrategy toPassedStatusChangingStrategy, + ToSkippedStatusChangingStrategy toSkippedStatusChangingStrategy) { + this.toFailedStatusChangingStrategy = toFailedStatusChangingStrategy; + this.toPassedStatusChangingStrategy = toPassedStatusChangingStrategy; + this.toSkippedStatusChangingStrategy = toSkippedStatusChangingStrategy; + } + + @Bean + public Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping() { + return ImmutableMap.<StatusEnum, StatusChangingStrategy>builder() + .put(StatusEnum.PASSED, toPassedStatusChangingStrategy) + .put(StatusEnum.INFO, toPassedStatusChangingStrategy) + .put(StatusEnum.WARN, toPassedStatusChangingStrategy) + .put(StatusEnum.FAILED, toFailedStatusChangingStrategy) + .put(StatusEnum.SKIPPED, toSkippedStatusChangingStrategy) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/JacksonConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/JacksonConfiguration.java index 13d74f7a7b..a7aabe0d82 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/JacksonConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/JacksonConfiguration.java @@ -31,17 +31,17 @@ @Configuration public class JacksonConfiguration { - /** - * @return Configured object mapper - */ - @Bean(name = "objectMapper") - public ObjectMapper objectMapper() { - ObjectMapper om = new ObjectMapper(); - om.setAnnotationIntrospector(new JacksonAnnotationIntrospector()); - om.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); - om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - om.registerModule(new JacksonViewAwareModule(om)); - om.registerModule(new JavaTimeModule()); - return om; - } + /** + * @return Configured object mapper + */ + @Bean(name = "objectMapper") + public ObjectMapper objectMapper() { + ObjectMapper om = new ObjectMapper(); + om.setAnnotationIntrospector(new JacksonAnnotationIntrospector()); + om.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + om.registerModule(new JacksonViewAwareModule(om)); + om.registerModule(new JavaTimeModule()); + return om; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/MergeStrategyConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/MergeStrategyConfig.java index 39c9cead53..39aaed35ae 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/MergeStrategyConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/MergeStrategyConfig.java @@ -16,8 +16,15 @@ package com.epam.ta.reportportal.core.configs; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.core.item.identity.TestItemUniqueIdGenerator; -import com.epam.ta.reportportal.core.item.impl.merge.strategy.*; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.BasicLaunchMergeStrategy; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.BasicStatisticsCalculationStrategy; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.DeepLaunchMergeStrategy; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.LaunchMergeFactory; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.MergeStrategyType; +import com.epam.ta.reportportal.core.item.impl.merge.strategy.StatisticsCalculationFactory; import com.epam.ta.reportportal.core.item.merge.LaunchMergeStrategy; import com.epam.ta.reportportal.core.item.merge.StatisticsCalculationStrategy; import com.epam.ta.reportportal.dao.AttachmentRepository; @@ -25,74 +32,74 @@ import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - -import static java.util.Collections.singletonMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class MergeStrategyConfig { - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - private final TestItemUniqueIdGenerator testItemUniqueIdGenerator; + private final TestItemUniqueIdGenerator testItemUniqueIdGenerator; - private final LogRepository logRepository; + private final LogRepository logRepository; - private final AttachmentRepository attachmentRepository; + private final AttachmentRepository attachmentRepository; - @Autowired - public MergeStrategyConfig(TestItemRepository testItemRepository, LaunchRepository launchRepository, - TestItemUniqueIdGenerator testItemUniqueIdGenerator, LogRepository logRepository, AttachmentRepository attachmentRepository) { - this.testItemRepository = testItemRepository; - this.launchRepository = launchRepository; - this.testItemUniqueIdGenerator = testItemUniqueIdGenerator; - this.logRepository = logRepository; - this.attachmentRepository = attachmentRepository; - } + @Autowired + public MergeStrategyConfig(TestItemRepository testItemRepository, + LaunchRepository launchRepository, + TestItemUniqueIdGenerator testItemUniqueIdGenerator, LogRepository logRepository, + AttachmentRepository attachmentRepository) { + this.testItemRepository = testItemRepository; + this.launchRepository = launchRepository; + this.testItemUniqueIdGenerator = testItemUniqueIdGenerator; + this.logRepository = logRepository; + this.attachmentRepository = attachmentRepository; + } - @Bean - public Map<MergeStrategyType, StatisticsCalculationStrategy> statisticsCalculationStrategyMaping() { - return singletonMap(MergeStrategyType.BASIC, new BasicStatisticsCalculationStrategy()); - } + @Bean + public Map<MergeStrategyType, StatisticsCalculationStrategy> statisticsCalculationStrategyMaping() { + return singletonMap(MergeStrategyType.BASIC, new BasicStatisticsCalculationStrategy()); + } - @Bean - public StatisticsCalculationFactory statisticsCalculationFactory() { - return new StatisticsCalculationFactory(statisticsCalculationStrategyMaping()); - } + @Bean + public StatisticsCalculationFactory statisticsCalculationFactory() { + return new StatisticsCalculationFactory(statisticsCalculationStrategyMaping()); + } - @Bean - public Map<MergeStrategyType, LaunchMergeStrategy> launchMergeStrategyMapping() { - return ImmutableMap.<MergeStrategyType, LaunchMergeStrategy>builder().put(MergeStrategyType.BASIC, - new BasicLaunchMergeStrategy(launchRepository, - testItemRepository, - logRepository, - attachmentRepository, - testItemUniqueIdGenerator, - statisticsCalculationFactory() - ) - ) - .put(MergeStrategyType.DEEP, - new DeepLaunchMergeStrategy(launchRepository, - testItemRepository, - logRepository, - attachmentRepository, - testItemUniqueIdGenerator - ) - ) - .build(); - } + @Bean + public Map<MergeStrategyType, LaunchMergeStrategy> launchMergeStrategyMapping() { + return ImmutableMap.<MergeStrategyType, LaunchMergeStrategy>builder() + .put(MergeStrategyType.BASIC, + new BasicLaunchMergeStrategy(launchRepository, + testItemRepository, + logRepository, + attachmentRepository, + testItemUniqueIdGenerator, + statisticsCalculationFactory() + ) + ) + .put(MergeStrategyType.DEEP, + new DeepLaunchMergeStrategy(launchRepository, + testItemRepository, + logRepository, + attachmentRepository, + testItemUniqueIdGenerator + ) + ) + .build(); + } - @Bean - public LaunchMergeFactory launchMergeFactory() { - return new LaunchMergeFactory(launchMergeStrategyMapping()); - } + @Bean + public LaunchMergeFactory launchMergeFactory() { + return new LaunchMergeFactory(launchMergeStrategyMapping()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/MultipartDataConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/MultipartDataConfig.java index ce2da3b199..dfc5000a0c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/MultipartDataConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/MultipartDataConfig.java @@ -1,24 +1,29 @@ package com.epam.ta.reportportal.core.configs; +import com.epam.ta.reportportal.util.BinaryDataResponseWriter; +import javax.activation.MimetypesFileTypeMap; import org.apache.tika.parser.AutoDetectParser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import javax.activation.MimetypesFileTypeMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class MultipartDataConfig { - @Bean - public MimetypesFileTypeMap mimetypesFileTypeMap() { - return new MimetypesFileTypeMap(); - } + @Bean + public MimetypesFileTypeMap mimetypesFileTypeMap() { + return new MimetypesFileTypeMap(); + } + + @Bean + public AutoDetectParser autoDetectParser() { + return new AutoDetectParser(); + } - @Bean - public AutoDetectParser autoDetectParser() { - return new AutoDetectParser(); - } + @Bean + public BinaryDataResponseWriter binaryDataResponseWriter() { + return new BinaryDataResponseWriter(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/MvcConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/MvcConfig.java index f4248e49e6..2d084bd336 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/MvcConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/MvcConfig.java @@ -13,16 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.epam.ta.reportportal.core.configs; +import static com.google.common.base.Strings.isNullOrEmpty; + import com.epam.ta.reportportal.commons.ExceptionMappings; import com.epam.ta.reportportal.commons.exception.forwarding.ClientResponseForwardingExceptionHandler; import com.epam.ta.reportportal.commons.exception.rest.DefaultErrorResolver; import com.epam.ta.reportportal.commons.exception.rest.ReportPortalExceptionResolver; import com.epam.ta.reportportal.commons.exception.rest.RestExceptionHandler; -import com.epam.ta.reportportal.ws.resolver.*; +import com.epam.ta.reportportal.ws.resolver.ActiveUserWebArgumentResolver; +import com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver; +import com.epam.ta.reportportal.ws.resolver.JsonViewSupportFactoryBean; +import com.epam.ta.reportportal.ws.resolver.PagingHandlerMethodArgumentResolver; +import com.epam.ta.reportportal.ws.resolver.PredefinedFilterCriteriaResolver; +import com.epam.ta.reportportal.ws.resolver.SortArgumentResolver; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Preconditions; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -49,11 +60,6 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import java.util.Collections; -import java.util.List; - -import static com.google.common.base.Strings.isNullOrEmpty; - /** * Class-based Spring MVC Configuration * @@ -63,169 +69,184 @@ @EnableConfigurationProperties(MvcConfig.MultipartConfig.class) public class MvcConfig implements WebMvcConfigurer { - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private List<HttpMessageConverter<?>> converters; - - private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/public/", "classpath:/META-INF/resources/", - "classpath:/resources/" }; - - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - if (!registry.hasMappingForPattern("/**")) { - registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS); - } - if (!registry.hasMappingForPattern("/webjars/**")) { - registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); - } - } - - @Bean - public SortArgumentResolver sortArgumentResolver() { - SortArgumentResolver argumentResolver = new SortArgumentResolver(); - argumentResolver.setSortParameter("page.sort"); - argumentResolver.setQualifierDelimiter("+"); - return argumentResolver; - } - - @Bean - public JsonViewSupportFactoryBean jsonViewSupportFactoryBean() { - return new JsonViewSupportFactoryBean(); - } - - @Override - public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { - argumentResolvers.clear(); - PagingHandlerMethodArgumentResolver pageableResolver = new PagingHandlerMethodArgumentResolver(sortArgumentResolver()); - pageableResolver.setPrefix("page."); - pageableResolver.setOneIndexedParameters(true); - - argumentResolvers.add(pageableResolver); - - argumentResolvers.add(new ActiveUserWebArgumentResolver()); - argumentResolvers.add(new FilterCriteriaResolver()); - argumentResolvers.add(new PredefinedFilterCriteriaResolver()); - } - - @Override - public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { - converters.clear(); - converters.add(jsonConverter()); - converters.add(stringConverter()); - } - - @Override - public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) { - /* to propagate exceptions from downstream services */ - ClientResponseForwardingExceptionHandler forwardingExceptionHandler = new ClientResponseForwardingExceptionHandler(); - forwardingExceptionHandler.setOrder(Ordered.HIGHEST_PRECEDENCE); - exceptionResolvers.add(forwardingExceptionHandler); - - RestExceptionHandler handler = new RestExceptionHandler(); - handler.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); - - DefaultErrorResolver defaultErrorResolver = new DefaultErrorResolver(ExceptionMappings.DEFAULT_MAPPING); - handler.setErrorResolver(new ReportPortalExceptionResolver(defaultErrorResolver)); - handler.setMessageConverters(Collections.singletonList(jsonConverter())); - exceptionResolvers.add(handler); - } - - @Override - public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { - configurer.favorPathExtension(false); - } - - @Override - public void configurePathMatch(PathMatchConfigurer configurer) { - configurer.setUseSuffixPatternMatch(false); - } - - @Bean - public BeanValidationPostProcessor beanValidationPostProcessor() { - return new BeanValidationPostProcessor(); - } - - @Bean - public MappingJackson2HttpMessageConverter jsonConverter() { - return new MappingJackson2HttpMessageConverter(objectMapper); - } - - @Bean - public StringHttpMessageConverter stringConverter() { - StringHttpMessageConverter converter = new StringHttpMessageConverter(); - converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN)); - return converter; - } - - @Bean - HttpMessageConverters httpMessageConverters() { - return new HttpMessageConverters(converters); - } - - @Profile("!unittest") - @Bean - @Order(0) - public MultipartFilter multipartFilter() { - MultipartFilter multipartFilter = new MultipartFilter(); - multipartFilter.setMultipartResolverBeanName(DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME); - return multipartFilter; - } - - @Profile("!unittest") - @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) - public CommonsMultipartResolver multipartResolver(MultipartConfig multipartConfig) { - CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver() { - @Override - protected DiskFileItemFactory newFileItemFactory() { - DiskFileItemFactory diskFileItemFactory = super.newFileItemFactory(); - diskFileItemFactory.setFileCleaningTracker(null); - return diskFileItemFactory; - } - - @Override - public void cleanupMultipart(MultipartHttpServletRequest request) { - // - } - }; - - //Lazy resolving gives a way to process file limits inside a controller - //level and handle exceptions in proper way. Fixes reportportal/reportportal#19 - commonsMultipartResolver.setResolveLazily(true); - - commonsMultipartResolver.setMaxUploadSize(multipartConfig.maxUploadSize); - commonsMultipartResolver.setMaxUploadSizePerFile(multipartConfig.maxFileSize); - return commonsMultipartResolver; - } - - @ConfigurationProperties("rp.upload") - public static class MultipartConfig { - long maxUploadSize = 128L * 1024L * 1024L; - long maxFileSize = 128L * 1024L * 1024L; - - public void setMaxUploadSize(String maxUploadSize) { - this.maxUploadSize = parseSize(maxUploadSize); - } - - public void setMaxFileSize(String maxFileSize) { - this.maxFileSize = parseSize(maxFileSize); - } - - private long parseSize(String size) { - Preconditions.checkArgument(!isNullOrEmpty(size), "Size must not be empty"); - size = size.toUpperCase(); - if (size.endsWith("KB")) { - return Long.parseLong(size.substring(0, size.length() - 2)) * 1024; - } - if (size.endsWith("MB")) { - return Long.parseLong(size.substring(0, size.length() - 2)) * 1024 * 1024; - } - if (size.endsWith("GB")) { - return Long.parseLong(size.substring(0, size.length() - 2)) * 1024 * 1024 * 1024; - } - return Long.parseLong(size); - } - } + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private List<HttpMessageConverter<?>> converters; + + private static final String[] CLASSPATH_RESOURCE_LOCATIONS = + { "classpath:/public/", "classpath:/META-INF/resources/", "classpath:/resources/" }; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + if (!registry.hasMappingForPattern("/**")) { + registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS); + } + if (!registry.hasMappingForPattern("/webjars/**")) { + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + } + + @Bean + public SortArgumentResolver sortArgumentResolver() { + SortArgumentResolver argumentResolver = new SortArgumentResolver(); + argumentResolver.setSortParameter("page.sort"); + argumentResolver.setQualifierDelimiter("+"); + return argumentResolver; + } + + @Bean + public JsonViewSupportFactoryBean jsonViewSupportFactoryBean() { + return new JsonViewSupportFactoryBean(); + } + + @Override + public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { + argumentResolvers.clear(); + PagingHandlerMethodArgumentResolver pageableResolver = + new PagingHandlerMethodArgumentResolver(sortArgumentResolver()); + pageableResolver.setPrefix("page."); + pageableResolver.setOneIndexedParameters(true); + + argumentResolvers.add(pageableResolver); + + argumentResolvers.add(new ActiveUserWebArgumentResolver()); + argumentResolvers.add(new FilterCriteriaResolver()); + argumentResolvers.add(new PredefinedFilterCriteriaResolver()); + } + + @Override + public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { + converters.clear(); + converters.add(jsonConverter()); + converters.add(openMetricsTextStringConverter()); + converters.add(stringConverter()); + } + + @Override + public void configureHandlerExceptionResolvers( + List<HandlerExceptionResolver> exceptionResolvers) { + /* to propagate exceptions from downstream services */ + ClientResponseForwardingExceptionHandler forwardingExceptionHandler = + new ClientResponseForwardingExceptionHandler(); + forwardingExceptionHandler.setOrder(Ordered.HIGHEST_PRECEDENCE); + exceptionResolvers.add(forwardingExceptionHandler); + + RestExceptionHandler handler = new RestExceptionHandler(); + handler.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); + + DefaultErrorResolver defaultErrorResolver = + new DefaultErrorResolver(ExceptionMappings.DEFAULT_MAPPING); + handler.setErrorResolver(new ReportPortalExceptionResolver(defaultErrorResolver)); + handler.setMessageConverters(Collections.singletonList(jsonConverter())); + exceptionResolvers.add(handler); + } + + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { + configurer.favorPathExtension(false); + } + + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setUseSuffixPatternMatch(false); + } + + @Bean + public BeanValidationPostProcessor beanValidationPostProcessor() { + return new BeanValidationPostProcessor(); + } + + @Bean + public MappingJackson2HttpMessageConverter jsonConverter() { + return new MappingJackson2HttpMessageConverter(objectMapper); + } + + @Bean + public StringHttpMessageConverter stringConverter() { + StringHttpMessageConverter converter = new StringHttpMessageConverter(); + converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN)); + return converter; + } + + @Bean + public StringHttpMessageConverter openMetricsTextStringConverter() { + StringHttpMessageConverter converter = new StringHttpMessageConverter(); + converter.setSupportedMediaTypes(Collections.singletonList( + new MediaType("application", "openmetrics-text", StandardCharsets.UTF_8))); + return converter; + } + + @Bean + HttpMessageConverters httpMessageConverters() { + return new HttpMessageConverters(converters); + } + + @Profile("!unittest") + @Bean + @Order(0) + public MultipartFilter multipartFilter() { + MultipartFilter multipartFilter = new MultipartFilter(); + multipartFilter.setMultipartResolverBeanName(DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME); + return multipartFilter; + } + + @Profile("!unittest") + @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) + public CommonsMultipartResolver multipartResolver(MultipartConfig multipartConfig) { + CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver() { + @Override + protected DiskFileItemFactory newFileItemFactory() { + DiskFileItemFactory diskFileItemFactory = super.newFileItemFactory(); + diskFileItemFactory.setFileCleaningTracker(null); + return diskFileItemFactory; + } + + @Override + public void cleanupMultipart(MultipartHttpServletRequest request) { + // + } + }; + + //Lazy resolving gives a way to process file limits inside a controller + //level and handle exceptions in proper way. Fixes reportportal/reportportal#19 + commonsMultipartResolver.setResolveLazily(true); + + commonsMultipartResolver.setMaxUploadSize(multipartConfig.maxUploadSize); + commonsMultipartResolver.setMaxUploadSizePerFile(multipartConfig.maxFileSize); + return commonsMultipartResolver; + } + + @ConfigurationProperties("rp.upload") + public static class MultipartConfig { + + long maxUploadSize = 128L * 1024L * 1024L; + long maxFileSize = 128L * 1024L * 1024L; + + public void setMaxUploadSize(String maxUploadSize) { + this.maxUploadSize = parseSize(maxUploadSize); + } + + public void setMaxFileSize(String maxFileSize) { + this.maxFileSize = parseSize(maxFileSize); + } + + private long parseSize(String size) { + Preconditions.checkArgument(!isNullOrEmpty(size), "Size must not be empty"); + size = size.toUpperCase(); + if (size.endsWith("KB")) { + return Long.parseLong(size.substring(0, size.length() - 2)) * 1024; + } + if (size.endsWith("MB")) { + return Long.parseLong(size.substring(0, size.length() - 2)) * 1024 * 1024; + } + if (size.endsWith("GB")) { + return Long.parseLong(size.substring(0, size.length() - 2)) * 1024 * 1024 * 1024; + } + return Long.parseLong(size); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/PluginConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/PluginConfiguration.java index 933df708cb..08d97e97db 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/PluginConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/PluginConfiguration.java @@ -16,105 +16,134 @@ package com.epam.ta.reportportal.core.configs; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.integration.plugin.PluginLoader; +import com.epam.ta.reportportal.core.integration.plugin.binary.PluginFilesProvider; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; import com.epam.ta.reportportal.dao.IntegrationTypeRepository; import com.epam.ta.reportportal.plugin.Pf4jPluginManager; import com.epam.ta.reportportal.plugin.ReportPortalExtensionFactory; -import org.pf4j.*; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Set; +import javax.activation.FileTypeMap; +import org.pf4j.DefaultExtensionFinder; +import org.pf4j.DefaultPluginManager; +import org.pf4j.ExtensionFactory; +import org.pf4j.ExtensionFinder; +import org.pf4j.LegacyExtensionFinder; +import org.pf4j.ManifestPluginDescriptorFinder; +import org.pf4j.PluginDescriptorFinder; +import org.pf4j.PluginManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - -import java.io.IOException; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.Set; - -import static java.util.Optional.ofNullable; +import org.springframework.mail.javamail.ConfigurableMimeFileTypeMap; @Configuration public class PluginConfiguration { - @Autowired - private AutowireCapableBeanFactory context; - - @Autowired - private PluginLoader pluginLoader; - - @Autowired - private IntegrationTypeRepository integrationTypeRepository; - - @Autowired - private ApplicationEventPublisher applicationEventPublisher; - - @Value("${rp.plugins.path}") - private String pluginsPath; - - @Value("${rp.plugins.temp.path}") - private String pluginsTempPath; - - @Value("${rp.plugins.resources.path}") - private String pluginsResourcesPath; - - @Bean - public Pf4jPluginBox pf4jPluginBox() throws IOException { - Pf4jPluginManager pluginManager = new Pf4jPluginManager(pluginsPath, - pluginsTempPath, - pluginsResourcesPath, - pluginLoader, - integrationTypeRepository, - pluginManager(), - context, - applicationEventPublisher - ); - pluginManager.startUp(); - return pluginManager; - } - - @Bean - public PluginManager pluginManager() { - - return new DefaultPluginManager(Paths.get(pluginsPath)) { - @Override - protected PluginDescriptorFinder createPluginDescriptorFinder() { - return pluginDescriptorFinder(); - } - - @Override - protected ExtensionFactory createExtensionFactory() { - return new ReportPortalExtensionFactory(pluginsResourcesPath, this, context); - } - - @Override - protected ExtensionFinder createExtensionFinder() { - RpExtensionFinder extensionFinder = new RpExtensionFinder(this); - addPluginStateListener(extensionFinder); - return extensionFinder; - } - - class RpExtensionFinder extends DefaultExtensionFinder { - - private RpExtensionFinder(PluginManager pluginManager) { - super(pluginManager); - finders.clear(); - finders.add(new LegacyExtensionFinder(pluginManager) { - @Override - public Set<String> findClassNames(String pluginId) { - return ofNullable(super.findClassNames(pluginId)).orElseGet(Collections::emptySet); - } - }); - } - } - }; - } - - @Bean - public PluginDescriptorFinder pluginDescriptorFinder() { - return new ManifestPluginDescriptorFinder(); - } + @Autowired + private AutowireCapableBeanFactory context; + + @Autowired + private PluginLoader pluginLoader; + + @Autowired + private IntegrationTypeRepository integrationTypeRepository; + + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + + @Value("${rp.plugins.path}") + private String pluginsPath; + + @Value("${rp.plugins.temp.path}") + private String pluginsTempPath; + + @Value("${rp.plugins.resources.path}") + private String pluginsResourcesPath; + + @Value("${rp.plugins.resources.public}") + private String publicFolderQualifier; + + @Bean + public Pf4jPluginBox pf4jPluginBox() throws IOException { + Pf4jPluginManager pluginManager = new Pf4jPluginManager(pluginsPath, + pluginsTempPath, + pluginsResourcesPath, + pluginLoader, + integrationTypeRepository, + pluginManager(), + context, + applicationEventPublisher + ); + pluginManager.startUp(); + return pluginManager; + } + + @Bean + public PluginManager pluginManager() { + + return new DefaultPluginManager(Paths.get(pluginsPath)) { + @Override + protected PluginDescriptorFinder createPluginDescriptorFinder() { + return pluginDescriptorFinder(); + } + + @Override + protected ExtensionFactory createExtensionFactory() { + return new ReportPortalExtensionFactory(pluginsResourcesPath, this, context); + } + + @Override + protected ExtensionFinder createExtensionFinder() { + RpExtensionFinder extensionFinder = new RpExtensionFinder(this); + addPluginStateListener(extensionFinder); + return extensionFinder; + } + + class RpExtensionFinder extends DefaultExtensionFinder { + + private RpExtensionFinder(PluginManager pluginManager) { + super(pluginManager); + finders.clear(); + finders.add(new LegacyExtensionFinder(pluginManager) { + @Override + public Set<String> findClassNames(String pluginId) { + return ofNullable(super.findClassNames(pluginId)).orElseGet(Collections::emptySet); + } + }); + } + } + }; + } + + @Bean + public PluginDescriptorFinder pluginDescriptorFinder() { + return new ManifestPluginDescriptorFinder(); + } + + @Bean + public FileTypeMap fileTypeMap() { + return new ConfigurableMimeFileTypeMap(); + } + + @Bean + public PluginFilesProvider pluginPublicFilesProvider() { + return new PluginFilesProvider(pluginsResourcesPath, publicFolderQualifier, fileTypeMap(), + integrationTypeRepository); + } + + @Bean + public PluginFilesProvider pluginFilesProvider() { + return new PluginFilesProvider(pluginsResourcesPath, "", fileTypeMap(), + integrationTypeRepository); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/ProjectValidationConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/ProjectValidationConfig.java index bedc74316f..d21e156d2b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/ProjectValidationConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/ProjectValidationConfig.java @@ -4,27 +4,27 @@ import com.epam.ta.reportportal.core.project.validator.attribute.DelayBoundValidator; import com.epam.ta.reportportal.core.project.validator.attribute.ProjectAttributeValidator; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; +import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - @Configuration public class ProjectValidationConfig { - @Bean - public DelayBoundValidator delayBoundValidator() { - return new DelayBoundValidator(getDelayBoundRules()); - } + @Bean + public DelayBoundValidator delayBoundValidator() { + return new DelayBoundValidator(getDelayBoundRules()); + } - private List<DelayBoundLessRule> getDelayBoundRules() { - return List.of(new DelayBoundLessRule(ProjectAttributeEnum.KEEP_SCREENSHOTS, ProjectAttributeEnum.KEEP_LOGS), - new DelayBoundLessRule(ProjectAttributeEnum.KEEP_LOGS, ProjectAttributeEnum.KEEP_LAUNCHES) - ); - } + private List<DelayBoundLessRule> getDelayBoundRules() { + return List.of(new DelayBoundLessRule(ProjectAttributeEnum.KEEP_SCREENSHOTS, + ProjectAttributeEnum.KEEP_LOGS), + new DelayBoundLessRule(ProjectAttributeEnum.KEEP_LOGS, ProjectAttributeEnum.KEEP_LAUNCHES) + ); + } - @Bean - public ProjectAttributeValidator projectAttributeValidator() { - return new ProjectAttributeValidator(delayBoundValidator()); - } + @Bean + public ProjectAttributeValidator projectAttributeValidator() { + return new ProjectAttributeValidator(delayBoundValidator()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalApp.java b/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalApp.java index 979929cda3..26ba489a01 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalApp.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalApp.java @@ -27,14 +27,15 @@ * * @author Andrei Varabyeu */ -@SpringBootApplication(scanBasePackages = { "com.epam.ta.reportportal", "com.epam.reportportal" }, exclude = { - MultipartAutoConfiguration.class, FlywayAutoConfiguration.class }) +@SpringBootApplication(scanBasePackages = {"com.epam.ta.reportportal", + "com.epam.reportportal"}, exclude = { + MultipartAutoConfiguration.class, FlywayAutoConfiguration.class}) @Configuration -@Import({ com.epam.ta.reportportal.config.DatabaseConfiguration.class }) +@Import({com.epam.ta.reportportal.config.DatabaseConfiguration.class}) public class ReportPortalApp { - public static void main(String[] args) { - SpringApplication.run(ReportPortalApp.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ReportPortalApp.class, args); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelper.java b/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelper.java index 907fc7bd1c..460b0eab5c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelper.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelper.java @@ -12,36 +12,37 @@ */ public class ReportPortalClassLoadHelper extends ResourceLoaderClassLoadHelper { - @Nullable - private ResourceLoader resourceLoader; - - public ReportPortalClassLoadHelper() { - } - - public ReportPortalClassLoadHelper(@Nullable ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - @Override - public void initialize() { - super.initialize(); - if (this.resourceLoader == null) { - this.resourceLoader = SchedulerFactoryBean.getConfigTimeResourceLoader(); - if (this.resourceLoader == null) { - this.resourceLoader = new DefaultResourceLoader(); - } - } - } - - @Override - public Class<?> loadClass(String name) throws ClassNotFoundException { - Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); - return this.resourceLoader.getClassLoader().loadClass(name); - } - - @SuppressWarnings("unchecked") - @Override - public <T> Class<? extends T> loadClass(String name, Class<T> clazz) throws ClassNotFoundException { - return (Class<? extends T>) loadClass(name); - } + @Nullable + private ResourceLoader resourceLoader; + + public ReportPortalClassLoadHelper() { + } + + public ReportPortalClassLoadHelper(@Nullable ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public void initialize() { + super.initialize(); + if (this.resourceLoader == null) { + this.resourceLoader = SchedulerFactoryBean.getConfigTimeResourceLoader(); + if (this.resourceLoader == null) { + this.resourceLoader = new DefaultResourceLoader(); + } + } + } + + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + Assert.state(this.resourceLoader != null, "ResourceLoaderClassLoadHelper not initialized"); + return this.resourceLoader.getClassLoader().loadClass(name); + } + + @SuppressWarnings("unchecked") + @Override + public <T> Class<? extends T> loadClass(String name, Class<T> clazz) + throws ClassNotFoundException { + return (Class<? extends T>) loadClass(name); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/SchedulerConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/SchedulerConfiguration.java index 9f621912db..a994945398 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/SchedulerConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/SchedulerConfiguration.java @@ -16,7 +16,14 @@ package com.epam.ta.reportportal.core.configs; import com.epam.reportportal.extension.classloader.ReportPortalResourceLoader; -import com.epam.ta.reportportal.job.*; +import com.epam.ta.reportportal.job.CleanExpiredCreationBidsJob; +import com.epam.ta.reportportal.job.FlushingDataJob; +import com.epam.ta.reportportal.job.InterruptBrokenLaunchesJob; +import java.time.Duration; +import java.util.List; +import java.util.Properties; +import javax.inject.Named; +import javax.sql.DataSource; import org.quartz.Job; import org.quartz.JobDetail; import org.quartz.SimpleTrigger; @@ -27,166 +34,173 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; import org.springframework.core.io.ResourceLoader; -import org.springframework.scheduling.quartz.*; +import org.springframework.scheduling.quartz.CronTriggerFactoryBean; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; +import org.springframework.scheduling.quartz.SpringBeanJobFactory; import org.springframework.transaction.PlatformTransactionManager; -import javax.inject.Named; -import javax.sql.DataSource; -import java.time.Duration; -import java.util.List; -import java.util.Properties; - @Configuration @Conditional(Conditions.NotTestCondition.class) -@EnableConfigurationProperties({ SchedulerConfiguration.QuartzProperties.class }) +@EnableConfigurationProperties({SchedulerConfiguration.QuartzProperties.class}) public class SchedulerConfiguration { - @Autowired - List<Trigger> listOfTrigger; - - @Autowired - private QuartzProperties quartzProperties; - - @Autowired - private AutowireCapableBeanFactory context; - - @Autowired - private DataSource dataSource; - - @Autowired - private PlatformTransactionManager transactionManager; - - @Autowired - private ReportPortalResourceLoader resourceLoader; - - @Bean - @Primary - public SchedulerFactoryBean schedulerFactoryBean() { - SchedulerFactoryBean scheduler = new SchedulerFactoryBean() { - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - if (this.resourceLoader == null) { - super.setResourceLoader(resourceLoader); - } - } - }; - scheduler.setApplicationContextSchedulerContextKey("applicationContext"); - - scheduler.setOverwriteExistingJobs(true); - scheduler.setResourceLoader(resourceLoader); - scheduler.setQuartzProperties(quartzProperties.getQuartz()); - scheduler.setDataSource(dataSource); - scheduler.setTransactionManager(transactionManager); - scheduler.setAutoStartup(true); // to not automatically start after startup - scheduler.setWaitForJobsToCompleteOnShutdown(true); - scheduler.setJobFactory(beanJobFactory()); - - // Here we will set all the trigger beans we have defined. - if (null != listOfTrigger && !listOfTrigger.isEmpty()) { - scheduler.setTriggers(listOfTrigger.toArray(new Trigger[listOfTrigger.size()])); - } - - return scheduler; - } - - @Bean - public SpringBeanJobFactory beanJobFactory() { - return new SpringBeanJobFactory() { - @Override - protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { - final Object jobInstance = super.createJobInstance(bundle); - context.autowireBean(jobInstance); - return jobInstance; - } - }; - } - - @Bean - public SimpleTriggerFactoryBean interruptLaunchesTrigger(@Named("interruptLaunchesJobBean") JobDetail jobDetail, - @Value("${com.ta.reportportal.job.interrupt.broken.launches.cron}") String interruptLaunchesCron) { - return createTriggerDelayed(jobDetail, Duration.parse(interruptLaunchesCron).toMillis()); - } - - @Bean - public SimpleTriggerFactoryBean cleanExpiredCreationBidsTrigger(@Named("cleanExpiredCreationBidsJobBean") JobDetail jobDetail, - @Value("${com.ta.reportportal.job.clean.bids.cron}") String cleanBidsCron) { - return createTrigger(jobDetail, Duration.parse(cleanBidsCron).toMillis()); - } - - @Bean - @Profile("demo") - public SimpleTriggerFactoryBean flushingDataTrigger(@Named("flushingDataJob") JobDetail jobDetail, - @Value("${com.ta.reportportal.rp.flushing.time.cron}") String flushingCron) { - return createTrigger(jobDetail, Duration.parse(flushingCron).toMillis()); - } - - @Bean("interruptLaunchesJobBean") - public JobDetailFactoryBean interruptLaunchesJob() { - return createJobDetail(InterruptBrokenLaunchesJob.class); - } - - @Bean("cleanExpiredCreationBidsJobBean") - public JobDetailFactoryBean cleanExpiredCreationBidsJob() { - return createJobDetail(CleanExpiredCreationBidsJob.class); - } - - @Bean - @Profile("demo") - @Named("flushingDataJob") - public JobDetailFactoryBean flushingDataJob() { - return createJobDetail(FlushingDataJob.class); - } - - public SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) { - SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); - factoryBean.setJobDetail(jobDetail); - factoryBean.setStartDelay(0L); - factoryBean.setRepeatInterval(pollFrequencyMs); - factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); - // in case of misfire, ignore all missed triggers and continue : - factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); - return factoryBean; - } - - public SimpleTriggerFactoryBean createTriggerDelayed(JobDetail jobDetail, long pollFrequencyMs) { - SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); - factoryBean.setJobDetail(jobDetail); - factoryBean.setStartDelay(pollFrequencyMs); - factoryBean.setRepeatInterval(pollFrequencyMs); - factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); - // in case of misfire, ignore all missed triggers and continue : - factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); - return factoryBean; - } - - // Use this method for creating cron triggers instead of simple triggers: - public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) { - CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); - factoryBean.setJobDetail(jobDetail); - factoryBean.setCronExpression(cronExpression); - factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); - return factoryBean; - } - - public static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass) { - JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); - factoryBean.setJobClass(jobClass); - // job has to be durable to be stored in DB: - factoryBean.setDurability(true); - return factoryBean; - } - - @ConfigurationProperties("spring.application") - public static class QuartzProperties { - - private final Properties quartz = new Properties(); - - public Properties getQuartz() { - return quartz; - } - - } + @Autowired + List<Trigger> listOfTrigger; + + @Autowired + private QuartzProperties quartzProperties; + + @Autowired + private AutowireCapableBeanFactory context; + + @Autowired + private DataSource dataSource; + + @Autowired + private PlatformTransactionManager transactionManager; + + @Autowired + private ReportPortalResourceLoader resourceLoader; + + @Bean + @Primary + public SchedulerFactoryBean schedulerFactoryBean() { + SchedulerFactoryBean scheduler = new SchedulerFactoryBean() { + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + if (this.resourceLoader == null) { + super.setResourceLoader(resourceLoader); + } + } + }; + scheduler.setApplicationContextSchedulerContextKey("applicationContext"); + + scheduler.setOverwriteExistingJobs(true); + scheduler.setResourceLoader(resourceLoader); + scheduler.setQuartzProperties(quartzProperties.getQuartz()); + scheduler.setDataSource(dataSource); + scheduler.setTransactionManager(transactionManager); + scheduler.setAutoStartup(true); // to not automatically start after startup + scheduler.setWaitForJobsToCompleteOnShutdown(true); + scheduler.setJobFactory(beanJobFactory()); + + // Here we will set all the trigger beans we have defined. + if (null != listOfTrigger && !listOfTrigger.isEmpty()) { + scheduler.setTriggers(listOfTrigger.toArray(new Trigger[listOfTrigger.size()])); + } + + return scheduler; + } + + @Bean + public SpringBeanJobFactory beanJobFactory() { + return new SpringBeanJobFactory() { + @Override + protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { + final Object jobInstance = super.createJobInstance(bundle); + context.autowireBean(jobInstance); + return jobInstance; + } + }; + } + + @Bean + public SimpleTriggerFactoryBean interruptLaunchesTrigger( + @Named("interruptLaunchesJobBean") JobDetail jobDetail, + @Value("${com.ta.reportportal.job.interrupt.broken.launches.cron}") String interruptLaunchesCron) { + return createTriggerDelayed(jobDetail, Duration.parse(interruptLaunchesCron).toMillis()); + } + + @Bean + public SimpleTriggerFactoryBean cleanExpiredCreationBidsTrigger( + @Named("cleanExpiredCreationBidsJobBean") JobDetail jobDetail, + @Value("${com.ta.reportportal.job.clean.bids.cron}") String cleanBidsCron) { + return createTrigger(jobDetail, Duration.parse(cleanBidsCron).toMillis()); + } + + @Bean + @Profile("demo") + public SimpleTriggerFactoryBean flushingDataTrigger(@Named("flushingDataJob") JobDetail jobDetail, + @Value("${com.ta.reportportal.rp.flushing.time.cron}") String flushingCron) { + return createTrigger(jobDetail, Duration.parse(flushingCron).toMillis()); + } + + @Bean("interruptLaunchesJobBean") + public JobDetailFactoryBean interruptLaunchesJob() { + return createJobDetail(InterruptBrokenLaunchesJob.class); + } + + @Bean("cleanExpiredCreationBidsJobBean") + public JobDetailFactoryBean cleanExpiredCreationBidsJob() { + return createJobDetail(CleanExpiredCreationBidsJob.class); + } + + @Bean + @Profile("demo") + @Named("flushingDataJob") + public JobDetailFactoryBean flushingDataJob() { + return createJobDetail(FlushingDataJob.class); + } + + public SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) { + SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); + factoryBean.setJobDetail(jobDetail); + factoryBean.setStartDelay(0L); + factoryBean.setRepeatInterval(pollFrequencyMs); + factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); + // in case of misfire, ignore all missed triggers and continue : + factoryBean.setMisfireInstruction( + SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); + return factoryBean; + } + + public SimpleTriggerFactoryBean createTriggerDelayed(JobDetail jobDetail, long pollFrequencyMs) { + SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); + factoryBean.setJobDetail(jobDetail); + factoryBean.setStartDelay(pollFrequencyMs); + factoryBean.setRepeatInterval(pollFrequencyMs); + factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); + // in case of misfire, ignore all missed triggers and continue : + factoryBean.setMisfireInstruction( + SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT); + return factoryBean; + } + + // Use this method for creating cron triggers instead of simple triggers: + public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, + String cronExpression) { + CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); + factoryBean.setJobDetail(jobDetail); + factoryBean.setCronExpression(cronExpression); + factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); + return factoryBean; + } + + public static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass) { + JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); + factoryBean.setJobClass(jobClass); + // job has to be durable to be stored in DB: + factoryBean.setDurability(true); + return factoryBean; + } + + @ConfigurationProperties("spring.application") + public static class QuartzProperties { + + private final Properties quartz = new Properties(); + + public Properties getQuartz() { + return quartz; + } + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/SecurityConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/SecurityConfiguration.java index 4e17b0a5ce..a118981afe 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/SecurityConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/SecurityConfiguration.java @@ -22,6 +22,8 @@ import com.epam.ta.reportportal.dao.ServerSettingsRepository; import com.epam.ta.reportportal.entity.ServerSettings; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -53,9 +55,6 @@ import org.springframework.security.web.access.expression.WebExpressionVoter; import org.springframework.util.StringUtils; -import java.util.List; -import java.util.Optional; - /** * Spring's Security Configuration * @@ -64,147 +63,149 @@ @Configuration class SecurityConfiguration { - @Bean - public PermissionEvaluatorFactoryBean permissionEvaluator() { - return new PermissionEvaluatorFactoryBean(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Configuration - @EnableGlobalMethodSecurity(proxyTargetClass = true, prePostEnabled = true) - public static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { - - @Autowired - private RoleHierarchy roleHierarchy; - - @Autowired - private PermissionEvaluator permissionEvaluator; - - @Override - protected MethodSecurityExpressionHandler createExpressionHandler() { - DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); - handler.setRoleHierarchy(roleHierarchy); - handler.setPermissionEvaluator(permissionEvaluator); - return handler; - } - - } - - @Configuration - @EnableResourceServer - public static class SecurityServerConfiguration extends ResourceServerConfigurerAdapter { - - private static final String SECRET_KEY = "secret.key"; - - @Value("${rp.jwt.signing-key}") - private String signingKey; - - @Autowired - private PermissionEvaluator permissionEvaluator; - - @Autowired - private DatabaseUserDetailsService userDetailsService; - - @Autowired - private ServerSettingsRepository serverSettingsRepository; - - @Bean - public static PermissionEvaluatorFactoryBean permissionEvaluatorFactoryBean() { - return new PermissionEvaluatorFactoryBean(); - } - - @Bean - public static RoleHierarchy userRoleHierarchy() { - return new UserRoleHierarchy(); - } - - @Bean - public TokenStore tokenStore() { - return new CombinedTokenStore(accessTokenConverter()); - } - - @Bean - @Profile("!unittest") - public JwtAccessTokenConverter accessTokenConverter() { - JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter(); - jwtConverter.setSigningKey(getSecret()); - - DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); - DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); - defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); - accessTokenConverter.setUserTokenConverter(defaultUserAuthenticationConverter); - - jwtConverter.setAccessTokenConverter(accessTokenConverter); - - return jwtConverter; - } - - private String getSecret() { - if (!StringUtils.isEmpty(signingKey)) { - return signingKey; - } - Optional<ServerSettings> secretKey = serverSettingsRepository.findByKey(SECRET_KEY); - return secretKey.isPresent() ? secretKey.get().getValue() : serverSettingsRepository.generateSecret(); - } - - @Bean - @Primary - public DefaultTokenServices tokenServices() { - DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); - defaultTokenServices.setTokenStore(tokenStore()); - defaultTokenServices.setSupportRefreshToken(true); - defaultTokenServices.setTokenEnhancer(accessTokenConverter()); - return defaultTokenServices; - } - - private DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() { - OAuth2WebSecurityExpressionHandler handler = new OAuth2WebSecurityExpressionHandler(); - handler.setRoleHierarchy(userRoleHierarchy()); - handler.setPermissionEvaluator(permissionEvaluator); - return handler; - } - - private AccessDecisionManager webAccessDecisionManager() { - List<AccessDecisionVoter<?>> accessDecisionVoters = Lists.newArrayList(); - accessDecisionVoters.add(new AuthenticatedVoter()); - WebExpressionVoter webVoter = new WebExpressionVoter(); - webVoter.setExpressionHandler(webSecurityExpressionHandler()); - accessDecisionVoters.add(webVoter); - - return new AffirmativeBased(accessDecisionVoters); - } - - @Override - public void configure(HttpSecurity http) throws Exception { - http.authorizeRequests() - .accessDecisionManager(webAccessDecisionManager()) - .antMatchers("/**/user/registration/info*", - "/**/user/registration**", - "/**/user/password/reset/*", - "/**/user/password/reset**", - "/**/user/password/restore**", - "/documentation.html", - "/health", - "/info" - ) - .permitAll() - /* set of special endpoints for another microservices from RP ecosystem */ - .antMatchers("/api-internal/**") - .hasRole("COMPONENT") - .antMatchers("/v2/**", "/swagger-resources", "/certificate/**", "/api/**", "/**") - .hasRole("USER") - .anyRequest() - .authenticated() - .and() - .csrf() - .disable(); - } - - } + @Bean + public PermissionEvaluatorFactoryBean permissionEvaluator() { + return new PermissionEvaluatorFactoryBean(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Configuration + @EnableGlobalMethodSecurity(proxyTargetClass = true, prePostEnabled = true) + public static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { + + @Autowired + private RoleHierarchy roleHierarchy; + + @Autowired + private PermissionEvaluator permissionEvaluator; + + @Override + protected MethodSecurityExpressionHandler createExpressionHandler() { + DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); + handler.setRoleHierarchy(roleHierarchy); + handler.setPermissionEvaluator(permissionEvaluator); + return handler; + } + + } + + @Configuration + @EnableResourceServer + public static class SecurityServerConfiguration extends ResourceServerConfigurerAdapter { + + private static final String SECRET_KEY = "secret.key"; + + @Value("${rp.jwt.signing-key}") + private String signingKey; + + @Autowired + private PermissionEvaluator permissionEvaluator; + + @Autowired + private DatabaseUserDetailsService userDetailsService; + + @Autowired + private ServerSettingsRepository serverSettingsRepository; + + @Bean + public static PermissionEvaluatorFactoryBean permissionEvaluatorFactoryBean() { + return new PermissionEvaluatorFactoryBean(); + } + + @Bean + public static RoleHierarchy userRoleHierarchy() { + return new UserRoleHierarchy(); + } + + @Bean + public TokenStore tokenStore() { + return new CombinedTokenStore(accessTokenConverter()); + } + + @Bean + @Profile("!unittest") + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter(); + jwtConverter.setSigningKey(getSecret()); + + DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); + DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); + defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); + accessTokenConverter.setUserTokenConverter(defaultUserAuthenticationConverter); + + jwtConverter.setAccessTokenConverter(accessTokenConverter); + + return jwtConverter; + } + + private String getSecret() { + if (!StringUtils.isEmpty(signingKey)) { + return signingKey; + } + Optional<ServerSettings> secretKey = serverSettingsRepository.findByKey(SECRET_KEY); + return secretKey.isPresent() ? secretKey.get().getValue() + : serverSettingsRepository.generateSecret(); + } + + @Bean + @Primary + public DefaultTokenServices tokenServices() { + DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); + defaultTokenServices.setTokenStore(tokenStore()); + defaultTokenServices.setSupportRefreshToken(true); + defaultTokenServices.setTokenEnhancer(accessTokenConverter()); + return defaultTokenServices; + } + + private DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() { + OAuth2WebSecurityExpressionHandler handler = new OAuth2WebSecurityExpressionHandler(); + handler.setRoleHierarchy(userRoleHierarchy()); + handler.setPermissionEvaluator(permissionEvaluator); + return handler; + } + + private AccessDecisionManager webAccessDecisionManager() { + List<AccessDecisionVoter<?>> accessDecisionVoters = Lists.newArrayList(); + accessDecisionVoters.add(new AuthenticatedVoter()); + WebExpressionVoter webVoter = new WebExpressionVoter(); + webVoter.setExpressionHandler(webSecurityExpressionHandler()); + accessDecisionVoters.add(webVoter); + + return new AffirmativeBased(accessDecisionVoters); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .accessDecisionManager(webAccessDecisionManager()) + .antMatchers("/**/user**/registration/info*", + "/**/user**/registration**", + "/**/user**/password/reset/*", + "/**/user**/password/reset**", + "/**/user**/password/restore**", + "/**/plugin/public/**", + "/documentation.html", + "/health", + "/info" + ) + .permitAll() + /* set of special endpoints for another microservices from RP ecosystem */ + .antMatchers("/api-internal/**") + .hasRole("COMPONENT") + .antMatchers("/v2/**", "/swagger-resources", "/certificate/**", "/api/**", "/**") + .hasRole("USER") + .anyRequest() + .authenticated() + .and() + .csrf() + .disable(); + } + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/Swagger2Configuration.java b/src/main/java/com/epam/ta/reportportal/core/configs/Swagger2Configuration.java index c9dcea28ef..82271717dc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/Swagger2Configuration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/Swagger2Configuration.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.configs; +import static com.epam.ta.reportportal.commons.querygen.constant.ProjectCriteriaConstant.CRITERIA_PROJECT_ATTRIBUTE_NAME; +import static com.google.common.base.Predicates.not; +import static com.google.common.base.Predicates.or; +import static com.google.common.collect.Lists.newArrayList; +import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; +import static springfox.documentation.spi.schema.contexts.ModelContext.inputParam; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.CriteriaHolder; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -30,6 +37,14 @@ import com.fasterxml.classmate.TypeResolver; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import java.sql.Timestamp; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.servlet.ServletContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -58,22 +73,6 @@ import springfox.documentation.swagger.web.UiConfigurationBuilder; import springfox.documentation.swagger2.annotations.EnableSwagger2; -import javax.servlet.ServletContext; -import java.sql.Timestamp; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.ProjectCriteriaConstant.CRITERIA_PROJECT_ATTRIBUTE_NAME; -import static com.google.common.base.Predicates.not; -import static com.google.common.base.Predicates.or; -import static com.google.common.collect.Lists.newArrayList; -import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; -import static springfox.documentation.spi.schema.contexts.ModelContext.inputParam; - /** * SWAGGER 2.0 UI page configuration for Report Portal application * @@ -87,16 +86,17 @@ @ComponentScan(basePackages = "com.epam.ta.reportportal.ws.controller") public class Swagger2Configuration { - private static final Set<String> hiddenParams = ImmutableSet.<String>builder().add(CRITERIA_PROJECT_ATTRIBUTE_NAME).build(); + private static final Set<String> hiddenParams = ImmutableSet.<String>builder() + .add(CRITERIA_PROJECT_ATTRIBUTE_NAME).build(); - @Autowired - private ServletContext servletContext; + @Autowired + private ServletContext servletContext; - @Value("${spring.application.name}") - private String applicationName; + @Value("${spring.application.name}") + private String applicationName; - @Value("${info.build.version}") - private String buildVersion; + @Value("${info.build.version}") + private String buildVersion; @Bean public Docket docket() { @@ -112,178 +112,193 @@ public Docket docket() { Collections.emptyList() ); - // @formatter:off - Docket rpDocket = new Docket(DocumentationType.SWAGGER_2) - .ignoredParameterTypes(ReportPortalUser.class, Filter.class, Queryable.class, Pageable.class, UserRole.class) - .pathProvider(rpPathProvider()) - .useDefaultResponseMessages(false) - /* remove default endpoints from listing */ - .select().apis(not(or( - basePackage("org.springframework.boot"), - basePackage("org.springframework.cloud")))) - .build(); - //@formatter:on - - rpDocket.apiInfo(rpInfo); - return rpDocket; - } - - @Bean - public PathProvider rpPathProvider() { - return new RelativePathProvider(servletContext) { - @Override - public String getApplicationBasePath() { - return "/" + applicationName + super.getApplicationBasePath(); - } - }; - } - - @Bean - OperationPageableParameterReader pageableParameterBuilderPlugin(TypeNameExtractor nameExtractor, TypeResolver resolver) { - return new OperationPageableParameterReader(nameExtractor, resolver); - } - - @Bean - public UiConfiguration uiConfig() { - return UiConfigurationBuilder.builder().build(); - } - - @Component - public class OperationPageableParameterReader implements OperationBuilderPlugin { - private final TypeNameExtractor nameExtractor; - private final TypeResolver resolver; - - private final ResolvedType pageableType; - private final ResolvedType filterType; - - @Autowired - public OperationPageableParameterReader(TypeNameExtractor nameExtractor, TypeResolver resolver) { - this.nameExtractor = nameExtractor; - this.resolver = resolver; - this.pageableType = resolver.resolve(Pageable.class); - this.filterType = resolver.resolve(Filter.class); - } - - @Override - public void apply(OperationContext context) { - List<ResolvedMethodParameter> methodParameters = context.getParameters(); - List<Parameter> parameters = newArrayList(); - - for (ResolvedMethodParameter methodParameter : methodParameters) { - ResolvedType resolvedType = methodParameter.getParameterType(); - ParameterContext parameterContext = new ParameterContext( - methodParameter, - new ParameterBuilder(), - context.getDocumentationContext(), - context.getGenericsNamingStrategy(), - context - ); - Function<ResolvedType, ? extends ModelReference> factory = createModelRefFactory(parameterContext); - ModelReference stringModel = factory.apply(resolver.resolve(List.class, String.class)); - - if (pageableType.equals(resolvedType)) { - - ModelReference intModel = factory.apply(resolver.resolve(Integer.TYPE)); - - parameters.add(new ParameterBuilder().parameterType("query") - .name("page.page") - .modelRef(intModel) - .description("Results page you want to retrieve (0..N)") - .build()); - parameters.add(new ParameterBuilder().parameterType("query") - .name("page.size") - .modelRef(intModel) - .description("Number of records per page") - .build()); - parameters.add(new ParameterBuilder().parameterType("query") - .name("page.sort") - .modelRef(stringModel) - .allowMultiple(true) - .description("Sorting criteria in the format: property, (asc|desc). " + "Default sort order is ascending. " - + "Multiple sort criteria are supported.") - .build()); - context.operationBuilder().parameters(parameters); - - } else if (filterType.equals(resolvedType)) { - FilterFor filterClass = methodParameter.findAnnotation(FilterFor.class).get(); - - List<Parameter> defaultParams = Lists.newArrayList(); - if (filterClass.value() == TestItem.class || filterClass.value() == Launch.class) { - defaultParams = StatisticsHelper.defaultStatisticsFields() - .map(it -> buildParameters(parameterContext, factory, it)) - .collect(Collectors.toList()); - } - - List<CriteriaHolder> criteriaList = FilterTarget.findByClass(filterClass.value()).getCriteriaHolders(); - List<Parameter> params = criteriaList.stream() - .filter(ch -> !hiddenParams.contains(ch.getFilterCriteria())) - .map(it -> buildParameters(parameterContext, factory, it)) - /* if type is not a collection and first letter is not capital (all known to swagger types start from lower case) */ - .filter(p -> !(null == p.getModelRef().getItemType() && Character.isUpperCase(p.getModelRef() - .getType() - .toCharArray()[0]))) - .collect(Collectors.toList()); - - params.addAll(defaultParams); - context.operationBuilder().parameters(params); - } - } - } - - private Parameter buildParameters(ParameterContext parameterContext, Function<ResolvedType, ? extends ModelReference> factory, - CriteriaHolder criteriaHolder) { - return parameterContext.parameterBuilder() - .parameterType("query") - .name("filter.eq." + criteriaHolder.getFilterCriteria()) - .allowMultiple(true) - .modelRef(factory.apply(resolver.resolve( - criteriaHolder.getDataType() == Timestamp.class ? Date.class : criteriaHolder.getDataType()))) - .description("Filters by '" + criteriaHolder.getFilterCriteria() + "'") - .build(); - } - - private Parameter buildParameters(ParameterContext parameterContext, Function<ResolvedType, ? extends ModelReference> factory, - String parameter) { - return parameterContext.parameterBuilder() - .parameterType("query") - .name("filter.eq." + parameter) - .allowMultiple(true) - .modelRef(factory.apply(resolver.resolve(Long.class))) - .description("Filters by '" + parameter + "'") - .build(); - } - - @Override - public boolean supports(DocumentationType delimiter) { - return true; - } - - private Function<ResolvedType, ? extends ModelReference> createModelRefFactory(ParameterContext context) { - ModelContext modelContext = inputParam( - Docket.DEFAULT_GROUP_NAME, - context.resolvedMethodParameter().getParameterType().getErasedType(), - context.getDocumentationType(), - context.getAlternateTypeProvider(), - context.getGenericNamingStrategy(), - context.getIgnorableParameterTypes() - ); - return ResolvedTypes.modelRefFactory(modelContext, nameExtractor); - } - } - - @SuppressWarnings("unused") - private static class RPPathProvider extends RelativePathProvider { - - private String gatewayPath; - - RPPathProvider(ServletContext servletContext, String gatewayPath) { - super(servletContext); - this.gatewayPath = gatewayPath; - } - - @Override - protected String applicationPath() { - return "/" + gatewayPath + super.applicationPath(); - } - } + // @formatter:off + Docket rpDocket = new Docket(DocumentationType.SWAGGER_2) + .ignoredParameterTypes(ReportPortalUser.class, Filter.class, Queryable.class, + Pageable.class, UserRole.class) + .pathProvider(rpPathProvider()) + .useDefaultResponseMessages(false) + /* remove default endpoints from listing */ + .select().apis(not(or( + basePackage("org.springframework.boot"), + basePackage("org.springframework.cloud")))) + .build(); + //@formatter:on + + rpDocket.apiInfo(rpInfo); + return rpDocket; + } + + @Bean + public PathProvider rpPathProvider() { + return new RelativePathProvider(servletContext) { + @Override + public String getApplicationBasePath() { + if (super.getApplicationBasePath().contains(applicationName)) { + return super.getApplicationBasePath(); + } + return "/" + applicationName + super.getApplicationBasePath(); + } + }; + } + + @Bean + OperationPageableParameterReader pageableParameterBuilderPlugin(TypeNameExtractor nameExtractor, + TypeResolver resolver) { + return new OperationPageableParameterReader(nameExtractor, resolver); + } + + @Bean + public UiConfiguration uiConfig() { + return UiConfigurationBuilder.builder().build(); + } + + @Component + public class OperationPageableParameterReader implements OperationBuilderPlugin { + + private final TypeNameExtractor nameExtractor; + private final TypeResolver resolver; + + private final ResolvedType pageableType; + private final ResolvedType filterType; + + @Autowired + public OperationPageableParameterReader(TypeNameExtractor nameExtractor, + TypeResolver resolver) { + this.nameExtractor = nameExtractor; + this.resolver = resolver; + this.pageableType = resolver.resolve(Pageable.class); + this.filterType = resolver.resolve(Filter.class); + } + + @Override + public void apply(OperationContext context) { + List<ResolvedMethodParameter> methodParameters = context.getParameters(); + List<Parameter> parameters = newArrayList(); + + for (ResolvedMethodParameter methodParameter : methodParameters) { + ResolvedType resolvedType = methodParameter.getParameterType(); + ParameterContext parameterContext = new ParameterContext( + methodParameter, + new ParameterBuilder(), + context.getDocumentationContext(), + context.getGenericsNamingStrategy(), + context + ); + Function<ResolvedType, ? extends ModelReference> factory = createModelRefFactory( + parameterContext); + ModelReference stringModel = factory.apply(resolver.resolve(List.class, String.class)); + + if (pageableType.equals(resolvedType)) { + + ModelReference intModel = factory.apply(resolver.resolve(Integer.TYPE)); + + parameters.add(new ParameterBuilder().parameterType("query") + .name("page.page") + .modelRef(intModel) + .description("Results page you want to retrieve (0..N)") + .build()); + parameters.add(new ParameterBuilder().parameterType("query") + .name("page.size") + .modelRef(intModel) + .description("Number of records per page") + .build()); + parameters.add(new ParameterBuilder().parameterType("query") + .name("page.sort") + .modelRef(stringModel) + .allowMultiple(true) + .description("Sorting criteria in the format: property, (asc|desc). " + + "Default sort order is ascending. " + + "Multiple sort criteria are supported.") + .build()); + context.operationBuilder().parameters(parameters); + + } else if (filterType.equals(resolvedType)) { + FilterFor filterClass = methodParameter.findAnnotation(FilterFor.class).get(); + + List<Parameter> defaultParams = Lists.newArrayList(); + if (filterClass.value() == TestItem.class || filterClass.value() == Launch.class) { + defaultParams = StatisticsHelper.defaultStatisticsFields() + .map(it -> buildParameters(parameterContext, factory, it)) + .collect(Collectors.toList()); + } + + List<CriteriaHolder> criteriaList = FilterTarget.findByClass(filterClass.value()) + .getCriteriaHolders(); + List<Parameter> params = criteriaList.stream() + .filter(ch -> !hiddenParams.contains(ch.getFilterCriteria())) + .map(it -> buildParameters(parameterContext, factory, it)) + /* if type is not a collection and first letter is not capital (all known to swagger types start from lower case) */ + .filter(p -> !(null == p.getModelRef().getItemType() && Character.isUpperCase( + p.getModelRef() + .getType() + .toCharArray()[0]))) + .collect(Collectors.toList()); + + params.addAll(defaultParams); + context.operationBuilder().parameters(params); + } + } + } + + private Parameter buildParameters(ParameterContext parameterContext, + Function<ResolvedType, ? extends ModelReference> factory, + CriteriaHolder criteriaHolder) { + return parameterContext.parameterBuilder() + .parameterType("query") + .name("filter.eq." + criteriaHolder.getFilterCriteria()) + .allowMultiple(true) + .modelRef(factory.apply(resolver.resolve( + criteriaHolder.getDataType() == Timestamp.class ? Date.class + : criteriaHolder.getDataType()))) + .description("Filters by '" + criteriaHolder.getFilterCriteria() + "'") + .build(); + } + + private Parameter buildParameters(ParameterContext parameterContext, + Function<ResolvedType, ? extends ModelReference> factory, + String parameter) { + return parameterContext.parameterBuilder() + .parameterType("query") + .name("filter.eq." + parameter) + .allowMultiple(true) + .modelRef(factory.apply(resolver.resolve(Long.class))) + .description("Filters by '" + parameter + "'") + .build(); + } + + @Override + public boolean supports(DocumentationType delimiter) { + return true; + } + + private Function<ResolvedType, ? extends ModelReference> createModelRefFactory( + ParameterContext context) { + ModelContext modelContext = inputParam( + Docket.DEFAULT_GROUP_NAME, + context.resolvedMethodParameter().getParameterType().getErasedType(), + context.getDocumentationType(), + context.getAlternateTypeProvider(), + context.getGenericNamingStrategy(), + context.getIgnorableParameterTypes() + ); + return ResolvedTypes.modelRefFactory(modelContext, nameExtractor); + } + } + + @SuppressWarnings("unused") + private static class RPPathProvider extends RelativePathProvider { + + private String gatewayPath; + + RPPathProvider(ServletContext servletContext, String gatewayPath) { + super(servletContext); + this.gatewayPath = gatewayPath; + } + + @Override + protected String applicationPath() { + return "/" + gatewayPath + super.applicationPath(); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/WidgetConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/WidgetConfig.java index cf6ba4dd2b..8e617143b3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/WidgetConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/WidgetConfig.java @@ -19,8 +19,32 @@ import com.epam.ta.reportportal.core.widget.content.BuildFilterStrategy; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.content.MultilevelLoadContentStrategy; -import com.epam.ta.reportportal.core.widget.content.filter.*; -import com.epam.ta.reportportal.core.widget.content.loader.*; +import com.epam.ta.reportportal.core.widget.content.filter.ActivityFilterStrategy; +import com.epam.ta.reportportal.core.widget.content.filter.GeneralLaunchFilterStrategy; +import com.epam.ta.reportportal.core.widget.content.filter.LaunchHistoryFilterStrategy; +import com.epam.ta.reportportal.core.widget.content.filter.ProductStatusFilterStrategy; +import com.epam.ta.reportportal.core.widget.content.loader.ActivityContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.BugTrendChartContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.CasesTrendContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.ChartInvestigatedContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.ComponentHealthCheckContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.FlakyCasesTableContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.LaunchExecutionAndIssueStatisticsContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.LaunchesComparisonContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.LaunchesDurationContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.LaunchesTableContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.LineChartContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.MostTimeConsumingContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.NotPassedTestsContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.OverallStatisticsContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.PassingRatePerLaunchContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.PassingRateSummaryContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.ProductStatusContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.ProductStatusFilterGroupedContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.ProductStatusLaunchGroupedContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.TopPatternContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.TopTestCasesContentLoader; +import com.epam.ta.reportportal.core.widget.content.loader.UniqueBugContentLoader; import com.epam.ta.reportportal.core.widget.content.loader.materialized.CumulativeTrendChartContentLoaderImpl; import com.epam.ta.reportportal.core.widget.content.loader.materialized.HealthCheckTableReadyContentLoader; import com.epam.ta.reportportal.core.widget.content.loader.materialized.MaterializedWidgetContentLoader; @@ -28,7 +52,11 @@ import com.epam.ta.reportportal.core.widget.content.loader.materialized.generator.FailedViewStateGenerator; import com.epam.ta.reportportal.core.widget.content.loader.materialized.generator.HealthCheckTableGenerator; import com.epam.ta.reportportal.core.widget.content.loader.materialized.generator.ViewGenerator; -import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.*; +import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.CreatedMaterializedWidgetStateHandler; +import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.EmptyMaterializedWidgetStateHandler; +import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.FailedMaterializedWidgetStateHandler; +import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler; +import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.ReadyMaterializedWidgetStateHandler; import com.epam.ta.reportportal.core.widget.content.loader.util.ProductStatusContentLoaderManager; import com.epam.ta.reportportal.core.widget.content.remover.MaterializedViewRemover; import com.epam.ta.reportportal.core.widget.content.remover.StaleMaterializedViewRemover; @@ -39,6 +67,8 @@ import com.epam.ta.reportportal.entity.widget.WidgetType; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import java.util.Map; +import java.util.Set; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -46,9 +76,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; -import java.util.Set; - /** * Configuration related to widgets. * @@ -58,169 +85,204 @@ @Configuration public class WidgetConfig implements ApplicationContextAware { - private ApplicationContext applicationContext; - - @Autowired - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Bean("contentLoader") - public Map<WidgetType, LoadContentStrategy> contentLoader() { - return ImmutableMap.<WidgetType, LoadContentStrategy>builder().put(WidgetType.FLAKY_TEST_CASES, - applicationContext.getBean(FlakyCasesTableContentLoader.class) - ) - .put(WidgetType.OVERALL_STATISTICS, applicationContext.getBean(OverallStatisticsContentLoader.class)) - .put(WidgetType.PASSING_RATE_SUMMARY, applicationContext.getBean(PassingRateSummaryContentLoader.class)) - .put(WidgetType.OLD_LINE_CHART, applicationContext.getBean(LineChartContentLoader.class)) - .put(WidgetType.INVESTIGATED_TREND, applicationContext.getBean(ChartInvestigatedContentLoader.class)) - .put(WidgetType.STATISTIC_TREND, applicationContext.getBean(LineChartContentLoader.class)) - .put(WidgetType.LAUNCH_STATISTICS, applicationContext.getBean(LaunchExecutionAndIssueStatisticsContentLoader.class)) - .put(WidgetType.CASES_TREND, applicationContext.getBean(CasesTrendContentLoader.class)) - .put(WidgetType.NOT_PASSED, applicationContext.getBean(NotPassedTestsContentLoader.class)) - .put(WidgetType.UNIQUE_BUG_TABLE, applicationContext.getBean(UniqueBugContentLoader.class)) - .put(WidgetType.BUG_TREND, applicationContext.getBean(BugTrendChartContentLoader.class)) - .put(WidgetType.ACTIVITY, applicationContext.getBean(ActivityContentLoader.class)) - .put(WidgetType.LAUNCHES_COMPARISON_CHART, applicationContext.getBean(LaunchesComparisonContentLoader.class)) - .put(WidgetType.LAUNCHES_DURATION_CHART, applicationContext.getBean(LaunchesDurationContentLoader.class)) - .put(WidgetType.LAUNCHES_TABLE, applicationContext.getBean(LaunchesTableContentLoader.class)) - .put(WidgetType.TOP_TEST_CASES, applicationContext.getBean(TopTestCasesContentLoader.class)) - .put(WidgetType.PASSING_RATE_PER_LAUNCH, applicationContext.getBean(PassingRatePerLaunchContentLoader.class)) - .put(WidgetType.PRODUCT_STATUS, applicationContext.getBean(ProductStatusContentLoaderManager.class)) - .put(WidgetType.MOST_TIME_CONSUMING, applicationContext.getBean(MostTimeConsumingContentLoader.class)) - .build(); - } - - @Bean("multilevelContentLoader") - public Map<WidgetType, MultilevelLoadContentStrategy> multilevelContentLoader() { - return ImmutableMap.<WidgetType, MultilevelLoadContentStrategy>builder().put(WidgetType.TOP_PATTERN_TEMPLATES, - applicationContext.getBean(TopPatternContentLoader.class) - ) - .put(WidgetType.COMPONENT_HEALTH_CHECK, applicationContext.getBean(ComponentHealthCheckContentLoader.class)) - .build(); - } - - @Bean("buildFilterStrategy") - public Map<WidgetType, BuildFilterStrategy> buildFilterStrategy() { - return ImmutableMap.<WidgetType, BuildFilterStrategy>builder().put(WidgetType.OLD_LINE_CHART, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.INVESTIGATED_TREND, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.STATISTIC_TREND, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.LAUNCH_STATISTICS, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.OVERALL_STATISTICS, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.CASES_TREND, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.NOT_PASSED, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.BUG_TREND, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.LAUNCHES_TABLE, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.PASSING_RATE_SUMMARY, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.CUMULATIVE, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.PRODUCT_STATUS, (ProductStatusFilterStrategy) applicationContext.getBean("productStatusFilterStrategy")) - .put(WidgetType.UNIQUE_BUG_TABLE, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.ACTIVITY, (ActivityFilterStrategy) applicationContext.getBean("activityFilterStrategy")) - .put(WidgetType.LAUNCHES_COMPARISON_CHART, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.LAUNCHES_DURATION_CHART, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.TOP_TEST_CASES, (LaunchHistoryFilterStrategy) applicationContext.getBean("launchHistoryFilterStrategy")) - .put(WidgetType.PASSING_RATE_PER_LAUNCH, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.FLAKY_TEST_CASES, (GeneralLaunchFilterStrategy) applicationContext.getBean("launchHistoryFilterStrategy")) - .put(WidgetType.MOST_TIME_CONSUMING, (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) - .put(WidgetType.TOP_PATTERN_TEMPLATES, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.COMPONENT_HEALTH_CHECK, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, - (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") - ) - .build(); - } - - @Bean("productStatusContentLoader") - public Map<String, ProductStatusContentLoader> productStatusContentLoader() { - return ImmutableMap.<String, ProductStatusContentLoader>builder().put("launch", - applicationContext.getBean(ProductStatusLaunchGroupedContentLoader.class) - ) - .put("filter", applicationContext.getBean(ProductStatusFilterGroupedContentLoader.class)) - .build(); - } - - @Bean("groupingStrategy") - public Map<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup> group() { - return ImmutableMap.<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup>builder().put(InfoInterval.ONE_MONTH, - ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY - ) - .put(InfoInterval.THREE_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) - .put(InfoInterval.SIX_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) - .build(); - } - - @Bean("unfilteredWidgetTypes") - public Set<WidgetType> unfilteredWidgetTypes() { - return ImmutableSet.<WidgetType>builder().add(WidgetType.ACTIVITY) - .add(WidgetType.TOP_TEST_CASES) - .add(WidgetType.PASSING_RATE_PER_LAUNCH) - .add(WidgetType.MOST_TIME_CONSUMING) - .add(WidgetType.FLAKY_TEST_CASES) - .build(); - } - - @Bean("widgetStateHandlerMapping") - public Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping() { - return ImmutableMap.<WidgetState, MaterializedWidgetStateHandler>builder().put(WidgetState.CREATED, - applicationContext.getBean(CreatedMaterializedWidgetStateHandler.class) - ) - .put(WidgetState.READY, applicationContext.getBean(ReadyMaterializedWidgetStateHandler.class)) - .put(WidgetState.RENDERING, applicationContext.getBean(EmptyMaterializedWidgetStateHandler.class)) - .put(WidgetState.FAILED, applicationContext.getBean(FailedMaterializedWidgetStateHandler.class)) - .build(); - } - - @Bean("materializedWidgetContentLoaderMapping") - public Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping() { - return ImmutableMap.<WidgetType, MaterializedWidgetContentLoader>builder().put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, - applicationContext.getBean(HealthCheckTableReadyContentLoader.class) - ) - .put(WidgetType.CUMULATIVE, applicationContext.getBean(CumulativeTrendChartContentLoaderImpl.class)) - .build(); - } - - @Bean("cumulativeFailedViewStateGenerator") - public FailedViewStateGenerator cumulativeFailedViewStateGenerator() { - return new FailedViewStateGenerator(applicationContext.getBean(CumulativeTrendChartViewGenerator.class), - applicationContext.getBean(WidgetRepository.class) - ); - } - - @Bean("healthCheckTableFailedViewStateGenerator") - public FailedViewStateGenerator healthCheckTableFailedViewStateGenerator() { - return new FailedViewStateGenerator(applicationContext.getBean(HealthCheckTableGenerator.class), - applicationContext.getBean(WidgetRepository.class) - ); - } - - @Bean("viewGeneratorMapping") - public Map<WidgetType, ViewGenerator> viewGeneratorMapping() { - return ImmutableMap.<WidgetType, ViewGenerator>builder() - .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, healthCheckTableFailedViewStateGenerator()) - .put(WidgetType.CUMULATIVE, cumulativeFailedViewStateGenerator()) - .build(); - } - - @Bean("widgetContentRemoverMapping") - public Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping() { - return ImmutableMap.<WidgetState, WidgetContentRemover>builder() - .put(WidgetState.READY, applicationContext.getBean(MaterializedViewRemover.class)) - .put(WidgetState.RENDERING, applicationContext.getBean(StaleMaterializedViewRemover.class)) - .build(); - } + private ApplicationContext applicationContext; + + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Bean("contentLoader") + public Map<WidgetType, LoadContentStrategy> contentLoader() { + return ImmutableMap.<WidgetType, LoadContentStrategy>builder().put(WidgetType.FLAKY_TEST_CASES, + applicationContext.getBean(FlakyCasesTableContentLoader.class) + ) + .put(WidgetType.OVERALL_STATISTICS, + applicationContext.getBean(OverallStatisticsContentLoader.class)) + .put(WidgetType.PASSING_RATE_SUMMARY, + applicationContext.getBean(PassingRateSummaryContentLoader.class)) + .put(WidgetType.OLD_LINE_CHART, applicationContext.getBean(LineChartContentLoader.class)) + .put(WidgetType.INVESTIGATED_TREND, + applicationContext.getBean(ChartInvestigatedContentLoader.class)) + .put(WidgetType.STATISTIC_TREND, applicationContext.getBean(LineChartContentLoader.class)) + .put(WidgetType.LAUNCH_STATISTICS, + applicationContext.getBean(LaunchExecutionAndIssueStatisticsContentLoader.class)) + .put(WidgetType.CASES_TREND, applicationContext.getBean(CasesTrendContentLoader.class)) + .put(WidgetType.NOT_PASSED, applicationContext.getBean(NotPassedTestsContentLoader.class)) + .put(WidgetType.UNIQUE_BUG_TABLE, applicationContext.getBean(UniqueBugContentLoader.class)) + .put(WidgetType.BUG_TREND, applicationContext.getBean(BugTrendChartContentLoader.class)) + .put(WidgetType.ACTIVITY, applicationContext.getBean(ActivityContentLoader.class)) + .put(WidgetType.LAUNCHES_COMPARISON_CHART, + applicationContext.getBean(LaunchesComparisonContentLoader.class)) + .put(WidgetType.LAUNCHES_DURATION_CHART, + applicationContext.getBean(LaunchesDurationContentLoader.class)) + .put(WidgetType.LAUNCHES_TABLE, + applicationContext.getBean(LaunchesTableContentLoader.class)) + .put(WidgetType.TOP_TEST_CASES, applicationContext.getBean(TopTestCasesContentLoader.class)) + .put(WidgetType.PASSING_RATE_PER_LAUNCH, + applicationContext.getBean(PassingRatePerLaunchContentLoader.class)) + .put(WidgetType.PRODUCT_STATUS, + applicationContext.getBean(ProductStatusContentLoaderManager.class)) + .put(WidgetType.MOST_TIME_CONSUMING, + applicationContext.getBean(MostTimeConsumingContentLoader.class)) + .build(); + } + + @Bean("multilevelContentLoader") + public Map<WidgetType, MultilevelLoadContentStrategy> multilevelContentLoader() { + return ImmutableMap.<WidgetType, MultilevelLoadContentStrategy>builder() + .put(WidgetType.TOP_PATTERN_TEMPLATES, + applicationContext.getBean(TopPatternContentLoader.class) + ) + .put(WidgetType.COMPONENT_HEALTH_CHECK, + applicationContext.getBean(ComponentHealthCheckContentLoader.class)) + .build(); + } + + @Bean("buildFilterStrategy") + public Map<WidgetType, BuildFilterStrategy> buildFilterStrategy() { + return ImmutableMap.<WidgetType, BuildFilterStrategy>builder().put(WidgetType.OLD_LINE_CHART, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.INVESTIGATED_TREND, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.STATISTIC_TREND, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.LAUNCH_STATISTICS, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.OVERALL_STATISTICS, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.CASES_TREND, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.NOT_PASSED, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.BUG_TREND, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.LAUNCHES_TABLE, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.PASSING_RATE_SUMMARY, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.CUMULATIVE, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.PRODUCT_STATUS, + (ProductStatusFilterStrategy) applicationContext.getBean("productStatusFilterStrategy")) + .put(WidgetType.UNIQUE_BUG_TABLE, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.ACTIVITY, + (ActivityFilterStrategy) applicationContext.getBean("activityFilterStrategy")) + .put(WidgetType.LAUNCHES_COMPARISON_CHART, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.LAUNCHES_DURATION_CHART, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.TOP_TEST_CASES, + (LaunchHistoryFilterStrategy) applicationContext.getBean("launchHistoryFilterStrategy")) + .put(WidgetType.PASSING_RATE_PER_LAUNCH, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.FLAKY_TEST_CASES, + (GeneralLaunchFilterStrategy) applicationContext.getBean("launchHistoryFilterStrategy")) + .put(WidgetType.MOST_TIME_CONSUMING, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy")) + .put(WidgetType.TOP_PATTERN_TEMPLATES, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.COMPONENT_HEALTH_CHECK, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, + (GeneralLaunchFilterStrategy) applicationContext.getBean("generalLaunchFilterStrategy") + ) + .build(); + } + + @Bean("productStatusContentLoader") + public Map<String, ProductStatusContentLoader> productStatusContentLoader() { + return ImmutableMap.<String, ProductStatusContentLoader>builder().put("launch", + applicationContext.getBean(ProductStatusLaunchGroupedContentLoader.class) + ) + .put("filter", applicationContext.getBean(ProductStatusFilterGroupedContentLoader.class)) + .build(); + } + + @Bean("groupingStrategy") + public Map<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup> group() { + return ImmutableMap.<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup>builder() + .put(InfoInterval.ONE_MONTH, + ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY + ) + .put(InfoInterval.THREE_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) + .put(InfoInterval.SIX_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) + .build(); + } + + @Bean("unfilteredWidgetTypes") + public Set<WidgetType> unfilteredWidgetTypes() { + return ImmutableSet.<WidgetType>builder().add(WidgetType.ACTIVITY) + .add(WidgetType.TOP_TEST_CASES) + .add(WidgetType.PASSING_RATE_PER_LAUNCH) + .add(WidgetType.MOST_TIME_CONSUMING) + .add(WidgetType.FLAKY_TEST_CASES) + .build(); + } + + @Bean("widgetStateHandlerMapping") + public Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping() { + return ImmutableMap.<WidgetState, MaterializedWidgetStateHandler>builder() + .put(WidgetState.CREATED, + applicationContext.getBean(CreatedMaterializedWidgetStateHandler.class) + ) + .put(WidgetState.READY, + applicationContext.getBean(ReadyMaterializedWidgetStateHandler.class)) + .put(WidgetState.RENDERING, + applicationContext.getBean(EmptyMaterializedWidgetStateHandler.class)) + .put(WidgetState.FAILED, + applicationContext.getBean(FailedMaterializedWidgetStateHandler.class)) + .build(); + } + + @Bean("materializedWidgetContentLoaderMapping") + public Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping() { + return ImmutableMap.<WidgetType, MaterializedWidgetContentLoader>builder() + .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, + applicationContext.getBean(HealthCheckTableReadyContentLoader.class) + ) + .put(WidgetType.CUMULATIVE, + applicationContext.getBean(CumulativeTrendChartContentLoaderImpl.class)) + .build(); + } + + @Bean("cumulativeFailedViewStateGenerator") + public FailedViewStateGenerator cumulativeFailedViewStateGenerator() { + return new FailedViewStateGenerator( + applicationContext.getBean(CumulativeTrendChartViewGenerator.class), + applicationContext.getBean(WidgetRepository.class) + ); + } + + @Bean("healthCheckTableFailedViewStateGenerator") + public FailedViewStateGenerator healthCheckTableFailedViewStateGenerator() { + return new FailedViewStateGenerator(applicationContext.getBean(HealthCheckTableGenerator.class), + applicationContext.getBean(WidgetRepository.class) + ); + } + + @Bean("viewGeneratorMapping") + public Map<WidgetType, ViewGenerator> viewGeneratorMapping() { + return ImmutableMap.<WidgetType, ViewGenerator>builder() + .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, healthCheckTableFailedViewStateGenerator()) + .put(WidgetType.CUMULATIVE, cumulativeFailedViewStateGenerator()) + .build(); + } + + @Bean("widgetContentRemoverMapping") + public Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping() { + return ImmutableMap.<WidgetState, WidgetContentRemover>builder() + .put(WidgetState.READY, applicationContext.getBean(MaterializedViewRemover.class)) + .put(WidgetState.RENDERING, applicationContext.getBean(StaleMaterializedViewRemover.class)) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/WidgetValidatorConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/WidgetValidatorConfig.java index f1441d33a9..cb22a167bf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/WidgetValidatorConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/WidgetValidatorConfig.java @@ -1,59 +1,100 @@ package com.epam.ta.reportportal.core.configs; -import com.epam.ta.reportportal.core.widget.content.updater.validator.*; +import com.epam.ta.reportportal.core.widget.content.updater.validator.ActivityContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.BugTrendChartContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.CasesTrendContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.ChartInvestigatedContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.ComponentHealthCheckContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.CumulativeTrendChartValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.FlakyCasesTableContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.LaunchExecutionAndIssueStatisticsContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.LaunchesComparisonContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.LaunchesDurationContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.LaunchesTableContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.LineChartContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.MostTimeConsumingContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.MultilevelValidatorStrategy; +import com.epam.ta.reportportal.core.widget.content.updater.validator.NotPassedTestsContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.OverallStatisticsContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.PassingRatePerLaunchContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.PassingRateSummaryContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.ProductStatusContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.TopPatternContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.TopTestCasesContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.UniqueBugContentValidator; +import com.epam.ta.reportportal.core.widget.content.updater.validator.WidgetValidatorStrategy; import com.epam.ta.reportportal.entity.widget.WidgetType; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - @Configuration public class WidgetValidatorConfig { - private ApplicationContext applicationContext; - @Autowired - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + private ApplicationContext applicationContext; + + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @Bean("widgetValidatorLoader") - public Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader() { - return ImmutableMap.<WidgetType, WidgetValidatorStrategy>builder().put(WidgetType.FLAKY_TEST_CASES, - applicationContext.getBean(FlakyCasesTableContentValidator.class) - ) - .put(WidgetType.OVERALL_STATISTICS, applicationContext.getBean(OverallStatisticsContentValidator.class)) - .put(WidgetType.PASSING_RATE_SUMMARY, applicationContext.getBean(PassingRateSummaryContentValidator.class)) - .put(WidgetType.OLD_LINE_CHART, applicationContext.getBean(LineChartContentValidator.class)) - .put(WidgetType.INVESTIGATED_TREND, applicationContext.getBean(ChartInvestigatedContentValidator.class)) - .put(WidgetType.STATISTIC_TREND, applicationContext.getBean(LineChartContentValidator.class)) - .put(WidgetType.LAUNCH_STATISTICS, applicationContext.getBean(LaunchExecutionAndIssueStatisticsContentValidator.class)) - .put(WidgetType.CASES_TREND, applicationContext.getBean(CasesTrendContentValidator.class)) - .put(WidgetType.NOT_PASSED, applicationContext.getBean(NotPassedTestsContentValidator.class)) - .put(WidgetType.UNIQUE_BUG_TABLE, applicationContext.getBean(UniqueBugContentValidator.class)) - .put(WidgetType.BUG_TREND, applicationContext.getBean(BugTrendChartContentValidator.class)) - .put(WidgetType.ACTIVITY, applicationContext.getBean(ActivityContentValidator.class)) - .put(WidgetType.LAUNCHES_COMPARISON_CHART, applicationContext.getBean(LaunchesComparisonContentValidator.class)) - .put(WidgetType.LAUNCHES_DURATION_CHART, applicationContext.getBean(LaunchesDurationContentValidator.class)) - .put(WidgetType.LAUNCHES_TABLE, applicationContext.getBean(LaunchesTableContentValidator.class)) - .put(WidgetType.TOP_TEST_CASES, applicationContext.getBean(TopTestCasesContentValidator.class)) - .put(WidgetType.PASSING_RATE_PER_LAUNCH, applicationContext.getBean(PassingRatePerLaunchContentValidator.class)) - .put(WidgetType.MOST_TIME_CONSUMING, applicationContext.getBean(MostTimeConsumingContentValidator.class)) - .put(WidgetType.PRODUCT_STATUS, applicationContext.getBean(ProductStatusContentValidator.class)) - .build(); - } + @Bean("widgetValidatorLoader") + public Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader() { + return ImmutableMap.<WidgetType, WidgetValidatorStrategy>builder() + .put(WidgetType.FLAKY_TEST_CASES, + applicationContext.getBean(FlakyCasesTableContentValidator.class) + ) + .put(WidgetType.OVERALL_STATISTICS, + applicationContext.getBean(OverallStatisticsContentValidator.class)) + .put(WidgetType.PASSING_RATE_SUMMARY, + applicationContext.getBean(PassingRateSummaryContentValidator.class)) + .put(WidgetType.OLD_LINE_CHART, applicationContext.getBean(LineChartContentValidator.class)) + .put(WidgetType.INVESTIGATED_TREND, + applicationContext.getBean(ChartInvestigatedContentValidator.class)) + .put(WidgetType.STATISTIC_TREND, + applicationContext.getBean(LineChartContentValidator.class)) + .put(WidgetType.LAUNCH_STATISTICS, + applicationContext.getBean(LaunchExecutionAndIssueStatisticsContentValidator.class)) + .put(WidgetType.CASES_TREND, applicationContext.getBean(CasesTrendContentValidator.class)) + .put(WidgetType.NOT_PASSED, + applicationContext.getBean(NotPassedTestsContentValidator.class)) + .put(WidgetType.UNIQUE_BUG_TABLE, + applicationContext.getBean(UniqueBugContentValidator.class)) + .put(WidgetType.BUG_TREND, applicationContext.getBean(BugTrendChartContentValidator.class)) + .put(WidgetType.ACTIVITY, applicationContext.getBean(ActivityContentValidator.class)) + .put(WidgetType.LAUNCHES_COMPARISON_CHART, + applicationContext.getBean(LaunchesComparisonContentValidator.class)) + .put(WidgetType.LAUNCHES_DURATION_CHART, + applicationContext.getBean(LaunchesDurationContentValidator.class)) + .put(WidgetType.LAUNCHES_TABLE, + applicationContext.getBean(LaunchesTableContentValidator.class)) + .put(WidgetType.TOP_TEST_CASES, + applicationContext.getBean(TopTestCasesContentValidator.class)) + .put(WidgetType.PASSING_RATE_PER_LAUNCH, + applicationContext.getBean(PassingRatePerLaunchContentValidator.class)) + .put(WidgetType.MOST_TIME_CONSUMING, + applicationContext.getBean(MostTimeConsumingContentValidator.class)) + .put(WidgetType.PRODUCT_STATUS, + applicationContext.getBean(ProductStatusContentValidator.class)) + .build(); + } - @Bean("multilevelValidatorLoader") - public Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader() { - return ImmutableMap.<WidgetType, MultilevelValidatorStrategy>builder().put(WidgetType.CUMULATIVE, - applicationContext.getBean(CumulativeTrendChartValidator.class) - ) - .put(WidgetType.TOP_PATTERN_TEMPLATES, applicationContext.getBean(TopPatternContentValidator.class)) - .put(WidgetType.COMPONENT_HEALTH_CHECK, applicationContext.getBean(ComponentHealthCheckContentValidator.class)) - .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, applicationContext.getBean(ComponentHealthCheckContentValidator.class)) - .build(); - } + @Bean("multilevelValidatorLoader") + public Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader() { + return ImmutableMap.<WidgetType, MultilevelValidatorStrategy>builder() + .put(WidgetType.CUMULATIVE, + applicationContext.getBean(CumulativeTrendChartValidator.class) + ) + .put(WidgetType.TOP_PATTERN_TEMPLATES, + applicationContext.getBean(TopPatternContentValidator.class)) + .put(WidgetType.COMPONENT_HEALTH_CHECK, + applicationContext.getBean(ComponentHealthCheckContentValidator.class)) + .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, + applicationContext.getBean(ComponentHealthCheckContentValidator.class)) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/XmlImportConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/XmlImportConfig.java index a070d630b0..fe41c4a6d2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/XmlImportConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/XmlImportConfig.java @@ -26,4 +26,5 @@ @Configuration @Conditional(Conditions.NotTestCondition.class) public class XmlImportConfig { + } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/analyzer/auto/LaunchAutoAnalysisConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/analyzer/auto/LaunchAutoAnalysisConfig.java index ce36e19ac5..9cce40db47 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/analyzer/auto/LaunchAutoAnalysisConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/analyzer/auto/LaunchAutoAnalysisConfig.java @@ -37,53 +37,57 @@ @Configuration public class LaunchAutoAnalysisConfig { - private final GetLaunchHandler getLaunchHandler; + private final GetLaunchHandler getLaunchHandler; - private final AnalyzeCollectorFactory analyzeCollectorFactory; - private final AnalyzerService analyzerService; + private final AnalyzeCollectorFactory analyzeCollectorFactory; + private final AnalyzerService analyzerService; - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - private final TaskExecutor autoAnalyzeTaskExecutor; + private final TaskExecutor autoAnalyzeTaskExecutor; - @Autowired - public LaunchAutoAnalysisConfig(GetLaunchHandler getLaunchHandler, AnalyzeCollectorFactory analyzeCollectorFactory, - AnalyzerService analyzerService, LogIndexer logIndexer, TaskExecutor autoAnalyzeTaskExecutor) { - this.getLaunchHandler = getLaunchHandler; - this.analyzeCollectorFactory = analyzeCollectorFactory; - this.analyzerService = analyzerService; - this.logIndexer = logIndexer; - this.autoAnalyzeTaskExecutor = autoAnalyzeTaskExecutor; - } + @Autowired + public LaunchAutoAnalysisConfig(GetLaunchHandler getLaunchHandler, + AnalyzeCollectorFactory analyzeCollectorFactory, + AnalyzerService analyzerService, LogIndexer logIndexer, + TaskExecutor autoAnalyzeTaskExecutor) { + this.getLaunchHandler = getLaunchHandler; + this.analyzeCollectorFactory = analyzeCollectorFactory; + this.analyzerService = analyzerService; + this.logIndexer = logIndexer; + this.autoAnalyzeTaskExecutor = autoAnalyzeTaskExecutor; + } - @Bean - public LaunchAutoAnalysisStarter manualAnalysisStarter() { - return new ExistingAnalyzerStarter(analyzerService, asyncAutoAnalysisStarter()); - } + @Bean + public LaunchAutoAnalysisStarter manualAnalysisStarter() { + return new ExistingAnalyzerStarter(analyzerService, asyncAutoAnalysisStarter()); + } - @Bean - public LaunchAutoAnalysisStarter autoAnalysisStarter() { - return new ExistingAnalyzerStarter(analyzerService, indexingAutoAnalysisStarter()); - } + @Bean + public LaunchAutoAnalysisStarter autoAnalysisStarter() { + return new ExistingAnalyzerStarter(analyzerService, indexingAutoAnalysisStarter()); + } - @Bean - public CollectingAutoAnalysisStarter collectingAutoAnalysisStarter() { - return new CollectingAutoAnalysisStarter(getLaunchHandler, analyzeCollectorFactory, analyzerService, logIndexer); - } + @Bean + public CollectingAutoAnalysisStarter collectingAutoAnalysisStarter() { + return new CollectingAutoAnalysisStarter(getLaunchHandler, analyzeCollectorFactory, + analyzerService, logIndexer); + } - @Bean - public AsyncAutoAnalysisStarter asyncAutoAnalysisStarter() { - return new AsyncAutoAnalysisStarter(autoAnalyzeTaskExecutor, collectingAutoAnalysisStarter()); - } + @Bean + public AsyncAutoAnalysisStarter asyncAutoAnalysisStarter() { + return new AsyncAutoAnalysisStarter(autoAnalyzeTaskExecutor, collectingAutoAnalysisStarter()); + } - @Bean - public AutoAnalysisEnabledStarter autoAnalysisEnabledStarter() { - return new AutoAnalysisEnabledStarter(collectingAutoAnalysisStarter()); - } + @Bean + public AutoAnalysisEnabledStarter autoAnalysisEnabledStarter() { + return new AutoAnalysisEnabledStarter(collectingAutoAnalysisStarter()); + } - @Bean - public IndexingAutoAnalysisStarter indexingAutoAnalysisStarter() { - return new IndexingAutoAnalysisStarter(getLaunchHandler, logIndexer, autoAnalysisEnabledStarter()); - } + @Bean + public IndexingAutoAnalysisStarter indexingAutoAnalysisStarter() { + return new IndexingAutoAnalysisStarter(getLaunchHandler, logIndexer, + autoAnalysisEnabledStarter()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/GenerateClusterPipelineConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/GenerateClusterPipelineConfig.java index 500efbed75..5df770f458 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/GenerateClusterPipelineConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/GenerateClusterPipelineConfig.java @@ -26,56 +26,57 @@ import com.epam.ta.reportportal.dao.ItemAttributeRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.pipeline.PipelineConstructor; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class GenerateClusterPipelineConfig { - private final CreateClusterHandler createClusterHandler; + private final CreateClusterHandler createClusterHandler; - private final ClusterDataProviderResolver clusterDataProviderResolver; + private final ClusterDataProviderResolver clusterDataProviderResolver; - private final ClusterRepository clusterRepository; - private final LogRepository logRepository; - private final ItemAttributeRepository itemAttributeRepository; + private final ClusterRepository clusterRepository; + private final LogRepository logRepository; + private final ItemAttributeRepository itemAttributeRepository; - @Autowired - public GenerateClusterPipelineConfig(CreateClusterHandler createClusterHandler, ClusterDataProviderResolver clusterDataProviderResolver, - ClusterRepository clusterRepository, LogRepository logRepository, ItemAttributeRepository itemAttributeRepository) { - this.createClusterHandler = createClusterHandler; - this.clusterDataProviderResolver = clusterDataProviderResolver; - this.clusterRepository = clusterRepository; - this.logRepository = logRepository; - this.itemAttributeRepository = itemAttributeRepository; - } + @Autowired + public GenerateClusterPipelineConfig(CreateClusterHandler createClusterHandler, + ClusterDataProviderResolver clusterDataProviderResolver, + ClusterRepository clusterRepository, LogRepository logRepository, + ItemAttributeRepository itemAttributeRepository) { + this.createClusterHandler = createClusterHandler; + this.clusterDataProviderResolver = clusterDataProviderResolver; + this.clusterRepository = clusterRepository; + this.logRepository = logRepository; + this.itemAttributeRepository = itemAttributeRepository; + } - @Bean - public PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor() { - return new PipelineConstructor<>(List.of(deleteClustersPartProvider(), - saveClusterDataPartProvider(), - saveLastRunAttributePartProvider() - )); - } + @Bean + public PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor() { + return new PipelineConstructor<>(List.of(deleteClustersPartProvider(), + saveClusterDataPartProvider(), + saveLastRunAttributePartProvider() + )); + } - @Bean - public DeleteClustersPartProvider deleteClustersPartProvider() { - return new DeleteClustersPartProvider(clusterRepository, logRepository); - } + @Bean + public DeleteClustersPartProvider deleteClustersPartProvider() { + return new DeleteClustersPartProvider(clusterRepository, logRepository); + } - @Bean - public SaveClusterDataPartProvider saveClusterDataPartProvider() { - return new SaveClusterDataPartProvider(clusterDataProviderResolver, createClusterHandler); - } + @Bean + public SaveClusterDataPartProvider saveClusterDataPartProvider() { + return new SaveClusterDataPartProvider(clusterDataProviderResolver, createClusterHandler); + } - @Bean - public SaveLastRunAttributePartProvider saveLastRunAttributePartProvider() { - return new SaveLastRunAttributePartProvider(itemAttributeRepository); - } + @Bean + public SaveLastRunAttributePartProvider saveLastRunAttributePartProvider() { + return new SaveLastRunAttributePartProvider(itemAttributeRepository); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/evaluator/DataProviderEvaluatorConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/evaluator/DataProviderEvaluatorConfig.java index 21cadb51bc..e53c41958a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/evaluator/DataProviderEvaluatorConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/evaluator/DataProviderEvaluatorConfig.java @@ -1,12 +1,12 @@ /* * Copyright 2021 EPAM Systems - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://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. @@ -20,35 +20,38 @@ import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.AnalyzerItemClusterDataProvider; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.AnalyzerLaunchClusterDataProvider; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator.ClusterDataProviderEvaluator; +import java.util.function.Predicate; import org.apache.commons.collections4.CollectionUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.function.Predicate; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class DataProviderEvaluatorConfig { - @Bean - public ClusterDataProviderEvaluator launchClusterDataProviderEvaluator(AnalyzerLaunchClusterDataProvider launchClusterDataProvider) { - return new ClusterDataProviderEvaluator(launchClusterDataProviderPredicate(), launchClusterDataProvider); - } - - @Bean - public ClusterDataProviderEvaluator itemClusterDataProviderEvaluator(AnalyzerItemClusterDataProvider itemClusterDataProvider) { - return new ClusterDataProviderEvaluator(itemClusterDataProviderPredicate(), itemClusterDataProvider); - } - - @Bean - public Predicate<GenerateClustersConfig> launchClusterDataProviderPredicate() { - return config -> CollectionUtils.isEmpty(config.getEntityContext().getItemIds()); - } - - @Bean - public Predicate<GenerateClustersConfig> itemClusterDataProviderPredicate() { - return config -> CollectionUtils.isNotEmpty(config.getEntityContext().getItemIds()); - } + @Bean + public ClusterDataProviderEvaluator launchClusterDataProviderEvaluator( + AnalyzerLaunchClusterDataProvider launchClusterDataProvider) { + return new ClusterDataProviderEvaluator(launchClusterDataProviderPredicate(), + launchClusterDataProvider); + } + + @Bean + public ClusterDataProviderEvaluator itemClusterDataProviderEvaluator( + AnalyzerItemClusterDataProvider itemClusterDataProvider) { + return new ClusterDataProviderEvaluator(itemClusterDataProviderPredicate(), + itemClusterDataProvider); + } + + @Bean + public Predicate<GenerateClustersConfig> launchClusterDataProviderPredicate() { + return config -> CollectionUtils.isEmpty(config.getEntityContext().getItemIds()); + } + + @Bean + public Predicate<GenerateClustersConfig> itemClusterDataProviderPredicate() { + return config -> CollectionUtils.isNotEmpty(config.getEntityContext().getItemIds()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/provider/DataProviderConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/provider/DataProviderConfig.java index 6e8b2b0a67..d24e0088c8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/provider/DataProviderConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/provider/DataProviderConfig.java @@ -31,28 +31,30 @@ @Configuration public class DataProviderConfig { - private final GetLaunchHandler getLaunchHandler; - - private final LaunchPreparerService launchPreparerService; - private final AnalyzerServiceClient analyzerServiceClient; - - private final TestItemRepository testItemRepository; - - public DataProviderConfig(GetLaunchHandler getLaunchHandler, LaunchPreparerService launchPreparerService, - AnalyzerServiceClient analyzerServiceClient, TestItemRepository testItemRepository) { - this.getLaunchHandler = getLaunchHandler; - this.launchPreparerService = launchPreparerService; - this.analyzerServiceClient = analyzerServiceClient; - this.testItemRepository = testItemRepository; - } - - @Bean - public AnalyzerLaunchClusterDataProvider analyzerLaunchClusterDataProvider() { - return new AnalyzerLaunchClusterDataProvider(analyzerServiceClient, launchPreparerService); - } - - @Bean - public AnalyzerItemClusterDataProvider analyzerItemClusterDataProvider() { - return new AnalyzerItemClusterDataProvider(analyzerServiceClient, getLaunchHandler, testItemRepository, launchPreparerService); - } + private final GetLaunchHandler getLaunchHandler; + + private final LaunchPreparerService launchPreparerService; + private final AnalyzerServiceClient analyzerServiceClient; + + private final TestItemRepository testItemRepository; + + public DataProviderConfig(GetLaunchHandler getLaunchHandler, + LaunchPreparerService launchPreparerService, + AnalyzerServiceClient analyzerServiceClient, TestItemRepository testItemRepository) { + this.getLaunchHandler = getLaunchHandler; + this.launchPreparerService = launchPreparerService; + this.analyzerServiceClient = analyzerServiceClient; + this.testItemRepository = testItemRepository; + } + + @Bean + public AnalyzerLaunchClusterDataProvider analyzerLaunchClusterDataProvider() { + return new AnalyzerLaunchClusterDataProvider(analyzerServiceClient, launchPreparerService); + } + + @Bean + public AnalyzerItemClusterDataProvider analyzerItemClusterDataProvider() { + return new AnalyzerItemClusterDataProvider(analyzerServiceClient, getLaunchHandler, + testItemRepository, launchPreparerService); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/resolver/DataProviderResolverConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/resolver/DataProviderResolverConfig.java index f2b4efcb57..58a353d4c2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/resolver/DataProviderResolverConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/data/resolver/DataProviderResolverConfig.java @@ -18,21 +18,22 @@ import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.ClusterDataProviderResolver; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator.ClusterDataProviderEvaluator; +import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class DataProviderResolverConfig { - @Bean - public ClusterDataProviderResolver clusterDataProviderResolver(ClusterDataProviderEvaluator launchClusterDataProviderEvaluator, - ClusterDataProviderEvaluator itemClusterDataProviderEvaluator) { - return new ClusterDataProviderResolver(List.of(launchClusterDataProviderEvaluator, itemClusterDataProviderEvaluator)); - } + @Bean + public ClusterDataProviderResolver clusterDataProviderResolver( + ClusterDataProviderEvaluator launchClusterDataProviderEvaluator, + ClusterDataProviderEvaluator itemClusterDataProviderEvaluator) { + return new ClusterDataProviderResolver( + List.of(launchClusterDataProviderEvaluator, itemClusterDataProviderEvaluator)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/starter/UniqueErrorAnalysisStarterConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/starter/UniqueErrorAnalysisStarterConfig.java index f1e0352c89..fedf39c943 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/cluster/starter/UniqueErrorAnalysisStarterConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/cluster/starter/UniqueErrorAnalysisStarterConfig.java @@ -29,13 +29,15 @@ @Configuration public class UniqueErrorAnalysisStarterConfig { - @Bean - public UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter(@Autowired UniqueErrorGenerator uniqueErrorGenerator) { - return new UniqueErrorAnalysisStarter(uniqueErrorGenerator); - } + @Bean + public UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter( + @Autowired UniqueErrorGenerator uniqueErrorGenerator) { + return new UniqueErrorAnalysisStarter(uniqueErrorGenerator); + } - @Bean - public UniqueErrorAnalysisStarter uniqueErrorAnalysisStarterAsync(@Autowired UniqueErrorGeneratorAsync uniqueErrorGeneratorAsync) { - return new UniqueErrorAnalysisStarter(uniqueErrorGeneratorAsync); - } + @Bean + public UniqueErrorAnalysisStarter uniqueErrorAnalysisStarterAsync( + @Autowired UniqueErrorGeneratorAsync uniqueErrorGeneratorAsync) { + return new UniqueErrorAnalysisStarter(uniqueErrorGeneratorAsync); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/event/listener/EventListenerConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/event/listener/EventListenerConfig.java index be84788721..1ea9ef6dc7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/event/listener/EventListenerConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/event/listener/EventListenerConfig.java @@ -17,31 +17,37 @@ package com.epam.ta.reportportal.core.configs.event.listener; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; import com.epam.ta.reportportal.core.events.listener.LaunchFinishedEventListener; import com.epam.ta.reportportal.core.events.listener.TestItemFinishedEventListener; +import com.epam.ta.reportportal.core.events.listener.TestItemIssueResolvedEventListener; import com.epam.ta.reportportal.core.events.subscriber.impl.delegate.ProjectConfigDelegatingSubscriber; +import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class EventListenerConfig { - @Bean - public LaunchFinishedEventListener launchFinishedEventListener( - ProjectConfigDelegatingSubscriber<LaunchFinishedEvent> launchFinishedDelegatingSubscriber) { - return new LaunchFinishedEventListener(List.of(launchFinishedDelegatingSubscriber)); - } + @Bean + public LaunchFinishedEventListener launchFinishedEventListener( + ProjectConfigDelegatingSubscriber<LaunchFinishedEvent> launchFinishedDelegatingSubscriber) { + return new LaunchFinishedEventListener(List.of(launchFinishedDelegatingSubscriber)); + } - @Bean - public TestItemFinishedEventListener testItemFinishedEventListener( - ProjectConfigDelegatingSubscriber<ItemFinishedEvent> itemFinishedDelegatingSubscriber) { - return new TestItemFinishedEventListener(List.of(itemFinishedDelegatingSubscriber)); - } + @Bean + public TestItemIssueResolvedEventListener testItemIssueResolvedEventListener( + ProjectConfigDelegatingSubscriber<IssueResolvedEvent> itemIssueResolvedDelegatingSubscriber) { + return new TestItemIssueResolvedEventListener(List.of(itemIssueResolvedDelegatingSubscriber)); + } -} + @Bean + public TestItemFinishedEventListener testItemFinishedEventListener( + ProjectConfigDelegatingSubscriber<TestItemFinishedEvent> testItemFinishedDelegatingSubscriber) { + return new TestItemFinishedEventListener(List.of(testItemFinishedDelegatingSubscriber)); + } +} \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/EventPublisherConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/EventPublisherConfig.java index 6dba24825c..c46e938513 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/EventPublisherConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/EventPublisherConfig.java @@ -16,42 +16,42 @@ package com.epam.ta.reportportal.core.configs.event.publisher; +import static org.springframework.context.support.AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME; + import com.epam.reportportal.extension.event.LaunchAutoAnalysisFinishEvent; import com.epam.reportportal.extension.event.LaunchStartUniqueErrorAnalysisEvent; import com.epam.reportportal.extension.event.LaunchUniqueErrorAnalysisFinishEvent; import com.epam.ta.reportportal.core.events.multicaster.DelegatingApplicationEventMulticaster; +import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.util.ErrorHandler; -import java.util.Set; - -import static org.springframework.context.support.AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class EventPublisherConfig { - private final ErrorHandler loggingEventErrorHandler; - - @Autowired - public EventPublisherConfig(ErrorHandler loggingEventErrorHandler) { - this.loggingEventErrorHandler = loggingEventErrorHandler; - } - - @Bean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME) - public ApplicationEventMulticaster applicationEventMulticaster() { - final DelegatingApplicationEventMulticaster eventMulticaster = new DelegatingApplicationEventMulticaster(Set.of( - LaunchAutoAnalysisFinishEvent.class, - LaunchUniqueErrorAnalysisFinishEvent.class, - LaunchStartUniqueErrorAnalysisEvent.class - )); - eventMulticaster.setErrorHandler(loggingEventErrorHandler); - return eventMulticaster; - } + private final ErrorHandler loggingEventErrorHandler; + + @Autowired + public EventPublisherConfig(ErrorHandler loggingEventErrorHandler) { + this.loggingEventErrorHandler = loggingEventErrorHandler; + } + + @Bean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME) + public ApplicationEventMulticaster applicationEventMulticaster() { + final DelegatingApplicationEventMulticaster eventMulticaster = new DelegatingApplicationEventMulticaster( + Set.of( + LaunchAutoAnalysisFinishEvent.class, + LaunchUniqueErrorAnalysisFinishEvent.class, + LaunchStartUniqueErrorAnalysisEvent.class + )); + eventMulticaster.setErrorHandler(loggingEventErrorHandler); + return eventMulticaster; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/LoggingEventErrorHandler.java b/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/LoggingEventErrorHandler.java index edd66b1506..62274dd77b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/LoggingEventErrorHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/event/publisher/LoggingEventErrorHandler.java @@ -27,10 +27,10 @@ @Service public class LoggingEventErrorHandler implements ErrorHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(LoggingEventErrorHandler.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LoggingEventErrorHandler.class); - @Override - public void handleError(Throwable throwable) { - LOGGER.error("Error during event publishing", throwable); - } + @Override + public void handleError(Throwable throwable) { + LOGGER.error("Error during event publishing", throwable); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/event/subscriber/EventSubscriberConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/event/subscriber/EventSubscriberConfig.java index f53fd11b54..d7a5776e08 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/event/subscriber/EventSubscriberConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/event/subscriber/EventSubscriberConfig.java @@ -17,45 +17,64 @@ package com.epam.ta.reportportal.core.configs.event.subscriber; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; +import com.epam.ta.reportportal.core.events.handler.item.TestItemAutoAnalysisRunner; +import com.epam.ta.reportportal.core.events.handler.item.TestItemPatternAnalysisRunner; import com.epam.ta.reportportal.core.events.handler.item.TestItemIndexRunner; import com.epam.ta.reportportal.core.events.handler.item.TestItemUniqueErrorAnalysisRunner; -import com.epam.ta.reportportal.core.events.handler.launch.*; +import com.epam.ta.reportportal.core.events.handler.launch.LaunchAnalysisFinishEventPublisher; +import com.epam.ta.reportportal.core.events.handler.launch.LaunchAutoAnalysisRunner; +import com.epam.ta.reportportal.core.events.handler.launch.LaunchNotificationRunner; +import com.epam.ta.reportportal.core.events.handler.launch.LaunchPatternAnalysisRunner; +import com.epam.ta.reportportal.core.events.handler.launch.LaunchUniqueErrorAnalysisRunner; import com.epam.ta.reportportal.core.events.subscriber.impl.delegate.ProjectConfigDelegatingSubscriber; import com.epam.ta.reportportal.core.project.config.ProjectConfigProvider; +import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class EventSubscriberConfig { - @Bean - public ProjectConfigDelegatingSubscriber<LaunchFinishedEvent> launchFinishedDelegatingSubscriber( - ProjectConfigProvider projectConfigProvider, LaunchAutoAnalysisRunner autoAnalysisEventHandler, - LaunchUniqueErrorAnalysisRunner uniqueErrorAnalysisEventHandler, - LaunchAnalysisFinishEventPublisher launchAnalysisFinishEventPublisher, LaunchPatternAnalysisRunner patternAnalysisEventHandler, - LaunchNotificationRunner notificationEventHandler) { - return new ProjectConfigDelegatingSubscriber<>(projectConfigProvider, - List.of(autoAnalysisEventHandler, - uniqueErrorAnalysisEventHandler, - launchAnalysisFinishEventPublisher, - patternAnalysisEventHandler, - notificationEventHandler - ) - ); - } + @Bean + public ProjectConfigDelegatingSubscriber<LaunchFinishedEvent> launchFinishedDelegatingSubscriber( + ProjectConfigProvider projectConfigProvider, + LaunchAutoAnalysisRunner autoAnalysisEventHandler, + LaunchUniqueErrorAnalysisRunner uniqueErrorAnalysisEventHandler, + LaunchAnalysisFinishEventPublisher launchAnalysisFinishEventPublisher, + LaunchPatternAnalysisRunner patternAnalysisEventHandler, + LaunchNotificationRunner notificationEventHandler) { + return new ProjectConfigDelegatingSubscriber<>(projectConfigProvider, + List.of(autoAnalysisEventHandler, + uniqueErrorAnalysisEventHandler, + launchAnalysisFinishEventPublisher, + patternAnalysisEventHandler, + notificationEventHandler + ) + ); + } + + @Bean + public ProjectConfigDelegatingSubscriber<IssueResolvedEvent> itemIssueResolvedDelegatingSubscriber( + ProjectConfigProvider projectConfigProvider, TestItemIndexRunner testItemIndexRunner, + TestItemUniqueErrorAnalysisRunner testItemUniqueErrorAnalysisRunner) { + return new ProjectConfigDelegatingSubscriber<>(projectConfigProvider, + List.of(testItemIndexRunner, testItemUniqueErrorAnalysisRunner) + ); + } + + @Bean + public ProjectConfigDelegatingSubscriber<TestItemFinishedEvent> testItemFinishedDelegatingSubscriber( + ProjectConfigProvider projectConfigProvider, + TestItemPatternAnalysisRunner testItemPatternAnalysisRunner, + TestItemAutoAnalysisRunner testItemAutoAnalysisRunner) { + return new ProjectConfigDelegatingSubscriber<>(projectConfigProvider, + List.of(testItemPatternAnalysisRunner, testItemAutoAnalysisRunner) + ); + } - @Bean - public ProjectConfigDelegatingSubscriber<ItemFinishedEvent> itemFinishedDelegatingSubscriber( - ProjectConfigProvider projectConfigProvider, TestItemIndexRunner testItemIndexRunner, - TestItemUniqueErrorAnalysisRunner testItemUniqueErrorAnalysisRunner) { - return new ProjectConfigDelegatingSubscriber<>(projectConfigProvider, - List.of(testItemIndexRunner, testItemUniqueErrorAnalysisRunner) - ); - } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/AnalyzerRabbitMqConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/AnalyzerRabbitMqConfiguration.java index d585d996c1..89ba9e755e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/AnalyzerRabbitMqConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/AnalyzerRabbitMqConfiguration.java @@ -22,6 +22,7 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.rabbitmq.http.client.Client; +import java.net.URI; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -33,8 +34,6 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import java.net.URI; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @@ -42,39 +41,41 @@ @Conditional(Conditions.NotTestCondition.class) public class AnalyzerRabbitMqConfiguration { - @Autowired - private MessageConverter messageConverter; + @Autowired + private MessageConverter messageConverter; - @Bean - public RabbitMqManagementClient managementTemplate(@Value("${rp.amqp.api-address}") String address, - @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { - Client rabbitClient; - try { - rabbitClient = new Client(address); - } catch (Exception e) { - throw new ReportPortalException( - ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, - "Cannot create a HTTP rabbit client instance. Incorrect api address " + address - ); - } - return new RabbitMqManagementClientTemplate(rabbitClient, virtualHost); - } + @Bean + public RabbitMqManagementClient managementTemplate( + @Value("${rp.amqp.api-address}") String address, + @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { + Client rabbitClient; + try { + rabbitClient = new Client(address); + } catch (Exception e) { + throw new ReportPortalException( + ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, + "Cannot create a HTTP rabbit client instance. Incorrect api address " + address + ); + } + return new RabbitMqManagementClientTemplate(rabbitClient, virtualHost); + } - @Bean(name = "analyzerConnectionFactory") - public ConnectionFactory analyzerConnectionFactory(@Value("${rp.amqp.addresses}") URI addresses, - @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { - CachingConnectionFactory factory = new CachingConnectionFactory(addresses); - factory.setVirtualHost(virtualHost); - return factory; - } + @Bean(name = "analyzerConnectionFactory") + public ConnectionFactory analyzerConnectionFactory(@Value("${rp.amqp.addresses}") URI addresses, + @Value("${rp.amqp.analyzer-vhost}") String virtualHost) { + CachingConnectionFactory factory = new CachingConnectionFactory(addresses); + factory.setVirtualHost(virtualHost); + return factory; + } - @Bean(name = "analyzerRabbitTemplate") - public RabbitTemplate analyzerRabbitTemplate(@Autowired @Qualifier("analyzerConnectionFactory") ConnectionFactory connectionFactory, - @Value("${rp.amqp.reply-timeout}") long replyTimeout) { - RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); - rabbitTemplate.setMessageConverter(messageConverter); - rabbitTemplate.setReplyTimeout(replyTimeout); - return rabbitTemplate; - } + @Bean(name = "analyzerRabbitTemplate") + public RabbitTemplate analyzerRabbitTemplate( + @Autowired @Qualifier("analyzerConnectionFactory") ConnectionFactory connectionFactory, + @Value("${rp.amqp.reply-timeout}") long replyTimeout) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(messageConverter); + rabbitTemplate.setReplyTimeout(replyTimeout); + return rabbitTemplate; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/BackgroundProcessingConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/BackgroundProcessingConfiguration.java index 7b62dd2d41..895f250f8b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/BackgroundProcessingConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/BackgroundProcessingConfiguration.java @@ -1,7 +1,10 @@ package com.epam.ta.reportportal.core.configs.rabbit; import com.epam.ta.reportportal.core.configs.Conditions; -import org.springframework.amqp.core.*; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Queue; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -10,23 +13,24 @@ @Configuration @Conditional(Conditions.NotTestCondition.class) public class BackgroundProcessingConfiguration { - public static final String LOG_MESSAGE_SAVING_QUEUE_NAME = "log_message_saving"; - public static final String LOG_MESSAGE_SAVING_ROUTING_KEY = "log_message_saving"; - public static final String PROCESSING_EXCHANGE_NAME = "processing"; - @Bean - Queue logMessageSavingQueue() { - return new Queue(LOG_MESSAGE_SAVING_QUEUE_NAME); - } + public static final String LOG_MESSAGE_SAVING_QUEUE_NAME = "log_message_saving"; + public static final String LOG_MESSAGE_SAVING_ROUTING_KEY = "log_message_saving"; + public static final String PROCESSING_EXCHANGE_NAME = "processing"; - @Bean - DirectExchange exchangeProcessing() { - return new DirectExchange(PROCESSING_EXCHANGE_NAME); - } + @Bean + Queue logMessageSavingQueue() { + return new Queue(LOG_MESSAGE_SAVING_QUEUE_NAME); + } - @Bean - Binding bindingSavingLogs(@Qualifier("logMessageSavingQueue") Queue queue, - @Qualifier("exchangeProcessing") DirectExchange exchange) { - return BindingBuilder.bind(queue).to(exchange).with(LOG_MESSAGE_SAVING_ROUTING_KEY); - } + @Bean + DirectExchange exchangeProcessing() { + return new DirectExchange(PROCESSING_EXCHANGE_NAME); + } + + @Bean + Binding bindingSavingLogs(@Qualifier("logMessageSavingQueue") Queue queue, + @Qualifier("exchangeProcessing") DirectExchange exchange) { + return BindingBuilder.bind(queue).to(exchange).with(LOG_MESSAGE_SAVING_ROUTING_KEY); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/DeserializablePair.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/DeserializablePair.java index 6bb0751168..703bc0c1f2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/DeserializablePair.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/DeserializablePair.java @@ -17,32 +17,34 @@ package com.epam.ta.reportportal.core.configs.rabbit; /** - * Jackson's crazy to deserialize class w/o default constructor - * To avoid mixins, we will create our own pair container + * Jackson's crazy to deserialize class w/o default constructor To avoid mixins, we will create our + * own pair container * * @author Konstantin Antipin */ public class DeserializablePair<L, R> { - private L left; - private R right; + private L left; - public DeserializablePair() {} + private R right; - private DeserializablePair(L left, R right) { - this.left = left; - this.right = right; - } + public DeserializablePair() { + } - public L getLeft() { - return left; - } + private DeserializablePair(L left, R right) { + this.left = left; + this.right = right; + } - public R getRight() { - return right; - } + public L getLeft() { + return left; + } - public static <L, R> DeserializablePair<L, R> of(L left, R right) { - return new DeserializablePair(left, right); - } + public R getRight() { + return right; + } + + public static <L, R> DeserializablePair<L, R> of(L left, R right) { + return new DeserializablePair(left, right); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/InternalConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/InternalConfiguration.java index d546804a45..bbc8fcd843 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/InternalConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/InternalConfiguration.java @@ -19,7 +19,15 @@ import com.epam.ta.reportportal.core.configs.Conditions; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.events.MessageBusImpl; -import org.springframework.amqp.core.*; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.amqp.core.AnonymousQueue; +import org.springframework.amqp.core.Base64UrlNamingStrategy; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.FanoutExchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.TopicExchange; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -33,104 +41,100 @@ @Conditional(Conditions.NotTestCondition.class) public class InternalConfiguration { - /** - * Exchanges - */ - public static final String EXCHANGE_EVENTS = "broadcast.events"; - public static final String EXCHANGE_ACTIVITY = "activity"; - public static final String EXCHANGE_ATTACHMENT = "attachment"; - public static final String EXCHANGE_NOTIFICATION = "notification"; - - /** - * Queues - */ - public static final String KEY_EVENTS = "broadcast.events"; - public static final String QUEUE_ACTIVITY = "activity"; - public static final String QUEUE_ACTIVITY_KEY = "activity.#"; - public static final String QUEUE_ATTACHMENT_DELETE = "attachment.delete"; - public static final String QUEUE_EMAIL = "notification.email"; - - public static final String QUEUE_QUERY_RQ = "query-rq"; - - @Bean - public MessageBus messageBus(@Autowired @Qualifier(value = "rabbitTemplate") AmqpTemplate amqpTemplate) { - return new MessageBusImpl(amqpTemplate); - } - - /** - * Exchanges definition - */ - - @Bean - public FanoutExchange eventsExchange() { - return new FanoutExchange(EXCHANGE_EVENTS, false, false); - } - - @Bean - public TopicExchange activityExchange() { - return new TopicExchange(EXCHANGE_ACTIVITY, true, false); - } - - @Bean - public DirectExchange attachmentExchange() { - return new DirectExchange(EXCHANGE_ATTACHMENT, true, false); - } - - @Bean - public DirectExchange notificationExchange() { - return new DirectExchange(EXCHANGE_NOTIFICATION, true, false); - } - - /** - * Queues definition - */ - - @Bean - public Queue eventsQueue() { - return new AnonymousQueue(new Base64UrlNamingStrategy(KEY_EVENTS + ".")); - } - - @Bean - public Queue activityQueue() { - return new Queue(QUEUE_ACTIVITY); - } - - @Bean - public Queue deleteAttachmentQueue() { - return new Queue(QUEUE_ATTACHMENT_DELETE); - } - - @Bean - public Queue queryQueue() { - return new Queue(QUEUE_QUERY_RQ); - } - - @Bean - public Queue emailNotificationQueue() { - return new Queue(QUEUE_EMAIL); - } - - /** - * Bindings - */ - - @Bean - public Binding eventsQueueBinding() { - return BindingBuilder.bind(eventsQueue()).to(eventsExchange()); - } - - @Bean - public Binding eventsActivityBinding() { - return BindingBuilder.bind(activityQueue()).to(activityExchange()).with(QUEUE_ACTIVITY_KEY); - } - - @Bean - public Binding attachmentDeleteBinding() { - return BindingBuilder.bind(deleteAttachmentQueue()).to(attachmentExchange()).with(QUEUE_ATTACHMENT_DELETE); - } - - @Bean - public Binding emailNotificationBinding() { - return BindingBuilder.bind(emailNotificationQueue()).to(notificationExchange()).with(QUEUE_EMAIL); - } + /** + * Exchanges + */ + public static final String EXCHANGE_EVENTS = "broadcast.events"; + public static final String EXCHANGE_ACTIVITY = "activity"; + public static final String EXCHANGE_ATTACHMENT = "attachment"; + public static final String EXCHANGE_NOTIFICATION = "notification"; + + /** + * Queues + */ + public static final String KEY_EVENTS = "broadcast.events"; + public static final String QUEUE_ACTIVITY = "activity"; + public static final String QUEUE_ACTIVITY_KEY = "activity.#"; + public static final String QUEUE_ATTACHMENT_DELETE = "attachment.delete"; + public static final String QUEUE_EMAIL = "notification.email"; + + public static final String QUEUE_QUERY_RQ = "query-rq"; + + @Bean + public MessageBus messageBus( + @Autowired @Qualifier(value = "rabbitTemplate") AmqpTemplate amqpTemplate) { + return new MessageBusImpl(amqpTemplate); + } + + // Exchanges definition + + @Bean + public FanoutExchange eventsExchange() { + return new FanoutExchange(EXCHANGE_EVENTS, false, false); + } + + @Bean + public TopicExchange activityExchange() { + return new TopicExchange(EXCHANGE_ACTIVITY, true, false); + } + + @Bean + public DirectExchange attachmentExchange() { + return new DirectExchange(EXCHANGE_ATTACHMENT, true, false); + } + + @Bean + public DirectExchange notificationExchange() { + return new DirectExchange(EXCHANGE_NOTIFICATION, true, false); + } + + // Queues definition + + @Bean + public Queue eventsQueue() { + return new AnonymousQueue(new Base64UrlNamingStrategy(KEY_EVENTS + ".")); + } + + @Bean + public Queue activityQueue() { + return new Queue(QUEUE_ACTIVITY); + } + + @Bean + public Queue deleteAttachmentQueue() { + return new Queue(QUEUE_ATTACHMENT_DELETE); + } + + @Bean + public Queue queryQueue() { + return new Queue(QUEUE_QUERY_RQ); + } + + @Bean + public Queue emailNotificationQueue() { + return new Queue(QUEUE_EMAIL); + } + + // Bindings + + @Bean + public Binding eventsQueueBinding() { + return BindingBuilder.bind(eventsQueue()).to(eventsExchange()); + } + + @Bean + public Binding eventsActivityBinding() { + return BindingBuilder.bind(activityQueue()).to(activityExchange()).with(QUEUE_ACTIVITY_KEY); + } + + @Bean + public Binding attachmentDeleteBinding() { + return BindingBuilder.bind(deleteAttachmentQueue()).to(attachmentExchange()) + .with(QUEUE_ATTACHMENT_DELETE); + } + + @Bean + public Binding emailNotificationBinding() { + return BindingBuilder.bind(emailNotificationQueue()).to(notificationExchange()).with(QUEUE_EMAIL); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/RabbitMqConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/RabbitMqConfiguration.java index c4c15571cf..c82aeb9509 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/RabbitMqConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/RabbitMqConfiguration.java @@ -21,6 +21,7 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.fasterxml.jackson.databind.ObjectMapper; import com.rabbitmq.http.client.Client; +import java.net.URI; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.rabbit.annotation.EnableRabbit; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; @@ -38,8 +39,6 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import java.net.URI; - /** * @author Pavel Bortnik */ @@ -48,52 +47,55 @@ @Conditional(Conditions.NotTestCondition.class) public class RabbitMqConfiguration { - @Autowired - private ObjectMapper objectMapper; + @Autowired + private ObjectMapper objectMapper; - @Bean - public MessageConverter jsonMessageConverter() { - return new Jackson2JsonMessageConverter(objectMapper); - } + @Bean + public MessageConverter jsonMessageConverter() { + return new Jackson2JsonMessageConverter(objectMapper); + } - @Bean - public ConnectionFactory connectionFactory(@Value("${rp.amqp.api-address}") String apiAddress, - @Value("${rp.amqp.addresses}") URI addresses, @Value("${rp.amqp.base-vhost}") String virtualHost) { - try { - Client client = new Client(apiAddress); - client.createVhost(virtualHost); - } catch (Exception e) { - throw new ReportPortalException(ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, - "Unable to create RabbitMq virtual host: " + e.getMessage() - ); - } - final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(addresses); - cachingConnectionFactory.setVirtualHost(virtualHost); - return cachingConnectionFactory; - } + @Bean + public ConnectionFactory connectionFactory(@Value("${rp.amqp.api-address}") String apiAddress, + @Value("${rp.amqp.addresses}") URI addresses, + @Value("${rp.amqp.base-vhost}") String virtualHost) { + try { + Client client = new Client(apiAddress); + client.createVhost(virtualHost); + } catch (Exception e) { + throw new ReportPortalException(ErrorType.UNCLASSIFIED_REPORT_PORTAL_ERROR, + "Unable to create RabbitMq virtual host: " + e.getMessage() + ); + } + final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory( + addresses); + cachingConnectionFactory.setVirtualHost(virtualHost); + return cachingConnectionFactory; + } - @Bean - public AmqpAdmin amqpAdmin(@Autowired ConnectionFactory connectionFactory) { - return new RabbitAdmin(connectionFactory); - } + @Bean + public AmqpAdmin amqpAdmin(@Autowired ConnectionFactory connectionFactory) { + return new RabbitAdmin(connectionFactory); + } - @Bean(name = "rabbitTemplate") - public RabbitTemplate rabbitTemplate(@Autowired @Qualifier("connectionFactory") ConnectionFactory connectionFactory) { - RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); - rabbitTemplate.setMessageConverter(jsonMessageConverter()); - return rabbitTemplate; - } + @Bean(name = "rabbitTemplate") + public RabbitTemplate rabbitTemplate( + @Autowired @Qualifier("connectionFactory") ConnectionFactory connectionFactory) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(jsonMessageConverter()); + return rabbitTemplate; + } - @Bean - public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory( - @Autowired @Qualifier("connectionFactory") ConnectionFactory connectionFactory) { - SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); - factory.setConnectionFactory(connectionFactory); - factory.setDefaultRequeueRejected(false); - factory.setErrorHandler(new ConditionalRejectingErrorHandler()); - factory.setAutoStartup(true); - factory.setMessageConverter(jsonMessageConverter()); - return factory; - } + @Bean + public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory( + @Autowired @Qualifier("connectionFactory") ConnectionFactory connectionFactory) { + SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory); + factory.setDefaultRequeueRejected(false); + factory.setErrorHandler(new ConditionalRejectingErrorHandler()); + factory.setAutoStartup(true); + factory.setMessageConverter(jsonMessageConverter()); + return factory; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/ReportingConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/ReportingConfiguration.java index 405aaf14d8..6b7cfc6100 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/ReportingConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/rabbit/ReportingConfiguration.java @@ -18,9 +18,18 @@ import com.epam.ta.reportportal.core.configs.Conditions; import com.epam.ta.reportportal.ws.rabbit.AsyncReportingListener; +import java.util.ArrayList; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.amqp.core.*; +import org.springframework.amqp.core.AmqpAdmin; +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.Exchange; +import org.springframework.amqp.core.ExchangeBuilder; +import org.springframework.amqp.core.MessageListener; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.QueueBuilder; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; @@ -34,9 +43,6 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import java.util.ArrayList; -import java.util.List; - /** * @author Konstantin Antipin */ @@ -44,167 +50,175 @@ @Conditional(Conditions.NotTestCondition.class) public class ReportingConfiguration { - private static final Logger logger = LoggerFactory.getLogger(ReportingConfiguration.class); - - public static final long DEAD_LETTER_DELAY_MILLIS = 60_000L; - public static final long DEAD_LETTER_MAX_RETRY = 10L; - - /** - * Exchanges - */ - public static final String EXCHANGE_REPORTING = "reporting"; - public static final String EXCHANGE_REPORTING_RETRY = "reporting.retry"; - - /** - * Queue definitions - */ - public static final String QUEUE_PREFIX = "reporting"; - public static final String QUEUE_RETRY_PREFIX = "reporting.retry"; - public static final String QUEUE_DLQ = "reporting.dlq"; - - @Value("${rp.amqp.queues}") - public int queueAmount; - - /** - * Cluster configuration parameter. - * Number of queues to be processed by this service-api pod (default effectively infinite) - * Note: should correlate with number QUEUE_AMOUNT & number of service-api pods being started in cluster - */ - @Value("${rp.amqp.queuesPerPod:1000000}") - private int queuesPerPod; - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private ConfigurableListableBeanFactory configurableBeanFactory; - - @Bean - public Exchange reportingExchange(AmqpAdmin amqpAdmin) { - Exchange exchange = ExchangeBuilder.directExchange(EXCHANGE_REPORTING).durable(true).build(); - amqpAdmin.declareExchange(exchange); - return exchange; - } - - @Bean - public Exchange reportingRetryExchange(AmqpAdmin amqpAdmin) { - Exchange exchange = ExchangeBuilder.directExchange(EXCHANGE_REPORTING_RETRY).durable(true).build(); - amqpAdmin.declareExchange(exchange); - return exchange; - } - - @Bean - public List<Queue> queues(AmqpAdmin amqpAdmin) { - List<Queue> queues = new ArrayList(); - for (int i = 0; i < queueAmount; i++) { - String index = String.valueOf(i); - String queueName = QUEUE_PREFIX + "." + index; - Queue queue = QueueBuilder.durable(queueName) - .withArgument("x-dead-letter-exchange", EXCHANGE_REPORTING_RETRY) - .withArgument("x-dead-letter-routing-key", index) - .build(); - queue.setShouldDeclare(true); - queue.setAdminsThatShouldDeclare(amqpAdmin); - registerSingleton(queueName, queue); - amqpAdmin.declareQueue(queue); - queues.add(queue); - } - return queues; - } - - @Bean - public List<Queue> retryQueues(AmqpAdmin amqpAdmin) { - List<Queue> queues = new ArrayList(); - for (int i = 0; i < queueAmount; i++) { - String index = String.valueOf(i); - String queueName = QUEUE_RETRY_PREFIX + "." + index; - Queue retryQueue = QueueBuilder.durable(queueName) - .withArgument("x-dead-letter-exchange", EXCHANGE_REPORTING) - .withArgument("x-dead-letter-routing-key", index) - .withArgument("x-message-ttl", DEAD_LETTER_DELAY_MILLIS) - .build(); - retryQueue.setShouldDeclare(true); - retryQueue.setAdminsThatShouldDeclare(amqpAdmin); - registerSingleton(queueName, retryQueue); - amqpAdmin.declareQueue(retryQueue); - queues.add(retryQueue); - } - return queues; - } - - @Bean - public Queue queueDlq(AmqpAdmin amqpAdmin) { - Queue queue = QueueBuilder.durable(QUEUE_DLQ).build(); - queue.setShouldDeclare(true); - queue.setAdminsThatShouldDeclare(amqpAdmin); - amqpAdmin.declareQueue(queue); - return queue; - } - - @Bean - public List<Binding> bindings(AmqpAdmin amqpAdmin, @Qualifier("reportingExchange") Exchange reportingExchange, - @Qualifier("reportingRetryExchange") Exchange reportingRetryExchange, @Qualifier("queues") List<Queue> queues, - @Qualifier("queueDlq") Queue queueDlq, @Qualifier("retryQueues") List<Queue> retryQueues) { - List<Binding> bindings = new ArrayList<>(); - int i = 0; - for (Queue queue : queues) { - String index = String.valueOf(i); - Binding queueBinding = BindingBuilder.bind(queue).to(reportingExchange).with(index).noargs(); - bindings.add(queueBinding); - queueBinding.setShouldDeclare(true); - queueBinding.setAdminsThatShouldDeclare(amqpAdmin); - amqpAdmin.declareBinding(queueBinding); - registerSingleton("queueBinding." + queue.getName(), queueBinding); - i++; - } - i = 0; - for (Queue retryQueue : retryQueues) { - String index = String.valueOf(i); - Binding queueBinding = BindingBuilder.bind(retryQueue).to(reportingRetryExchange).with(index).noargs(); - bindings.add(queueBinding); - queueBinding.setShouldDeclare(true); - queueBinding.setAdminsThatShouldDeclare(amqpAdmin); - amqpAdmin.declareBinding(queueBinding); - registerSingleton("queueBinding." + retryQueue.getName(), queueBinding); - i++; - } - Binding queueBinding = BindingBuilder.bind(queueDlq).to(reportingRetryExchange).with(QUEUE_DLQ).noargs(); - amqpAdmin.declareBinding(queueBinding); - - return bindings; - } - - @Bean - @Qualifier("reportingListenerContainers") - public List<AbstractMessageListenerContainer> listenerContainers(ConnectionFactory connectionFactory, - ApplicationEventPublisher applicationEventPublisher, @Qualifier("queues") List<Queue> queues) { - List<AbstractMessageListenerContainer> containers = new ArrayList<>(); - int consumersCount = 0; - while (consumersCount < queuesPerPod) { - SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(connectionFactory); - containers.add(listenerContainer); - listenerContainer.setConnectionFactory(connectionFactory); - listenerContainer.addQueueNames(queues.get(consumersCount).getName()); - listenerContainer.setExclusive(true); - listenerContainer.setMissingQueuesFatal(false); - listenerContainer.setApplicationEventPublisher(applicationEventPublisher); - listenerContainer.setupMessageListener(reportingListener()); - listenerContainer.afterPropertiesSet(); - consumersCount++; - logger.info("Consumer is created, current consumers count is {}", consumersCount); - } - return containers; - } - - @Bean - public MessageListener reportingListener() { - return new AsyncReportingListener(); - } - - private void registerSingleton(String name, Object bean) { - configurableBeanFactory.registerSingleton(name.trim(), bean); - applicationContext.getAutowireCapableBeanFactory().autowireBean(bean); - applicationContext.getAutowireCapableBeanFactory().initializeBean(bean, name); - } + private static final Logger logger = LoggerFactory.getLogger(ReportingConfiguration.class); + + public static final long DEAD_LETTER_DELAY_MILLIS = 60_000L; + public static final long DEAD_LETTER_MAX_RETRY = 10L; + + /** + * Exchanges + */ + public static final String EXCHANGE_REPORTING = "reporting"; + public static final String EXCHANGE_REPORTING_RETRY = "reporting.retry"; + + /** + * Queue definitions + */ + public static final String QUEUE_PREFIX = "reporting"; + public static final String QUEUE_RETRY_PREFIX = "reporting.retry"; + public static final String QUEUE_DLQ = "reporting.dlq"; + + @Value("${rp.amqp.queues}") + public int queueAmount; + + /** + * Cluster configuration parameter. Number of queues to be processed by this service-api pod + * (default effectively infinite) Note: should correlate with number QUEUE_AMOUNT & number of + * service-api pods being started in cluster + */ + @Value("${rp.amqp.queuesPerPod:1000000}") + private int queuesPerPod; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private ConfigurableListableBeanFactory configurableBeanFactory; + + @Bean + public Exchange reportingExchange(AmqpAdmin amqpAdmin) { + Exchange exchange = ExchangeBuilder.directExchange(EXCHANGE_REPORTING).durable(true).build(); + amqpAdmin.declareExchange(exchange); + return exchange; + } + + @Bean + public Exchange reportingRetryExchange(AmqpAdmin amqpAdmin) { + Exchange exchange = ExchangeBuilder.directExchange(EXCHANGE_REPORTING_RETRY).durable(true) + .build(); + amqpAdmin.declareExchange(exchange); + return exchange; + } + + @Bean + public List<Queue> queues(AmqpAdmin amqpAdmin) { + List<Queue> queues = new ArrayList(); + for (int i = 0; i < queueAmount; i++) { + String index = String.valueOf(i); + String queueName = QUEUE_PREFIX + "." + index; + Queue queue = QueueBuilder.durable(queueName) + .withArgument("x-dead-letter-exchange", EXCHANGE_REPORTING_RETRY) + .withArgument("x-dead-letter-routing-key", index) + .build(); + queue.setShouldDeclare(true); + queue.setAdminsThatShouldDeclare(amqpAdmin); + registerSingleton(queueName, queue); + amqpAdmin.declareQueue(queue); + queues.add(queue); + } + return queues; + } + + @Bean + public List<Queue> retryQueues(AmqpAdmin amqpAdmin) { + List<Queue> queues = new ArrayList(); + for (int i = 0; i < queueAmount; i++) { + String index = String.valueOf(i); + String queueName = QUEUE_RETRY_PREFIX + "." + index; + Queue retryQueue = QueueBuilder.durable(queueName) + .withArgument("x-dead-letter-exchange", EXCHANGE_REPORTING) + .withArgument("x-dead-letter-routing-key", index) + .withArgument("x-message-ttl", DEAD_LETTER_DELAY_MILLIS) + .build(); + retryQueue.setShouldDeclare(true); + retryQueue.setAdminsThatShouldDeclare(amqpAdmin); + registerSingleton(queueName, retryQueue); + amqpAdmin.declareQueue(retryQueue); + queues.add(retryQueue); + } + return queues; + } + + @Bean + public Queue queueDlq(AmqpAdmin amqpAdmin) { + Queue queue = QueueBuilder.durable(QUEUE_DLQ).build(); + queue.setShouldDeclare(true); + queue.setAdminsThatShouldDeclare(amqpAdmin); + amqpAdmin.declareQueue(queue); + return queue; + } + + @Bean + public List<Binding> bindings(AmqpAdmin amqpAdmin, + @Qualifier("reportingExchange") Exchange reportingExchange, + @Qualifier("reportingRetryExchange") Exchange reportingRetryExchange, + @Qualifier("queues") List<Queue> queues, + @Qualifier("queueDlq") Queue queueDlq, @Qualifier("retryQueues") List<Queue> retryQueues) { + List<Binding> bindings = new ArrayList<>(); + int i = 0; + for (Queue queue : queues) { + String index = String.valueOf(i); + Binding queueBinding = BindingBuilder.bind(queue).to(reportingExchange).with(index).noargs(); + bindings.add(queueBinding); + queueBinding.setShouldDeclare(true); + queueBinding.setAdminsThatShouldDeclare(amqpAdmin); + amqpAdmin.declareBinding(queueBinding); + registerSingleton("queueBinding." + queue.getName(), queueBinding); + i++; + } + i = 0; + for (Queue retryQueue : retryQueues) { + String index = String.valueOf(i); + Binding queueBinding = BindingBuilder.bind(retryQueue).to(reportingRetryExchange).with(index) + .noargs(); + bindings.add(queueBinding); + queueBinding.setShouldDeclare(true); + queueBinding.setAdminsThatShouldDeclare(amqpAdmin); + amqpAdmin.declareBinding(queueBinding); + registerSingleton("queueBinding." + retryQueue.getName(), queueBinding); + i++; + } + Binding queueBinding = BindingBuilder.bind(queueDlq).to(reportingRetryExchange).with(QUEUE_DLQ) + .noargs(); + amqpAdmin.declareBinding(queueBinding); + + return bindings; + } + + @Bean + @Qualifier("reportingListenerContainers") + public List<AbstractMessageListenerContainer> listenerContainers( + ConnectionFactory connectionFactory, + ApplicationEventPublisher applicationEventPublisher, + @Qualifier("queues") List<Queue> queues) { + List<AbstractMessageListenerContainer> containers = new ArrayList<>(); + int consumersCount = 0; + while (consumersCount < queuesPerPod) { + SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer( + connectionFactory); + containers.add(listenerContainer); + listenerContainer.setConnectionFactory(connectionFactory); + listenerContainer.addQueueNames(queues.get(consumersCount).getName()); + listenerContainer.setExclusive(true); + listenerContainer.setMissingQueuesFatal(false); + listenerContainer.setApplicationEventPublisher(applicationEventPublisher); + listenerContainer.setupMessageListener(reportingListener()); + listenerContainer.afterPropertiesSet(); + consumersCount++; + logger.info("Consumer is created, current consumers count is {}", consumersCount); + } + return containers; + } + + @Bean + public MessageListener reportingListener() { + return new AsyncReportingListener(); + } + + private void registerSingleton(String name, Object bean) { + configurableBeanFactory.registerSingleton(name.trim(), bean); + applicationContext.getAutowireCapableBeanFactory().autowireBean(bean); + applicationContext.getAutowireCapableBeanFactory().initializeBean(bean, name); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/remover/ContentRemoverConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/remover/ContentRemoverConfig.java index de4a49f17b..714cf82a88 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/remover/ContentRemoverConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/remover/ContentRemoverConfig.java @@ -19,22 +19,31 @@ import com.epam.ta.reportportal.core.remover.project.ProjectClusterRemover; import com.epam.ta.reportportal.core.remover.project.ProjectContentRemover; import com.epam.ta.reportportal.core.remover.project.ProjectWidgetRemover; +import com.epam.ta.reportportal.core.remover.user.UserContentRemover; +import com.epam.ta.reportportal.core.remover.user.UserPhotoRemover; +import com.epam.ta.reportportal.core.remover.user.UserWidgetRemover; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class ContentRemoverConfig { - @Bean - public ProjectContentRemover projectContentRemover(@Autowired ProjectClusterRemover projectClusterRemover, - @Autowired ProjectWidgetRemover projectWidgetRemover) { - return new ProjectContentRemover(List.of(projectClusterRemover, projectWidgetRemover)); - } + @Bean + public ProjectContentRemover projectContentRemover( + @Autowired ProjectClusterRemover projectClusterRemover, + @Autowired ProjectWidgetRemover projectWidgetRemover) { + return new ProjectContentRemover(List.of(projectClusterRemover, projectWidgetRemover)); + } + + @Bean + public UserContentRemover userContentRemover(@Autowired UserWidgetRemover userWidgetRemover, + @Autowired UserPhotoRemover userPhotoRemover) { + return new UserContentRemover(List.of(userWidgetRemover, userPhotoRemover)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/configs/resource/ResourceAttributeHandlerConfig.java b/src/main/java/com/epam/ta/reportportal/core/configs/resource/ResourceAttributeHandlerConfig.java index 42342c7be8..7361307741 100644 --- a/src/main/java/com/epam/ta/reportportal/core/configs/resource/ResourceAttributeHandlerConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/configs/resource/ResourceAttributeHandlerConfig.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.configs.resource; +import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ItemAttributeType; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ResourceAttributeHandler; @@ -28,14 +30,11 @@ import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.resolver.ItemAttributeTypeResolverDelegate; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; import com.google.common.collect.ImmutableMap; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - import java.util.List; import java.util.Map; import java.util.Set; - -import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -43,42 +42,43 @@ @Configuration public class ResourceAttributeHandlerConfig { - @Bean - public ResourceAttributeHandler<LaunchResource> launchResourceAttributeUpdater() { - return new LaunchResourceAttributeUpdater(); - } + @Bean + public ResourceAttributeHandler<LaunchResource> launchResourceAttributeUpdater() { + return new LaunchResourceAttributeUpdater(); + } - @Bean - public ResourceAttributeHandler<LaunchResource> launchResourceMetadataAttributeUpdater() { - return new LaunchResourceMetadataAttributeUpdater(Set.of(RP_CLUSTER_LAST_RUN_KEY)); - } + @Bean + public ResourceAttributeHandler<LaunchResource> launchResourceMetadataAttributeUpdater() { + return new LaunchResourceMetadataAttributeUpdater(Set.of(RP_CLUSTER_LAST_RUN_KEY)); + } - @Bean - public ResourceAttributeHandler<LaunchResource> unresolvedAttributesLaunchLogger() { - return new LaunchResourceAttributeLogger("Attributes with unresolved type: "); - } + @Bean + public ResourceAttributeHandler<LaunchResource> unresolvedAttributesLaunchLogger() { + return new LaunchResourceAttributeLogger("Attributes with unresolved type: "); + } - @Bean - public ItemAttributeTypeMatcher systemAttributeTypePredicateMatcher() { - return new PredicateItemAttributeTypeMatcher(ItemAttribute::isSystem, ItemAttributeType.SYSTEM); - } + @Bean + public ItemAttributeTypeMatcher systemAttributeTypePredicateMatcher() { + return new PredicateItemAttributeTypeMatcher(ItemAttribute::isSystem, ItemAttributeType.SYSTEM); + } - @Bean - public ItemAttributeTypeMatcher publicAttributeTypePredicateMatcher() { - return new PredicateItemAttributeTypeMatcher(it -> !it.isSystem(), ItemAttributeType.PUBLIC); - } + @Bean + public ItemAttributeTypeMatcher publicAttributeTypePredicateMatcher() { + return new PredicateItemAttributeTypeMatcher(it -> !it.isSystem(), ItemAttributeType.PUBLIC); + } - @Bean - public ItemAttributeTypeResolver itemAttributeTypeResolver() { - return new ItemAttributeTypeResolverDelegate(List.of(publicAttributeTypePredicateMatcher(), systemAttributeTypePredicateMatcher())); - } + @Bean + public ItemAttributeTypeResolver itemAttributeTypeResolver() { + return new ItemAttributeTypeResolverDelegate( + List.of(publicAttributeTypePredicateMatcher(), systemAttributeTypePredicateMatcher())); + } - @Bean - public Map<ItemAttributeType, ResourceAttributeHandler<LaunchResource>> attributeUpdaterMapping() { - return ImmutableMap.<ItemAttributeType, ResourceAttributeHandler<LaunchResource>>builder() - .put(ItemAttributeType.PUBLIC, launchResourceAttributeUpdater()) - .put(ItemAttributeType.SYSTEM, launchResourceMetadataAttributeUpdater()) - .put(ItemAttributeType.UNRESOLVED, unresolvedAttributesLaunchLogger()) - .build(); - } + @Bean + public Map<ItemAttributeType, ResourceAttributeHandler<LaunchResource>> attributeUpdaterMapping() { + return ImmutableMap.<ItemAttributeType, ResourceAttributeHandler<LaunchResource>>builder() + .put(ItemAttributeType.PUBLIC, launchResourceAttributeUpdater()) + .put(ItemAttributeType.SYSTEM, launchResourceMetadataAttributeUpdater()) + .put(ItemAttributeType.UNRESOLVED, unresolvedAttributesLaunchLogger()) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/dashboard/CreateDashboardHandler.java b/src/main/java/com/epam/ta/reportportal/core/dashboard/CreateDashboardHandler.java index fe51a96911..994d2ed7cf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/dashboard/CreateDashboardHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/dashboard/CreateDashboardHandler.java @@ -25,14 +25,15 @@ */ public interface CreateDashboardHandler { - /** - * Creates a new dashboard. - * - * @param projectDetails Project details - * @param rq Dashboard details - * @param user User - * @return EntryCreatedRS - */ - EntryCreatedRS createDashboard(ReportPortalUser.ProjectDetails projectDetails, CreateDashboardRQ rq, ReportPortalUser user); + /** + * Creates a new dashboard. + * + * @param projectDetails Project details + * @param rq Dashboard details + * @param user User + * @return EntryCreatedRS + */ + EntryCreatedRS createDashboard(ReportPortalUser.ProjectDetails projectDetails, + CreateDashboardRQ rq, ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/dashboard/DeleteDashboardHandler.java b/src/main/java/com/epam/ta/reportportal/core/dashboard/DeleteDashboardHandler.java index dec61a3805..44a2ac46ed 100644 --- a/src/main/java/com/epam/ta/reportportal/core/dashboard/DeleteDashboardHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/dashboard/DeleteDashboardHandler.java @@ -24,14 +24,15 @@ */ public interface DeleteDashboardHandler { - /** - * Delete {@link com.epam.ta.reportportal.entity.dashboard.Dashboard} instance with specified id - * - * @param dashboardId Dashboard id - * @param projectDetails Project details - * @param user User - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS deleteDashboard(Long dashboardId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Delete {@link com.epam.ta.reportportal.entity.dashboard.Dashboard} instance with specified id + * + * @param dashboardId Dashboard id + * @param projectDetails Project details + * @param user User + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS deleteDashboard(Long dashboardId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/dashboard/GetDashboardHandler.java b/src/main/java/com/epam/ta/reportportal/core/dashboard/GetDashboardHandler.java index d45b36a2ef..2b9f95f44d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/dashboard/GetDashboardHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/dashboard/GetDashboardHandler.java @@ -42,6 +42,8 @@ public interface GetDashboardHandler { * * @param projectDetails Project details * @param user User + * @param pageable Page Details + * @param filter {@link Filter} * @return Page of permitted dashboard resources */ Iterable<DashboardResource> getDashboards(ReportPortalUser.ProjectDetails projectDetails, Pageable pageable, Filter filter, diff --git a/src/main/java/com/epam/ta/reportportal/core/dashboard/UpdateDashboardHandler.java b/src/main/java/com/epam/ta/reportportal/core/dashboard/UpdateDashboardHandler.java index d07eccc001..9fa2d7fcb8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/dashboard/UpdateDashboardHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/dashboard/UpdateDashboardHandler.java @@ -17,6 +17,7 @@ package com.epam.ta.reportportal.core.dashboard; import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.dashboard.AddWidgetRq; import com.epam.ta.reportportal.ws.model.dashboard.UpdateDashboardRQ; @@ -26,40 +27,43 @@ */ public interface UpdateDashboardHandler { - /** - * Update dashboard with specified id - * - * @param projectDetails Project details - * @param rq Update details - * @param dashboardId Dashboard id to be updated - * @param user User - * @return OperationCompletionRS - */ - OperationCompletionRS updateDashboard(ReportPortalUser.ProjectDetails projectDetails, UpdateDashboardRQ rq, Long dashboardId, - ReportPortalUser user); + /** + * Update dashboard with specified id + * + * @param projectDetails Project details + * @param rq Update details + * @param dashboardId Dashboard id to be updated + * @param user User + * @return OperationCompletionRS + */ + OperationCompletionRS updateDashboard(ReportPortalUser.ProjectDetails projectDetails, + UpdateDashboardRQ rq, Long dashboardId, + ReportPortalUser user); - /** - * Add a new widget to the specified dashboard - * - * @param dashboardId Dashboard id - * @param projectDetails Project details - * @param rq Widget details - * @param user User - * @return OperationCompletionRS - */ - OperationCompletionRS addWidget(Long dashboardId, ReportPortalUser.ProjectDetails projectDetails, AddWidgetRq rq, - ReportPortalUser user); + /** + * Add a new widget to the specified dashboard + * + * @param dashboardId Dashboard id + * @param projectDetails Project details + * @param rq Widget details + * @param user User + * @return OperationCompletionRS + */ + OperationCompletionRS addWidget(Long dashboardId, ReportPortalUser.ProjectDetails projectDetails, + AddWidgetRq rq, + ReportPortalUser user); - /** - * Removes a specified widget from the specified dashboard - * - * @param widgetId Widget id - * @param dashboardId Dashboard id - * @param projectDetails Project details - * @param user - * @return OperationCompletionRS - */ - OperationCompletionRS removeWidget(Long widgetId, Long dashboardId, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Removes a specified widget from the specified dashboard + * + * @param widgetId Widget id + * @param dashboardId Dashboard id + * @param projectDetails Project details + * @param user {@link ReportPortalUser} + * @return OperationCompletionRS + */ + OperationCompletionRS removeWidget(Long widgetId, Long dashboardId, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/AnalysisEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/AnalysisEvent.java index 1f5b9fe689..49a04c171b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/AnalysisEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/AnalysisEvent.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.List; /** @@ -26,39 +25,39 @@ */ public class AnalysisEvent { - private Launch launch; + private Launch launch; - private List<Long> itemIds; + private List<Long> itemIds; - private AnalyzerConfig analyzerConfig; + private AnalyzerConfig analyzerConfig; - public AnalysisEvent(Launch launch, List<Long> itemIds, AnalyzerConfig analyzerConfig) { - this.launch = launch; - this.itemIds = itemIds; - this.analyzerConfig = analyzerConfig; - } + public AnalysisEvent(Launch launch, List<Long> itemIds, AnalyzerConfig analyzerConfig) { + this.launch = launch; + this.itemIds = itemIds; + this.analyzerConfig = analyzerConfig; + } - public List<Long> getItemIds() { - return itemIds; - } + public List<Long> getItemIds() { + return itemIds; + } - public void setItemIds(List<Long> itemIds) { - this.itemIds = itemIds; - } + public void setItemIds(List<Long> itemIds) { + this.itemIds = itemIds; + } - public AnalyzerConfig getAnalyzerConfig() { - return analyzerConfig; - } + public AnalyzerConfig getAnalyzerConfig() { + return analyzerConfig; + } - public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { - this.analyzerConfig = analyzerConfig; - } + public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { + this.analyzerConfig = analyzerConfig; + } - public Launch getLaunch() { - return launch; - } + public Launch getLaunch() { + return launch; + } - public void setLaunch(Launch launch) { - this.launch = launch; - } + public void setLaunch(Launch launch) { + this.launch = launch; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/Event.java b/src/main/java/com/epam/ta/reportportal/core/events/Event.java index 674c2f79ac..c45bf6ccf0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/Event.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/Event.java @@ -20,4 +20,5 @@ * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface Event { + } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/MessageBus.java b/src/main/java/com/epam/ta/reportportal/core/events/MessageBus.java index dac882ecf6..adb78f1cf2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/MessageBus.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/MessageBus.java @@ -16,10 +16,6 @@ package com.epam.ta.reportportal.core.events; -import com.epam.ta.reportportal.core.events.attachment.DeleteAttachmentEvent; - -import java.util.concurrent.ExecutionException; - /** * MessageBus is an abstraction for dealing with events over external event-streaming system * @@ -27,36 +23,28 @@ */ public interface MessageBus { - void publish(String exchange, String route, Object o) throws ExecutionException, InterruptedException; - - /** - * Sends event by the given route - * - * @param route Route - * @param o Payload - */ - void publish(String route, Object o); - - /** - * Sends event to special broadcasting exchange - * - * @param o Payload - */ - void broadcastEvent(Object o); - - /** - * Sends activity - * - * @param o Payload - */ - void publishActivity(ActivityEvent o); - - /** - * Publish event to remove {@link com.epam.ta.reportportal.entity.attachment.Attachment} - * from the database and {@link com.epam.ta.reportportal.filesystem.DataStore} - * - * @param event {@link DeleteAttachmentEvent} - */ - void publishDeleteAttachmentEvent(DeleteAttachmentEvent event); + /** + * Sends event by the given route and exchange + * + * @param exchange Exchange name + * @param route Route + * @param o Payload + */ + void publish(String exchange, String route, Object o); + + /** + * Sends event by the given route + * + * @param route Route + * @param o Payload + */ + void publish(String route, Object o); + + /** + * Sends activity + * + * @param o Payload + */ + void publishActivity(ActivityEvent o); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/MessageBusImpl.java b/src/main/java/com/epam/ta/reportportal/core/events/MessageBusImpl.java index 3f168fbe26..6e05016da0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/MessageBusImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/MessageBusImpl.java @@ -17,11 +17,7 @@ package com.epam.ta.reportportal.core.events; import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_ACTIVITY; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_ATTACHMENT; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_EVENTS; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.QUEUE_ATTACHMENT_DELETE; -import com.epam.ta.reportportal.core.events.attachment.DeleteAttachmentEvent; import com.epam.ta.reportportal.entity.activity.Activity; import java.util.Objects; import org.springframework.amqp.core.AmqpTemplate; @@ -36,17 +32,12 @@ public MessageBusImpl(AmqpTemplate amqpTemplate) { @Override public void publish(String exchange, String route, Object o) { - this.amqpTemplate.convertAndSend(exchange, route, o); + amqpTemplate.convertAndSend(exchange, route, o); } @Override public void publish(String route, Object o) { - this.amqpTemplate.convertSendAndReceive(route, o); - } - - @Override - public void broadcastEvent(Object o) { - this.amqpTemplate.convertAndSend(EXCHANGE_EVENTS, "", o); + amqpTemplate.convertAndSend(route, o); } /** @@ -69,11 +60,4 @@ private String generateKey(Activity activity) { activity.getObjectType(), activity.getEventName()); } - - @Override - public void publishDeleteAttachmentEvent(DeleteAttachmentEvent event) { - - amqpTemplate.convertAndSend(EXCHANGE_ATTACHMENT, QUEUE_ATTACHMENT_DELETE, event); - - } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/ProjectIdAwareEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/ProjectIdAwareEvent.java index 116d188702..075594851f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/ProjectIdAwareEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/ProjectIdAwareEvent.java @@ -21,5 +21,5 @@ */ public interface ProjectIdAwareEvent extends Event { - Long getProjectId(); + Long getProjectId(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/AbstractEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/AbstractEvent.java index 804320174d..dbf440cbe4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/AbstractEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/AbstractEvent.java @@ -21,8 +21,8 @@ */ public abstract class AbstractEvent { - private Long userId; - private String userLogin; + protected Long userId; + protected String userLogin; protected AbstractEvent() { } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/AroundEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/AroundEvent.java index f1616f4bbe..cba2a11862 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/AroundEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/AroundEvent.java @@ -22,21 +22,21 @@ */ public class AroundEvent<T> extends BeforeEvent<T> { - private T after; + private T after; - public AroundEvent() { - } + public AroundEvent() { + } - public AroundEvent(Long userId, String userLogin, T before, T after) { - super(userId, userLogin, before); - this.after = Preconditions.checkNotNull(after); - } + public AroundEvent(Long userId, String userLogin, T before, T after) { + super(userId, userLogin, before); + this.after = Preconditions.checkNotNull(after); + } - public T getAfter() { - return after; - } + public T getAfter() { + return after; + } - public void setAfter(T after) { - this.after = after; - } + public void setAfter(T after) { + this.after = after; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/AssignUserEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/AssignUserEvent.java index 404eb2d37a..c262f722d0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/AssignUserEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/AssignUserEvent.java @@ -16,6 +16,7 @@ package com.epam.ta.reportportal.core.events.activity; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; import static com.epam.ta.reportportal.entity.activity.ActivityAction.ASSIGN_USER; import com.epam.ta.reportportal.builder.ActivityBuilder; @@ -31,12 +32,13 @@ public class AssignUserEvent extends AbstractEvent implements ActivityEvent { private UserActivityResource userActivityResource; - public AssignUserEvent() { - } + private final boolean isSystemEvent; - public AssignUserEvent(UserActivityResource userActivityResource, Long userId, String userLogin) { + public AssignUserEvent(UserActivityResource userActivityResource, Long userId, String userLogin, + boolean isSystemEvent) { super(userId, userLogin); this.userActivityResource = userActivityResource; + this.isSystemEvent = isSystemEvent; } public UserActivityResource getUserActivityResource() { @@ -58,9 +60,9 @@ public Activity toActivity() { .addObjectName(userActivityResource.getFullName()) .addObjectType(EventObject.USER) .addProjectId(userActivityResource.getDefaultProjectId()) - .addSubjectId(getUserId()) - .addSubjectName(getUserLogin()) - .addSubjectType(EventSubject.USER) + .addSubjectId(isSystemEvent ? null : getUserId()) + .addSubjectName(isSystemEvent ? RP_SUBJECT_NAME : getUserLogin()) + .addSubjectType(isSystemEvent ? EventSubject.APPLICATION : EventSubject.USER) .get(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/BeforeEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/BeforeEvent.java index f166147eef..7a680f07ec 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/BeforeEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/BeforeEvent.java @@ -24,21 +24,21 @@ */ public class BeforeEvent<T> extends AbstractEvent { - private T before; + private T before; - public BeforeEvent() { - } + public BeforeEvent() { + } - public BeforeEvent(Long userId, String userLogin, T before) { - super(userId, userLogin); - this.before = Preconditions.checkNotNull(before); - } + public BeforeEvent(Long userId, String userLogin, T before) { + super(userId, userLogin); + this.before = Preconditions.checkNotNull(before); + } - public T getBefore() { - return before; - } + public T getBefore() { + return before; + } - public void setBefore(T before) { - this.before = before; - } + public void setBefore(T before) { + this.before = before; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/CreateInvitationLinkEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/CreateInvitationLinkEvent.java new file mode 100644 index 0000000000..88cc5b8cea --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/CreateInvitationLinkEvent.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.events.activity; + +import com.epam.ta.reportportal.builder.ActivityBuilder; +import com.epam.ta.reportportal.core.events.ActivityEvent; +import com.epam.ta.reportportal.entity.activity.Activity; +import com.epam.ta.reportportal.entity.activity.EventAction; +import com.epam.ta.reportportal.entity.activity.EventObject; +import com.epam.ta.reportportal.entity.activity.EventPriority; +import com.epam.ta.reportportal.entity.activity.EventSubject; + +/** + * Event on creation invite link. + * + * @author Andrei Piankouski + */ +public class CreateInvitationLinkEvent extends AbstractEvent implements ActivityEvent { + + private static final String EVENT_NAME = "createInvitationLink"; + + private final Long projectId; + + public CreateInvitationLinkEvent(Long userId, String userLogin, Long projectId) { + super(userId, userLogin); + this.projectId = projectId; + } + + @Override + public Activity toActivity() { + return new ActivityBuilder() + .addCreatedNow() + .addAction(EventAction.CREATE) + .addEventName(EVENT_NAME) + .addPriority(EventPriority.HIGH) + .addObjectName(EventObject.INVITATION_LINK.getValue()) + .addObjectType(EventObject.INVITATION_LINK) + .addSubjectId(getUserId()) + .addSubjectName(getUserLogin()) + .addSubjectType(EventSubject.USER) + .addProjectId(projectId) + .get(); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/LaunchFinishedEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/LaunchFinishedEvent.java index e8d660e0f4..2fa5a95429 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/LaunchFinishedEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/LaunchFinishedEvent.java @@ -13,8 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.epam.ta.reportportal.core.events.activity; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; + import com.epam.ta.reportportal.builder.ActivityBuilder; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.ActivityEvent; @@ -46,28 +49,32 @@ public class LaunchFinishedEvent extends AbstractEvent implements ActivityEvent, private String baseUrl; + private final boolean isSystemEvent; + public LaunchFinishedEvent(Launch launch) { + this(launch, null, null, true); this.id = launch.getId(); this.name = launch.getName(); this.mode = launch.getMode(); this.projectId = launch.getProjectId(); } - public LaunchFinishedEvent(Launch launch, Long userId, String userLogin) { + public LaunchFinishedEvent(Launch launch, Long userId, String userLogin, boolean isSystemEvent) { super(userId, userLogin); this.id = launch.getId(); this.name = launch.getName(); this.mode = launch.getMode(); this.projectId = launch.getProjectId(); + this.isSystemEvent = isSystemEvent; } public LaunchFinishedEvent(Launch launch, Long userId, String userLogin, String baseUrl) { - this(launch, userId, userLogin); + this(launch, userId, userLogin, false); this.baseUrl = baseUrl; } public LaunchFinishedEvent(Launch launch, ReportPortalUser user, String baseUrl) { - this(launch, user.getUserId(), user.getUsername()); + this(launch, user.getUserId(), user.getUsername(), false); this.user = user; this.baseUrl = baseUrl; } @@ -132,9 +139,9 @@ public Activity toActivity() { .addObjectName(name) .addObjectType(EventObject.LAUNCH) .addProjectId(projectId) - .addSubjectId(getUserId()) - .addSubjectName(getUserLogin()) - .addSubjectType(EventSubject.USER) + .addSubjectId(isSystemEvent ? null : getUserId()) + .addSubjectName(isSystemEvent ? RP_SUBJECT_NAME : getUserLogin()) + .addSubjectType(isSystemEvent ? EventSubject.APPLICATION : EventSubject.USER) .get(); } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/UnassignUserEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/UnassignUserEvent.java index 86554fb310..b323e36465 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/UnassignUserEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/UnassignUserEvent.java @@ -16,6 +16,7 @@ package com.epam.ta.reportportal.core.events.activity; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; import static com.epam.ta.reportportal.entity.activity.ActivityAction.UNASSIGN_USER; import com.epam.ta.reportportal.builder.ActivityBuilder; @@ -79,7 +80,7 @@ public Activity toActivity() { .addObjectType(EventObject.USER) .addProjectId(userActivityResource.getDefaultProjectId()) .addSubjectId(isSystemEvent ? null : getUserId()) - .addSubjectName(isSystemEvent ? "ReportPortal" : getUserLogin()) + .addSubjectName(isSystemEvent ? RP_SUBJECT_NAME : getUserLogin()) .addSubjectType(isSystemEvent ? EventSubject.APPLICATION : EventSubject.USER) .get(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEvent.java index f7b6fc8b23..7576388859 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEvent.java @@ -15,6 +15,8 @@ */ package com.epam.ta.reportportal.core.events.activity; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; + import com.epam.ta.reportportal.builder.ActivityBuilder; import com.epam.ta.reportportal.core.events.ActivityEvent; import com.epam.ta.reportportal.entity.activity.Activity; @@ -31,14 +33,13 @@ public class UserCreatedEvent extends AbstractEvent implements ActivityEvent { private UserActivityResource userActivityResource; - - public UserCreatedEvent() { - } + private final boolean isSystemEvent; public UserCreatedEvent(UserActivityResource userActivityResource, Long userId, - String userLogin) { + String userLogin, boolean isSystemEvent) { super(userId, userLogin); this.userActivityResource = userActivityResource; + this.isSystemEvent = isSystemEvent; } public UserActivityResource getUserActivityResource() { @@ -59,9 +60,9 @@ public Activity toActivity() { .addObjectId(userActivityResource.getId()) .addObjectName(userActivityResource.getFullName()) .addObjectType(EventObject.USER) - .addSubjectId(getUserId()) - .addSubjectName(getUserLogin()) - .addSubjectType(EventSubject.USER) + .addSubjectId(isSystemEvent ? null : getUserId()) + .addSubjectName(isSystemEvent ? RP_SUBJECT_NAME : getUserLogin()) + .addSubjectType(isSystemEvent ? EventSubject.APPLICATION : EventSubject.USER) .get(); } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemFinishedEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/IssueResolvedEvent.java similarity index 61% rename from src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemFinishedEvent.java rename to src/main/java/com/epam/ta/reportportal/core/events/activity/item/IssueResolvedEvent.java index 83d3e3983a..279e5319ac 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemFinishedEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/IssueResolvedEvent.java @@ -21,30 +21,30 @@ /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ -public class ItemFinishedEvent implements ProjectIdAwareEvent { +public class IssueResolvedEvent implements ProjectIdAwareEvent { - private final Long itemId; + private final Long itemId; - private final Long launchId; + private final Long launchId; - private final Long projectId; + private final Long projectId; - public ItemFinishedEvent(Long itemId, Long launchId, Long projectId) { - this.itemId = itemId; - this.launchId = launchId; - this.projectId = projectId; - } + public IssueResolvedEvent(Long itemId, Long launchId, Long projectId) { + this.itemId = itemId; + this.launchId = launchId; + this.projectId = projectId; + } - public Long getItemId() { - return itemId; - } + public Long getItemId() { + return itemId; + } - public Long getLaunchId() { - return launchId; - } + public Long getLaunchId() { + return launchId; + } - @Override - public Long getProjectId() { - return projectId; - } + @Override + public Long getProjectId() { + return projectId; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemRetryEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemRetryEvent.java index 46da848b9c..f6e3569f3d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemRetryEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/ItemRetryEvent.java @@ -23,32 +23,32 @@ */ public class ItemRetryEvent implements Event { - private final Long projectId; + private final Long projectId; - private final Long launchId; + private final Long launchId; - private final Long itemId; + private final Long itemId; - private ItemRetryEvent(Long projectId, Long launchId, Long itemId) { - this.projectId = projectId; - this.launchId = launchId; - this.itemId = itemId; - } + private ItemRetryEvent(Long projectId, Long launchId, Long itemId) { + this.projectId = projectId; + this.launchId = launchId; + this.itemId = itemId; + } - public Long getProjectId() { - return projectId; - } + public Long getProjectId() { + return projectId; + } - public Long getLaunchId() { - return launchId; - } + public Long getLaunchId() { + return launchId; + } - public Long getItemId() { - return itemId; - } + public Long getItemId() { + return itemId; + } - public static ItemRetryEvent of(Long projectId, Long launchId, Long itemId) { - return new ItemRetryEvent(projectId, launchId, itemId); - } + public static ItemRetryEvent of(Long projectId, Long launchId, Long itemId) { + return new ItemRetryEvent(projectId, launchId, itemId); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/item/TestItemFinishedEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/TestItemFinishedEvent.java new file mode 100644 index 0000000000..767fcb9795 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/item/TestItemFinishedEvent.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ +package com.epam.ta.reportportal.core.events.activity.item; + +import com.epam.ta.reportportal.core.events.ProjectIdAwareEvent; +import com.epam.ta.reportportal.entity.item.TestItem; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +public class TestItemFinishedEvent implements ProjectIdAwareEvent { + + private final TestItem testItem; + + private final Long projectId; + + public TestItemFinishedEvent(TestItem testItem, Long projectId) { + this.testItem = testItem; + this.projectId = projectId; + } + + public TestItem getTestItem() { + return testItem; + } + + @Override + public Long getProjectId() { + return projectId; + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/events/activity/util/ActivityDetailsUtil.java b/src/main/java/com/epam/ta/reportportal/core/events/activity/util/ActivityDetailsUtil.java index e270e6f3ac..dfbae1a2ce 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/activity/util/ActivityDetailsUtil.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/activity/util/ActivityDetailsUtil.java @@ -52,6 +52,7 @@ private ActivityDetailsUtil() { public static final String ITEM_IDS = "itemIds"; public static final String LAUNCH_ID = "launchId"; public static final String PATTERN_NAME = "patternName"; + public static final String RP_SUBJECT_NAME = "ReportPortal"; public static Optional<HistoryField> processName(String oldName, String newName) { if (!Strings.isNullOrEmpty(newName) && !oldName.equals(newName)) { diff --git a/src/main/java/com/epam/ta/reportportal/core/events/attachment/DeleteAttachmentEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/attachment/DeleteAttachmentEvent.java index b803a8049f..cb96331789 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/attachment/DeleteAttachmentEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/attachment/DeleteAttachmentEvent.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.Lists; - import java.util.List; /** @@ -26,39 +25,39 @@ */ public class DeleteAttachmentEvent { - @JsonProperty(value = "ids") - private List<Long> ids; + @JsonProperty(value = "ids") + private List<Long> ids; - @JsonProperty(value = "paths") - private List<String> paths; + @JsonProperty(value = "paths") + private List<String> paths; - public DeleteAttachmentEvent() { - ids = Lists.newArrayList(); - paths = Lists.newArrayList(); - } + public DeleteAttachmentEvent() { + ids = Lists.newArrayList(); + paths = Lists.newArrayList(); + } - public DeleteAttachmentEvent(List<Long> ids) { - this.ids = ids; - } + public DeleteAttachmentEvent(List<Long> ids) { + this.ids = ids; + } - public DeleteAttachmentEvent(List<Long> ids, List<String> paths) { - this.ids = ids; - this.paths = paths; - } + public DeleteAttachmentEvent(List<Long> ids, List<String> paths) { + this.ids = ids; + this.paths = paths; + } - public List<Long> getIds() { - return ids; - } + public List<Long> getIds() { + return ids; + } - public void setIds(List<Long> ids) { - this.ids = ids; - } + public void setIds(List<Long> ids) { + this.ids = ids; + } - public List<String> getPaths() { - return paths; - } + public List<String> getPaths() { + return paths; + } - public void setPaths(List<String> paths) { - this.paths = paths; - } + public void setPaths(List<String> paths) { + this.paths = paths; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/AttachDefaultPhotoEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/AttachDefaultPhotoEventHandler.java index 60c801b216..d771363a12 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/AttachDefaultPhotoEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/AttachDefaultPhotoEventHandler.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.events.handler; +import static com.epam.ta.reportportal.util.MultipartFileUtils.getMultipartFile; + import com.epam.ta.reportportal.binary.UserBinaryDataService; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.events.activity.UserCreatedEvent; @@ -31,8 +33,6 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import static com.epam.ta.reportportal.util.MultipartFileUtils.getMultipartFile; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @@ -41,31 +41,35 @@ @Transactional public class AttachDefaultPhotoEventHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(UserCreatedEvent.class); + private static final Logger LOGGER = LoggerFactory.getLogger(UserCreatedEvent.class); - private final UserRepository userRepository; + private final UserRepository userRepository; - private final UserBinaryDataService userBinaryDataService; + private final UserBinaryDataService userBinaryDataService; - @Autowired - public AttachDefaultPhotoEventHandler(UserRepository userRepository, UserBinaryDataService userBinaryDataService) { - this.userRepository = userRepository; - this.userBinaryDataService = userBinaryDataService; - } + @Autowired + public AttachDefaultPhotoEventHandler(UserRepository userRepository, + UserBinaryDataService userBinaryDataService) { + this.userRepository = userRepository; + this.userBinaryDataService = userBinaryDataService; + } - @EventListener - public void handleContextRefresh(ContextRefreshedEvent event) { - userRepository.findByLogin("superadmin").ifPresent(it -> attachPhoto(it, "image/superAdminPhoto.jpg")); - userRepository.findByLogin("default").ifPresent(it -> attachPhoto(it, "image/defaultUserPhoto.jpg")); - } + @EventListener + public void handleContextRefresh(ContextRefreshedEvent event) { + userRepository.findByLogin("superadmin") + .ifPresent(it -> attachPhoto(it, "image/superAdminPhoto.jpg")); + userRepository.findByLogin("default") + .ifPresent(it -> attachPhoto(it, "image/defaultUserPhoto.jpg")); + } - private void attachPhoto(User user, String photoPath) { - if (StringUtils.isEmpty(user.getAttachment())) { - try { - userBinaryDataService.saveUserPhoto(user, getMultipartFile(photoPath)); - } catch (Exception exception) { - LOGGER.error(Suppliers.formattedSupplier("Cannot attach default photo to user '{}'.", user.getLogin()).get(), exception); - } - } - } + private void attachPhoto(User user, String photoPath) { + if (StringUtils.isEmpty(user.getAttachment())) { + try { + userBinaryDataService.saveUserPhoto(user, getMultipartFile(photoPath)); + } catch (Exception exception) { + LOGGER.error(Suppliers.formattedSupplier("Cannot attach default photo to user '{}'.", + user.getLogin()).get(), exception); + } + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/ConfigurableEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/ConfigurableEventHandler.java index f20e048f27..51b46a3a01 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/ConfigurableEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/ConfigurableEventHandler.java @@ -23,5 +23,5 @@ */ public interface ConfigurableEventHandler<T extends Event, C> { - void handle(T event, C config); + void handle(T event, C config); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandler.java index 5cb030f52c..190f6abe39 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandler.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.events.handler; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.AUTO_ANALYZER_KEY; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; + import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; @@ -33,11 +38,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.AUTO_ANALYZER_KEY; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @@ -45,42 +45,47 @@ @Transactional public class DefectTypeDeletedHandler { - private final AnalyzerStatusCache analyzerStatusCache; + private final AnalyzerStatusCache analyzerStatusCache; - private final AnalyzerServiceClient analyzerServiceClient; + private final AnalyzerServiceClient analyzerServiceClient; - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - private final ProjectRepository projectRepository; + private final ProjectRepository projectRepository; - @Autowired - public DefectTypeDeletedHandler(AnalyzerStatusCache analyzerStatusCache, AnalyzerServiceClient analyzerServiceClient, - LaunchRepository launchRepository, LogIndexer logIndexer, ProjectRepository projectRepository) { - this.analyzerStatusCache = analyzerStatusCache; - this.analyzerServiceClient = analyzerServiceClient; - this.launchRepository = launchRepository; - this.logIndexer = logIndexer; - this.projectRepository = projectRepository; - } + @Autowired + public DefectTypeDeletedHandler(AnalyzerStatusCache analyzerStatusCache, + AnalyzerServiceClient analyzerServiceClient, + LaunchRepository launchRepository, LogIndexer logIndexer, + ProjectRepository projectRepository) { + this.analyzerStatusCache = analyzerStatusCache; + this.analyzerServiceClient = analyzerServiceClient; + this.launchRepository = launchRepository; + this.logIndexer = logIndexer; + this.projectRepository = projectRepository; + } - @Transactional - @Retryable(value = ReportPortalException.class, maxAttempts = 5, backoff = @Backoff(value = 5000L)) - @TransactionalEventListener - public void handleDefectTypeDeleted(DefectTypeDeletedEvent event) { - Project project = projectRepository.findById(event.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, event.getProjectId())); + @Transactional + @Retryable(value = ReportPortalException.class, maxAttempts = 5, backoff = @Backoff(value = 5000L)) + @TransactionalEventListener + public void handleDefectTypeDeleted(DefectTypeDeletedEvent event) { + Project project = projectRepository.findById(event.getProjectId()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, event.getProjectId())); - if (analyzerServiceClient.hasClients()) { - Cache<Long, Long> analyzeStatus = analyzerStatusCache.getAnalyzeStatus(AUTO_ANALYZER_KEY) - .orElseThrow(() -> new ReportPortalException(ErrorType.ANALYZER_NOT_FOUND, AUTO_ANALYZER_KEY)); - expect(analyzeStatus.asMap().containsValue(event.getProjectId()), equalTo(false)).verify(ErrorType.FORBIDDEN_OPERATION, - "Index can not be removed until auto-analysis proceeds." - ); + if (analyzerServiceClient.hasClients()) { + Cache<Long, Long> analyzeStatus = analyzerStatusCache.getAnalyzeStatus(AUTO_ANALYZER_KEY) + .orElseThrow( + () -> new ReportPortalException(ErrorType.ANALYZER_NOT_FOUND, AUTO_ANALYZER_KEY)); + expect(analyzeStatus.asMap().containsValue(event.getProjectId()), equalTo(false)).verify( + ErrorType.FORBIDDEN_OPERATION, + "Index can not be removed until auto-analysis proceeds." + ); - logIndexer.index(event.getProjectId(), getAnalyzerConfig(project)); - } - } + logIndexer.index(event.getProjectId(), getAnalyzerConfig(project)); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/GenerateWidgetViewEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/GenerateWidgetViewEventHandler.java index 4846d413b7..cfa1d63959 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/GenerateWidgetViewEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/GenerateWidgetViewEventHandler.java @@ -1,5 +1,11 @@ package com.epam.ta.reportportal.core.events.handler; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.REFRESH; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.events.widget.GenerateWidgetViewEvent; import com.epam.ta.reportportal.core.widget.content.BuildFilterStrategy; @@ -9,6 +15,7 @@ import com.epam.ta.reportportal.entity.widget.WidgetType; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -20,62 +27,57 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.REFRESH; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class GenerateWidgetViewEventHandler { - private final WidgetRepository widgetRepository; - private final Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping; - private final MaterializedViewNameGenerator materializedViewNameGenerator; - private final TaskExecutor widgetViewExecutor; - private final Map<WidgetType, ViewGenerator> viewGeneratorMapping; + private final WidgetRepository widgetRepository; + private final Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping; + private final MaterializedViewNameGenerator materializedViewNameGenerator; + private final TaskExecutor widgetViewExecutor; + private final Map<WidgetType, ViewGenerator> viewGeneratorMapping; - @Autowired - public GenerateWidgetViewEventHandler(WidgetRepository widgetRepository, - @Qualifier("buildFilterStrategy") Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping, - MaterializedViewNameGenerator materializedViewNameGenerator, @Qualifier("widgetViewExecutor") TaskExecutor widgetViewExecutor, - @Qualifier("viewGeneratorMapping") Map<WidgetType, ViewGenerator> viewGeneratorMapping) { - this.widgetRepository = widgetRepository; - this.buildFilterStrategyMapping = buildFilterStrategyMapping; - this.materializedViewNameGenerator = materializedViewNameGenerator; - this.widgetViewExecutor = widgetViewExecutor; - this.viewGeneratorMapping = viewGeneratorMapping; - } + @Autowired + public GenerateWidgetViewEventHandler(WidgetRepository widgetRepository, + @Qualifier("buildFilterStrategy") Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping, + MaterializedViewNameGenerator materializedViewNameGenerator, + @Qualifier("widgetViewExecutor") TaskExecutor widgetViewExecutor, + @Qualifier("viewGeneratorMapping") Map<WidgetType, ViewGenerator> viewGeneratorMapping) { + this.widgetRepository = widgetRepository; + this.buildFilterStrategyMapping = buildFilterStrategyMapping; + this.materializedViewNameGenerator = materializedViewNameGenerator; + this.widgetViewExecutor = widgetViewExecutor; + this.viewGeneratorMapping = viewGeneratorMapping; + } - @Async - @Transactional(propagation = Propagation.REQUIRES_NEW) - @TransactionalEventListener - public void onApplicationEvent(GenerateWidgetViewEvent event) { - widgetRepository.findById(event.getWidgetId()).ifPresent(widget -> { - WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_TO_CREATE_WIDGET, - formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) - )); + @Async + @Transactional(propagation = Propagation.REQUIRES_NEW) + @TransactionalEventListener + public void onApplicationEvent(GenerateWidgetViewEvent event) { + widgetRepository.findById(event.getWidgetId()).ifPresent(widget -> { + WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_TO_CREATE_WIDGET, + formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) + )); - Map<Filter, Sort> filterSortMapping = buildFilterStrategyMapping.get(widgetType).buildFilter(widget); - Filter launchesFilter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort launchesSort = GROUP_SORTS.apply(filterSortMapping.values()); + Map<Filter, Sort> filterSortMapping = buildFilterStrategyMapping.get(widgetType) + .buildFilter(widget); + Filter launchesFilter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort launchesSort = GROUP_SORTS.apply(filterSortMapping.values()); - ofNullable(viewGeneratorMapping.get(widgetType)).ifPresent(viewGenerator -> widgetViewExecutor.execute(() -> viewGenerator.generate( - BooleanUtils.toBoolean(event.getParams().getFirst(REFRESH)), - materializedViewNameGenerator.generate(widget), - widget, - launchesFilter, - launchesSort, - event.getParams() - ))); + ofNullable(viewGeneratorMapping.get(widgetType)).ifPresent( + viewGenerator -> widgetViewExecutor.execute(() -> viewGenerator.generate( + BooleanUtils.toBoolean(event.getParams().getFirst(REFRESH)), + materializedViewNameGenerator.generate(widget), + widget, + launchesFilter, + launchesSort, + event.getParams() + ))); - }); - } + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/StartAnalysisEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/StartAnalysisEventHandler.java index 4aeb7f34ca..70e683570a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/StartAnalysisEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/StartAnalysisEventHandler.java @@ -29,24 +29,25 @@ @Component public class StartAnalysisEventHandler { - private final AnalyzerServiceAsync analyzerServiceAsync; - - private final LogIndexer logIndexer; - - @Autowired - public StartAnalysisEventHandler(AnalyzerServiceAsync analyzerServiceAsync, LogIndexer logIndexer) { - this.analyzerServiceAsync = analyzerServiceAsync; - this.logIndexer = logIndexer; - } - - @TransactionalEventListener - public void handleEvent(AnalysisEvent event) { - analyzerServiceAsync.analyze(event.getLaunch(), event.getItemIds(), event.getAnalyzerConfig()) - .thenApply(it -> logIndexer.indexItemsLogs(event.getLaunch().getProjectId(), - event.getLaunch().getId(), - event.getItemIds(), - event.getAnalyzerConfig() - )); - } + private final AnalyzerServiceAsync analyzerServiceAsync; + + private final LogIndexer logIndexer; + + @Autowired + public StartAnalysisEventHandler(AnalyzerServiceAsync analyzerServiceAsync, + LogIndexer logIndexer) { + this.analyzerServiceAsync = analyzerServiceAsync; + this.logIndexer = logIndexer; + } + + @TransactionalEventListener + public void handleEvent(AnalysisEvent event) { + analyzerServiceAsync.analyze(event.getLaunch(), event.getItemIds(), event.getAnalyzerConfig()) + .thenApply(it -> logIndexer.indexItemsLogs(event.getLaunch().getProjectId(), + event.getLaunch().getId(), + event.getItemIds(), + event.getAnalyzerConfig() + )); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/TestItemRetryEventHandler.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/TestItemRetryEventHandler.java index 91a466b433..080969d972 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/TestItemRetryEventHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/TestItemRetryEventHandler.java @@ -18,29 +18,29 @@ import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.events.activity.item.ItemRetryEvent; +import java.util.Collections; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import org.springframework.transaction.event.TransactionalEventListener; -import java.util.Collections; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Component public class TestItemRetryEventHandler { - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - @Autowired - public TestItemRetryEventHandler(LogIndexer logIndexer) { - this.logIndexer = logIndexer; - } + @Autowired + public TestItemRetryEventHandler(LogIndexer logIndexer) { + this.logIndexer = logIndexer; + } - @Async - @TransactionalEventListener - public void onItemRetry(ItemRetryEvent event) { - logIndexer.indexItemsRemoveAsync(event.getProjectId(), Collections.singletonList(event.getItemId())); - } + @Async + @TransactionalEventListener + public void onItemRetry(ItemRetryEvent event) { + logIndexer.indexItemsRemoveAsync(event.getProjectId(), + Collections.singletonList(event.getItemId())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemAutoAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemAutoAnalysisRunner.java new file mode 100644 index 0000000000..49faf257c4 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemAutoAnalysisRunner.java @@ -0,0 +1,87 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.events.handler.item; + +import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerService; +import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; +import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; +import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; +import com.epam.ta.reportportal.core.launch.GetLaunchHandler; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.epam.ta.reportportal.entity.launch.Launch; +import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.springframework.stereotype.Component; + +/** + * Run auto analyzer for finished test item with immediateAutoAnalysis attribute. + * + * @author <a href="mailto:andrei_piankouski@epam.com">Andrei Piankouski</a> + */ +@Component +public class TestItemAutoAnalysisRunner implements + ConfigurableEventHandler<TestItemFinishedEvent, Map<String, String>> { + + protected static final String IMMEDIATE_AUTO_ANALYSIS = "immediateAutoAnalysis"; + + private final AnalyzerService analyzerService; + + private final LogIndexer logIndexer; + + private final GetLaunchHandler getLaunchHandler; + + public TestItemAutoAnalysisRunner(AnalyzerService analyzerService, LogIndexer logIndexer, + GetLaunchHandler getLaunchHandler) { + this.analyzerService = analyzerService; + this.logIndexer = logIndexer; + this.getLaunchHandler = getLaunchHandler; + } + + @Override + public void handle(TestItemFinishedEvent testItemFinishedEvent, + Map<String, String> projectConfig) { + if (analyzerService.hasAnalyzers() && isNeedToRunAA(testItemFinishedEvent.getTestItem())) { + final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(projectConfig); + TestItem testItem = testItemFinishedEvent.getTestItem(); + logIndex(testItem, testItemFinishedEvent.getProjectId(), analyzerConfig); + Launch launch = getLaunchHandler.get(testItem.getLaunchId()); + analyzerService.runAnalyzers(launch, List.of(testItem.getItemId()), analyzerConfig); + logIndex(testItem, testItemFinishedEvent.getProjectId(), analyzerConfig); + } + } + + private void logIndex(TestItem testItem, Long projectId, AnalyzerConfig config) { + logIndexer.indexItemsLogs(projectId, testItem.getLaunchId(), List.of(testItem.getItemId()), + config); + } + + private boolean isNeedToRunAA(TestItem testItem) { + if (Objects.nonNull(testItem.getItemResults().getIssue()) && testItem.getItemResults() + .getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() + .equals(TestItemIssueGroup.TO_INVESTIGATE)) { + return testItem.getAttributes().stream() + .filter(at -> !at.getTestItem().getItemResults().getIssue().getIgnoreAnalyzer()) + .anyMatch(at -> IMMEDIATE_AUTO_ANALYSIS.equals(at.getKey()) && Boolean.parseBoolean( + at.getValue()) && at.isSystem()); + } + return false; + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunner.java index 253b4543f2..dde65e4bda 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunner.java @@ -18,40 +18,40 @@ import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.Lists; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class TestItemIndexRunner implements ConfigurableEventHandler<ItemFinishedEvent, Map<String, String>> { +public class TestItemIndexRunner implements + ConfigurableEventHandler<IssueResolvedEvent, Map<String, String>> { - private final LogIndexer logIndexer; + private final LogIndexer logIndexer; - @Autowired - public TestItemIndexRunner(LogIndexer logIndexer) { - this.logIndexer = logIndexer; - } + @Autowired + public TestItemIndexRunner(LogIndexer logIndexer) { + this.logIndexer = logIndexer; + } - @Override - @Transactional(readOnly = true) - public void handle(ItemFinishedEvent event, Map<String, String> projectConfig) { + @Override + @Transactional(readOnly = true) + public void handle(IssueResolvedEvent event, Map<String, String> projectConfig) { - final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(projectConfig); + final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(projectConfig); - logIndexer.indexItemsLogs( - event.getProjectId(), - event.getLaunchId(), - Lists.newArrayList(event.getItemId()), - analyzerConfig - ); - } + logIndexer.indexItemsLogs( + event.getProjectId(), + event.getLaunchId(), + Lists.newArrayList(event.getItemId()), + analyzerConfig + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunner.java new file mode 100644 index 0000000000..f6fa77945d --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunner.java @@ -0,0 +1,55 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ +package com.epam.ta.reportportal.core.events.handler.item; + +import com.epam.ta.reportportal.core.analyzer.pattern.handler.ItemsPatternsAnalyzer; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; +import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; +import com.epam.ta.reportportal.entity.ItemAttribute; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +@Service +public class TestItemPatternAnalysisRunner implements + ConfigurableEventHandler<TestItemFinishedEvent, Map<String, String>> { + + protected static final String IMMEDIATE_PATTERN_ANALYSIS = "immediatePatternAnalysis"; + + private final ItemsPatternsAnalyzer patternsAnalyzer; + + public TestItemPatternAnalysisRunner(ItemsPatternsAnalyzer patternsAnalyzer) { + this.patternsAnalyzer = patternsAnalyzer; + } + + @Override + public void handle(TestItemFinishedEvent event, Map<String, String> config) { + if (isImmediatePaProvided(event)) { + patternsAnalyzer.analyze(event.getProjectId(), event.getTestItem().getLaunchId(), + Collections.singletonList(event.getTestItem().getItemId())); + } + } + + private static boolean isImmediatePaProvided(TestItemFinishedEvent event) { + Optional<ItemAttribute> immediatePa = event.getTestItem().getAttributes().stream() + .filter(it -> IMMEDIATE_PATTERN_ANALYSIS.equals(it.getKey())).findAny(); + return immediatePa.isPresent() && Boolean.parseBoolean(immediatePa.get().getValue()); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunner.java index f17b52ace2..f281499da6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunner.java @@ -16,57 +16,54 @@ package com.epam.ta.reportportal.core.events.handler.item; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getUniqueErrorConfig; + +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; import com.epam.ta.reportportal.core.launch.cluster.ClusterGenerator; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.epam.ta.reportportal.ws.model.project.UniqueErrorConfig; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getUniqueErrorConfig; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class TestItemUniqueErrorAnalysisRunner implements ConfigurableEventHandler<ItemFinishedEvent, Map<String, String>> { +public class TestItemUniqueErrorAnalysisRunner implements + ConfigurableEventHandler<IssueResolvedEvent, Map<String, String>> { - private final ClusterGenerator clusterGenerator; - private final ApplicationEventPublisher eventPublisher; + private final ClusterGenerator clusterGenerator; - public TestItemUniqueErrorAnalysisRunner(@Qualifier("uniqueErrorGenerator") ClusterGenerator clusterGenerator, - ApplicationEventPublisher eventPublisher) { - this.clusterGenerator = clusterGenerator; - this.eventPublisher = eventPublisher; - } + public TestItemUniqueErrorAnalysisRunner( + @Qualifier("uniqueErrorGenerator") ClusterGenerator clusterGenerator) { + this.clusterGenerator = clusterGenerator; + } - @Override - public void handle(ItemFinishedEvent event, Map<String, String> projectConfig) { - final UniqueErrorConfig uniqueErrorConfig = getUniqueErrorConfig(projectConfig); + @Override + public void handle(IssueResolvedEvent event, Map<String, String> projectConfig) { + final UniqueErrorConfig uniqueErrorConfig = getUniqueErrorConfig(projectConfig); - if (uniqueErrorConfig.isEnabled()) { - final GenerateClustersConfig clustersConfig = new GenerateClustersConfig(); - clustersConfig.setForUpdate(true); - clustersConfig.setCleanNumbers(uniqueErrorConfig.isRemoveNumbers()); + if (uniqueErrorConfig.isEnabled()) { + final GenerateClustersConfig clustersConfig = new GenerateClustersConfig(); + clustersConfig.setForUpdate(true); + clustersConfig.setCleanNumbers(uniqueErrorConfig.isRemoveNumbers()); - final AnalyzerConfig analyzerConfig = getAnalyzerConfig(projectConfig); - clustersConfig.setAnalyzerConfig(analyzerConfig); + final AnalyzerConfig analyzerConfig = getAnalyzerConfig(projectConfig); + clustersConfig.setAnalyzerConfig(analyzerConfig); - final ClusterEntityContext entityContext = ClusterEntityContext.of(event.getLaunchId(), - event.getProjectId(), - List.of(event.getItemId()) - ); - clustersConfig.setEntityContext(entityContext); + final ClusterEntityContext entityContext = ClusterEntityContext.of(event.getLaunchId(), + event.getProjectId(), + List.of(event.getItemId()) + ); + clustersConfig.setEntityContext(entityContext); - clusterGenerator.generate(clustersConfig); - } - } + clusterGenerator.generate(clustersConfig); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisher.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisher.java index 9f50d52560..1b2ea25c93 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisher.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisher.java @@ -19,27 +19,27 @@ import com.epam.reportportal.extension.event.LaunchAnalysisFinishEvent; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class LaunchAnalysisFinishEventPublisher implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { +public class LaunchAnalysisFinishEventPublisher implements + ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { - private final ApplicationEventPublisher eventPublisher; + private final ApplicationEventPublisher eventPublisher; - @Autowired - public LaunchAnalysisFinishEventPublisher(ApplicationEventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - } + @Autowired + public LaunchAnalysisFinishEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } - @Override - public void handle(LaunchFinishedEvent event, Map<String, String> config) { - eventPublisher.publishEvent(new LaunchAnalysisFinishEvent(event.getId(), config)); - } + @Override + public void handle(LaunchFinishedEvent event, Map<String, String> config) { + eventPublisher.publishEvent(new LaunchAnalysisFinishEvent(event.getId(), config)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunner.java index bc9b70c016..5f2fa63d8b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunner.java @@ -23,32 +23,33 @@ import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.Set; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class LaunchAutoAnalysisRunner implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { - - private final LaunchAutoAnalysisStarter autoAnalysisStarter; - - public LaunchAutoAnalysisRunner(LaunchAutoAnalysisStarter autoAnalysisStarter) { - this.autoAnalysisStarter = autoAnalysisStarter; - } - - @Override - public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { - final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(projectConfig); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(launchFinishedEvent.getId(), - analyzerConfig, - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - launchFinishedEvent.getUser() - ); - autoAnalysisStarter.start(config); - } +public class LaunchAutoAnalysisRunner implements + ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { + + private final LaunchAutoAnalysisStarter autoAnalysisStarter; + + public LaunchAutoAnalysisRunner(LaunchAutoAnalysisStarter autoAnalysisStarter) { + this.autoAnalysisStarter = autoAnalysisStarter; + } + + @Override + public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { + final AnalyzerConfig analyzerConfig = AnalyzerUtils.getAnalyzerConfig(projectConfig); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of( + launchFinishedEvent.getId(), + analyzerConfig, + Set.of(AnalyzeItemsMode.IGNORE_IMMEDIATE), + launchFinishedEvent.getUser() + ); + autoAnalysisStarter.start(config); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunner.java index e610c7418d..21f6530d54 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunner.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.core.statistics.StatisticsHelper.extractStatisticsCount; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; + import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; import com.epam.ta.reportportal.core.integration.GetIntegrationHandler; @@ -39,6 +46,11 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.google.common.annotations.VisibleForTesting; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.slf4j.Logger; @@ -47,187 +59,212 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.core.statistics.StatisticsHelper.extractStatisticsCount; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class LaunchNotificationRunner implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { - - public static final Logger LOGGER = LoggerFactory.getLogger(LaunchNotificationRunner.class); - - private final GetProjectHandler getProjectHandler; - private final GetLaunchHandler getLaunchHandler; - private final GetIntegrationHandler getIntegrationHandler; - private final MailServiceFactory mailServiceFactory; - private final UserRepository userRepository; - - @Autowired - public LaunchNotificationRunner(GetProjectHandler getProjectHandler, GetLaunchHandler getLaunchHandler, - GetIntegrationHandler getIntegrationHandler, MailServiceFactory mailServiceFactory, UserRepository userRepository) { - this.getProjectHandler = getProjectHandler; - this.getLaunchHandler = getLaunchHandler; - this.getIntegrationHandler = getIntegrationHandler; - this.mailServiceFactory = mailServiceFactory; - this.userRepository = userRepository; - } - - @Override - @Transactional(readOnly = true) - public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { - - boolean isNotificationsEnabled = BooleanUtils.toBoolean(projectConfig.get(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute())); - - if (isNotificationsEnabled) { - getIntegrationHandler.getEnabledByProjectIdOrGlobalAndIntegrationGroup(launchFinishedEvent.getProjectId(), - IntegrationGroupEnum.NOTIFICATION - ) - .flatMap(mailServiceFactory::getDefaultEmailService) - .ifPresentOrElse(emailService -> sendEmail(launchFinishedEvent, emailService), - () -> LOGGER.warn("Unable to find {} integration for project {}", - IntegrationGroupEnum.NOTIFICATION, - launchFinishedEvent.getProjectId() - ) - ); - - } - - } - - /** - * Try to send email when it is needed - * - * @param launch Launch to be used - * @param project Project - * @param emailService Mail Service - */ - private void sendEmail(LaunchFinishedEvent launchFinishedEvent, EmailService emailService) { - - final Launch launch = getLaunchHandler.get(launchFinishedEvent.getId()); - final Project project = getProjectHandler.get(launch.getProjectId()); - - project.getSenderCases().stream().filter(SenderCase::isEnabled).forEach(ec -> { - SendCase sendCase = ec.getSendCase(); - boolean successRate = isSuccessRateEnough(launch, sendCase); - boolean matchedNames = isLaunchNameMatched(launch, ec); - boolean matchedTags = isAttributesMatched(launch, ec.getLaunchAttributeRules(), ec.getAttributesOperator()); - - Set<String> recipients = ec.getRecipients(); - if (successRate && matchedNames && matchedTags) { - String[] recipientsArray = findRecipients(userRepository.findLoginById(launch.getUserId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, launch.getUserId())), recipients); - try { - emailService.sendLaunchFinishNotification(recipientsArray, - String.format("%s/ui/#%s", launchFinishedEvent.getBaseUrl(), project.getName()), - project, - launch - ); - } catch (Exception e) { - LOGGER.error("Unable to send email.", e); - } - } - }); - - } - - private String[] findRecipients(String owner, Set<String> recipients) { - return recipients.stream().map(recipient -> { - if (recipient.contains("@")) { - return recipient; - } else { - String toFind = recipient.equals(ProjectUtils.getOwner()) ? owner : recipient; - Optional<User> user = userRepository.findByLogin(toFind); - return user.map(User::getEmail).orElse(null); - } - }).filter(Objects::nonNull).distinct().toArray(String[]::new); - } - - /** - * @param launch launch to be evaluated - * @return success rate of provided launch in % - */ - private static double getSuccessRate(Launch launch) { - double ti = extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()).doubleValue(); - double pb = extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, launch.getStatistics()).doubleValue(); - double si = extractStatisticsCount(DEFECTS_SYSTEM_ISSUE_TOTAL, launch.getStatistics()).doubleValue(); - double ab = extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, launch.getStatistics()).doubleValue(); - double total = extractStatisticsCount(EXECUTIONS_TOTAL, launch.getStatistics()).doubleValue(); - return total == 0 ? total : (ti + pb + si + ab) / total; - } - - /** - * @param launch Launch to be evaluated - * @param option SendCase option - * @return TRUE of success rate is enough for notification - */ - private boolean isSuccessRateEnough(Launch launch, SendCase option) { - switch (option) { - case ALWAYS: - return true; - case FAILED: - return getLaunchHandler.hasItemsWithIssues(launch); - case TO_INVESTIGATE: - return extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()) > 0; - case MORE_10: - return getSuccessRate(launch) > 0.1; - case MORE_20: - return getSuccessRate(launch) > 0.2; - case MORE_50: - return getSuccessRate(launch) > 0.5; - default: - return false; - } - } - - /** - * Validate matching of finished launch name and project settings for emailing - * - * @param launch Launch to be evaluated - * @param oneCase Mail case - * @return TRUE if launch name matched - */ - private static boolean isLaunchNameMatched(Launch launch, SenderCase oneCase) { - Set<String> configuredNames = oneCase.getLaunchNames(); - return (null == configuredNames) || (configuredNames.isEmpty()) || configuredNames.contains(launch.getName()); - } - - /** - * Validate matching of finished launch tags and project settings for emailing - * - * @param launch Launch to be evaluated - * @return TRUE if tags matched - */ - @VisibleForTesting - private static boolean isAttributesMatched(Launch launch, Set<LaunchAttributeRule> launchAttributeRules, LogicalOperator logicalOperator) { - - if (CollectionUtils.isEmpty(launchAttributeRules)) { - return true; - } - - Set<ItemAttributeResource> itemAttributesResource = launchAttributeRules.stream() - .map(NotificationConfigConverter.TO_ATTRIBUTE_RULE_RESOURCE) - .collect(Collectors.toSet()); - - Set<ItemAttributeResource> itemAttributes = launch.getAttributes().stream().filter(attribute -> !attribute.isSystem()).map(attribute -> { - ItemAttributeResource attributeResource = new ItemAttributeResource(); - attributeResource.setKey(attribute.getKey()); - attributeResource.setValue(attribute.getValue()); - return attributeResource; - }).collect(Collectors.toSet()); - - if (LogicalOperator.AND.equals(logicalOperator)) { - return itemAttributes.containsAll(itemAttributesResource); - } - - return CollectionUtils.containsAny(itemAttributes, itemAttributesResource); - } +public class LaunchNotificationRunner + implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { + + public static final Logger LOGGER = LoggerFactory.getLogger(LaunchNotificationRunner.class); + + private final GetProjectHandler getProjectHandler; + private final GetLaunchHandler getLaunchHandler; + private final GetIntegrationHandler getIntegrationHandler; + private final MailServiceFactory mailServiceFactory; + private final UserRepository userRepository; + + @Autowired + public LaunchNotificationRunner(GetProjectHandler getProjectHandler, + GetLaunchHandler getLaunchHandler, GetIntegrationHandler getIntegrationHandler, + MailServiceFactory mailServiceFactory, UserRepository userRepository) { + this.getProjectHandler = getProjectHandler; + this.getLaunchHandler = getLaunchHandler; + this.getIntegrationHandler = getIntegrationHandler; + this.mailServiceFactory = mailServiceFactory; + this.userRepository = userRepository; + } + + @Override + @Transactional(readOnly = true) + public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { + + boolean isNotificationsEnabled = BooleanUtils.toBoolean( + projectConfig.get(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute())); + + if (isNotificationsEnabled) { + getIntegrationHandler.getEnabledByProjectIdOrGlobalAndIntegrationGroup( + launchFinishedEvent.getProjectId(), IntegrationGroupEnum.NOTIFICATION) + .flatMap(mailServiceFactory::getDefaultEmailService) + .ifPresentOrElse(emailService -> sendEmail(launchFinishedEvent, emailService), + () -> LOGGER.warn("Unable to find {} integration for project {}", + IntegrationGroupEnum.NOTIFICATION, launchFinishedEvent.getProjectId() + ) + ); + + } + + } + + /** + * Try to send email when it is needed + * + * @param launch Launch to be used + * @param project Project + * @param emailService Mail Service + */ + private void sendEmail(LaunchFinishedEvent launchFinishedEvent, EmailService emailService) { + + final Launch launch = getLaunchHandler.get(launchFinishedEvent.getId()); + final Project project = getProjectHandler.get(launch.getProjectId()); + + project.getSenderCases().stream().filter(SenderCase::isEnabled).forEach(ec -> { + SendCase sendCase = ec.getSendCase(); + boolean successRate = isSuccessRateEnough(launch, sendCase); + boolean matchedNames = isLaunchNameMatched(launch, ec); + boolean matchedTags = + isAttributesMatched(launch, ec.getLaunchAttributeRules(), ec.getAttributesOperator()); + + Set<String> recipients = ec.getRecipients(); + if (successRate && matchedNames && matchedTags) { + String[] recipientsArray = findRecipients( + userRepository.findLoginById(launch.getUserId()).orElseThrow( + () -> new ReportPortalException(ErrorType.USER_NOT_FOUND, launch.getUserId())), + recipients + ); + try { + if (launchFinishedEvent.getBaseUrl() != null) { + emailService.sendLaunchFinishNotification(recipientsArray, + String.format("%s/ui/#%s", launchFinishedEvent.getBaseUrl(), project.getName()), + project, launch + ); + } else { + emailService.sendLaunchFinishNotification( + recipientsArray, String.format("/ui/#%s", project.getName()), project, launch); + } + } catch (Exception e) { + LOGGER.error("Unable to send email.", e); + } + } + }); + + } + + private String[] findRecipients(String owner, Set<String> recipients) { + return recipients.stream().map(recipient -> { + if (recipient.contains("@")) { + return recipient; + } else { + String toFind = recipient.equals(ProjectUtils.getOwner()) ? owner : recipient; + Optional<User> user = userRepository.findByLogin(toFind); + return user.map(User::getEmail).orElse(null); + } + }).filter(Objects::nonNull).distinct().toArray(String[]::new); + } + + /** + * @param launch launch to be evaluated + * @return success rate of provided launch in % + */ + private static double getSuccessRate(Launch launch) { + double ti = + extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()).doubleValue(); + double pb = + extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, launch.getStatistics()).doubleValue(); + double si = + extractStatisticsCount(DEFECTS_SYSTEM_ISSUE_TOTAL, launch.getStatistics()).doubleValue(); + double ab = + extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, launch.getStatistics()).doubleValue(); + double total = extractStatisticsCount(EXECUTIONS_TOTAL, launch.getStatistics()).doubleValue(); + return total == 0 ? total : (ti + pb + si + ab) / total; + } + + /** + * @param launch Launch to be evaluated + * @param option SendCase option + * @return TRUE of success rate is enough for notification + */ + private boolean isSuccessRateEnough(Launch launch, SendCase option) { + switch (option) { + case ALWAYS: + return true; + case FAILED: + return getLaunchHandler.hasItemsWithIssues(launch); + case TO_INVESTIGATE: + return extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()) > 0; + case MORE_10: + return getSuccessRate(launch) > 0.1; + case MORE_20: + return getSuccessRate(launch) > 0.2; + case MORE_50: + return getSuccessRate(launch) > 0.5; + default: + return false; + } + } + + /** + * Validate matching of finished launch name and project settings for emailing + * + * @param launch Launch to be evaluated + * @param oneCase Mail case + * @return TRUE if launch name matched + */ + private static boolean isLaunchNameMatched(Launch launch, SenderCase oneCase) { + Set<String> configuredNames = oneCase.getLaunchNames(); + return (null == configuredNames) || (configuredNames.isEmpty()) || configuredNames.contains( + launch.getName()); + } + + /** + * Validate matching of finished launch tags and project settings for emailing + * + * @param launch Launch to be evaluated + * @return TRUE if tags matched + */ + @VisibleForTesting + private static boolean isAttributesMatched(Launch launch, + Set<LaunchAttributeRule> launchAttributeRules, LogicalOperator logicalOperator) { + + if (CollectionUtils.isEmpty(launchAttributeRules)) { + return true; + } + + Set<ItemAttributeResource> itemAttributesResource = + launchAttributeRules.stream().map(NotificationConfigConverter.TO_ATTRIBUTE_RULE_RESOURCE) + .collect(Collectors.toSet()); + + Set<ItemAttributeResource> itemAttributes = + launch.getAttributes().stream().filter(attribute -> !attribute.isSystem()) + .map(attribute -> { + ItemAttributeResource attributeResource = new ItemAttributeResource(); + attributeResource.setKey(attribute.getKey()); + attributeResource.setValue(attribute.getValue()); + return attributeResource; + }).collect(Collectors.toSet()); + + if (LogicalOperator.AND.equals(logicalOperator)) { + return itemAttributesResource.stream().allMatch(resourceAttr -> itemAttributes.stream() + .anyMatch(attr -> areAttributesMatched(attr, resourceAttr))); + } + + return itemAttributes.stream().anyMatch(attr -> itemAttributesResource.stream() + .anyMatch(resourceAttr -> areAttributesMatched(attr, resourceAttr))); + } + + private static boolean areAttributesMatched(ItemAttributeResource itemAttribute, + ItemAttributeResource itemAttributeResource) { + // Case 1: Key and Value are the same + boolean isEqual = + Objects.equals(itemAttribute.getKey(), itemAttributeResource.getKey()) && Objects.equals( + itemAttribute.getValue(), itemAttributeResource.getValue()); + + // Case 2: Key is null in itemAttributesResource and the Value is the same + boolean isValueEqualWithKeyNull = + itemAttributeResource.getKey() == null && Objects.equals(itemAttribute.getValue(), + itemAttributeResource.getValue() + ); + return isEqual || isValueEqualWithKeyNull; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunner.java index 825d6df0cc..1ce570340e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunner.java @@ -17,45 +17,48 @@ package com.epam.ta.reportportal.core.events.handler.launch; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.core.analyzer.pattern.PatternAnalyzer; +import com.epam.ta.reportportal.core.analyzer.pattern.service.LaunchPatternAnalyzer; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.epam.ta.reportportal.entity.launch.Launch; +import com.google.common.collect.Sets; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class LaunchPatternAnalysisRunner implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { +public class LaunchPatternAnalysisRunner implements + ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { - private final GetLaunchHandler getLaunchHandler; - private final PatternAnalyzer patternAnalyzer; + private final GetLaunchHandler getLaunchHandler; + private final LaunchPatternAnalyzer launchPatternAnalyzer; - @Autowired - public LaunchPatternAnalysisRunner(GetLaunchHandler getLaunchHandler, PatternAnalyzer patternAnalyzer) { - this.getLaunchHandler = getLaunchHandler; - this.patternAnalyzer = patternAnalyzer; - } + @Autowired + public LaunchPatternAnalysisRunner(GetLaunchHandler getLaunchHandler, + LaunchPatternAnalyzer launchPatternAnalyzer) { + this.getLaunchHandler = getLaunchHandler; + this.launchPatternAnalyzer = launchPatternAnalyzer; + } - @Override - @Transactional - public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { + @Override + @Transactional + public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { - boolean isPatternAnalysisEnabled = BooleanUtils.toBoolean(projectConfig.get(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute())); + boolean isPatternAnalysisEnabled = BooleanUtils.toBoolean( + projectConfig.get(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute())); - if (isPatternAnalysisEnabled) { - final Launch launch = getLaunchHandler.get(launchFinishedEvent.getId()); - patternAnalyzer.analyzeTestItems(launch, Collections.singleton(AnalyzeItemsMode.TO_INVESTIGATE)); - } - } + if (isPatternAnalysisEnabled) { + final Launch launch = getLaunchHandler.get(launchFinishedEvent.getId()); + launchPatternAnalyzer.analyzeLaunch(launch, + Sets.newHashSet(AnalyzeItemsMode.TO_INVESTIGATE, AnalyzeItemsMode.IGNORE_IMMEDIATE)); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunner.java b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunner.java index 279c1fb2f7..4194d712e1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunner.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunner.java @@ -16,40 +16,43 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED; + import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; import com.epam.ta.reportportal.core.launch.cluster.UniqueErrorAnalysisStarter; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class LaunchUniqueErrorAnalysisRunner implements ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { - - private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; - - @Autowired - public LaunchUniqueErrorAnalysisRunner(@Qualifier("uniqueErrorAnalysisStarter") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { - this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; - } - - @Override - public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { - final boolean enabled = BooleanUtils.toBoolean(projectConfig.get(AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute())); - if (enabled) { - uniqueErrorAnalysisStarter.start(ClusterEntityContext.of(launchFinishedEvent.getId(), launchFinishedEvent.getProjectId()), - projectConfig - ); - } - } +public class LaunchUniqueErrorAnalysisRunner implements + ConfigurableEventHandler<LaunchFinishedEvent, Map<String, String>> { + + private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; + + @Autowired + public LaunchUniqueErrorAnalysisRunner( + @Qualifier("uniqueErrorAnalysisStarter") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { + this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; + } + + @Override + public void handle(LaunchFinishedEvent launchFinishedEvent, Map<String, String> projectConfig) { + final boolean enabled = BooleanUtils.toBoolean( + projectConfig.get(AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute())); + if (enabled) { + uniqueErrorAnalysisStarter.start( + ClusterEntityContext.of(launchFinishedEvent.getId(), launchFinishedEvent.getProjectId()), + projectConfig + ); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/listener/LaunchFinishedEventListener.java b/src/main/java/com/epam/ta/reportportal/core/events/listener/LaunchFinishedEventListener.java index 65acb7fa89..8bd764b721 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/listener/LaunchFinishedEventListener.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/listener/LaunchFinishedEventListener.java @@ -19,31 +19,30 @@ import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.subscriber.EventSubscriber; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; +import java.util.List; import org.springframework.scheduling.annotation.Async; import org.springframework.transaction.event.TransactionalEventListener; -import java.util.List; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public class LaunchFinishedEventListener { - private final List<EventSubscriber<LaunchFinishedEvent>> subscribers; + private final List<EventSubscriber<LaunchFinishedEvent>> subscribers; - public LaunchFinishedEventListener(List<EventSubscriber<LaunchFinishedEvent>> subscribers) { - this.subscribers = subscribers; - } + public LaunchFinishedEventListener(List<EventSubscriber<LaunchFinishedEvent>> subscribers) { + this.subscribers = subscribers; + } - @Async(value = "eventListenerExecutor") - @TransactionalEventListener - public void onApplicationEvent(LaunchFinishedEvent event) { - if (LaunchModeEnum.DEBUG == event.getMode()) { - return; - } + @Async(value = "eventListenerExecutor") + @TransactionalEventListener + public void onApplicationEvent(LaunchFinishedEvent event) { + if (LaunchModeEnum.DEBUG == event.getMode()) { + return; + } - subscribers.forEach(s -> s.handleEvent(event)); + subscribers.forEach(s -> s.handleEvent(event)); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListener.java b/src/main/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListener.java index 609e17aa82..ab41e66666 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListener.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListener.java @@ -20,32 +20,32 @@ import com.epam.ta.reportportal.core.launch.cluster.UniqueErrorAnalysisStarter; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.project.config.ProjectConfigProvider; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class StartLaunchUniqueErrorAnalysisEventListener { - private final ProjectConfigProvider projectConfigProvider; - private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; + private final ProjectConfigProvider projectConfigProvider; + private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; - @Autowired - public StartLaunchUniqueErrorAnalysisEventListener(ProjectConfigProvider projectConfigProvider, - @Qualifier("uniqueErrorAnalysisStarter") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { - this.projectConfigProvider = projectConfigProvider; - this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; - } + @Autowired + public StartLaunchUniqueErrorAnalysisEventListener(ProjectConfigProvider projectConfigProvider, + @Qualifier("uniqueErrorAnalysisStarter") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { + this.projectConfigProvider = projectConfigProvider; + this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; + } - @EventListener - public void onApplicationEvent(LaunchStartUniqueErrorAnalysisEvent event) { - final Map<String, String> projectConfig = projectConfigProvider.provide(event.getProjectId()); - uniqueErrorAnalysisStarter.start(ClusterEntityContext.of(event.getSource(), event.getProjectId()), projectConfig); - } + @EventListener + public void onApplicationEvent(LaunchStartUniqueErrorAnalysisEvent event) { + final Map<String, String> projectConfig = projectConfigProvider.provide(event.getProjectId()); + uniqueErrorAnalysisStarter.start( + ClusterEntityContext.of(event.getSource(), event.getProjectId()), projectConfig); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListener.java b/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListener.java index a7cb65ecc2..dec6fe874b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListener.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 EPAM Systems + * Copyright 2023 EPAM Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,30 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.epam.ta.reportportal.core.events.listener; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; import com.epam.ta.reportportal.core.events.subscriber.EventSubscriber; +import java.util.List; import org.springframework.scheduling.annotation.Async; import org.springframework.transaction.event.TransactionalEventListener; -import java.util.List; - /** - * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public class TestItemFinishedEventListener { - private final List<EventSubscriber<ItemFinishedEvent>> subscribers; + private final List<EventSubscriber<TestItemFinishedEvent>> subscribers; - public TestItemFinishedEventListener(List<EventSubscriber<ItemFinishedEvent>> subscribers) { - this.subscribers = subscribers; - } + public TestItemFinishedEventListener(List<EventSubscriber<TestItemFinishedEvent>> subscribers) { + this.subscribers = subscribers; + } - @Async(value = "eventListenerExecutor") - @TransactionalEventListener - public void onApplicationEvent(ItemFinishedEvent event) { - subscribers.forEach(s -> s.handleEvent(event)); - } + @Async(value = "eventListenerExecutor") + @TransactionalEventListener + public void onApplicationEvent(TestItemFinishedEvent event) { + subscribers.forEach(s -> s.handleEvent(event)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemIssueResolvedEventListener.java b/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemIssueResolvedEventListener.java new file mode 100644 index 0000000000..7a89b37e0c --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/events/listener/TestItemIssueResolvedEventListener.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.events.listener; + +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; +import com.epam.ta.reportportal.core.events.subscriber.EventSubscriber; +import java.util.List; +import org.springframework.scheduling.annotation.Async; +import org.springframework.transaction.event.TransactionalEventListener; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +public class TestItemIssueResolvedEventListener { + + private final List<EventSubscriber<IssueResolvedEvent>> subscribers; + + public TestItemIssueResolvedEventListener(List<EventSubscriber<IssueResolvedEvent>> subscribers) { + this.subscribers = subscribers; + } + + @Async(value = "eventListenerExecutor") + @TransactionalEventListener + public void onApplicationEvent(IssueResolvedEvent event) { + subscribers.forEach(s -> s.handleEvent(event)); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/events/multicaster/DelegatingApplicationEventMulticaster.java b/src/main/java/com/epam/ta/reportportal/core/events/multicaster/DelegatingApplicationEventMulticaster.java index 29b0a2b681..9f9c6fd8fc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/multicaster/DelegatingApplicationEventMulticaster.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/multicaster/DelegatingApplicationEventMulticaster.java @@ -16,80 +16,82 @@ package com.epam.ta.reportportal.core.events.multicaster; +import static java.util.Optional.ofNullable; + +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.SimpleApplicationEventMulticaster; -import java.util.Set; - -import static java.util.Optional.ofNullable; - /** - * Extension for {@link SimpleApplicationEventMulticaster} to allow error handling only for provided set of events + * Extension for {@link SimpleApplicationEventMulticaster} to allow error handling only for provided + * set of events * * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class DelegatingApplicationEventMulticaster extends SimpleApplicationEventMulticaster { - private final Set<Class<?>> errorHandlingEventTypes; + private final Set<Class<?>> errorHandlingEventTypes; - public DelegatingApplicationEventMulticaster(Set<Class<?>> errorHandlingEventTypes) { - this.errorHandlingEventTypes = errorHandlingEventTypes; - } + public DelegatingApplicationEventMulticaster(Set<Class<?>> errorHandlingEventTypes) { + this.errorHandlingEventTypes = errorHandlingEventTypes; + } - @Override - protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { - ofNullable(getErrorHandler()).filter(h -> errorHandlingEventTypes.contains(event.getClass())).ifPresentOrElse(h -> { - try { - doInvokeListener(listener, event); - } catch (Throwable err) { - h.handleError(err); - } - }, () -> doInvokeListener(listener, event)); - } + @Override + protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { + ofNullable(getErrorHandler()).filter(h -> errorHandlingEventTypes.contains(event.getClass())) + .ifPresentOrElse(h -> { + try { + doInvokeListener(listener, event); + } catch (Throwable err) { + h.handleError(err); + } + }, () -> doInvokeListener(listener, event)); + } - /** - * @see SimpleApplicationEventMulticaster - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { - try { - listener.onApplicationEvent(event); - } catch (ClassCastException ex) { - String msg = ex.getMessage(); - if (msg == null || matchesClassCastMessage(msg, event.getClass())) { - // Possibly a lambda-defined listener which we could not resolve the generic event type for - // -> let's suppress the exception and just log a debug message. - Log logger = LogFactory.getLog(getClass()); - if (logger.isTraceEnabled()) { - logger.trace("Non-matching event type for listener: " + listener, ex); - } - } else { - throw ex; - } - } - } + /** + * @see SimpleApplicationEventMulticaster + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { + try { + listener.onApplicationEvent(event); + } catch (ClassCastException ex) { + String msg = ex.getMessage(); + if (msg == null || matchesClassCastMessage(msg, event.getClass())) { + // Possibly a lambda-defined listener which we could not resolve the generic event type for + // -> let's suppress the exception and just log a debug message. + Log logger = LogFactory.getLog(getClass()); + if (logger.isTraceEnabled()) { + logger.trace("Non-matching event type for listener: " + listener, ex); + } + } else { + throw ex; + } + } + } - /** - * @see SimpleApplicationEventMulticaster - */ - private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) { - // On Java 8, the message starts with the class name: "java.lang.String cannot be cast..." - if (classCastMessage.startsWith(eventClass.getName())) { - return true; - } - // On Java 11, the message starts with "class ..." a.k.a. Class.toString() - if (classCastMessage.startsWith(eventClass.toString())) { - return true; - } - // On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..." - int moduleSeparatorIndex = classCastMessage.indexOf('/'); - if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) { - return true; - } - // Assuming an unrelated class cast failure... - return false; - } + /** + * @see SimpleApplicationEventMulticaster + */ + private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) { + // On Java 8, the message starts with the class name: "java.lang.String cannot be cast..." + if (classCastMessage.startsWith(eventClass.getName())) { + return true; + } + // On Java 11, the message starts with "class ..." a.k.a. Class.toString() + if (classCastMessage.startsWith(eventClass.toString())) { + return true; + } + // On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..." + int moduleSeparatorIndex = classCastMessage.indexOf('/'); + if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), + moduleSeparatorIndex + 1)) { + return true; + } + // Assuming an unrelated class cast failure... + return false; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/subscriber/EventSubscriber.java b/src/main/java/com/epam/ta/reportportal/core/events/subscriber/EventSubscriber.java index 3cebb0847e..0a45f490e5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/subscriber/EventSubscriber.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/subscriber/EventSubscriber.java @@ -23,5 +23,5 @@ */ public interface EventSubscriber<T extends Event> { - void handleEvent(T event); + void handleEvent(T event); } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriber.java b/src/main/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriber.java index 39e46604bf..ef9d5044eb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriber.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriber.java @@ -20,27 +20,27 @@ import com.epam.ta.reportportal.core.events.handler.ConfigurableEventHandler; import com.epam.ta.reportportal.core.events.subscriber.EventSubscriber; import com.epam.ta.reportportal.core.project.config.ProjectConfigProvider; - import java.util.List; import java.util.Map; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ -public class ProjectConfigDelegatingSubscriber<T extends ProjectIdAwareEvent> implements EventSubscriber<T> { +public class ProjectConfigDelegatingSubscriber<T extends ProjectIdAwareEvent> implements + EventSubscriber<T> { - private final ProjectConfigProvider projectConfigProvider; - private final List<ConfigurableEventHandler<T, Map<String, String>>> eventHandlers; + private final ProjectConfigProvider projectConfigProvider; + private final List<ConfigurableEventHandler<T, Map<String, String>>> eventHandlers; - public ProjectConfigDelegatingSubscriber(ProjectConfigProvider projectConfigProvider, - List<ConfigurableEventHandler<T, Map<String, String>>> eventHandlers) { - this.projectConfigProvider = projectConfigProvider; - this.eventHandlers = eventHandlers; - } + public ProjectConfigDelegatingSubscriber(ProjectConfigProvider projectConfigProvider, + List<ConfigurableEventHandler<T, Map<String, String>>> eventHandlers) { + this.projectConfigProvider = projectConfigProvider; + this.eventHandlers = eventHandlers; + } - @Override - public void handleEvent(T event) { - final Map<String, String> projectConfig = projectConfigProvider.provide(event.getProjectId()); - eventHandlers.forEach(h -> h.handle(event, projectConfig)); - } + @Override + public void handleEvent(T event) { + final Map<String, String> projectConfig = projectConfigProvider.provide(event.getProjectId()); + eventHandlers.forEach(h -> h.handle(event, projectConfig)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateComponentHealthCheckTableEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateComponentHealthCheckTableEvent.java index aacd822d1d..c55573f419 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateComponentHealthCheckTableEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateComponentHealthCheckTableEvent.java @@ -1,7 +1,6 @@ package com.epam.ta.reportportal.core.events.widget; import com.google.common.collect.Lists; - import java.util.List; /** @@ -9,31 +8,32 @@ */ public class GenerateComponentHealthCheckTableEvent { - private final Long widgetId; - private final boolean refresh; - private final List<String> attributeKeys; - - public GenerateComponentHealthCheckTableEvent(Long widgetId, boolean refresh) { - this.widgetId = widgetId; - this.refresh = refresh; - this.attributeKeys = Lists.newArrayList(); - } - - public GenerateComponentHealthCheckTableEvent(Long widgetId, boolean refresh, List<String> attributeKeys) { - this.widgetId = widgetId; - this.refresh = refresh; - this.attributeKeys = attributeKeys; - } - - public Long getWidgetId() { - return widgetId; - } - - public boolean isRefresh() { - return refresh; - } - - public List<String> getAttributeKeys() { - return attributeKeys; - } + private final Long widgetId; + private final boolean refresh; + private final List<String> attributeKeys; + + public GenerateComponentHealthCheckTableEvent(Long widgetId, boolean refresh) { + this.widgetId = widgetId; + this.refresh = refresh; + this.attributeKeys = Lists.newArrayList(); + } + + public GenerateComponentHealthCheckTableEvent(Long widgetId, boolean refresh, + List<String> attributeKeys) { + this.widgetId = widgetId; + this.refresh = refresh; + this.attributeKeys = attributeKeys; + } + + public Long getWidgetId() { + return widgetId; + } + + public boolean isRefresh() { + return refresh; + } + + public List<String> getAttributeKeys() { + return attributeKeys; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateWidgetViewEvent.java b/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateWidgetViewEvent.java index f0430dfcd8..cf73138a93 100644 --- a/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateWidgetViewEvent.java +++ b/src/main/java/com/epam/ta/reportportal/core/events/widget/GenerateWidgetViewEvent.java @@ -8,24 +8,24 @@ */ public class GenerateWidgetViewEvent { - private final Long widgetId; - private final MultiValueMap<String, String> params; + private final Long widgetId; + private final MultiValueMap<String, String> params; - public GenerateWidgetViewEvent(Long widgetId, MultiValueMap<String, String> params) { - this.widgetId = widgetId; - this.params = params; - } + public GenerateWidgetViewEvent(Long widgetId, MultiValueMap<String, String> params) { + this.widgetId = widgetId; + this.params = params; + } - public GenerateWidgetViewEvent(Long widgetId) { - this.widgetId = widgetId; - this.params = new LinkedMultiValueMap<>(); - } + public GenerateWidgetViewEvent(Long widgetId) { + this.widgetId = widgetId; + this.params = new LinkedMultiValueMap<>(); + } - public Long getWidgetId() { - return widgetId; - } + public Long getWidgetId() { + return widgetId; + } - public MultiValueMap<String, String> getParams() { - return params; - } + public MultiValueMap<String, String> getParams() { + return params; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/file/DeleteFilesHandler.java b/src/main/java/com/epam/ta/reportportal/core/file/DeleteFilesHandler.java index 11ef8832ee..49161f40a1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/file/DeleteFilesHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/file/DeleteFilesHandler.java @@ -1,5 +1,8 @@ package com.epam.ta.reportportal.core.file; +import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_ATTACHMENT; +import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.QUEUE_ATTACHMENT_DELETE; + import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.events.attachment.DeleteAttachmentEvent; import com.epam.ta.reportportal.exception.ReportPortalException; @@ -10,48 +13,49 @@ import com.opencsv.CSVParserBuilder; import com.opencsv.CSVReader; import com.opencsv.CSVReaderBuilder; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.List; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.List; - @Service public class DeleteFilesHandler { - private static final int FILE_ID = 1; - private static final int CSV_SKIP_LINES = 1; - private static final int THUMBNAIL_ID = 2; - private static final int BATCH = 250; + private static final int FILE_ID = 1; + private static final int CSV_SKIP_LINES = 1; + private static final int THUMBNAIL_ID = 2; + private static final int BATCH = 250; - @Autowired - private MessageBus messageBus; + @Autowired + private MessageBus messageBus; - public OperationCompletionRS removeFilesByCsv(MultipartFile file) { - CSVParser parser = new CSVParserBuilder().withSeparator(',').withIgnoreQuotations(true).build(); - try (CSVReader csvReader = new CSVReaderBuilder(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)).withSkipLines( - CSV_SKIP_LINES).withCSVParser(parser).build()) { - List<String[]> attachments = csvReader.readAll(); - List<String> pathsForDelete = Lists.newArrayListWithCapacity(attachments.size()); - attachments.forEach(attachmentLine -> { - pathsForDelete.add(attachmentLine[FILE_ID]); - if (!StringUtils.isEmpty(attachmentLine[THUMBNAIL_ID])) { - pathsForDelete.add(attachmentLine[THUMBNAIL_ID]); - } - }); - ListUtils.partition(pathsForDelete, BATCH).forEach(partition -> { - DeleteAttachmentEvent deleteAttachmentEvent = new DeleteAttachmentEvent(); - deleteAttachmentEvent.setPaths(partition); - messageBus.publishDeleteAttachmentEvent(deleteAttachmentEvent); - }); - return new OperationCompletionRS("Csv file " + file.getName() + " is accepted for delete process"); - } catch (Exception e) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, e.getMessage()); - } - } + public OperationCompletionRS removeFilesByCsv(MultipartFile file) { + CSVParser parser = new CSVParserBuilder().withSeparator(',').withIgnoreQuotations(true).build(); + try (CSVReader csvReader = new CSVReaderBuilder( + new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)).withSkipLines( + CSV_SKIP_LINES).withCSVParser(parser).build()) { + List<String[]> attachments = csvReader.readAll(); + List<String> pathsForDelete = Lists.newArrayListWithCapacity(attachments.size()); + attachments.forEach(attachmentLine -> { + pathsForDelete.add(attachmentLine[FILE_ID]); + if (!StringUtils.isEmpty(attachmentLine[THUMBNAIL_ID])) { + pathsForDelete.add(attachmentLine[THUMBNAIL_ID]); + } + }); + ListUtils.partition(pathsForDelete, BATCH).forEach(partition -> { + DeleteAttachmentEvent deleteAttachmentEvent = new DeleteAttachmentEvent(); + deleteAttachmentEvent.setPaths(partition); + messageBus.publish(EXCHANGE_ATTACHMENT, QUEUE_ATTACHMENT_DELETE, deleteAttachmentEvent); + }); + return new OperationCompletionRS( + "Csv file " + file.getName() + " is accepted for delete process"); + } catch (Exception e) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/file/GetFileHandler.java b/src/main/java/com/epam/ta/reportportal/core/file/GetFileHandler.java index 52b376d42f..119a4fdf07 100644 --- a/src/main/java/com/epam/ta/reportportal/core/file/GetFileHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/file/GetFileHandler.java @@ -17,7 +17,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.attachment.BinaryData; - import java.io.InputStream; /** @@ -25,29 +24,34 @@ */ public interface GetFileHandler { - /** - * Returns {@link InputStream} for current logged-in user photo - * - * @param loggedInUser Logged-in {@link ReportPortalUser} - * @return {@link InputStream} - */ - BinaryData getUserPhoto(ReportPortalUser loggedInUser, boolean loadThumbnail); + /** + * Returns {@link InputStream} for current logged-in user photo + * + * @param loggedInUser Logged-in {@link ReportPortalUser} + * @param loadThumbnail true if need to load thumbnail + * @return {@link InputStream} + */ + BinaryData getUserPhoto(ReportPortalUser loggedInUser, boolean loadThumbnail); - /** - * Returns {@link InputStream} for photo of the {@link com.epam.ta.reportportal.entity.user.User} with specified username - * - * @param username Username of user which photo to get - * @param loggedInUser Logged-in {@link ReportPortalUser} - * @return {@link InputStream} - */ - BinaryData getUserPhoto(String username, ReportPortalUser loggedInUser, String projectName, - boolean loadThumbnail); + /** + * Returns {@link InputStream} for photo of the {@link com.epam.ta.reportportal.entity.user.User} + * with specified username + * + * @param username Username of user which photo to get + * @param loggedInUser Logged-in {@link ReportPortalUser} + * @param projectName Project name + * @param loadThumbnail true if need to load thumbnail + * @return {@link InputStream} + */ + BinaryData getUserPhoto(String username, ReportPortalUser loggedInUser, String projectName, + boolean loadThumbnail); - /** - * Returns {@link InputStream} for the file with the specified id - * - * @param fileId Id of the file to get - * @return {@link InputStream} - */ - BinaryData loadFileById(Long fileId, ReportPortalUser.ProjectDetails projectDetails); + /** + * Returns {@link BinaryData} for the file with the specified id + * + * @param fileId Id of the file to get + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @return {@link BinaryData} file data + */ + BinaryData loadFileById(Long fileId, ReportPortalUser.ProjectDetails projectDetails); } diff --git a/src/main/java/com/epam/ta/reportportal/core/file/impl/GetFileHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/file/impl/GetFileHandlerImpl.java index 9cd1d92d66..3bc74f859e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/file/impl/GetFileHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/file/impl/GetFileHandlerImpl.java @@ -15,6 +15,9 @@ */ package com.epam.ta.reportportal.core.file.impl; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; + import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; import com.epam.ta.reportportal.binary.UserBinaryDataService; import com.epam.ta.reportportal.commons.ReportPortalUser; @@ -27,59 +30,61 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.function.Predicate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class GetFileHandlerImpl implements GetFileHandler { - private final UserRepository userRepository; + private final UserRepository userRepository; - private final UserBinaryDataService userDataStoreService; + private final UserBinaryDataService userDataStoreService; - private final AttachmentBinaryDataService attachmentBinaryDataService; + private final AttachmentBinaryDataService attachmentBinaryDataService; - private final ProjectExtractor projectExtractor; + private final ProjectExtractor projectExtractor; - @Autowired - public GetFileHandlerImpl(UserRepository userRepository, UserBinaryDataService userDataStoreService, - AttachmentBinaryDataService attachmentBinaryDataService, ProjectExtractor projectExtractor) { - this.userRepository = userRepository; - this.userDataStoreService = userDataStoreService; - this.attachmentBinaryDataService = attachmentBinaryDataService; - this.projectExtractor = projectExtractor; - } + @Autowired + public GetFileHandlerImpl(UserRepository userRepository, + UserBinaryDataService userDataStoreService, + AttachmentBinaryDataService attachmentBinaryDataService, ProjectExtractor projectExtractor) { + this.userRepository = userRepository; + this.userDataStoreService = userDataStoreService; + this.attachmentBinaryDataService = attachmentBinaryDataService; + this.projectExtractor = projectExtractor; + } - @Override - public BinaryData getUserPhoto(ReportPortalUser loggedInUser, boolean loadThumbnail) { - User user = userRepository.findByLogin(loggedInUser.getUsername()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, loggedInUser.getUsername())); - return userDataStoreService.loadUserPhoto(user, loadThumbnail); - } + @Override + public BinaryData getUserPhoto(ReportPortalUser loggedInUser, boolean loadThumbnail) { + User user = userRepository.findByLogin(loggedInUser.getUsername()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.USER_NOT_FOUND, loggedInUser.getUsername())); + return userDataStoreService.loadUserPhoto(user, loadThumbnail); + } - @Override - public BinaryData getUserPhoto(String username, ReportPortalUser loggedInUser, String projectName, boolean loadThumbnail) { - User user = userRepository.findByLogin(username).orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, username)); - ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetailsAdmin(loggedInUser, projectName); - if (loggedInUser.getUserRole() != UserRole.ADMINISTRATOR) { - expect( - ProjectUtils.isAssignedToProject(user, projectDetails.getProjectId()), - Predicate.isEqual(true) - ).verify(ErrorType.ACCESS_DENIED, formattedSupplier("You are not assigned to project '{}'", projectDetails.getProjectName())); - } - return userDataStoreService.loadUserPhoto(user, loadThumbnail); - } + @Override + public BinaryData getUserPhoto(String username, ReportPortalUser loggedInUser, String projectName, + boolean loadThumbnail) { + User user = userRepository.findByLogin(username) + .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, username)); + ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetailsAdmin( + loggedInUser, projectName); + if (loggedInUser.getUserRole() != UserRole.ADMINISTRATOR) { + expect( + ProjectUtils.isAssignedToProject(user, projectDetails.getProjectId()), + Predicate.isEqual(true) + ).verify(ErrorType.ACCESS_DENIED, formattedSupplier("You are not assigned to project '{}'", + projectDetails.getProjectName())); + } + return userDataStoreService.loadUserPhoto(user, loadThumbnail); + } - @Override - public BinaryData loadFileById(Long fileId, ReportPortalUser.ProjectDetails projectDetails) { - return attachmentBinaryDataService.load(fileId, projectDetails); - } + @Override + public BinaryData loadFileById(Long fileId, ReportPortalUser.ProjectDetails projectDetails) { + return attachmentBinaryDataService.load(fileId, projectDetails); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/DeleteUserFilterHandler.java b/src/main/java/com/epam/ta/reportportal/core/filter/DeleteUserFilterHandler.java index 32ee4b9f12..81bbd11ada 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/DeleteUserFilterHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/DeleteUserFilterHandler.java @@ -26,14 +26,15 @@ */ public interface DeleteUserFilterHandler { - /** - * Delete complex filter by id - * - * @param id Filter id - * @param projectDetails Project details - * @param user User - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS deleteFilter(Long id, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Delete complex filter by id + * + * @param id Filter id + * @param projectDetails Project details + * @param user User + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS deleteFilter(Long id, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/SearchCriteriaService.java b/src/main/java/com/epam/ta/reportportal/core/filter/SearchCriteriaService.java index 3256564739..cfb5c93d17 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/SearchCriteriaService.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/SearchCriteriaService.java @@ -18,9 +18,7 @@ import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.filter.predefined.PredefinedFilterType; -import com.epam.ta.reportportal.ws.model.SearchCriteria; import com.epam.ta.reportportal.ws.model.SearchCriteriaRQ; -import java.util.Set; /** * Service for converting SearchCriteria to Filter. diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/UpdateUserFilterHandler.java b/src/main/java/com/epam/ta/reportportal/core/filter/UpdateUserFilterHandler.java index 187bcdfaf1..2374c0eb67 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/UpdateUserFilterHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/UpdateUserFilterHandler.java @@ -34,37 +34,37 @@ */ public interface UpdateUserFilterHandler { - /** - * Creates new filter - * - * @param createFilterRQ - * @param projectName - * @param user - * @return EntryCreatedRS - */ - EntryCreatedRS createFilter(UpdateUserFilterRQ createFilterRQ, String projectName, ReportPortalUser user); + /** + * Creates new filter for a specific project and user. + * + * @param createFilterRQ The request containing the filter creation data + * @param projectName The name of the project where the filter will be created + * @param user The {@link ReportPortalUser} who is creating the filter + * @return An {@link EntryCreatedRS} instance containing the created filter's ID + */ + EntryCreatedRS createFilter(UpdateUserFilterRQ createFilterRQ, String projectName, ReportPortalUser user); - /** - * Update user filter with specified id - * - * @param userFilterId User filter id - * @param updateRQ Update filter details - * @param projectDetails Project details - * @param user User - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS updateUserFilter(Long userFilterId, UpdateUserFilterRQ updateRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Update user filter with specified id + * + * @param userFilterId User filter id + * @param updateRQ Update filter details + * @param projectDetails Project details + * @param user User + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS updateUserFilter(Long userFilterId, UpdateUserFilterRQ updateRQ, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Update user filter - * - * @param updateRQ - * @param projectDetails - * @param user - * @return List of {@link OperationCompletionRS} - */ - List<OperationCompletionRS> updateUserFilter(CollectionsRQ<BulkUpdateFilterRQ> updateRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Update user filter + * + * @param updateRQ Request for filter update + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} filter's owner + * @return List of {@link OperationCompletionRS} + */ + List<OperationCompletionRS> updateUserFilter(CollectionsRQ<BulkUpdateFilterRQ> updateRQ, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/impl/DeleteUserFilterHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/filter/impl/DeleteUserFilterHandlerImpl.java index 13984cb1d3..bb1a88f3a3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/impl/DeleteUserFilterHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/impl/DeleteUserFilterHandlerImpl.java @@ -37,13 +37,13 @@ @Service public class DeleteUserFilterHandlerImpl implements DeleteUserFilterHandler { - private final UserFilterRepository userFilterRepository; - private final MessageBus messageBus; + private final UserFilterRepository userFilterRepository; + private final MessageBus messageBus; @Autowired public DeleteUserFilterHandlerImpl(UserFilterRepository userFilterRepository, MessageBus messageBus) { - this.userFilterRepository = userFilterRepository; - this.messageBus = messageBus; + this.userFilterRepository = userFilterRepository; + this.messageBus = messageBus; } @Override diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/impl/GetUserFilterHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/filter/impl/GetUserFilterHandlerImpl.java index a1f80caafb..d106551e61 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/impl/GetUserFilterHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/impl/GetUserFilterHandlerImpl.java @@ -30,6 +30,7 @@ import com.epam.ta.reportportal.ws.model.OwnedEntityResource; import com.epam.ta.reportportal.ws.model.filter.UserFilterResource; import com.google.common.collect.Lists; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -45,18 +46,18 @@ @Transactional(readOnly = true) public class GetUserFilterHandlerImpl implements GetUserFilterHandler { - private UserFilterRepository filterRepository; - private final ProjectExtractor projectExtractor; + private UserFilterRepository filterRepository; + private final ProjectExtractor projectExtractor; - @Autowired - public GetUserFilterHandlerImpl(ProjectExtractor projectExtractor) { - this.projectExtractor = projectExtractor; - } + @Autowired + public GetUserFilterHandlerImpl(ProjectExtractor projectExtractor) { + this.projectExtractor = projectExtractor; + } - @Autowired - public void setFilterRepository(UserFilterRepository filterRepository) { - this.filterRepository = filterRepository; - } + @Autowired + public void setFilterRepository(UserFilterRepository filterRepository) { + this.filterRepository = filterRepository; + } @Override public UserFilterResource getUserFilter(Long id, ReportPortalUser.ProjectDetails projectDetails) { @@ -68,24 +69,28 @@ public UserFilterResource getUserFilter(Long id, ReportPortalUser.ProjectDetails return UserFilterConverter.TO_FILTER_RESOURCE.apply(userFilter); } - @Override - public Iterable<UserFilterResource> getUserFilters(String projectName, Pageable pageable, Filter filter, ReportPortalUser user) { - ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetails(user, projectName); - Page<UserFilter> userFilters = filterRepository.findByFilter(ProjectFilter.of(filter, projectDetails.getProjectId()), pageable); + @Override + public Iterable<UserFilterResource> getUserFilters(String projectName, Pageable pageable, Filter filter, + ReportPortalUser user) { + ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetails(user, + projectName); + Page<UserFilter> userFilters = filterRepository.findByFilter(ProjectFilter.of(filter, projectDetails.getProjectId()), pageable); return PagedResourcesAssembler.pageConverter(UserFilterConverter.TO_FILTER_RESOURCE).apply(userFilters); - } + } - @Override - public Iterable<OwnedEntityResource> getFiltersNames(ReportPortalUser.ProjectDetails projectDetails, Pageable pageable, Filter filter, + @Override + public Iterable<OwnedEntityResource> getFiltersNames(ReportPortalUser.ProjectDetails projectDetails, Pageable pageable, Filter filter, ReportPortalUser user) { - final Page<UserFilter> userFilters = filterRepository.findByFilter(ProjectFilter.of(filter, projectDetails.getProjectId()), - pageable - ); - return PagedResourcesAssembler.pageConverter(UserFilterConverter.TO_OWNED_ENTITY_RESOURCE).apply(userFilters); - } + final Page<UserFilter> userFilters = filterRepository.findByFilter( + ProjectFilter.of(filter, projectDetails.getProjectId()), + pageable + ); + return PagedResourcesAssembler.pageConverter(UserFilterConverter.TO_OWNED_ENTITY_RESOURCE) + .apply(userFilters); + } - @Override - public List<UserFilter> getFiltersById(Long[] ids, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + @Override + public List<UserFilter> getFiltersById(Long[] ids, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { return filterRepository.findAllByIdInAndProjectId(Lists.newArrayList(ids), projectDetails.getProjectId()); } } diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/impl/UpdateUserFilterHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/filter/impl/UpdateUserFilterHandlerImpl.java index 18600e4fbe..83911724ef 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/impl/UpdateUserFilterHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/impl/UpdateUserFilterHandlerImpl.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.filter.impl; +import static com.epam.ta.reportportal.commons.Preconditions.NOT_EMPTY_COLLECTION; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.converter.converters.UserFilterConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.USER_FILTER_NOT_FOUND; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.CriteriaHolder; @@ -32,7 +37,11 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.converter.builders.UserFilterBuilder; -import com.epam.ta.reportportal.ws.model.*; +import com.epam.ta.reportportal.ws.model.CollectionsRQ; +import com.epam.ta.reportportal.ws.model.EntryCreatedRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.ValidationConstraints; import com.epam.ta.reportportal.ws.model.activity.UserFilterActivityResource; import com.epam.ta.reportportal.ws.model.filter.BulkUpdateFilterRQ; import com.epam.ta.reportportal.ws.model.filter.UpdateUserFilterRQ; @@ -43,11 +52,9 @@ import java.util.List; import java.util.Optional; import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.Preconditions.NOT_EMPTY_COLLECTION; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.converter.converters.UserFilterConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.USER_FILTER_NOT_FOUND; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Service public class UpdateUserFilterHandlerImpl implements UpdateUserFilterHandler { @@ -68,11 +75,13 @@ public UpdateUserFilterHandlerImpl(ProjectExtractor projectExtractor, UserFilter this.messageBus = messageBus; } - @Override - public EntryCreatedRS createFilter(UpdateUserFilterRQ createFilterRQ, String projectName, ReportPortalUser user) { - ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetails(user, projectName); + @Override + public EntryCreatedRS createFilter(UpdateUserFilterRQ createFilterRQ, String projectName, + ReportPortalUser user) { + ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetails(user, + projectName); - validateFilterRq(createFilterRQ); + validateFilterRq(createFilterRQ); BusinessRule.expect(userFilterRepository.existsByNameAndOwnerAndProjectId(createFilterRQ.getName(), user.getUsername(), @@ -80,10 +89,10 @@ public EntryCreatedRS createFilter(UpdateUserFilterRQ createFilterRQ, String pro ), BooleanUtils::isFalse) .verify(ErrorType.USER_FILTER_ALREADY_EXISTS, createFilterRQ.getName(), user.getUsername(), projectName); - UserFilter filter = new UserFilterBuilder().addFilterRq(createFilterRQ) - .addProject(projectDetails.getProjectId()) - .addOwner(user.getUsername()) - .get(); + UserFilter filter = new UserFilterBuilder().addFilterRq(createFilterRQ) + .addProject(projectDetails.getProjectId()) + .addOwner(user.getUsername()) + .get(); userFilterRepository.save(filter); messageBus.publishActivity(new FilterCreatedEvent(TO_ACTIVITY_RESOURCE.apply(filter), user.getUserId(), user.getUsername())); @@ -105,7 +114,7 @@ public OperationCompletionRS updateUserFilter(Long userFilterId, UpdateUserFilte user.getUserId() ); - if (!userFilter.getName().equals(updateRQ.getName())) { + if (!userFilter.getName().equals(updateRQ.getName())) { BusinessRule.expect(userFilterRepository.existsByNameAndOwnerAndProjectId(updateRQ.getName(), userFilter.getOwner(), @@ -118,8 +127,8 @@ public OperationCompletionRS updateUserFilter(Long userFilterId, UpdateUserFilte ); } - UserFilterActivityResource before = TO_ACTIVITY_RESOURCE.apply(userFilter); - UserFilter updated = new UserFilterBuilder(userFilter).addFilterRq(updateRQ).get(); + UserFilterActivityResource before = TO_ACTIVITY_RESOURCE.apply(userFilter); + UserFilter updated = new UserFilterBuilder(userFilter).addFilterRq(updateRQ).get(); messageBus.publishActivity(new FilterUpdatedEvent(before, TO_ACTIVITY_RESOURCE.apply(updated), @@ -129,34 +138,36 @@ public OperationCompletionRS updateUserFilter(Long userFilterId, UpdateUserFilte return new OperationCompletionRS("User filter with ID = '" + updated.getId() + "' successfully updated."); } - @Override - public List<OperationCompletionRS> updateUserFilter(CollectionsRQ<BulkUpdateFilterRQ> updateRQ, - ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - throw new UnsupportedOperationException("Not implemented"); - } + @Override + public List<OperationCompletionRS> updateUserFilter(CollectionsRQ<BulkUpdateFilterRQ> updateRQ, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + throw new UnsupportedOperationException("Not implemented"); + } - /** + /** * Validation of update filter rq * * @param updateFilerRq Request */ private void validateFilterRq(UpdateUserFilterRQ updateFilerRq) { - FilterTarget filterTarget = FilterTarget.findByClass(ObjectType.getObjectTypeByName(updateFilerRq.getObjectType()) - .getClassObject()); + FilterTarget filterTarget = FilterTarget.findByClass( + ObjectType.getObjectTypeByName(updateFilerRq.getObjectType()) + .getClassObject()); - BusinessRule.expect(updateFilerRq.getConditions(), NOT_EMPTY_COLLECTION) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter conditions should not be empty"); + BusinessRule.expect(updateFilerRq.getConditions(), NOT_EMPTY_COLLECTION) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter conditions should not be empty"); - BusinessRule.expect(updateFilerRq.getOrders(), NOT_EMPTY_COLLECTION) - .verify(ErrorType.BAD_REQUEST_ERROR, "Sort conditions should not be empty"); + BusinessRule.expect(updateFilerRq.getOrders(), NOT_EMPTY_COLLECTION) + .verify(ErrorType.BAD_REQUEST_ERROR, "Sort conditions should not be empty"); - //filter conditions validation - updateFilerRq.getConditions().forEach(it -> { - CriteriaHolder criteriaHolder = filterTarget.getCriteriaByFilter(it.getFilteringField()) - .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, - Suppliers.formattedSupplier("Filter parameter '{}' is not defined", it.getFilteringField()).get() - )); + //filter conditions validation + updateFilerRq.getConditions().forEach(it -> { + CriteriaHolder criteriaHolder = filterTarget.getCriteriaByFilter(it.getFilteringField()) + .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, + Suppliers.formattedSupplier("Filter parameter '{}' is not defined", + it.getFilteringField()).get() + )); Condition condition = Condition.findByMarker(it.getCondition()) .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, it.getCondition())); @@ -168,13 +179,14 @@ private void validateFilterRq(UpdateUserFilterRQ updateFilerRq) { it.setValue(value); }); - //order conditions validation - updateFilerRq.getOrders() - .forEach(order -> BusinessRule.expect(filterTarget.getCriteriaByFilter(order.getSortingColumnName()), Optional::isPresent) - .verify(ErrorType.INCORRECT_SORTING_PARAMETERS, - "Unable to find sort parameter '" + order.getSortingColumnName() + "'" - )); - } + //order conditions validation + updateFilerRq.getOrders() + .forEach(order -> BusinessRule.expect( + filterTarget.getCriteriaByFilter(order.getSortingColumnName()), Optional::isPresent) + .verify(ErrorType.INCORRECT_SORTING_PARAMETERS, + "Unable to find sort parameter '" + order.getSortingColumnName() + "'" + )); + } private String cutAttributesToMaxLength(String keyAndValue) { if (keyAndValue == null || keyAndValue.isEmpty()) { @@ -215,6 +227,7 @@ private String cutAttributeToLength(String attribute, int length){ } return attribute; } + private String cutStringToLength(String string, int length) { if (string.length() > length) { string = string.substring(0, length); diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterBuilder.java b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterBuilder.java index fa03d81821..60404bfa17 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterBuilder.java @@ -25,19 +25,19 @@ */ public abstract class PredefinedFilterBuilder { - public Queryable buildFilter(String[] params) { - checkParams(params); - return build(params); - } + public Queryable buildFilter(String[] params) { + checkParams(params); + return build(params); + } - abstract protected Queryable build(String[] params); + abstract protected Queryable build(String[] params); - protected void checkParams(String[] params) { - //empty by default - } + protected void checkParams(String[] params) { + //empty by default + } - protected Exception incorrectParamsException(String message) { - throw new ReportPortalException(ErrorType.INCORRECT_REQUEST, message); - } + protected Exception incorrectParamsException(String message) { + throw new ReportPortalException(ErrorType.INCORRECT_REQUEST, message); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterType.java b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterType.java index 64a06823c4..4f8b8898bc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterType.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilterType.java @@ -24,22 +24,23 @@ */ public enum PredefinedFilterType { - COLLAPSED("collapsed"), - USERS("users"), - PROJECTS("projects"), - ACTIVITIES("activities"); + COLLAPSED("collapsed"), + USERS("users"), + PROJECTS("projects"), + ACTIVITIES("activities"); - private String type; + private String type; - PredefinedFilterType(String type) { - this.type = type; - } + PredefinedFilterType(String type) { + this.type = type; + } - public static Optional<PredefinedFilterType> fromString(String value) { - return Arrays.stream(PredefinedFilterType.values()).filter(it -> it.getType().equalsIgnoreCase(value)).findFirst(); - } + public static Optional<PredefinedFilterType> fromString(String value) { + return Arrays.stream(PredefinedFilterType.values()) + .filter(it -> it.getType().equalsIgnoreCase(value)).findFirst(); + } - public String getType() { - return type; - } + public String getType() { + return type; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilters.java b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilters.java index 6dde00bab2..9e5d2467c2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilters.java +++ b/src/main/java/com/epam/ta/reportportal/core/filter/predefined/PredefinedFilters.java @@ -61,11 +61,6 @@ private PredefinedFilters() { //no instance required } - /** - * Костыль requested by UI team. Back-end team doesn't really understand what such a strange query - * is supposed to be used for. - * TODO Incompatible with free structure tree and BDD-like structure - */ public static final Collection<TestItemTypeEnum> HAS_METHOD_OR_CLASS = Arrays.stream( TestItemTypeEnum.values()).filter(it -> { String name = it.name(); diff --git a/src/main/java/com/epam/ta/reportportal/core/hierarchy/AbstractFinishHierarchyHandler.java b/src/main/java/com/epam/ta/reportportal/core/hierarchy/AbstractFinishHierarchyHandler.java index 9f24cd56b3..716405f69f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/hierarchy/AbstractFinishHierarchyHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/hierarchy/AbstractFinishHierarchyHandler.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.core.hierarchy; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.item.impl.status.ToSkippedStatusChangingStrategy.SKIPPED_ISSUE_KEY; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.SKIPPED; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.SUITE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; import com.epam.ta.reportportal.core.item.impl.retry.RetryHandler; @@ -31,187 +43,194 @@ import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.job.PageUtil; import com.epam.ta.reportportal.jooq.enums.JStatusEnum; -import org.apache.commons.lang3.BooleanUtils; -import org.springframework.data.domain.Pageable; - import java.time.LocalDateTime; -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.item.impl.status.ToSkippedStatusChangingStrategy.SKIPPED_ISSUE_KEY; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.*; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; -import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.SUITE; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.data.domain.Pageable; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractFinishHierarchyHandler<T> implements FinishHierarchyHandler<T> { - public static final int ITEM_PAGE_SIZE = 50; - - public static final String ATTRIBUTE_KEY_STATUS = "status"; - public static final String ATTRIBUTE_VALUE_INTERRUPTED = "interrupted"; - - protected final LaunchRepository launchRepository; - protected final TestItemRepository testItemRepository; - protected final ItemAttributeRepository itemAttributeRepository; - protected final IssueEntityRepository issueEntityRepository; - private final RetryHandler retryHandler; - private final IssueTypeHandler issueTypeHandler; - private final ChangeStatusHandler changeStatusHandler; - - public AbstractFinishHierarchyHandler(LaunchRepository launchRepository, TestItemRepository testItemRepository, - ItemAttributeRepository itemAttributeRepository, IssueEntityRepository issueEntityRepository, RetryHandler retryHandler, - IssueTypeHandler issueTypeHandler, - ChangeStatusHandler changeStatusHandler) { - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.itemAttributeRepository = itemAttributeRepository; - this.issueEntityRepository = issueEntityRepository; - this.retryHandler = retryHandler; - this.issueTypeHandler = issueTypeHandler; - this.changeStatusHandler = changeStatusHandler; - } - - protected abstract boolean isIssueRequired(StatusEnum status, T entity); - - protected abstract Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, T entity, StatusEnum status); - - protected boolean evaluateSkippedAttributeValue(StatusEnum status, Long launchId) { - if (SKIPPED.equals(status)) { - return itemAttributeRepository.findByLaunchIdAndKeyAndSystem(launchId, SKIPPED_ISSUE_KEY, true) - .map(attribute -> BooleanUtils.toBoolean(attribute.getValue())) - .orElse(false); - } else { - return false; - } - } - - protected Optional<IssueType> getIssueType(boolean isIssueRequired, Long projectId, String locator) { - if (isIssueRequired) { - return Optional.of(issueTypeHandler.defineIssueType(projectId, locator)); - } - return Optional.empty(); - } - - @Override - public int finishDescendants(T parentEntity, StatusEnum status, Date endDate, ReportPortalUser user, - ReportPortalUser.ProjectDetails projectDetails) { - - expect(status, s -> s != IN_PROGRESS).verify(INCORRECT_REQUEST, "Unable to update current status to - " + IN_PROGRESS); - - LocalDateTime endTime = TO_LOCAL_DATE_TIME.apply(endDate); - - final int withoutChildren = updateDescendantsWithoutChildren(parentEntity, projectDetails.getProjectId(), status, endTime, user); - final int withChildren = updateDescendantsWithChildren(parentEntity, endTime); - return withoutChildren + withChildren; - } - - private int updateDescendantsWithoutChildren(T entity, Long projectId, StatusEnum status, LocalDateTime endTime, ReportPortalUser user) { - AtomicInteger updatedCount = new AtomicInteger(0); - getIssueType(isIssueRequired(status, entity), - projectId, - TO_INVESTIGATE.getLocator() - ).ifPresentOrElse(issueType -> PageUtil.iterateOverContent(ITEM_PAGE_SIZE, - getItemIdsFunction(false, entity, IN_PROGRESS), - itemIdsWithoutChildrenHandler(issueType, status, endTime, projectId, user, updatedCount) - ), - () -> PageUtil.iterateOverContent(ITEM_PAGE_SIZE, - getItemIdsFunction(false, entity, IN_PROGRESS), - itemIdsWithoutChildrenHandler(status, endTime, projectId, user, updatedCount) - ) - ); - return updatedCount.get(); - } - - private Consumer<List<Long>> itemIdsWithoutChildrenHandler(IssueType issueType, StatusEnum status, LocalDateTime endTime, - Long projectId, ReportPortalUser user, AtomicInteger updatedCount) { - return itemIds -> { - Map<Long, TestItem> itemMapping = getItemMapping(itemIds); - itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { - finishItem(testItem, status, endTime); - attachIssue(testItem, issueType); - changeStatusHandler.changeParentStatus(testItem, projectId, user); - })); - updatedCount.addAndGet(itemIds.size()); - }; - } - - private Consumer<List<Long>> itemIdsWithoutChildrenHandler(StatusEnum status, LocalDateTime endTime, Long projectId, - ReportPortalUser user, AtomicInteger updatedCount) { - return itemIds -> { - Map<Long, TestItem> itemMapping = getItemMapping(itemIds); - itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { - finishItem(testItem, status, endTime); - changeStatusHandler.changeParentStatus(testItem, projectId, user); - })); - updatedCount.addAndGet(itemIds.size()); - }; - } - - /** - * Attach default issue to the item only if it wasn't already created - * - * @param testItem {@link TestItem} - * @param issueType {@link IssueType} - */ - private void attachIssue(TestItem testItem, IssueType issueType) { - if (!SUITE.sameLevel(testItem.getType()) && testItem.isHasStats()) { - issueEntityRepository.findById(testItem.getItemId()).ifPresentOrElse(issue -> { - }, () -> { - IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueType(issueType); - issueEntity.setTestItemResults(testItem.getItemResults()); - issueEntityRepository.save(issueEntity); - testItem.getItemResults().setIssue(issueEntity); - }); - } - } - - private int updateDescendantsWithChildren(T entity, LocalDateTime endTime) { - AtomicInteger updatedCount = new AtomicInteger(0); - PageUtil.iterateOverContent(ITEM_PAGE_SIZE, - getItemIdsFunction(true, entity, IN_PROGRESS), - itemIdsWithChildrenHandler(endTime, updatedCount) - ); - return updatedCount.get(); - } - - private Consumer<List<Long>> itemIdsWithChildrenHandler(LocalDateTime endTime, AtomicInteger updatedCount) { - return itemIds -> { - Map<Long, TestItem> itemMapping = getItemMapping(itemIds); - itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { - boolean isFailed = testItemRepository.hasDescendantsNotInStatus(testItem.getItemId(), - StatusEnum.PASSED.name(), - StatusEnum.INFO.name(), - StatusEnum.WARN.name() - ); - finishItem(testItem, isFailed ? FAILED : PASSED, endTime); - })); - updatedCount.addAndGet(itemIds.size()); - }; - } - - private Map<Long, TestItem> getItemMapping(List<Long> itemIds) { - return testItemRepository.findAllById(itemIds).stream().collect(Collectors.toMap(TestItem::getItemId, i -> i)); - } - - private void finishItem(TestItem testItem, StatusEnum status, LocalDateTime endTime) { - testItem.getItemResults().setStatus(status); - testItem.getItemResults().setEndTime(endTime); - ItemAttribute interruptedAttribute = new ItemAttribute(ATTRIBUTE_KEY_STATUS, ATTRIBUTE_VALUE_INTERRUPTED, false); - interruptedAttribute.setTestItem(testItem); - testItem.getAttributes().add(interruptedAttribute); - if (testItem.isHasRetries()) { - retryHandler.finishRetries(testItem.getItemId(), JStatusEnum.valueOf(status.name()), endTime); - } - } + public static final int ITEM_PAGE_SIZE = 50; + + public static final String ATTRIBUTE_KEY_STATUS = "status"; + public static final String ATTRIBUTE_VALUE_INTERRUPTED = "interrupted"; + + protected final LaunchRepository launchRepository; + protected final TestItemRepository testItemRepository; + protected final ItemAttributeRepository itemAttributeRepository; + protected final IssueEntityRepository issueEntityRepository; + private final RetryHandler retryHandler; + private final IssueTypeHandler issueTypeHandler; + private final ChangeStatusHandler changeStatusHandler; + + public AbstractFinishHierarchyHandler(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + ItemAttributeRepository itemAttributeRepository, IssueEntityRepository issueEntityRepository, + RetryHandler retryHandler, + IssueTypeHandler issueTypeHandler, + ChangeStatusHandler changeStatusHandler) { + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.itemAttributeRepository = itemAttributeRepository; + this.issueEntityRepository = issueEntityRepository; + this.retryHandler = retryHandler; + this.issueTypeHandler = issueTypeHandler; + this.changeStatusHandler = changeStatusHandler; + } + + protected abstract boolean isIssueRequired(StatusEnum status, T entity); + + protected abstract Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, + T entity, StatusEnum status); + + protected boolean evaluateSkippedAttributeValue(StatusEnum status, Long launchId) { + if (SKIPPED.equals(status)) { + return itemAttributeRepository.findByLaunchIdAndKeyAndSystem(launchId, SKIPPED_ISSUE_KEY, + true) + .map(attribute -> BooleanUtils.toBoolean(attribute.getValue())) + .orElse(false); + } else { + return false; + } + } + + protected Optional<IssueType> getIssueType(boolean isIssueRequired, Long projectId, + String locator) { + if (isIssueRequired) { + return Optional.of(issueTypeHandler.defineIssueType(projectId, locator)); + } + return Optional.empty(); + } + + @Override + public int finishDescendants(T parentEntity, StatusEnum status, Date endDate, + ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + + expect(status, s -> s != IN_PROGRESS).verify(INCORRECT_REQUEST, + "Unable to update current status to - " + IN_PROGRESS); + + LocalDateTime endTime = TO_LOCAL_DATE_TIME.apply(endDate); + + final int withoutChildren = updateDescendantsWithoutChildren(parentEntity, + projectDetails.getProjectId(), status, endTime, user); + final int withChildren = updateDescendantsWithChildren(parentEntity, endTime); + return withoutChildren + withChildren; + } + + private int updateDescendantsWithoutChildren(T entity, Long projectId, StatusEnum status, + LocalDateTime endTime, ReportPortalUser user) { + AtomicInteger updatedCount = new AtomicInteger(0); + getIssueType(isIssueRequired(status, entity), + projectId, + TO_INVESTIGATE.getLocator() + ).ifPresentOrElse(issueType -> PageUtil.iterateOverContent(ITEM_PAGE_SIZE, + getItemIdsFunction(false, entity, IN_PROGRESS), + itemIdsWithoutChildrenHandler(issueType, status, endTime, projectId, user, updatedCount) + ), + () -> PageUtil.iterateOverContent(ITEM_PAGE_SIZE, + getItemIdsFunction(false, entity, IN_PROGRESS), + itemIdsWithoutChildrenHandler(status, endTime, projectId, user, updatedCount) + ) + ); + return updatedCount.get(); + } + + private Consumer<List<Long>> itemIdsWithoutChildrenHandler(IssueType issueType, StatusEnum status, + LocalDateTime endTime, + Long projectId, ReportPortalUser user, AtomicInteger updatedCount) { + return itemIds -> { + Map<Long, TestItem> itemMapping = getItemMapping(itemIds); + itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { + finishItem(testItem, status, endTime); + attachIssue(testItem, issueType); + changeStatusHandler.changeParentStatus(testItem, projectId, user); + })); + updatedCount.addAndGet(itemIds.size()); + }; + } + + private Consumer<List<Long>> itemIdsWithoutChildrenHandler(StatusEnum status, + LocalDateTime endTime, Long projectId, + ReportPortalUser user, AtomicInteger updatedCount) { + return itemIds -> { + Map<Long, TestItem> itemMapping = getItemMapping(itemIds); + itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { + finishItem(testItem, status, endTime); + changeStatusHandler.changeParentStatus(testItem, projectId, user); + })); + updatedCount.addAndGet(itemIds.size()); + }; + } + + /** + * Attach default issue to the item only if it wasn't already created + * + * @param testItem {@link TestItem} + * @param issueType {@link IssueType} + */ + private void attachIssue(TestItem testItem, IssueType issueType) { + if (!SUITE.sameLevel(testItem.getType()) && testItem.isHasStats()) { + issueEntityRepository.findById(testItem.getItemId()).ifPresentOrElse(issue -> { + }, () -> { + IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueType(issueType); + issueEntity.setTestItemResults(testItem.getItemResults()); + issueEntityRepository.save(issueEntity); + testItem.getItemResults().setIssue(issueEntity); + }); + } + } + + private int updateDescendantsWithChildren(T entity, LocalDateTime endTime) { + AtomicInteger updatedCount = new AtomicInteger(0); + PageUtil.iterateOverContent(ITEM_PAGE_SIZE, + getItemIdsFunction(true, entity, IN_PROGRESS), + itemIdsWithChildrenHandler(endTime, updatedCount) + ); + return updatedCount.get(); + } + + private Consumer<List<Long>> itemIdsWithChildrenHandler(LocalDateTime endTime, + AtomicInteger updatedCount) { + return itemIds -> { + Map<Long, TestItem> itemMapping = getItemMapping(itemIds); + itemIds.forEach(itemId -> ofNullable(itemMapping.get(itemId)).ifPresent(testItem -> { + boolean isFailed = testItemRepository.hasDescendantsNotInStatus(testItem.getItemId(), + StatusEnum.PASSED.name(), + StatusEnum.INFO.name(), + StatusEnum.WARN.name() + ); + finishItem(testItem, isFailed ? FAILED : PASSED, endTime); + })); + updatedCount.addAndGet(itemIds.size()); + }; + } + + private Map<Long, TestItem> getItemMapping(List<Long> itemIds) { + return testItemRepository.findAllById(itemIds).stream() + .collect(Collectors.toMap(TestItem::getItemId, i -> i)); + } + + private void finishItem(TestItem testItem, StatusEnum status, LocalDateTime endTime) { + testItem.getItemResults().setStatus(status); + testItem.getItemResults().setEndTime(endTime); + ItemAttribute interruptedAttribute = new ItemAttribute(ATTRIBUTE_KEY_STATUS, + ATTRIBUTE_VALUE_INTERRUPTED, false); + interruptedAttribute.setTestItem(testItem); + testItem.getAttributes().add(interruptedAttribute); + if (testItem.isHasRetries()) { + retryHandler.finishRetries(testItem.getItemId(), JStatusEnum.valueOf(status.name()), endTime); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/hierarchy/FinishHierarchyHandler.java b/src/main/java/com/epam/ta/reportportal/core/hierarchy/FinishHierarchyHandler.java index 2ebd4d159a..d6daf274bf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/hierarchy/FinishHierarchyHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/hierarchy/FinishHierarchyHandler.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.enums.StatusEnum; - import java.util.Date; /** @@ -26,14 +25,14 @@ */ public interface FinishHierarchyHandler<T> { - /** - * @param parentEntity Parent entity which descendants should be finished - * @param status {@link StatusEnum} that should be assigned to descendants - * @param endDate {@link java.time.LocalDateTime} finish date for descendants - * @param user {@link ReportPortalUser} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @return finished descendants count - */ - int finishDescendants(T parentEntity, StatusEnum status, Date endDate, ReportPortalUser user, - ReportPortalUser.ProjectDetails projectDetails); + /** + * @param parentEntity Parent entity which descendants should be finished + * @param status {@link StatusEnum} that should be assigned to descendants + * @param endDate {@link java.time.LocalDateTime} finish date for descendants + * @param user {@link ReportPortalUser} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @return finished descendants count + */ + int finishDescendants(T parentEntity, StatusEnum status, Date endDate, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails); } diff --git a/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandler.java b/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandler.java index 64c1fa71d0..0a99f4731a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandler.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.hierarchy.impl; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; + import com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; import com.epam.ta.reportportal.core.item.impl.retry.RetryHandler; @@ -26,53 +28,54 @@ import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.launch.Launch; +import java.util.List; +import java.util.function.Function; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.function.Function; - -import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service("finishLaunchHierarchyHandler") public class FinishLaunchHierarchyHandler extends AbstractFinishHierarchyHandler<Launch> { - @Autowired - public FinishLaunchHierarchyHandler(LaunchRepository launchRepository, TestItemRepository testItemRepository, - ItemAttributeRepository itemAttributeRepository, RetryHandler retryHandler, IssueTypeHandler issueTypeHandler, - IssueEntityRepository issueEntityRepository, ChangeStatusHandler changeStatusHandler) { - super(launchRepository, - testItemRepository, - itemAttributeRepository, - issueEntityRepository, - retryHandler, - issueTypeHandler, - changeStatusHandler - ); - } + @Autowired + public FinishLaunchHierarchyHandler(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + ItemAttributeRepository itemAttributeRepository, RetryHandler retryHandler, + IssueTypeHandler issueTypeHandler, + IssueEntityRepository issueEntityRepository, ChangeStatusHandler changeStatusHandler) { + super(launchRepository, + testItemRepository, + itemAttributeRepository, + issueEntityRepository, + retryHandler, + issueTypeHandler, + changeStatusHandler + ); + } - @Override - protected boolean isIssueRequired(StatusEnum status, Launch launch) { - return FAILED.equals(status) || evaluateSkippedAttributeValue(status, launch.getId()); - } + @Override + protected boolean isIssueRequired(StatusEnum status, Launch launch) { + return FAILED.equals(status) || evaluateSkippedAttributeValue(status, launch.getId()); + } - @Override - protected Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, Launch launch, StatusEnum status) { - return hasChildren ? - pageable -> testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel(launch.getId(), - status, - pageable.getPageSize(), - pageable.getOffset() - ) : - pageable -> testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(launch.getId(), - status, - pageable.getPageSize(), - pageable.getOffset() - ); - } + @Override + protected Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, Launch launch, + StatusEnum status) { + return hasChildren ? + pageable -> testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel( + launch.getId(), + status, + pageable.getPageSize(), + pageable.getOffset() + ) : + pageable -> testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(launch.getId(), + status, + pageable.getPageSize(), + pageable.getOffset() + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishTestItemHierarchyHandler.java b/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishTestItemHierarchyHandler.java index d244dbb3bf..2f83ccea88 100644 --- a/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishTestItemHierarchyHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishTestItemHierarchyHandler.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.hierarchy.impl; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; import com.epam.ta.reportportal.core.item.impl.retry.RetryHandler; @@ -26,14 +29,10 @@ import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.item.TestItem; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.function.Function; - -import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; -import static java.util.Optional.ofNullable; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -41,38 +40,44 @@ @Service("finishTestItemHierarchyHandler") public class FinishTestItemHierarchyHandler extends AbstractFinishHierarchyHandler<TestItem> { - public FinishTestItemHierarchyHandler(LaunchRepository launchRepository, TestItemRepository testItemRepository, - ItemAttributeRepository itemAttributeRepository, IssueEntityRepository issueEntityRepository, RetryHandler retryHandler, - IssueTypeHandler issueTypeHandler, ChangeStatusHandler changeStatusHandler) { - super(launchRepository, - testItemRepository, - itemAttributeRepository, - issueEntityRepository, - retryHandler, - issueTypeHandler, - changeStatusHandler - ); - } + public FinishTestItemHierarchyHandler(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + ItemAttributeRepository itemAttributeRepository, IssueEntityRepository issueEntityRepository, + RetryHandler retryHandler, + IssueTypeHandler issueTypeHandler, ChangeStatusHandler changeStatusHandler) { + super(launchRepository, + testItemRepository, + itemAttributeRepository, + issueEntityRepository, + retryHandler, + issueTypeHandler, + changeStatusHandler + ); + } - @Override - protected boolean isIssueRequired(StatusEnum status, TestItem testItem) { - return FAILED.equals(status) || ofNullable(testItem.getLaunchId()).map(launchId -> evaluateSkippedAttributeValue(status, launchId)) - .orElse(false); - } + @Override + protected boolean isIssueRequired(StatusEnum status, TestItem testItem) { + return FAILED.equals(status) || ofNullable(testItem.getLaunchId()).map( + launchId -> evaluateSkippedAttributeValue(status, launchId)) + .orElse(false); + } - @Override - protected Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, TestItem testItem, StatusEnum status) { - return hasChildren ? - pageable -> testItemRepository.findIdsByHasChildrenAndParentPathAndStatusOrderedByPathLevel(testItem.getPath(), - StatusEnum.IN_PROGRESS, - pageable.getPageSize(), - pageable.getOffset() - ) : - pageable -> testItemRepository.findIdsByNotHasChildrenAndParentPathAndStatus(testItem.getPath(), - status, - pageable.getPageSize(), - pageable.getOffset() - ); - } + @Override + protected Function<Pageable, List<Long>> getItemIdsFunction(boolean hasChildren, + TestItem testItem, StatusEnum status) { + return hasChildren ? + pageable -> testItemRepository.findIdsByHasChildrenAndParentPathAndStatusOrderedByPathLevel( + testItem.getPath(), + StatusEnum.IN_PROGRESS, + pageable.getPageSize(), + pageable.getOffset() + ) : + pageable -> testItemRepository.findIdsByNotHasChildrenAndParentPathAndStatus( + testItem.getPath(), + status, + pageable.getPageSize(), + pageable.getOffset() + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/FileExtensionConstant.java b/src/main/java/com/epam/ta/reportportal/core/imprt/FileExtensionConstant.java index 91bef321a6..0f8bd22f78 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/FileExtensionConstant.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/FileExtensionConstant.java @@ -20,7 +20,7 @@ */ public class FileExtensionConstant { - //TODO return '.zip' and '.xml' - public static final String ZIP_EXTENSION = "zip"; - public static final String XML_EXTENSION = "xml"; + //TODO return '.zip' and '.xml' + public static final String ZIP_EXTENSION = "zip"; + public static final String XML_EXTENSION = "xml"; } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandler.java index 21b969be47..9ff51786e5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandler.java @@ -17,7 +17,7 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import java.util.Map; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import org.springframework.web.multipart.MultipartFile; /** @@ -32,9 +32,11 @@ public interface ImportLaunchHandler { * @param user user * @param format report format * @param file file with report + * @param baseUrl Application base url + * @param rq Launch import request * @return OperationCompletionRS */ OperationCompletionRS importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, String format, MultipartFile file, String baseUrl, - Map<String, String> params); + LaunchImportRQ rq); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImpl.java index 5c9cfdb579..e92d83e3fd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImpl.java @@ -13,82 +13,121 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.epam.ta.reportportal.core.imprt; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static org.apache.commons.io.FileUtils.ONE_MB; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.events.activity.ImportFinishedEvent; import com.epam.ta.reportportal.core.imprt.impl.ImportStrategy; import com.epam.ta.reportportal.core.imprt.impl.ImportStrategyFactory; import com.epam.ta.reportportal.core.imprt.impl.ImportType; +import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.LaunchImportCompletionRS; +import com.epam.ta.reportportal.ws.model.LaunchImportData; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import java.util.Map; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; +import java.io.File; +import java.io.IOException; +import java.util.Optional; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.IOException; - -import static com.epam.ta.reportportal.commons.Predicates.notNull; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; - @Service public class ImportLaunchHandlerImpl implements ImportLaunchHandler { - private static final int MAX_FILE_SIZE = 32 * 1024 * 1024; - private ImportStrategyFactory importStrategyFactory; - private MessageBus messageBus; + private static final long MAX_FILE_SIZE = 32 * ONE_MB; + + private final ImportStrategyFactory importStrategyFactory; + private final MessageBus messageBus; + private final LaunchRepository launchRepository; + - @Autowired - public ImportLaunchHandlerImpl(ImportStrategyFactory importStrategyFactory, MessageBus messageBus) { - this.importStrategyFactory = importStrategyFactory; - this.messageBus = messageBus; - } + @Autowired + public ImportLaunchHandlerImpl(ImportStrategyFactory importStrategyFactory, MessageBus messageBus, + LaunchRepository launchRepository) { + this.importStrategyFactory = importStrategyFactory; + this.messageBus = messageBus; + this.launchRepository = launchRepository; + } - @Override + @Override public OperationCompletionRS importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, String format, - MultipartFile file, String baseUrl, Map<String, String> params) { - - validate(file); - - ImportType type = ImportType.fromValue(format) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Unknown import type - " + format)); - - File tempFile = transferToTempFile(file); - ImportStrategy strategy = importStrategyFactory.getImportStrategy(type, file.getOriginalFilename()); - String launchId = strategy.importLaunch(projectDetails, user, tempFile, baseUrl, params); - messageBus.publishActivity(new ImportFinishedEvent(user.getUserId(), - user.getUsername(), - projectDetails.getProjectId(), - file.getOriginalFilename() - )); - return new OperationCompletionRS("Launch with id = " + launchId + " is successfully imported."); - } - - private void validate(MultipartFile file) { - expect(file.getOriginalFilename(), notNull()).verify(ErrorType.INCORRECT_REQUEST, "File name should be not empty."); - - expect(file.getOriginalFilename(), it -> it.endsWith(ZIP_EXTENSION) || it.endsWith(XML_EXTENSION)).verify(INCORRECT_REQUEST, - "Should be a zip archive or an xml file " + file.getOriginalFilename() - ); - expect(file.getSize(), size -> size <= MAX_FILE_SIZE).verify(INCORRECT_REQUEST, "File size is more than 32 Mb."); - } - - private File transferToTempFile(MultipartFile file) { - try { - File tmp = File.createTempFile(file.getOriginalFilename(), "." + FilenameUtils.getExtension(file.getOriginalFilename())); - file.transferTo(tmp); - return tmp; - } catch (IOException e) { - throw new ReportPortalException("Error during transferring multipart file.", e); - } - } + MultipartFile file, String baseUrl, LaunchImportRQ rq) { + + validate(file); + rq = getBackCompatibleRq(rq); + + ImportType type = ImportType.fromValue(format) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Unknown import type - " + format)); + + File tempFile = transferToTempFile(file); + ImportStrategy strategy = importStrategyFactory.getImportStrategy(type, + file.getOriginalFilename()); + String launchId = strategy.importLaunch(projectDetails, user, tempFile, baseUrl, rq); + messageBus.publishActivity(new ImportFinishedEvent(user.getUserId(), + user.getUsername(), + projectDetails.getProjectId(), + file.getOriginalFilename() + )); + return prepareLaunchImportResponse(launchId); + } + + //back compatibility with ui + private LaunchImportRQ getBackCompatibleRq(LaunchImportRQ rq) { + return Optional.ofNullable(rq).orElse(new LaunchImportRQ()); + } + + private void validate(MultipartFile file) { + expect(file.getOriginalFilename(), notNull()).verify(ErrorType.INCORRECT_REQUEST, + "File name should be not empty."); + + expect(file.getOriginalFilename(), + it -> it.endsWith(ZIP_EXTENSION) || it.endsWith(XML_EXTENSION)).verify(INCORRECT_REQUEST, + "Should be a zip archive or an xml file " + file.getOriginalFilename() + ); + expect(file.getSize(), size -> size <= MAX_FILE_SIZE).verify(INCORRECT_REQUEST, + "File size is more than 32 Mb."); + } + + private File transferToTempFile(MultipartFile file) { + try { + File tmp = File.createTempFile(file.getOriginalFilename(), + "." + FilenameUtils.getExtension(file.getOriginalFilename())); + file.transferTo(tmp); + return tmp; + } catch (IOException e) { + throw new ReportPortalException("Error during transferring multipart file.", e); + } + } + + private OperationCompletionRS prepareLaunchImportResponse(String launchId) { + + var launch = launchRepository.findByUuid(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND)); + + var data = new LaunchImportData(); + data.setId(launchId); + data.setName(launch.getName()); + data.setNumber(launch.getNumber()); + + var response = new LaunchImportCompletionRS(); + response.setResultMessage("Launch with id = " + launchId + " is successfully imported."); + response.setData(data); + + return response; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/AbstractImportStrategy.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/AbstractImportStrategy.java index 2f1ebba0aa..9cc95fde08 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/AbstractImportStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/AbstractImportStrategy.java @@ -15,7 +15,7 @@ */ package com.epam.ta.reportportal.core.imprt.impl; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static java.util.Optional.ofNullable; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.launch.FinishLaunchHandler; @@ -27,23 +27,22 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - +import com.google.common.collect.Sets; import java.time.LocalDateTime; import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -51,30 +50,10 @@ @Component public abstract class AbstractImportStrategy implements ImportStrategy { - public static final String LAUNCH_NAME = "launchName"; - public static final String LAUNCH_DESCRIPTION = "description"; - public static final String ATTRIBUTE_KEY = "attributeKey"; - public static final String ATTRIBUTE_VALUE = "attributeValue"; public static final String SKIPPED_IS_NOT_ISSUE = "skippedIsNotIssue"; - public static final String SKIPPED_ISSUE = "skippedIssue"; protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractImportStrategy.class); private static final Date initialStartTime = new Date(0); protected static final ExecutorService service = Executors.newFixedThreadPool(5); - public static final String LAUNCH_NAME_RESTRICTION_MSG = - "User can't import launch with the invalid number of symbols for Name."; - public static final String LAUNCH_DESCRIPTION_RESTRICTION_MSG = - "User can't import launch with the invalid number of symbols for Description."; - public static final String ATTRIBUTE_KEY_RESTRICTION_MSG = - "User can't import launch with the invalid number of symbols for Attribute Key."; - public static final String ATTRIBUTE_KEY_WITHOUT_VALUE_MSG = - "User can't import launch with only Attribute Key without Attribute Value."; - public static final String ATTRIBUTE_VALUE_RESTRICTION_MSG = - "User can't import launch with the invalid number of symbols for Attribute Value."; - public static final String INCORRECT_NOT_ISSUE_PARAMETER_MSG = - "User can't import launch with invalid value for parameter skippedIsNotIssue."; - public static final int MAX_ATTRIBUTE_LENGTH = 512; - public static final int MAX_DESCRIPTION_LENGTH = 2048; - public static final int MAX_NAME_LENGTH = 256; private StartLaunchHandler startLaunchHandler; @@ -107,30 +86,17 @@ protected ParseResults processResults(CompletableFuture... futures) { } protected String startLaunch(ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String launchName, Map<String, String> params) { + ReportPortalUser user, String launchName, LaunchImportRQ rq) { StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setStartTime(initialStartTime); - startLaunchRQ.setName(params.get(LAUNCH_NAME) != null ? params.get(LAUNCH_NAME) : launchName); - startLaunchRQ.setDescription(params.get(LAUNCH_DESCRIPTION)); - startLaunchRQ.setMode(Mode.DEFAULT); - Set<ItemAttributesRQ> itemAttributes = getItemAttributes(params); - startLaunchRQ.setAttributes(itemAttributes); + startLaunchRQ.setStartTime(ofNullable(rq.getStartTime()).orElse(initialStartTime)); + startLaunchRQ.setName(ofNullable(rq.getName()).orElse(launchName)); + ofNullable(rq.getDescription()) + .ifPresent(startLaunchRQ::setDescription); + startLaunchRQ.setMode(ofNullable(rq.getMode()).orElse(Mode.DEFAULT)); + startLaunchRQ.setAttributes(ofNullable(rq.getAttributes()).orElse(Sets.newHashSet())); return startLaunchHandler.startLaunch(user, projectDetails, startLaunchRQ).getId(); } - private Set<ItemAttributesRQ> getItemAttributes(Map<String, String> params) { - Set<ItemAttributesRQ> itemAttributes = new HashSet<>(); - if (params.get(ATTRIBUTE_VALUE) != null) { - itemAttributes.add( - new ItemAttributesRQ(params.get(ATTRIBUTE_KEY), params.get(ATTRIBUTE_VALUE))); - } - if (params.get(SKIPPED_IS_NOT_ISSUE) != null && Boolean.parseBoolean(params.get( - SKIPPED_IS_NOT_ISSUE))) { - itemAttributes.add(new ItemAttributesRQ(SKIPPED_ISSUE, "true", true)); - } - return itemAttributes; - } - protected void finishLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, ParseResults results, String baseUrl) { @@ -143,6 +109,14 @@ protected void finishLaunch(String launchId, ReportPortalUser.ProjectDetails pro launchRepository.save(launch); } + protected Boolean isSkippedNotIssue(Set<ItemAttributesRQ> attributes) { + return ofNullable(attributes).orElse(Collections.emptySet()).stream() + .filter( + attribute -> SKIPPED_IS_NOT_ISSUE.equals(attribute.getKey()) && attribute.isSystem()) + .findAny() + .filter(itemAttributesRQ -> Boolean.parseBoolean(itemAttributesRQ.getValue())).isPresent(); + } + /** * Got a cause exception message if it has any. * @@ -170,52 +144,4 @@ protected void updateBrokenLaunch(String savedLaunchId) { launchRepository.save(launch); } } - - protected void validateOverrideParameters(Map<String, String> params) { - validateLaunchName(params); - validateLaunchDescription(params); - validateAttributeKey(params); - validateAttributeKeyWithValue(params); - validateAttributeValue(params); - validateSkippedParameter(params); - } - - private void validateLaunchName(Map<String, String> params) { - String launchName = params.get(LAUNCH_NAME); - boolean isValid = launchName == null || (1 < launchName.length() && launchName.length() <= MAX_NAME_LENGTH); - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, LAUNCH_NAME_RESTRICTION_MSG); - } - - private void validateLaunchDescription(Map<String, String> params) { - String launchDescription = params.get(LAUNCH_DESCRIPTION); - boolean isValid = launchDescription == null || (launchDescription.length() <= MAX_DESCRIPTION_LENGTH); - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, LAUNCH_DESCRIPTION_RESTRICTION_MSG); - } - - private void validateAttributeKey(Map<String, String> params) { - String attributeKey = params.get(ATTRIBUTE_KEY); - boolean isValid = attributeKey == null || (attributeKey.length() <= MAX_ATTRIBUTE_LENGTH); - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTE_KEY_RESTRICTION_MSG); - } - - private void validateAttributeKeyWithValue(Map<String, String> params) { - String attributeKey = params.get(ATTRIBUTE_KEY); - String attributeValue = params.get(ATTRIBUTE_VALUE); - boolean isValid = attributeKey == null || attributeValue != null; - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTE_KEY_WITHOUT_VALUE_MSG); - } - - private void validateAttributeValue(Map<String, String> params) { - String attributeValue = params.get(ATTRIBUTE_VALUE); - boolean isValid = attributeValue == null || (attributeValue.length() <= MAX_ATTRIBUTE_LENGTH); - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTE_VALUE_RESTRICTION_MSG); - } - - private void validateSkippedParameter(Map<String, String> params) { - String notIssue = params.get(SKIPPED_IS_NOT_ISSUE); - boolean isValid = - notIssue == null || "true".equalsIgnoreCase(notIssue) || "false".equalsIgnoreCase(notIssue); - expect(isValid, Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, - INCORRECT_NOT_ISSUE_PARAMETER_MSG); - } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/DateUtils.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/DateUtils.java index 7d3f1f37bf..138e2d42b3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/DateUtils.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/DateUtils.java @@ -20,22 +20,22 @@ */ public final class DateUtils { - private DateUtils() { - //static only - } + private DateUtils() { + //static only + } - /** - * Converts string representation of seconds to millis - * - * @param duration String seconds - * @return long millis - */ - public static long toMillis(String duration) { - if (null != duration) { - Double value = Double.valueOf(duration) * 1000; - return value.longValue(); - } - return 0; - } + /** + * Converts string representation of seconds to millis + * + * @param duration String seconds + * @return long millis + */ + public static long toMillis(String duration) { + if (null != duration) { + Double value = Double.valueOf(duration) * 1000; + return value.longValue(); + } + return 0; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategy.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategy.java index 7038eef804..20c7e1911c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategy.java @@ -16,9 +16,8 @@ package com.epam.ta.reportportal.core.imprt.impl; import com.epam.ta.reportportal.commons.ReportPortalUser; - +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import java.io.File; -import java.util.Map; /** * Handler for processing launch importing. @@ -26,14 +25,17 @@ * @author Pavel_Bortnik */ public interface ImportStrategy { - /** - * Processing launch importing. - * - * @param projectDetails project - * @param user user - * @param file zip file that contains xml test reports - * @return launch uuid - */ - String importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - File file, String baseUrl, Map<String, String> params); + + /** + * Processing launch importing. + * + * @param projectDetails project + * @param user user + * @param file zip file that contains xml test reports + * @param baseUrl application base url + * @param rq {@link LaunchImportRQ} launch import request + * @return launch uuid + */ + String importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + File file, String baseUrl, LaunchImportRQ rq); } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactory.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactory.java index 5159f50ab2..d2c4f488c4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactory.java @@ -16,19 +16,19 @@ package com.epam.ta.reportportal.core.imprt.impl; /** - * Factory for launch import handlers. - * Could be implemented other imports in future versions. + * Factory for launch import handlers. Could be implemented other imports in future versions. * * @author Pavel_Bortnik */ public interface ImportStrategyFactory { - /** - * Return import handler for specified type of import. - * - * @param type import type - * @param fileName file name with extension - * @return handler - */ - ImportStrategy getImportStrategy(ImportType type, String fileName); + + /** + * Return import handler for specified type of import. + * + * @param type import type + * @param fileName file name with extension + * @return handler + */ + ImportStrategy getImportStrategy(ImportType type, String fileName); } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactoryImpl.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactoryImpl.java index b2a3cc921e..1bdb0d4529 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactoryImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportStrategyFactoryImpl.java @@ -15,33 +15,35 @@ */ package com.epam.ta.reportportal.core.imprt.impl; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; + import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; - @Service @Configuration public class ImportStrategyFactoryImpl implements ImportStrategyFactory { - private final Map<ImportType, Map<String, ImportStrategy>> MAPPING; + private final Map<ImportType, Map<String, ImportStrategy>> MAPPING; - @Autowired - public ImportStrategyFactoryImpl(ImportStrategy zipImportStrategy, ImportStrategy xmlImportStrategy) { - Map<String, ImportStrategy> xunitStrategyMap = ImmutableMap.<String, ImportStrategy>builder().put(ZIP_EXTENSION, zipImportStrategy) - .put(XML_EXTENSION, xmlImportStrategy) - .build(); - MAPPING = ImmutableMap.<ImportType, Map<String, ImportStrategy>>builder().put(ImportType.XUNIT, xunitStrategyMap).build(); - } + @Autowired + public ImportStrategyFactoryImpl(ImportStrategy zipImportStrategy, + ImportStrategy xmlImportStrategy) { + Map<String, ImportStrategy> xunitStrategyMap = ImmutableMap.<String, ImportStrategy>builder() + .put(ZIP_EXTENSION, zipImportStrategy) + .put(XML_EXTENSION, xmlImportStrategy) + .build(); + MAPPING = ImmutableMap.<ImportType, Map<String, ImportStrategy>>builder() + .put(ImportType.XUNIT, xunitStrategyMap).build(); + } - @Override - public ImportStrategy getImportStrategy(ImportType type, String filename) { - return MAPPING.get(type).get(FilenameUtils.getExtension(filename)); - } + @Override + public ImportStrategy getImportStrategy(ImportType type, String filename) { + return MAPPING.get(type).get(FilenameUtils.getExtension(filename)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportType.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportType.java index 654abe263a..5714e1edc6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportType.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ImportType.java @@ -19,9 +19,10 @@ import java.util.Optional; public enum ImportType { - XUNIT; + XUNIT; - public static Optional<ImportType> fromValue(String value) { - return Arrays.stream(ImportType.values()).filter(type -> type.name().equalsIgnoreCase(value)).findFirst(); - } + public static Optional<ImportType> fromValue(String value) { + return Arrays.stream(ImportType.values()).filter(type -> type.name().equalsIgnoreCase(value)) + .findFirst(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ParseResults.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ParseResults.java index ec9e5185b6..eac18a8839 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ParseResults.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ParseResults.java @@ -16,45 +16,44 @@ package com.epam.ta.reportportal.core.imprt.impl; import com.epam.ta.reportportal.commons.EntityUtils; - import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.Date; public class ParseResults { - private LocalDateTime startTime; + private LocalDateTime startTime; - private long duration; + private long duration; - ParseResults() { - startTime = LocalDateTime.now(); - } + ParseResults() { + startTime = LocalDateTime.now(); + } - public ParseResults(LocalDateTime startTime, long duration) { - this.startTime = startTime; - this.duration = duration; - } + public ParseResults(LocalDateTime startTime, long duration) { + this.startTime = startTime; + this.duration = duration; + } - public LocalDateTime getStartTime() { - return startTime; - } + public LocalDateTime getStartTime() { + return startTime; + } - public long getDuration() { - return duration; - } + public long getDuration() { + return duration; + } - void checkAndSetStartLaunchTime(LocalDateTime startSuiteTime) { - if (this.startTime.isAfter(startSuiteTime)) { - this.startTime = startSuiteTime; - } - } + void checkAndSetStartLaunchTime(LocalDateTime startSuiteTime) { + if (this.startTime.isAfter(startSuiteTime)) { + this.startTime = startSuiteTime; + } + } - void increaseDuration(long duration) { - this.duration += duration; - } + void increaseDuration(long duration) { + this.duration += duration; + } - public Date getEndTime() { - return EntityUtils.TO_DATE.apply(startTime.plus(duration, ChronoUnit.MILLIS)); - } + public Date getEndTime() { + return EntityUtils.TO_DATE.apply(startTime.plus(duration, ChronoUnit.MILLIS)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/XmlImportStrategy.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/XmlImportStrategy.java index 2ce5219297..c1bd76a038 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/XmlImportStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/XmlImportStrategy.java @@ -15,21 +15,20 @@ */ package com.epam.ta.reportportal.core.imprt.impl; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.imprt.impl.junit.XunitParseJob; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; -import java.util.Map; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.inject.Provider; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; - -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; -import static java.util.Optional.ofNullable; +import javax.inject.Provider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -42,10 +41,9 @@ public class XmlImportStrategy extends AbstractImportStrategy { @Override public String importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - File file, String baseUrl, Map<String, String> params) { - validateOverrideParameters(params); + File file, String baseUrl, LaunchImportRQ rq) { try { - return processXmlFile(file, projectDetails, user, baseUrl, params); + return processXmlFile(file, projectDetails, user, baseUrl, rq); } finally { try { ofNullable(file).ifPresent(File::delete); @@ -56,17 +54,16 @@ public String importLaunch(ReportPortalUser.ProjectDetails projectDetails, Repor } private String processXmlFile(File xml, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String baseUrl, Map<String, String> params) { + ReportPortalUser user, String baseUrl, LaunchImportRQ rq) { //copy of the launch's id to use it in catch block if something goes wrong String savedLaunchId = null; try (InputStream xmlStream = new FileInputStream(xml)) { String launchId = startLaunch(projectDetails, user, - xml.getName().substring(0, xml.getName().indexOf("." + XML_EXTENSION)), params); + xml.getName().substring(0, xml.getName().indexOf("." + XML_EXTENSION)), rq); savedLaunchId = launchId; XunitParseJob job = xmlParseJobProvider.get() .withParameters(projectDetails, launchId, user, xmlStream, - params.get(SKIPPED_IS_NOT_ISSUE) != null && Boolean.parseBoolean(params.get( - SKIPPED_IS_NOT_ISSUE))); + isSkippedNotIssue(rq.getAttributes())); ParseResults parseResults = job.call(); finishLaunch(launchId, projectDetails, user, parseResults, baseUrl); return launchId; diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ZipImportStrategy.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ZipImportStrategy.java index d9cbbb04fe..b6b83ac8b4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ZipImportStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/ZipImportStrategy.java @@ -15,15 +15,15 @@ */ package com.epam.ta.reportportal.core.imprt.impl; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; +import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.imprt.impl.junit.XunitParseJob; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; -import java.util.Map; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.inject.Provider; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -31,28 +31,28 @@ import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.XML_EXTENSION; -import static com.epam.ta.reportportal.core.imprt.FileExtensionConstant.ZIP_EXTENSION; -import static java.util.Optional.ofNullable; +import javax.inject.Provider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ZipImportStrategy extends AbstractImportStrategy { + private static final Predicate<ZipEntry> isFile = zipEntry -> !zipEntry.isDirectory(); - private static final Predicate<ZipEntry> isXml = zipEntry -> zipEntry.getName().endsWith(XML_EXTENSION); + private static final Predicate<ZipEntry> isXml = zipEntry -> zipEntry.getName() + .endsWith(XML_EXTENSION); @Autowired private Provider<XunitParseJob> xmlParseJobProvider; @Override public String importLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - File file, String baseUrl, Map<String, String> params) { - validateOverrideParameters(params); + File file, String baseUrl, LaunchImportRQ rq) { try { - return processZipFile(file, projectDetails, user, baseUrl, params); + return processZipFile(file, projectDetails, user, baseUrl, rq); } finally { try { ofNullable(file).ifPresent(File::delete); @@ -63,18 +63,17 @@ public String importLaunch(ReportPortalUser.ProjectDetails projectDetails, Repor } private String processZipFile(File zip, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String baseUrl, Map<String, String> params) { + ReportPortalUser user, String baseUrl, LaunchImportRQ rq) { //copy of the launch's id to use it in catch block if something goes wrong String savedLaunchId = null; try (ZipFile zipFile = new ZipFile(zip)) { String launchId = startLaunch(projectDetails, user, - zip.getName().substring(0, zip.getName().indexOf("." + ZIP_EXTENSION)), params); + zip.getName().substring(0, zip.getName().indexOf("." + ZIP_EXTENSION)), rq); savedLaunchId = launchId; CompletableFuture[] futures = zipFile.stream().filter(isFile.and(isXml)).map(zipEntry -> { XunitParseJob job = xmlParseJobProvider.get() .withParameters(projectDetails, launchId, user, getEntryStream(zipFile, zipEntry), - params.get(SKIPPED_IS_NOT_ISSUE) != null && Boolean.parseBoolean(params.get( - SKIPPED_IS_NOT_ISSUE))); + isSkippedNotIssue(rq.getAttributes())); return CompletableFuture.supplyAsync(job::call, service); }).toArray(CompletableFuture[]::new); ParseResults parseResults = processResults(futures); diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandler.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandler.java index 99b16f7566..935263f9bd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandler.java @@ -15,6 +15,9 @@ */ package com.epam.ta.reportportal.core.imprt.impl.junit; +import static com.epam.ta.reportportal.core.imprt.impl.DateUtils.toMillis; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; @@ -28,6 +31,18 @@ import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.google.common.base.Strings; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,19 +53,6 @@ import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.ChronoUnit; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.imprt.impl.DateUtils.toMillis; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; - @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class XunitImportHandler extends DefaultHandler { @@ -77,7 +79,7 @@ public XunitImportHandler(StartTestItemHandler startTestItemHandler, FinishTestI private ReportPortalUser.ProjectDetails projectDetails; private ReportPortalUser user; private String launchUuid; - private boolean skippedIsNotIssue = false; + private boolean isSkippedNotIssue = false; //need to know item's id to attach System.out/System.err logs private String currentItemUuid; @@ -193,29 +195,37 @@ private void startRootItem(String name, String timestamp) { itemUuids.push(id); } - private LocalDateTime parseTimeStamp(String timestamp) { - LocalDateTime localDateTime = null; - try { - localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timestamp)), ZoneId.systemDefault()); - } catch (NumberFormatException ignored) { - //ignored - } - if (null == localDateTime) { - DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendOptional(DateTimeFormatter.RFC_1123_DATE_TIME) - .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME) - .optionalStart() - .appendZoneId() - .optionalEnd() - .optionalStart() - .appendLiteral(' ') - .parseCaseSensitive() - .appendZoneId() - .optionalEnd() - .toFormatter(); - localDateTime = LocalDateTime.parse(timestamp, formatter); - } - return localDateTime; - } + private LocalDateTime parseTimeStamp(String timestamp) { + // try to parse datetime as Long, otherwise parse as timestamp + try { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timestamp)), ZoneOffset.UTC); + } catch (NumberFormatException ignored) { + DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .appendOptional(DateTimeFormatter.RFC_1123_DATE_TIME) + .appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + .optionalStart() + .appendOffsetId() + .appendZoneId() + .optionalEnd() + .optionalStart() + .appendLiteral(' ') + .parseCaseSensitive() + .appendZoneId() + .optionalEnd() + .toFormatter(); + + TemporalAccessor temporalAccessor = formatter.parse(timestamp); + if (isParsedTimeStampHasOffset(temporalAccessor)) { + return ZonedDateTime.from(temporalAccessor) + .withZoneSameInstant(ZoneOffset.UTC) + .toLocalDateTime(); + } else { + return LocalDateTime.from(temporalAccessor); + } + } + + } private void startTestItem(String name) { StartTestItemRQ rq = buildStartTestRq(name); @@ -256,7 +266,7 @@ private void finishTestItem() { } private void markAsNotIssue(FinishTestItemRQ rq) { - if (StatusEnum.SKIPPED.equals(status) && skippedIsNotIssue) { + if (StatusEnum.SKIPPED.equals(status) && isSkippedNotIssue) { Issue issue = new Issue(); issue.setIssueType(NOT_ISSUE_FLAG.getValue()); rq.setIssue(issue); @@ -275,11 +285,11 @@ private void attachLog(LogLevel logLevel) { } XunitImportHandler withParameters(ReportPortalUser.ProjectDetails projectDetails, String launchId, - ReportPortalUser user, boolean skipped) { + ReportPortalUser user, boolean isSkippedNotIssue) { this.projectDetails = projectDetails; this.launchUuid = launchId; this.user = user; - this.skippedIsNotIssue = skipped; + this.isSkippedNotIssue = isSkippedNotIssue; return this; } @@ -299,4 +309,9 @@ LocalDateTime getStartSuiteTime() { long getCommonDuration() { return commonDuration; } + + private boolean isParsedTimeStampHasOffset(TemporalAccessor temporalAccessor) { + return temporalAccessor.query(TemporalQueries.offset()) != null; + } + } diff --git a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitParseJob.java b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitParseJob.java index 82f1e94c18..60880a5c9b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitParseJob.java +++ b/src/main/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitParseJob.java @@ -73,9 +73,9 @@ public ParseResults call() { } public XunitParseJob withParameters(ReportPortalUser.ProjectDetails projectDetails, String launchId, ReportPortalUser user, - InputStream xmlInputStream, boolean skipped) { + InputStream xmlInputStream, boolean isSkippedNotIssue) { this.xmlInputStream = xmlInputStream; - this.handler = handler.withParameters(projectDetails, launchId, user, skipped); + this.handler = handler.withParameters(projectDetails, launchId, user, isSkippedNotIssue); return this; } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/CreateIntegrationHandler.java b/src/main/java/com/epam/ta/reportportal/core/integration/CreateIntegrationHandler.java index 3280968a84..707984f395 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/CreateIntegrationHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/CreateIntegrationHandler.java @@ -32,6 +32,7 @@ public interface CreateIntegrationHandler { * * @param pluginName Plugin name * @param createRequest {@link IntegrationRQ} + * @param user {@link ReportPortalUser} * @return {@link EntryCreatedRS} */ EntryCreatedRS createGlobalIntegration(IntegrationRQ createRequest, String pluginName, diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/ExecuteIntegrationHandler.java b/src/main/java/com/epam/ta/reportportal/core/integration/ExecuteIntegrationHandler.java index 3691d95487..4d1ac67cbf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/ExecuteIntegrationHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/ExecuteIntegrationHandler.java @@ -17,39 +17,50 @@ package com.epam.ta.reportportal.core.integration; import com.epam.ta.reportportal.commons.ReportPortalUser; - import java.util.Map; /** - * Executes one of provided commands for configured integration with id - * at existed plugin. + * Executes one of provided commands for configured integration with id at existed plugin. * * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public interface ExecuteIntegrationHandler { - /** - * Executes provided common plugin command - * - * @param projectDetails Project details - * @param pluginName Command name - * @param command Command to be executed - * @param executionParams Parameters for execute - * @return Result of the command execution - */ - Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, String pluginName, String command, - Map<String, Object> executionParams); + /** + * Executes provided common plugin command + * + * @param projectDetails Project details + * @param pluginName Command name + * @param command Command to be executed + * @param executionParams Parameters for execute + * @return Result of the command execution + */ + Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, String pluginName, + String command, + Map<String, Object> executionParams); + + /** + * Executes provided plugin public command + * + * @param pluginName Command name + * @param command Command to be executed + * @param executionParams Parameters for execute + * @return Result of the command execution + */ + Object executePublicCommand(String pluginName, String command, + Map<String, Object> executionParams); - /** - * Executes provided plugin command for existed integration - * - * @param projectDetails Project details - * @param integrationId Integration id - * @param command Command to be executed - * @param executionParams Parameters for execute - * @return Result of the command execution - */ - Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, Long integrationId, String command, - Map<String, Object> executionParams); + /** + * Executes provided plugin command for existed integration + * + * @param projectDetails Project details + * @param integrationId Integration id + * @param command Command to be executed + * @param executionParams Parameters for execute + * @return Result of the command execution + */ + Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, Long integrationId, + String command, + Map<String, Object> executionParams); } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/GetIntegrationHandler.java b/src/main/java/com/epam/ta/reportportal/core/integration/GetIntegrationHandler.java index 9bb75bc8db..e58315f011 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/GetIntegrationHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/GetIntegrationHandler.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; - import java.util.List; import java.util.Optional; @@ -29,59 +28,62 @@ */ public interface GetIntegrationHandler { - /** - * @param integrationId Integration id - * @param projectName Project name - * @return {@link IntegrationResource} - */ - IntegrationResource getProjectIntegrationById(Long integrationId, String projectName); - - IntegrationResource getGlobalIntegrationById(Long integrationId); - - Optional<Integration> getEnabledByProjectIdOrGlobalAndIntegrationGroup(Long projectId, IntegrationGroupEnum integrationGroup); - - Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, String url, String btsProject); - - Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, Long integrationId); - - Integration getEnabledBtsIntegration(Long integrationId); - - List<IntegrationResource> getGlobalIntegrations(); - - List<IntegrationResource> getGlobalIntegrations(String pluginName); - - /** - * Get project integrations - * - * @param projectName Project nam - * @return List of integrations - */ - List<IntegrationResource> getProjectIntegrations(String projectName); - - /** - * Get project integrations with plugin - * - * @param pluginName Plugin name - * @param projectName Project nam - * @return List of integrations - */ - List<IntegrationResource> getProjectIntegrations(String pluginName, String projectName); - - /** - * Test integration connection. Firstly tries to find a project integration. - * If doesn't exist it tries to find Global integration - * - * @param integrationId Integration id - * @param projectName Project name - * @return True if a connection is established - */ - boolean testConnection(Long integrationId, String projectName); - - /** - * Test integration connection. Connection attempt to the global integration - * - * @param integrationId Integration id - * @return True if a connection is established - */ - boolean testConnection(Long integrationId); + /** + * @param integrationId Integration id + * @param projectName Project name + * @return {@link IntegrationResource} + */ + IntegrationResource getProjectIntegrationById(Long integrationId, String projectName); + + IntegrationResource getGlobalIntegrationById(Long integrationId); + + Optional<Integration> getEnabledByProjectIdOrGlobalAndIntegrationGroup(Long projectId, + IntegrationGroupEnum integrationGroup); + + Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, String url, + String btsProject); + + Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, + Long integrationId); + + Integration getEnabledBtsIntegration(Long integrationId); + + List<IntegrationResource> getGlobalIntegrations(); + + List<IntegrationResource> getGlobalIntegrations(String pluginName); + + /** + * Get project integrations + * + * @param projectName Project nam + * @return List of integrations + */ + List<IntegrationResource> getProjectIntegrations(String projectName); + + /** + * Get project integrations with plugin + * + * @param pluginName Plugin name + * @param projectName Project nam + * @return List of integrations + */ + List<IntegrationResource> getProjectIntegrations(String pluginName, String projectName); + + /** + * Test integration connection. Firstly tries to find a project integration. If doesn't exist it + * tries to find Global integration + * + * @param integrationId Integration id + * @param projectName Project name + * @return True if a connection is established + */ + boolean testConnection(Long integrationId, String projectName); + + /** + * Test integration connection. Connection attempt to the global integration + * + * @param integrationId Integration id + * @return True if a connection is established + */ + boolean testConnection(Long integrationId); } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/impl/CreateIntegrationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/impl/CreateIntegrationHandlerImpl.java index 01089c8e4f..7bca6c9f23 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/impl/CreateIntegrationHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/impl/CreateIntegrationHandlerImpl.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.integration.impl; +import static com.epam.ta.reportportal.ws.converter.converters.IntegrationConverter.TO_ACTIVITY_RESOURCE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -35,6 +38,7 @@ import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.activity.IntegrationActivityResource; import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -42,11 +46,6 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.ws.converter.converters.IntegrationConverter.TO_ACTIVITY_RESOURCE; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @@ -102,7 +101,6 @@ public EntryCreatedRS createGlobalIntegration(IntegrationRQ createRequest, Strin integration.setCreator(user.getUsername()); integrationService.checkConnection(integration); integrationRepository.save(integration); - publishCreationActivity(integration, user); return new EntryCreatedRS(integration.getId()); diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerImpl.java index ddac984b76..315d1692e6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerImpl.java @@ -16,24 +16,25 @@ package com.epam.ta.reportportal.core.integration.impl; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.INTEGRATION_NOT_FOUND; +import static java.util.Optional.ofNullable; + import com.epam.reportportal.extension.ReportPortalExtensionPoint; import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.integration.ExecuteIntegrationHandler; import com.epam.ta.reportportal.core.plugin.PluginBox; import com.epam.ta.reportportal.dao.IntegrationRepository; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.function.Supplier; - -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; -import static com.epam.ta.reportportal.ws.model.ErrorType.INTEGRATION_NOT_FOUND; -import static java.util.Optional.ofNullable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -41,67 +42,96 @@ @Service public class ExecuteIntegrationHandlerImpl implements ExecuteIntegrationHandler { - private static final String ASYNC_MODE = "async"; - - //Required field for user authorization in plugin - private static final String PROJECT_ID = "projectId"; - - private final IntegrationRepository integrationRepository; - - private final PluginBox pluginBox; - - public ExecuteIntegrationHandlerImpl(IntegrationRepository integrationRepository, PluginBox pluginBox) { - this.integrationRepository = integrationRepository; - this.pluginBox = pluginBox; - } - - @Override - public Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, String pluginName, String command, - Map<String, Object> executionParams) { - ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(pluginName, ReportPortalExtensionPoint.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - formattedSupplier("Plugin for '{}' isn't installed", pluginName).get() - )); - executionParams.put(PROJECT_ID, projectDetails.getProjectId()); - return ofNullable(pluginInstance.getCommonCommand(command)).map(it -> it.executeCommand(executionParams)) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - formattedSupplier("Command '{}' is not found in plugin {}.", command, pluginName).get() - )); - } - - @Override - public Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, Long integrationId, String command, - Map<String, Object> executionParams) { - Integration integration = integrationRepository.findByIdAndProjectId(integrationId, projectDetails.getProjectId()) - .orElseGet(() -> integrationRepository.findGlobalById(integrationId) - .orElseThrow(() -> new ReportPortalException(INTEGRATION_NOT_FOUND, integrationId))); - - ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration.getType().getName(), ReportPortalExtensionPoint.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - formattedSupplier("Plugin for '{}' isn't installed", integration.getType().getName()).get() - )); - - Boolean asyncMode = ofNullable((Boolean) executionParams.get(ASYNC_MODE)).orElse(false); - - executionParams.put(PROJECT_ID, projectDetails.getProjectId()); - - return ofNullable(pluginInstance.getIntegrationCommand(command)).map(it -> { - if (asyncMode) { - supplyAsync(() -> it.executeCommand(integration, executionParams)); - return new OperationCompletionRS(formattedSupplier("Command '{}' accepted for processing in plugin", - command, - integration.getType().getName() - ).get()); - } - return it.executeCommand(integration, executionParams); - }).orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - formattedSupplier("Command '{}' is not found in plugin {}.", command, integration.getType().getName()).get() - )); - } - - @Async - //need for security context sharing into plugin - public <U> void supplyAsync(Supplier<U> supplier) { - supplier.get(); - } + private static final String ASYNC_MODE = "async"; + + //Required field for user authorization in plugin + private static final String PROJECT_ID = "projectId"; + private static final String PUBLIC_COMMAND_PREFIX = "public_"; + + private final IntegrationRepository integrationRepository; + + private final PluginBox pluginBox; + + public ExecuteIntegrationHandlerImpl(IntegrationRepository integrationRepository, + PluginBox pluginBox) { + this.integrationRepository = integrationRepository; + this.pluginBox = pluginBox; + } + + @Override + public Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, String pluginName, + String command, + Map<String, Object> executionParams) { + ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(pluginName, + ReportPortalExtensionPoint.class) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Plugin for '{}' isn't installed", pluginName).get() + )); + executionParams.put(PROJECT_ID, projectDetails.getProjectId()); + return ofNullable(pluginInstance.getCommonCommand(command)).map( + it -> it.executeCommand(executionParams)) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Command '{}' is not found in plugin {}.", command, pluginName).get() + )); + } + + @Override + public Object executePublicCommand(String pluginName, String command, + Map<String, Object> executionParams) { + BusinessRule.expect(command, c -> c.startsWith(PUBLIC_COMMAND_PREFIX)) + .verify(ACCESS_DENIED, formattedSupplier("Command '{}' is not public.", command).get()); + ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(pluginName, + ReportPortalExtensionPoint.class) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Plugin for '{}' isn't installed", pluginName).get() + )); + return ofNullable(pluginInstance.getCommonCommand(command)).map( + it -> it.executeCommand(executionParams)) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Public command '{}' is not found in plugin {}.", command, + pluginName).get() + )); + } + + @Override + public Object executeCommand(ReportPortalUser.ProjectDetails projectDetails, Long integrationId, + String command, + Map<String, Object> executionParams) { + Integration integration = integrationRepository.findByIdAndProjectId(integrationId, + projectDetails.getProjectId()) + .orElseGet(() -> integrationRepository.findGlobalById(integrationId) + .orElseThrow(() -> new ReportPortalException(INTEGRATION_NOT_FOUND, integrationId))); + + ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance( + integration.getType().getName(), ReportPortalExtensionPoint.class) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Plugin for '{}' isn't installed", + integration.getType().getName()).get() + )); + + Boolean asyncMode = ofNullable((Boolean) executionParams.get(ASYNC_MODE)).orElse(false); + + executionParams.put(PROJECT_ID, projectDetails.getProjectId()); + + return ofNullable(pluginInstance.getIntegrationCommand(command)).map(it -> { + if (asyncMode) { + supplyAsync(() -> it.executeCommand(integration, executionParams)); + return new OperationCompletionRS( + formattedSupplier("Command '{}' accepted for processing in plugin", + command, + integration.getType().getName() + ).get()); + } + return it.executeCommand(integration, executionParams); + }).orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + formattedSupplier("Command '{}' is not found in plugin {}.", command, + integration.getType().getName()).get() + )); + } + + @Async + //need for security context sharing into plugin + public <U> void supplyAsync(Supplier<U> supplier) { + supplier.get(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerImpl.java index 1b3de9faa2..d3c2e00305 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.integration.impl; +import static com.epam.ta.reportportal.ws.converter.converters.IntegrationConverter.TO_INTEGRATION_RESOURCE; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -33,17 +35,14 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.ws.converter.converters.IntegrationConverter.TO_INTEGRATION_RESOURCE; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:andrei_varabyeu@epam.com">Andrei Varabyeu</a> @@ -51,185 +50,218 @@ @Service public class GetIntegrationHandlerImpl implements GetIntegrationHandler { - private final Map<String, IntegrationService> integrationServiceMapping; - private final IntegrationService basicIntegrationService; - private final IntegrationRepository integrationRepository; - private final IntegrationTypeRepository integrationTypeRepository; - private final ProjectRepository projectRepository; - private final GetBugTrackingSystemHandler getBugTrackingSystemHandler; - - @Autowired - public GetIntegrationHandlerImpl(@Qualifier("integrationServiceMapping") Map<String, IntegrationService> integrationServiceMapping, - @Qualifier("basicIntegrationServiceImpl") IntegrationService integrationService, IntegrationRepository integrationRepository, - IntegrationTypeRepository integrationTypeRepository, ProjectRepository projectRepository, - GetBugTrackingSystemHandler getBugTrackingSystemHandler) { - this.integrationServiceMapping = integrationServiceMapping; - this.basicIntegrationService = integrationService; - this.integrationRepository = integrationRepository; - this.integrationTypeRepository = integrationTypeRepository; - this.projectRepository = projectRepository; - this.getBugTrackingSystemHandler = getBugTrackingSystemHandler; - } - - @Override - public IntegrationResource getProjectIntegrationById(Long integrationId, String projectName) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - Integration integration = integrationRepository.findByIdAndProjectId(integrationId, project.getId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); - return TO_INTEGRATION_RESOURCE.apply(integration); - } - - @Override - public IntegrationResource getGlobalIntegrationById(Long integrationId) { - Integration integration = integrationRepository.findGlobalById(integrationId) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); - return TO_INTEGRATION_RESOURCE.apply(integration); - } - - @Override - public Optional<Integration> getEnabledByProjectIdOrGlobalAndIntegrationGroup(Long projectId, IntegrationGroupEnum integrationGroup) { - - List<Long> integrationTypeIds = integrationTypeRepository.findAllByIntegrationGroup(integrationGroup) - .stream() - .map(IntegrationType::getId) - .collect(Collectors.toList()); - - List<Integration> integrations = integrationRepository.findAllByProjectIdAndInIntegrationTypeIds(projectId, integrationTypeIds); - - if (!CollectionUtils.isEmpty(integrations)) { - - return integrations.stream().filter(integration -> integration.getType().isEnabled() && integration.isEnabled()).findFirst(); - - } else { - - return getGlobalIntegrationByIntegrationTypeIds(integrationTypeIds); - } - - } - - @Override - public Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, String url, String btsProject) { - - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectDetails.getProjectName())); - - Integration integration = getBugTrackingSystemHandler.getEnabledProjectIntegration(projectDetails, url, btsProject) - .orElseGet(() -> { - Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration(url, btsProject) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, url)); - - IntegrationValidator.validateProjectLevelIntegrationConstraints(project, globalIntegration); - - return globalIntegration; - }); - validateIntegration(integration); - return integration; - } - - @Override - public Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, Long integrationId) { - - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectDetails.getProjectName())); - - Integration integration = getBugTrackingSystemHandler.getEnabledProjectIntegration(projectDetails, integrationId).orElseGet(() -> { - Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration(integrationId) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); - - IntegrationValidator.validateProjectLevelIntegrationConstraints(project, globalIntegration); - - return globalIntegration; - }); - validateIntegration(integration); - return integration; - } - - @Override - public Integration getEnabledBtsIntegration(Long integrationId) { - - Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration(integrationId) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); - - return globalIntegration; - } - - @Override - public List<IntegrationResource> getGlobalIntegrations() { - return integrationRepository.findAllGlobal().stream().map(TO_INTEGRATION_RESOURCE).collect(Collectors.toList()); - } - - @Override - public List<IntegrationResource> getGlobalIntegrations(String pluginName) { - IntegrationType integrationType = integrationTypeRepository.findByName(pluginName) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginName)); - return integrationRepository.findAllGlobalByType(integrationType) - .stream() - .map(TO_INTEGRATION_RESOURCE) - .collect(Collectors.toList()); - } - - @Override - public List<IntegrationResource> getProjectIntegrations(String projectName) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - return integrationRepository.findAllByProjectIdOrderByCreationDateDesc(project.getId()).stream().map(TO_INTEGRATION_RESOURCE).collect(Collectors.toList()); - } - - @Override - public List<IntegrationResource> getProjectIntegrations(String pluginName, String projectName) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - IntegrationType integrationType = integrationTypeRepository.findByName(pluginName) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginName)); - return integrationRepository.findAllByProjectIdAndTypeOrderByCreationDateDesc(project.getId(), integrationType) - .stream() - .map(TO_INTEGRATION_RESOURCE) - .collect(Collectors.toList()); - } - - @Override - public boolean testConnection(Long integrationId, String projectName) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - - Integration integration = integrationRepository.findByIdAndProjectId(integrationId, project.getId()) - .orElseGet(() -> integrationRepository.findGlobalById(integrationId) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId))); - - IntegrationService integrationService = integrationServiceMapping.getOrDefault(integration.getType().getName(), - this.basicIntegrationService - ); - return integrationService.checkConnection(integration); - } - - @Override - public boolean testConnection(Long integrationId) { - Integration integration = integrationRepository.findGlobalById(integrationId) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); - - IntegrationService integrationService = integrationServiceMapping.getOrDefault(integration.getType().getName(), - this.basicIntegrationService - ); - return integrationService.checkConnection(integration); - } - - private Optional<Integration> getGlobalIntegrationByIntegrationTypeIds(List<Long> integrationTypeIds) { - return integrationRepository.findAllGlobalInIntegrationTypeIds(integrationTypeIds) - .stream() - .filter(integration -> integration.getType().isEnabled() && integration.isEnabled()) - .findFirst(); - } - - private void validateIntegration(Integration integration) { - BusinessRule.expect(integration, i -> integration.getType().isEnabled()) - .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - Suppliers.formattedSupplier("'{}' type integrations are disabled by Administrator", integration.getType().getName()) - .get() - ); - BusinessRule.expect(integration, Integration::isEnabled) - .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - Suppliers.formattedSupplier("Integration with ID = '{}' is disabled", integration.getId()).get() - ); - } + private final Map<String, IntegrationService> integrationServiceMapping; + private final IntegrationService basicIntegrationService; + private final IntegrationRepository integrationRepository; + private final IntegrationTypeRepository integrationTypeRepository; + private final ProjectRepository projectRepository; + private final GetBugTrackingSystemHandler getBugTrackingSystemHandler; + + @Autowired + public GetIntegrationHandlerImpl( + @Qualifier("integrationServiceMapping") Map<String, IntegrationService> integrationServiceMapping, + @Qualifier("basicIntegrationServiceImpl") IntegrationService integrationService, + IntegrationRepository integrationRepository, + IntegrationTypeRepository integrationTypeRepository, ProjectRepository projectRepository, + GetBugTrackingSystemHandler getBugTrackingSystemHandler) { + this.integrationServiceMapping = integrationServiceMapping; + this.basicIntegrationService = integrationService; + this.integrationRepository = integrationRepository; + this.integrationTypeRepository = integrationTypeRepository; + this.projectRepository = projectRepository; + this.getBugTrackingSystemHandler = getBugTrackingSystemHandler; + } + + @Override + public IntegrationResource getProjectIntegrationById(Long integrationId, String projectName) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + Integration integration = integrationRepository.findByIdAndProjectId(integrationId, + project.getId()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); + return TO_INTEGRATION_RESOURCE.apply(integration); + } + + @Override + public IntegrationResource getGlobalIntegrationById(Long integrationId) { + Integration integration = integrationRepository.findGlobalById(integrationId) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); + return TO_INTEGRATION_RESOURCE.apply(integration); + } + + @Override + public Optional<Integration> getEnabledByProjectIdOrGlobalAndIntegrationGroup(Long projectId, + IntegrationGroupEnum integrationGroup) { + + List<Long> integrationTypeIds = integrationTypeRepository.findAllByIntegrationGroup( + integrationGroup) + .stream() + .map(IntegrationType::getId) + .collect(Collectors.toList()); + + List<Integration> integrations = integrationRepository.findAllByProjectIdAndInIntegrationTypeIds( + projectId, integrationTypeIds); + + if (!CollectionUtils.isEmpty(integrations)) { + + return integrations.stream() + .filter(integration -> integration.getType().isEnabled() && integration.isEnabled()) + .findFirst(); + + } else { + + return getGlobalIntegrationByIntegrationTypeIds(integrationTypeIds); + } + + } + + @Override + public Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, + String url, String btsProject) { + + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, + projectDetails.getProjectName())); + + Integration integration = getBugTrackingSystemHandler.getEnabledProjectIntegration( + projectDetails, url, btsProject) + .orElseGet(() -> { + Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration( + url, btsProject) + .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, url)); + + IntegrationValidator.validateProjectLevelIntegrationConstraints(project, + globalIntegration); + + return globalIntegration; + }); + validateIntegration(integration); + return integration; + } + + @Override + public Integration getEnabledBtsIntegration(ReportPortalUser.ProjectDetails projectDetails, + Long integrationId) { + + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, + projectDetails.getProjectName())); + + Integration integration = getBugTrackingSystemHandler.getEnabledProjectIntegration( + projectDetails, integrationId).orElseGet(() -> { + Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration( + integrationId) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); + + IntegrationValidator.validateProjectLevelIntegrationConstraints(project, globalIntegration); + + return globalIntegration; + }); + validateIntegration(integration); + return integration; + } + + @Override + public Integration getEnabledBtsIntegration(Long integrationId) { + + Integration globalIntegration = getBugTrackingSystemHandler.getEnabledGlobalIntegration( + integrationId) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); + + return globalIntegration; + } + + @Override + public List<IntegrationResource> getGlobalIntegrations() { + return integrationRepository.findAllGlobal().stream().map(TO_INTEGRATION_RESOURCE) + .collect(Collectors.toList()); + } + + @Override + public List<IntegrationResource> getGlobalIntegrations(String pluginName) { + IntegrationType integrationType = integrationTypeRepository.findByName(pluginName) + .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginName)); + return integrationRepository.findAllGlobalByType(integrationType) + .stream() + .map(TO_INTEGRATION_RESOURCE) + .collect(Collectors.toList()); + } + + @Override + public List<IntegrationResource> getProjectIntegrations(String projectName) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + return integrationRepository.findAllByProjectIdOrderByCreationDateDesc(project.getId()).stream() + .map(TO_INTEGRATION_RESOURCE).collect(Collectors.toList()); + } + + @Override + public List<IntegrationResource> getProjectIntegrations(String pluginName, String projectName) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + IntegrationType integrationType = integrationTypeRepository.findByName(pluginName) + .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginName)); + return integrationRepository.findAllByProjectIdAndTypeOrderByCreationDateDesc(project.getId(), + integrationType) + .stream() + .map(TO_INTEGRATION_RESOURCE) + .collect(Collectors.toList()); + } + + @Override + public boolean testConnection(Long integrationId, String projectName) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + + Integration integration = integrationRepository.findByIdAndProjectId(integrationId, + project.getId()) + .orElseGet(() -> integrationRepository.findGlobalById(integrationId) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId))); + + IntegrationService integrationService = integrationServiceMapping.getOrDefault( + integration.getType().getName(), + this.basicIntegrationService + ); + return integrationService.checkConnection(integration); + } + + @Override + public boolean testConnection(Long integrationId) { + Integration integration = integrationRepository.findGlobalById(integrationId) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, integrationId)); + + IntegrationService integrationService = integrationServiceMapping.getOrDefault( + integration.getType().getName(), + this.basicIntegrationService + ); + return integrationService.checkConnection(integration); + } + + private Optional<Integration> getGlobalIntegrationByIntegrationTypeIds( + List<Long> integrationTypeIds) { + return integrationRepository.findAllGlobalInIntegrationTypeIds(integrationTypeIds) + .stream() + .filter(integration -> integration.getType().isEnabled() && integration.isEnabled()) + .findFirst(); + } + + private void validateIntegration(Integration integration) { + BusinessRule.expect(integration, i -> integration.getType().isEnabled()) + .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier("'{}' type integrations are disabled by Administrator", + integration.getType().getName()) + .get() + ); + BusinessRule.expect(integration, Integration::isEnabled) + .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier("Integration with ID = '{}' is disabled", + integration.getId()).get() + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/GetPluginHandler.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/GetPluginHandler.java index d7b69ce4cd..0e3eaece79 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/GetPluginHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/GetPluginHandler.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.integration.plugin; import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; - import java.util.List; /** @@ -25,11 +24,18 @@ */ public interface GetPluginHandler { - /** - * Get a list of all existing plugins - * - * @return {@link List} of the {@link IntegrationTypeResource} - */ - List<IntegrationTypeResource> getPlugins(); + /** + * Get a list of all existing plugins + * + * @return {@link List} of the {@link IntegrationTypeResource} + */ + List<IntegrationTypeResource> getPlugins(); + + /** + * Get a list of all existing public plugins + * + * @return {@link List} of the {@link IntegrationTypeResource} + */ + List<IntegrationTypeResource> getPublicPlugins(); } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java index b170d4f8d3..602a523b32 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java @@ -19,91 +19,99 @@ import com.epam.ta.reportportal.core.plugin.PluginInfo; import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.pf4j.PluginException; -import org.pf4j.PluginWrapper; - import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; +import org.pf4j.PluginException; +import org.pf4j.PluginWrapper; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface PluginLoader { - /** - * Extract info about the plugin from the provided path - * - * @param pluginPath Plugin's path - * @return {@link PluginInfo} with {@link PluginInfo#getId()} and {@link PluginInfo#getVersion()} - */ - PluginInfo extractPluginInfo(Path pluginPath) throws PluginException; + /** + * Extract info about the plugin from the provided path + * + * @param pluginPath Plugin's path + * @return {@link PluginInfo} with {@link PluginInfo#getId()} and {@link PluginInfo#getVersion()} + * @throws PluginException if there is an issue in loading the plugin or the plugin is not found in the specified path + */ + PluginInfo extractPluginInfo(Path pluginPath) throws PluginException; - /** - * Creates the {@link IntegrationTypeDetails} object based on the params of the plugin - * - * @param pluginInfo {@link PluginInfo} with {@link PluginInfo#getId()} and {@link PluginInfo#getVersion()} - * @return {@link IntegrationTypeDetails} - */ - IntegrationTypeDetails resolvePluginDetails(PluginInfo pluginInfo); + /** + * Creates the {@link IntegrationTypeDetails} object based on the params of the plugin + * + * @param pluginInfo {@link PluginInfo} with {@link PluginInfo#getId()} and + * {@link PluginInfo#getVersion()} + * @return {@link IntegrationTypeDetails} + */ + IntegrationTypeDetails resolvePluginDetails(PluginInfo pluginInfo); - /** - * Validate the plugin with {@link com.epam.reportportal.extension.common.ExtensionPoint} - * on the presence of the mandatory extension class/classes - * - * @param plugin {@link PluginWrapper} - * @return true if the plugin has mandatory extension class/classes, else false - */ - boolean validatePluginExtensionClasses(PluginWrapper plugin); + /** + * Validate the plugin with {@link com.epam.reportportal.extension.common.ExtensionPoint} on the + * presence of the mandatory extension class/classes + * + * @param plugin {@link PluginWrapper} + * @return true if the plugin has mandatory extension class/classes, else false + */ + boolean validatePluginExtensionClasses(PluginWrapper plugin); - /** - * Save plugin in the {@link com.epam.ta.reportportal.filesystem.DataStore} - * - * @param fileName New plugin file name - * @param fileStream {@link InputStream} of the new plugin file - * @return File id of the saved file in the file system - * @throws ReportPortalException - */ - String saveToDataStore(String fileName, InputStream fileStream) throws ReportPortalException; + /** + * Save plugin in the {@link com.epam.ta.reportportal.filesystem.DataStore} + * + * @param fileName New plugin file name + * @param fileStream {@link InputStream} of the new plugin file + * @return File id of the saved file in the file system + * @throws ReportPortalException if can't save data + */ + String saveToDataStore(String fileName, InputStream fileStream) throws ReportPortalException; - /** - * Upload plugin file to the directory. - * - * @param pluginPath Path to save plugin file - * @param fileStream {@link InputStream} of the plugin file - */ - void savePlugin(Path pluginPath, InputStream fileStream) throws IOException; + /** + * Upload plugin file to the directory. + * + * @param pluginPath Path to save plugin file + * @param fileStream {@link InputStream} of the plugin file + * @throws IOException if can't save plugin + */ + void savePlugin(Path pluginPath, InputStream fileStream) throws IOException; - /** - * Copy plugin with resources from the {@link com.epam.ta.reportportal.filesystem.DataStore} to the provided path - * - * @param fileId {@link com.epam.ta.reportportal.core.integration.util.property.IntegrationDetailsProperties#FILE_ID} value - * @param pluginPath Path where to copy plugin file - * @param pluginResourcesPath Path were to copy plugin resources - */ - void copyFromDataStore(String fileId, Path pluginPath, Path pluginResourcesPath) throws IOException; + /** + * Copy plugin with resources from the {@link com.epam.ta.reportportal.filesystem.DataStore} to + * the provided path + * + * @param fileId value + * @param pluginPath Path where to copy plugin file + * @param pluginResourcesPath Path were to copy plugin resources + * @throws IOException in case errors due coping + */ + void copyFromDataStore(String fileId, Path pluginPath, Path pluginResourcesPath) + throws IOException; - /** - * Delete plugin file from the {@link com.epam.ta.reportportal.filesystem.DataStore} - * - * @param fileId {@link com.epam.ta.reportportal.core.integration.util.property.IntegrationDetailsProperties#FILE_ID} value - */ - void deleteFromDataStore(String fileId); + /** + * Delete plugin file from the {@link com.epam.ta.reportportal.filesystem.DataStore} + * + * @param fileId fileId of plugin + */ + void deleteFromDataStore(String fileId); - /** - * Copy plugin resources to the target path - * - * @param pluginPath Plugin path in the filesystem - * @param resourcesTargetPath Path to copy plugin resources - * @throws IOException - */ - void copyPluginResource(Path pluginPath, Path resourcesTargetPath) throws IOException, ReportPortalException; + /** + * Copy plugin resources to the target path + * + * @param pluginPath Plugin path in the filesystem + * @param resourcesTargetPath Path to copy plugin resources + * @throws IOException in case of errors due coping plugin + */ + void copyPluginResource(Path pluginPath, Path resourcesTargetPath) + throws IOException, ReportPortalException; - /** - * Remove the plugin file from the temporary directory and file name from the {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} - * - * @param pluginFileDirectory Path to the temporary directory with the plugin file - * @param pluginFileName Name of the plugin file - */ - void deleteTempPlugin(String pluginFileDirectory, String pluginFileName) throws IOException; + /** + * Remove the plugin file from the temporary directory and file name from the + * {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} + * + * @param pluginFileDirectory Path to the temporary directory with the plugin file + * @param pluginFileName Name of the plugin file + * @throws IOException in case errors due deleting + */ + void deleteTempPlugin(String pluginFileDirectory, String pluginFileName) throws IOException; } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/binary/PluginFilesProvider.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/binary/PluginFilesProvider.java new file mode 100644 index 0000000000..20439cb983 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/binary/PluginFilesProvider.java @@ -0,0 +1,76 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.integration.plugin.binary; + +import com.epam.ta.reportportal.dao.IntegrationTypeRepository; +import com.epam.ta.reportportal.entity.attachment.BinaryData; +import com.epam.ta.reportportal.entity.integration.IntegrationType; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.model.ErrorType; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Paths; +import javax.activation.FileTypeMap; +import org.apache.commons.io.FileUtils; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +public class PluginFilesProvider { + + private final String baseDirectory; + private final String folderQualifier; + + private final FileTypeMap fileTypeResolver; + + private final IntegrationTypeRepository integrationTypeRepository; + + public PluginFilesProvider(String baseDirectory, String folderQualifier, + FileTypeMap fileTypeResolver, + IntegrationTypeRepository integrationTypeRepository) { + this.baseDirectory = baseDirectory; + this.folderQualifier = folderQualifier; + this.fileTypeResolver = fileTypeResolver; + this.integrationTypeRepository = integrationTypeRepository; + } + + public BinaryData load(String pluginName, String fileName) { + final IntegrationType integrationType = integrationTypeRepository.findByName(pluginName) + .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginName)); + + final File file = Paths.get(baseDirectory, integrationType.getName(), folderQualifier, fileName) + .toFile(); + + if (!file.exists() || file.isDirectory()) { + throw new ReportPortalException(ErrorType.UNABLE_TO_LOAD_BINARY_DATA, fileName); + } + + return getBinaryData(file); + + } + + private BinaryData getBinaryData(File file) { + try { + final InputStream fileStream = FileUtils.openInputStream(file); + final String contentType = fileTypeResolver.getContentType(file.getName()); + return new BinaryData(contentType, (long) fileStream.available(), fileStream); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.UNABLE_TO_LOAD_BINARY_DATA, e.getMessage()); + } + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/GetPluginHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/GetPluginHandlerImpl.java index 051b1eec57..1a0080020f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/GetPluginHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/GetPluginHandlerImpl.java @@ -20,11 +20,10 @@ import com.epam.ta.reportportal.dao.IntegrationTypeRepository; import com.epam.ta.reportportal.ws.converter.converters.IntegrationTypeConverter; import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -32,18 +31,28 @@ @Service public class GetPluginHandlerImpl implements GetPluginHandler { - private final IntegrationTypeRepository integrationTypeRepository; + private static final String ACCESS_TYPE_PUBLIC_NAME = "public"; + + private final IntegrationTypeRepository integrationTypeRepository; + + @Autowired + public GetPluginHandlerImpl(IntegrationTypeRepository integrationTypeRepository) { + this.integrationTypeRepository = integrationTypeRepository; + } - @Autowired - public GetPluginHandlerImpl(IntegrationTypeRepository integrationTypeRepository) { - this.integrationTypeRepository = integrationTypeRepository; - } + @Override + public List<IntegrationTypeResource> getPlugins() { + return integrationTypeRepository.findAllByOrderByCreationDate() + .stream() + .map(IntegrationTypeConverter.TO_RESOURCE) + .collect(Collectors.toList()); + } - @Override - public List<IntegrationTypeResource> getPlugins() { - return integrationTypeRepository.findAllByOrderByCreationDate() - .stream() - .map(IntegrationTypeConverter.TO_RESOURCE) - .collect(Collectors.toList()); - } + @Override + public List<IntegrationTypeResource> getPublicPlugins() { + return integrationTypeRepository.findAllByAccessType(ACCESS_TYPE_PUBLIC_NAME) + .stream() + .map(IntegrationTypeConverter.TO_RESOURCE) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationService.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationService.java index f9c27c6ee8..ab43693205 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationService.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationService.java @@ -17,33 +17,34 @@ import com.epam.ta.reportportal.core.plugin.PluginBox; import com.epam.ta.reportportal.dao.IntegrationRepository; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Map; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Service public class AzureIntegrationService extends BasicIntegrationServiceImpl { - private BtsIntegrationService btsIntegrationService; + private BtsIntegrationService btsIntegrationService; - @Autowired - public AzureIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, - BtsIntegrationService btsIntegrationService) { - super(integrationRepository, pluginBox); - this.btsIntegrationService = btsIntegrationService; - } + @Autowired + public AzureIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, + BtsIntegrationService btsIntegrationService) { + super(integrationRepository, pluginBox); + this.btsIntegrationService = btsIntegrationService; + } - @Override - public Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> integrationParams) { - return btsIntegrationService.retrieveCreateParams(integrationType, integrationParams); - } + @Override + public Map<String, Object> retrieveCreateParams(String integrationType, + Map<String, Object> integrationParams) { + return btsIntegrationService.retrieveCreateParams(integrationType, integrationParams); + } - @Override - public Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> integrationParams) { - return btsIntegrationService.retrieveUpdatedParams(integrationType, integrationParams); - } + @Override + public Map<String, Object> retrieveUpdatedParams(String integrationType, + Map<String, Object> integrationParams) { + return btsIntegrationService.retrieveUpdatedParams(integrationType, integrationParams); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/BasicIntegrationServiceImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/BasicIntegrationServiceImpl.java index 8e35ac35c4..fb79c653f6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/BasicIntegrationServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/BasicIntegrationServiceImpl.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.integration.util; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static java.util.Optional.ofNullable; + import com.epam.reportportal.extension.CommonPluginCommand; import com.epam.reportportal.extension.PluginCommand; import com.epam.reportportal.extension.ReportPortalExtensionPoint; @@ -27,15 +30,11 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.converter.builders.IntegrationBuilder; import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.time.LocalDateTime; import java.util.Map; import java.util.Optional; - -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; -import static java.util.Optional.ofNullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -43,84 +42,102 @@ @Service public class BasicIntegrationServiceImpl implements IntegrationService { - private static final String TEST_CONNECTION_COMMAND = "testConnection"; - private static final String RETRIEVE_CREATE_PARAMS = "retrieveCreate"; - private static final String RETRIEVE_UPDATED_PARAMS = "retrieveUpdated"; - - protected IntegrationRepository integrationRepository; - - protected PluginBox pluginBox; - - @Autowired - public BasicIntegrationServiceImpl(IntegrationRepository integrationRepository, PluginBox pluginBox) { - this.integrationRepository = integrationRepository; - this.pluginBox = pluginBox; - } - - @Override - public Integration createIntegration(IntegrationRQ integrationRq, IntegrationType integrationType) { - return new IntegrationBuilder().withCreationDate(LocalDateTime.now()) - .withType(integrationType) - .withEnabled(integrationRq.getEnabled()) - .withName(integrationRq.getName()) - .withParams(new IntegrationParams(retrieveCreateParams(integrationType.getName(), integrationRq.getIntegrationParams()))) - .get(); - } - - @Override - public Integration updateIntegration(Integration integration, IntegrationRQ integrationRQ) { - Map<String, Object> validParams = retrieveUpdatedParams(integration.getType().getName(), integrationRQ.getIntegrationParams()); - IntegrationParams combinedParams = getCombinedParams(integration, validParams); - integration.setParams(combinedParams); - ofNullable(integrationRQ.getEnabled()).ifPresent(integration::setEnabled); - ofNullable(integrationRQ.getName()).ifPresent(integration::setName); - return integration; - } - - @Override - public Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> integrationParams) { - final Optional<CommonPluginCommand<?>> pluginCommand = getCommonCommand(integrationType, RETRIEVE_CREATE_PARAMS); - if (pluginCommand.isPresent()) { - return (Map<String, Object>) pluginCommand.get().executeCommand(integrationParams); - } - return integrationParams; - } - - @Override - public Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> integrationParams) { - final Optional<CommonPluginCommand<?>> pluginCommand = getCommonCommand(integrationType, RETRIEVE_UPDATED_PARAMS); - if (pluginCommand.isPresent()) { - return (Map<String, Object>) pluginCommand.get().executeCommand(integrationParams); - } - return integrationParams; - } - - @Override - public boolean checkConnection(Integration integration) { - final Optional<PluginCommand<?>> pluginCommand = getIntegrationCommand(integration.getType().getName(), TEST_CONNECTION_COMMAND); - if (pluginCommand.isPresent()) { - return (Boolean) pluginCommand.get().executeCommand(integration, integration.getParams().getParams()); - } - return true; - } - - private Optional<PluginCommand<?>> getIntegrationCommand(String integration, String commandName) { - ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration, ReportPortalExtensionPoint.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, "Plugin for {} isn't installed", integration)); - return ofNullable(pluginInstance.getIntegrationCommand(commandName)); - } - - private Optional<CommonPluginCommand<?>> getCommonCommand(String integration, String commandName) { - ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration, ReportPortalExtensionPoint.class) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, "Plugin for {} isn't installed", integration)); - return ofNullable(pluginInstance.getCommonCommand(commandName)); - } - - private IntegrationParams getCombinedParams(Integration integration, Map<String, Object> retrievedParams) { - if (integration.getParams() != null && integration.getParams().getParams() != null) { - integration.getParams().getParams().putAll(retrievedParams); - return integration.getParams(); - } - return new IntegrationParams(retrievedParams); - } + private static final String TEST_CONNECTION_COMMAND = "testConnection"; + private static final String RETRIEVE_CREATE_PARAMS = "retrieveCreate"; + private static final String RETRIEVE_UPDATED_PARAMS = "retrieveUpdated"; + + protected IntegrationRepository integrationRepository; + + protected PluginBox pluginBox; + + @Autowired + public BasicIntegrationServiceImpl(IntegrationRepository integrationRepository, + PluginBox pluginBox) { + this.integrationRepository = integrationRepository; + this.pluginBox = pluginBox; + } + + @Override + public Integration createIntegration(IntegrationRQ integrationRq, + IntegrationType integrationType) { + return new IntegrationBuilder().withCreationDate(LocalDateTime.now()) + .withType(integrationType) + .withEnabled(integrationRq.getEnabled()) + .withName(integrationRq.getName()) + .withParams(new IntegrationParams( + retrieveCreateParams(integrationType.getName(), integrationRq.getIntegrationParams()))) + .get(); + } + + @Override + public Integration updateIntegration(Integration integration, IntegrationRQ integrationRQ) { + Map<String, Object> validParams = retrieveUpdatedParams(integration.getType().getName(), + integrationRQ.getIntegrationParams()); + IntegrationParams combinedParams = getCombinedParams(integration, validParams); + integration.setParams(combinedParams); + ofNullable(integrationRQ.getEnabled()).ifPresent(integration::setEnabled); + ofNullable(integrationRQ.getName()).ifPresent(integration::setName); + return integration; + } + + @Override + public Map<String, Object> retrieveCreateParams(String integrationType, + Map<String, Object> integrationParams) { + final Optional<CommonPluginCommand<?>> pluginCommand = getCommonCommand(integrationType, + RETRIEVE_CREATE_PARAMS); + if (pluginCommand.isPresent()) { + return (Map<String, Object>) pluginCommand.get().executeCommand(integrationParams); + } + return integrationParams; + } + + @Override + public Map<String, Object> retrieveUpdatedParams(String integrationType, + Map<String, Object> integrationParams) { + final Optional<CommonPluginCommand<?>> pluginCommand = getCommonCommand(integrationType, + RETRIEVE_UPDATED_PARAMS); + if (pluginCommand.isPresent()) { + return (Map<String, Object>) pluginCommand.get().executeCommand(integrationParams); + } + return integrationParams; + } + + @Override + public boolean checkConnection(Integration integration) { + final Optional<PluginCommand<?>> pluginCommand = getIntegrationCommand( + integration.getType().getName(), TEST_CONNECTION_COMMAND); + if (pluginCommand.isPresent()) { + return (Boolean) pluginCommand.get() + .executeCommand(integration, integration.getParams().getParams()); + } + return true; + } + + private Optional<PluginCommand<?>> getIntegrationCommand(String integration, String commandName) { + ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration, + ReportPortalExtensionPoint.class) + .orElseThrow( + () -> new ReportPortalException(BAD_REQUEST_ERROR, "Plugin for {} isn't installed", + integration)); + return ofNullable(pluginInstance.getIntegrationCommand(commandName)); + } + + private Optional<CommonPluginCommand<?>> getCommonCommand(String integration, + String commandName) { + ReportPortalExtensionPoint pluginInstance = pluginBox.getInstance(integration, + ReportPortalExtensionPoint.class) + .orElseThrow( + () -> new ReportPortalException(BAD_REQUEST_ERROR, "Plugin for {} isn't installed", + integration)); + return ofNullable(pluginInstance.getCommonCommand(commandName)); + } + + private IntegrationParams getCombinedParams(Integration integration, + Map<String, Object> retrievedParams) { + if (integration.getParams() != null && integration.getParams().getParams() != null) { + integration.getParams().getParams().putAll(retrievedParams); + return integration.getParams(); + } + return new IntegrationParams(retrievedParams); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/BtsIntegrationService.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/BtsIntegrationService.java index 89952eb814..db252edcc9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/BtsIntegrationService.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/BtsIntegrationService.java @@ -15,6 +15,9 @@ */ package com.epam.ta.reportportal.core.integration.util; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_INTERACT_WITH_INTEGRATION; + import com.epam.reportportal.extension.bugtracking.BtsExtension; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.integration.util.property.BtsProperties; @@ -25,116 +28,129 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Maps; +import java.util.Map; +import java.util.Optional; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; import org.jasypt.util.text.BasicTextEncryptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_INTERACT_WITH_INTEGRATION; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Service public class BtsIntegrationService extends BasicIntegrationServiceImpl { - private final BasicTextEncryptor basicTextEncryptor; - - @Autowired - public BtsIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, BasicTextEncryptor basicTextEncryptor) { - super(integrationRepository, pluginBox); - this.basicTextEncryptor = basicTextEncryptor; - } - - @Override - public Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> integrationParams) { - expect(integrationParams, MapUtils::isNotEmpty).verify(ErrorType.BAD_REQUEST_ERROR, "No integration params provided"); - - Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize(BtsProperties.values().length); - - resultParams.put(BtsProperties.PROJECT.getName(), - BtsProperties.PROJECT.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, "BTS project is not specified.")) - ); - resultParams.put(BtsProperties.URL.getName(), - BtsProperties.URL.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, "BTS url is not specified.")) - ); - - final String authName = BtsProperties.AUTH_TYPE.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, "Auth type is not specified.")); - retrieveAuthParams(integrationParams, resultParams, authName); - resultParams.put(BtsProperties.AUTH_TYPE.getName(), authName); - - return resultParams; - } - - @Override - public Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> integrationParams) { - Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize(integrationParams.size()); - - BtsProperties.URL.getParam(integrationParams) - .ifPresent(url -> resultParams.put(BtsProperties.URL.getName(), url)); - - BtsProperties.PROJECT.getParam(integrationParams) - .ifPresent(url -> resultParams.put(BtsProperties.PROJECT.getName(), url)); - - BtsProperties.AUTH_TYPE.getParam(integrationParams).ifPresent(authName -> { - retrieveAuthParams(integrationParams, resultParams, authName); - resultParams.put(BtsProperties.AUTH_TYPE.getName(), authName); - }); - - Optional.ofNullable(integrationParams.get("defectFormFields")) - .ifPresent(defectFormFields -> resultParams.put("defectFormFields", defectFormFields)); - - return resultParams; - } - - @Override - public boolean checkConnection(Integration integration) { - BtsExtension extension = pluginBox.getInstance(integration.getType().getName(), BtsExtension.class) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - Suppliers.formattedSupplier("Could not find plugin with name '{}'.", integration.getType().getName()).get() - )); - expect(extension.testConnection(integration), BooleanUtils::isTrue).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "Connection refused." - ); - return true; - } - - /** - * Retrieves auth params based on auth type - */ - private Map<String, Object> retrieveAuthParams(Map<String, Object> integrationParams, Map<String, Object> resultParams, - String authName) { - AuthType authType = AuthType.findByName(authName) - .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_AUTHENTICATION_TYPE, authName)); - if (AuthType.BASIC.equals(authType)) { - resultParams.put(BtsProperties.USER_NAME.getName(), - BtsProperties.USER_NAME.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, - "Username value is not specified" - )) - ); - - String encryptedPassword = basicTextEncryptor.encrypt(BtsProperties.PASSWORD.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, "Password value is not specified"))); - resultParams.put(BtsProperties.PASSWORD.getName(), encryptedPassword); - } else if (AuthType.OAUTH.equals(authType)) { - final String encryptedAccessKey = basicTextEncryptor.encrypt(BtsProperties.OAUTH_ACCESS_KEY.getParam(integrationParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, "AccessKey value is not specified"))); - resultParams.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), encryptedAccessKey); - } else { - throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "Unsupported auth type for integration - " + authType.name() - ); - } - return resultParams; - } + private final BasicTextEncryptor basicTextEncryptor; + + @Autowired + public BtsIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, + BasicTextEncryptor basicTextEncryptor) { + super(integrationRepository, pluginBox); + this.basicTextEncryptor = basicTextEncryptor; + } + + @Override + public Map<String, Object> retrieveCreateParams(String integrationType, + Map<String, Object> integrationParams) { + expect(integrationParams, MapUtils::isNotEmpty).verify(ErrorType.BAD_REQUEST_ERROR, + "No integration params provided"); + + Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize( + BtsProperties.values().length); + + resultParams.put(BtsProperties.PROJECT.getName(), + BtsProperties.PROJECT.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "BTS project is not specified.")) + ); + resultParams.put(BtsProperties.URL.getName(), + BtsProperties.URL.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "BTS url is not specified.")) + ); + + final String authName = BtsProperties.AUTH_TYPE.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "Auth type is not specified.")); + retrieveAuthParams(integrationParams, resultParams, authName); + resultParams.put(BtsProperties.AUTH_TYPE.getName(), authName); + + return resultParams; + } + + @Override + public Map<String, Object> retrieveUpdatedParams(String integrationType, + Map<String, Object> integrationParams) { + Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize(integrationParams.size()); + + BtsProperties.URL.getParam(integrationParams) + .ifPresent(url -> resultParams.put(BtsProperties.URL.getName(), url)); + + BtsProperties.PROJECT.getParam(integrationParams) + .ifPresent(url -> resultParams.put(BtsProperties.PROJECT.getName(), url)); + + BtsProperties.AUTH_TYPE.getParam(integrationParams).ifPresent(authName -> { + retrieveAuthParams(integrationParams, resultParams, authName); + resultParams.put(BtsProperties.AUTH_TYPE.getName(), authName); + }); + + Optional.ofNullable(integrationParams.get("defectFormFields")) + .ifPresent(defectFormFields -> resultParams.put("defectFormFields", defectFormFields)); + + return resultParams; + } + + @Override + public boolean checkConnection(Integration integration) { + BtsExtension extension = pluginBox.getInstance(integration.getType().getName(), + BtsExtension.class) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier("Could not find plugin with name '{}'.", + integration.getType().getName()).get() + )); + expect(extension.testConnection(integration), BooleanUtils::isTrue).verify( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Connection refused." + ); + return true; + } + + /** + * Retrieves auth params based on auth type + */ + private Map<String, Object> retrieveAuthParams(Map<String, Object> integrationParams, + Map<String, Object> resultParams, + String authName) { + AuthType authType = AuthType.findByName(authName) + .orElseThrow( + () -> new ReportPortalException(ErrorType.INCORRECT_AUTHENTICATION_TYPE, authName)); + if (AuthType.BASIC.equals(authType)) { + resultParams.put(BtsProperties.USER_NAME.getName(), + BtsProperties.USER_NAME.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "Username value is not specified" + )) + ); + + String encryptedPassword = basicTextEncryptor.encrypt( + BtsProperties.PASSWORD.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "Password value is not specified"))); + resultParams.put(BtsProperties.PASSWORD.getName(), encryptedPassword); + } else if (AuthType.OAUTH.equals(authType)) { + final String encryptedAccessKey = basicTextEncryptor.encrypt( + BtsProperties.OAUTH_ACCESS_KEY.getParam(integrationParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_INTERACT_WITH_INTEGRATION, + "AccessKey value is not specified"))); + resultParams.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), encryptedAccessKey); + } else { + throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Unsupported auth type for integration - " + authType.name() + ); + } + return resultParams; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationService.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationService.java index 5d17c6c42c..595012e21e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationService.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationService.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.integration.util; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.fail; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.EMAIL_CONFIGURATION_IS_INCORRECT; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.admin.ServerAdminHandlerImpl; import com.epam.ta.reportportal.core.plugin.PluginBox; @@ -28,6 +34,9 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Maps; import com.mchange.lang.IntegerUtils; +import java.util.Map; +import java.util.Optional; +import javax.mail.MessagingException; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.validator.routines.UrlValidator; @@ -36,128 +45,131 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import javax.mail.MessagingException; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.fail; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.EMAIL_CONFIGURATION_IS_INCORRECT; -import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class EmailServerIntegrationService extends BasicIntegrationServiceImpl { - private static final Logger LOGGER = LoggerFactory.getLogger(ServerAdminHandlerImpl.class); - - private final BasicTextEncryptor basicTextEncryptor; - - private final MailServiceFactory emailServiceFactory; - - public EmailServerIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, - BasicTextEncryptor basicTextEncryptor, MailServiceFactory emailServiceFactory) { - super(integrationRepository, pluginBox); - this.basicTextEncryptor = basicTextEncryptor; - this.emailServiceFactory = emailServiceFactory; - } - - @Override - public Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> integrationParams) { - BusinessRule.expect(integrationParams, MapUtils::isNotEmpty).verify(ErrorType.BAD_REQUEST_ERROR, "No integration params provided"); - - Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize(EmailSettingsEnum.values().length); - - Optional<String> fromAttribute = EmailSettingsEnum.FROM.getAttribute(integrationParams); - - fromAttribute.ifPresent(from -> resultParams.put(EmailSettingsEnum.FROM.getAttribute(), from)); - - ofNullable(integrationParams.get(EmailSettingsEnum.PORT.getAttribute())).ifPresent(p -> { - int port = IntegerUtils.parseInt(String.valueOf(p), -1); - if ((port <= 0) || (port > 65535)) { - BusinessRule.fail().withError(ErrorType.INCORRECT_REQUEST, "Incorrect 'Port' value. Allowed value is [1..65535]"); - } - resultParams.put(EmailSettingsEnum.PORT.getAttribute(), p); - }); - - EmailSettingsEnum.PROTOCOL.getAttribute(integrationParams) - .ifPresent(protocol -> resultParams.put(EmailSettingsEnum.PROTOCOL.getAttribute(), protocol)); - - ofNullable(integrationParams.get(EmailSettingsEnum.AUTH_ENABLED.getAttribute())).ifPresent(authEnabledAttribute -> { - boolean isAuthEnabled = BooleanUtils.toBoolean(String.valueOf(authEnabledAttribute)); - if (isAuthEnabled) { - EmailSettingsEnum.USERNAME.getAttribute(integrationParams) - .ifPresent(username -> resultParams.put(EmailSettingsEnum.USERNAME.getAttribute(), username)); - EmailSettingsEnum.PASSWORD.getAttribute(integrationParams) - .ifPresent(password -> resultParams.put(EmailSettingsEnum.PASSWORD.getAttribute(), - basicTextEncryptor.encrypt(password) - )); - } else { - /* Auto-drop values on switched-off authentication */ - resultParams.put(EmailSettingsEnum.USERNAME.getAttribute(), null); - resultParams.put(EmailSettingsEnum.PASSWORD.getAttribute(), null); - } - resultParams.put(EmailSettingsEnum.AUTH_ENABLED.getAttribute(), isAuthEnabled); - }); - - EmailSettingsEnum.STAR_TLS_ENABLED.getAttribute(integrationParams) - .ifPresent(attr -> resultParams.put(EmailSettingsEnum.STAR_TLS_ENABLED.getAttribute(), BooleanUtils.toBoolean(attr))); - EmailSettingsEnum.SSL_ENABLED.getAttribute(integrationParams) - .ifPresent(attr -> resultParams.put(EmailSettingsEnum.SSL_ENABLED.getAttribute(), BooleanUtils.toBoolean(attr))); - EmailSettingsEnum.HOST.getAttribute(integrationParams) - .ifPresent(attr -> resultParams.put(EmailSettingsEnum.HOST.getAttribute(), attr)); - EmailSettingsEnum.RP_HOST.getAttribute(integrationParams) - .filter(UrlValidator.getInstance()::isValid) - .ifPresent(attr -> resultParams.put(EmailSettingsEnum.RP_HOST.getAttribute(), attr)); - - return resultParams; - } - - @Override - public Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> integrationParams) { - return retrieveCreateParams(integrationType, integrationParams); - } - - @Override - public boolean checkConnection(Integration integration) { - Optional<EmailService> emailService = emailServiceFactory.getEmailService(integration); - if (emailService.isPresent()) { - try { - emailService.get().testConnection(); - } catch (MessagingException ex) { - LOGGER.error("Cannot send email to user", ex); - fail().withError(FORBIDDEN_OPERATION, - "Email configuration is incorrect. Please, check your configuration. " + ex.getMessage() - ); - } - - // if an email integration is new and not saved at db yet - try to send a creation integration message - if (integration.getId() == null) { - try { - EmailSettingsEnum.AUTH_ENABLED.getAttribute(integration.getParams().getParams()).ifPresent(authEnabled -> { - if (BooleanUtils.toBoolean(authEnabled)) { - String sendTo = EmailSettingsEnum.USERNAME.getAttribute(integration.getParams().getParams()) - .orElseThrow(() -> new ReportPortalException(EMAIL_CONFIGURATION_IS_INCORRECT, - "Email server username is not specified." - )); - emailService.get().sendConnectionTestEmail(sendTo); - } - }); - } catch (Exception ex) { - fail().withError(EMAIL_CONFIGURATION_IS_INCORRECT, - formattedSupplier("Unable to send connection test email. " + ex.getMessage()) - ); - } - } - - } else { - return false; - } - return true; - } + private static final Logger LOGGER = LoggerFactory.getLogger(ServerAdminHandlerImpl.class); + + private final BasicTextEncryptor basicTextEncryptor; + + private final MailServiceFactory emailServiceFactory; + + public EmailServerIntegrationService(IntegrationRepository integrationRepository, + PluginBox pluginBox, + BasicTextEncryptor basicTextEncryptor, MailServiceFactory emailServiceFactory) { + super(integrationRepository, pluginBox); + this.basicTextEncryptor = basicTextEncryptor; + this.emailServiceFactory = emailServiceFactory; + } + + @Override + public Map<String, Object> retrieveCreateParams(String integrationType, + Map<String, Object> integrationParams) { + BusinessRule.expect(integrationParams, MapUtils::isNotEmpty) + .verify(ErrorType.BAD_REQUEST_ERROR, "No integration params provided"); + + Map<String, Object> resultParams = Maps.newHashMapWithExpectedSize( + EmailSettingsEnum.values().length); + + Optional<String> fromAttribute = EmailSettingsEnum.FROM.getAttribute(integrationParams); + + fromAttribute.ifPresent(from -> resultParams.put(EmailSettingsEnum.FROM.getAttribute(), from)); + + ofNullable(integrationParams.get(EmailSettingsEnum.PORT.getAttribute())).ifPresent(p -> { + int port = IntegerUtils.parseInt(String.valueOf(p), -1); + if ((port <= 0) || (port > 65535)) { + BusinessRule.fail().withError(ErrorType.INCORRECT_REQUEST, + "Incorrect 'Port' value. Allowed value is [1..65535]"); + } + resultParams.put(EmailSettingsEnum.PORT.getAttribute(), p); + }); + + EmailSettingsEnum.PROTOCOL.getAttribute(integrationParams) + .ifPresent( + protocol -> resultParams.put(EmailSettingsEnum.PROTOCOL.getAttribute(), protocol)); + + EmailSettingsEnum.USERNAME.getAttribute(integrationParams) + .ifPresent( + username -> resultParams.put(EmailSettingsEnum.USERNAME.getAttribute(), username)); + + ofNullable(integrationParams.get(EmailSettingsEnum.AUTH_ENABLED.getAttribute())).ifPresent( + authEnabledAttribute -> { + boolean isAuthEnabled = BooleanUtils.toBoolean(String.valueOf(authEnabledAttribute)); + if (isAuthEnabled) { + EmailSettingsEnum.PASSWORD.getAttribute(integrationParams) + .ifPresent(password -> resultParams.put(EmailSettingsEnum.PASSWORD.getAttribute(), + basicTextEncryptor.encrypt(password) + )); + } else { + /* Auto-drop values on switched-off authentication */ + resultParams.put(EmailSettingsEnum.PASSWORD.getAttribute(), null); + } + resultParams.put(EmailSettingsEnum.AUTH_ENABLED.getAttribute(), isAuthEnabled); + }); + + EmailSettingsEnum.STAR_TLS_ENABLED.getAttribute(integrationParams) + .ifPresent(attr -> resultParams.put(EmailSettingsEnum.STAR_TLS_ENABLED.getAttribute(), + BooleanUtils.toBoolean(attr))); + EmailSettingsEnum.SSL_ENABLED.getAttribute(integrationParams) + .ifPresent(attr -> resultParams.put(EmailSettingsEnum.SSL_ENABLED.getAttribute(), + BooleanUtils.toBoolean(attr))); + EmailSettingsEnum.HOST.getAttribute(integrationParams) + .ifPresent(attr -> resultParams.put(EmailSettingsEnum.HOST.getAttribute(), attr)); + EmailSettingsEnum.RP_HOST.getAttribute(integrationParams) + .filter(UrlValidator.getInstance()::isValid) + .ifPresent(attr -> resultParams.put(EmailSettingsEnum.RP_HOST.getAttribute(), attr)); + + return resultParams; + } + + @Override + public Map<String, Object> retrieveUpdatedParams(String integrationType, + Map<String, Object> integrationParams) { + return retrieveCreateParams(integrationType, integrationParams); + } + + @Override + public boolean checkConnection(Integration integration) { + Optional<EmailService> emailService = emailServiceFactory.getEmailService(integration); + if (emailService.isPresent()) { + try { + emailService.get().testConnection(); + } catch (MessagingException ex) { + LOGGER.error("Cannot send email to user", ex); + fail().withError(FORBIDDEN_OPERATION, + "Email configuration is incorrect. Please, check your configuration. " + ex.getMessage() + ); + } + + // if an email integration is new and not saved at db yet - try to send a creation integration message + if (integration.getId() == null) { + try { + EmailSettingsEnum.AUTH_ENABLED.getAttribute(integration.getParams().getParams()) + .ifPresent(authEnabled -> { + if (BooleanUtils.toBoolean(authEnabled)) { + String sendTo = EmailSettingsEnum.USERNAME.getAttribute( + integration.getParams().getParams()) + .orElseThrow(() -> new ReportPortalException(EMAIL_CONFIGURATION_IS_INCORRECT, + "Email server username is not specified." + )); + emailService.get().sendConnectionTestEmail(sendTo); + } + }); + } catch (Exception ex) { + fail().withError(EMAIL_CONFIGURATION_IS_INCORRECT, + formattedSupplier("Unable to send connection test email. " + ex.getMessage()) + ); + } + } + + } else { + return false; + } + return true; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/IntegrationService.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/IntegrationService.java index 0c37f653fd..8aa41b60e7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/IntegrationService.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/IntegrationService.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; - import java.util.Map; /** @@ -27,14 +26,14 @@ */ public interface IntegrationService { - Integration createIntegration(IntegrationRQ integrationRq, IntegrationType integrationType); + Integration createIntegration(IntegrationRQ integrationRq, IntegrationType integrationType); - Integration updateIntegration(Integration integration, IntegrationRQ integrationRQ); + Integration updateIntegration(Integration integration, IntegrationRQ integrationRQ); - Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> params); + Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> params); - Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> params); + Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> params); - boolean checkConnection(Integration integration); + boolean checkConnection(Integration integration); } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationService.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationService.java index 07516c2a7b..5e48b9d2b5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationService.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationService.java @@ -16,69 +16,76 @@ package com.epam.ta.reportportal.core.integration.util; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.integration.util.property.SauceLabsProperties.ACCESS_TOKEN; +import static com.epam.ta.reportportal.core.integration.util.property.SauceLabsProperties.USERNAME; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + import com.epam.ta.reportportal.core.plugin.PluginBox; import com.epam.ta.reportportal.dao.IntegrationRepository; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Maps; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.collections4.MapUtils; import org.jasypt.util.text.BasicTextEncryptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.HashMap; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.integration.util.property.SauceLabsProperties.ACCESS_TOKEN; -import static com.epam.ta.reportportal.core.integration.util.property.SauceLabsProperties.USERNAME; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Service public class SauceLabsIntegrationService extends BasicIntegrationServiceImpl { - private final BasicTextEncryptor encryptor; + private final BasicTextEncryptor encryptor; - @Autowired - public SauceLabsIntegrationService(IntegrationRepository integrationRepository, PluginBox pluginBox, BasicTextEncryptor encryptor) { - super(integrationRepository, pluginBox); - this.encryptor = encryptor; - } + @Autowired + public SauceLabsIntegrationService(IntegrationRepository integrationRepository, + PluginBox pluginBox, BasicTextEncryptor encryptor) { + super(integrationRepository, pluginBox); + this.encryptor = encryptor; + } - @Override - public Map<String, Object> retrieveCreateParams(String integrationType, Map<String, Object> integrationParams) { - expect(integrationParams, MapUtils::isNotEmpty).verify(BAD_REQUEST_ERROR, "No integration params provided"); + @Override + public Map<String, Object> retrieveCreateParams(String integrationType, + Map<String, Object> integrationParams) { + expect(integrationParams, MapUtils::isNotEmpty).verify(BAD_REQUEST_ERROR, + "No integration params provided"); - final String encryptedToken = encryptor.encrypt(ACCESS_TOKEN.getParameter(integrationParams) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, "Access token value is not specified"))); - final String username = USERNAME.getParameter(integrationParams) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, "Username value is not specified")); + final String encryptedToken = encryptor.encrypt(ACCESS_TOKEN.getParameter(integrationParams) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + "Access token value is not specified"))); + final String username = USERNAME.getParameter(integrationParams) + .orElseThrow( + () -> new ReportPortalException(BAD_REQUEST_ERROR, "Username value is not specified")); - HashMap<String, Object> result = Maps.newHashMapWithExpectedSize(integrationParams.size()); - result.put(ACCESS_TOKEN.getName(), encryptedToken); - result.put(USERNAME.getName(), username); + HashMap<String, Object> result = Maps.newHashMapWithExpectedSize(integrationParams.size()); + result.put(ACCESS_TOKEN.getName(), encryptedToken); + result.put(USERNAME.getName(), username); - integrationParams.entrySet() - .stream() - .filter(it -> !it.getKey().equals(ACCESS_TOKEN.getName()) && !it.getKey().equals(USERNAME.getName())) - .forEach(it -> result.put(it.getKey(), it.getValue())); + integrationParams.entrySet() + .stream() + .filter(it -> !it.getKey().equals(ACCESS_TOKEN.getName()) && !it.getKey() + .equals(USERNAME.getName())) + .forEach(it -> result.put(it.getKey(), it.getValue())); - return result; - } + return result; + } - @Override - public Map<String, Object> retrieveUpdatedParams(String integrationType, Map<String, Object> integrationParams) { - HashMap<String, Object> result = Maps.newHashMapWithExpectedSize(integrationParams.size()); - ACCESS_TOKEN.getParameter(integrationParams) - .ifPresent(token -> result.put(ACCESS_TOKEN.getName(), encryptor.encrypt(token))); - USERNAME.getParameter(integrationParams) - .ifPresent(username -> result.put(USERNAME.getName(), username)); - integrationParams.entrySet() - .stream() - .filter(it -> !it.getKey().equals(ACCESS_TOKEN.getName()) && !it.getKey().equals(USERNAME.getName())) - .forEach(it -> result.put(it.getKey(), it.getValue())); - return result; - } + @Override + public Map<String, Object> retrieveUpdatedParams(String integrationType, + Map<String, Object> integrationParams) { + HashMap<String, Object> result = Maps.newHashMapWithExpectedSize(integrationParams.size()); + ACCESS_TOKEN.getParameter(integrationParams) + .ifPresent(token -> result.put(ACCESS_TOKEN.getName(), encryptor.encrypt(token))); + USERNAME.getParameter(integrationParams) + .ifPresent(username -> result.put(USERNAME.getName(), username)); + integrationParams.entrySet() + .stream() + .filter(it -> !it.getKey().equals(ACCESS_TOKEN.getName()) && !it.getKey() + .equals(USERNAME.getName())) + .forEach(it -> result.put(it.getKey(), it.getValue())); + return result; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/AuthProperties.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/AuthProperties.java index 5213a6f36c..aea36dc671 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/AuthProperties.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/AuthProperties.java @@ -21,15 +21,15 @@ */ public enum AuthProperties { - MANAGER_PASSWORD("managerPassword"); + MANAGER_PASSWORD("managerPassword"); - private String name; + private String name; - AuthProperties(String name) { - this.name = name; - } + AuthProperties(String name) { + this.name = name; + } - public String getName() { - return name; - } + public String getName() { + return name; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/BtsProperties.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/BtsProperties.java index 8a6e75233a..08f086e201 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/BtsProperties.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/BtsProperties.java @@ -17,39 +17,38 @@ package com.epam.ta.reportportal.core.integration.util.property; import com.epam.ta.reportportal.entity.integration.IntegrationParams; - import java.util.HashMap; import java.util.Map; import java.util.Optional; public enum BtsProperties { - USER_NAME("username"), - PASSWORD("password"), - API_TOKEN("apiToken"), - PROJECT("project"), - AUTH_TYPE("authType"), - OAUTH_ACCESS_KEY("oauthAccessKey"), - URL("url"); - - private final String name; - - BtsProperties(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public Optional<String> getParam(Map<String, Object> params) { - return Optional.ofNullable(params.get(this.name)).map(String::valueOf); - } - - public void setParam(IntegrationParams params, String value) { - if (null == params.getParams()) { - params.setParams(new HashMap<>()); - } - params.getParams().put(this.name, value); - } + USER_NAME("username"), + PASSWORD("password"), + API_TOKEN("apiToken"), + PROJECT("project"), + AUTH_TYPE("authType"), + OAUTH_ACCESS_KEY("oauthAccessKey"), + URL("url"); + + private final String name; + + BtsProperties(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Optional<String> getParam(Map<String, Object> params) { + return Optional.ofNullable(params.get(this.name)).map(String::valueOf); + } + + public void setParam(IntegrationParams params, String value) { + if (null == params.getParams()) { + params.setParams(new HashMap<>()); + } + params.getParams().put(this.name, value); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/SauceLabsProperties.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/SauceLabsProperties.java index c4fbe59e5c..b818237244 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/property/SauceLabsProperties.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/property/SauceLabsProperties.java @@ -16,39 +16,38 @@ package com.epam.ta.reportportal.core.integration.util.property; -import com.epam.ta.reportportal.entity.integration.IntegrationParams; +import static java.util.Optional.ofNullable; +import com.epam.ta.reportportal.entity.integration.IntegrationParams; import java.util.HashMap; import java.util.Map; import java.util.Optional; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public enum SauceLabsProperties { - USERNAME("username"), - ACCESS_TOKEN("accessToken"); + USERNAME("username"), + ACCESS_TOKEN("accessToken"); - private String name; + private String name; - SauceLabsProperties(String name) { - this.name = name; - } + SauceLabsProperties(String name) { + this.name = name; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public Optional<String> getParameter(Map<String, Object> parameters) { - return ofNullable(parameters.get(this.name)).map(String::valueOf); - } + public Optional<String> getParameter(Map<String, Object> parameters) { + return ofNullable(parameters.get(this.name)).map(String::valueOf); + } - public void setParameter(IntegrationParams params, String value) { - if (null == params.getParams()) { - params.setParams(new HashMap<>()); - } - params.getParams().put(this.name, value); - } + public void setParameter(IntegrationParams params, String value) { + if (null == params.getParams()) { + params.setParams(new HashMap<>()); + } + params.getParams().put(this.name, value); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidator.java b/src/main/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidator.java index dcc40e6e31..9ad4eea6b3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidator.java @@ -16,50 +16,54 @@ package com.epam.ta.reportportal.core.integration.util.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.apache.commons.lang3.StringUtils; - import java.util.Objects; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import org.apache.commons.lang3.StringUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public final class IntegrationValidator { - private IntegrationValidator() { - //static only - } + private IntegrationValidator() { + //static only + } - /** - * Validation fails if a project has at least one integration with the same type as the provided global integration has - * - * @param project {@link Project} - * @param integration {@link Integration} with {@link Integration#project == NULL} - */ - public static void validateProjectLevelIntegrationConstraints(Project project, Integration integration) { + /** + * Validation fails if a project has at least one integration with the same type as the provided + * global integration has + * + * @param project {@link Project} + * @param integration {@link Integration} with {@link Integration#project == NULL} + */ + public static void validateProjectLevelIntegrationConstraints(Project project, + Integration integration) { - BusinessRule.expect(integration.getProject(), Objects::isNull) - .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - Suppliers.formattedSupplier("Integration with ID = '{}' is not global.", integration.getId()) - ); + BusinessRule.expect(integration.getProject(), Objects::isNull) + .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier("Integration with ID = '{}' is not global.", + integration.getId()) + ); - BusinessRule.expect(project.getIntegrations().stream().map(Integration::getType).noneMatch(it -> { - IntegrationType integrationType = integration.getType(); - return it.getIntegrationGroup() == integrationType.getIntegrationGroup() && StringUtils.equalsIgnoreCase(it.getName(), - integrationType.getName()); - }), equalTo(true)) - .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - Suppliers.formattedSupplier( - "Global integration with ID = '{}' has been found, but you cannot use it, because you have project-level integration(s) of that type", - integration.getId() - ).get() - ); - } + BusinessRule.expect( + project.getIntegrations().stream().map(Integration::getType).noneMatch(it -> { + IntegrationType integrationType = integration.getType(); + return it.getIntegrationGroup() == integrationType.getIntegrationGroup() + && StringUtils.equalsIgnoreCase(it.getName(), + integrationType.getName()); + }), equalTo(true)) + .verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier( + "Global integration with ID = '{}' has been found, but you cannot use it, because you have project-level integration(s) of that type", + integration.getId() + ).get() + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/DeleteTestItemHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/DeleteTestItemHandler.java index 6967fe3205..af63784c47 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/DeleteTestItemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/DeleteTestItemHandler.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; - import java.util.Collection; import java.util.List; @@ -30,24 +29,26 @@ */ public interface DeleteTestItemHandler { - /** - * Delete test item by id. - * - * @param itemId Item id - * @param projectDetails Project Details - * @param user User - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS deleteTestItem(Long itemId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Delete test item by id. + * + * @param itemId Item id + * @param projectDetails Project Details + * @param user User + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS deleteTestItem(Long itemId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Delete list of items by ids. - * - * @param ids Test item ids - * @param projectDetails Project Details - * @param user User - * @return {@link OperationCompletionRS} - */ - List<OperationCompletionRS> deleteTestItems(Collection<Long> ids, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Delete list of items by ids. + * + * @param ids Test item ids + * @param projectDetails Project Details + * @param user User + * @return {@link OperationCompletionRS} + */ + List<OperationCompletionRS> deleteTestItems(Collection<Long> ids, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/ExternalTicketHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/ExternalTicketHandler.java index 04a31fac88..98d67d87ad 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/ExternalTicketHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/ExternalTicketHandler.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.item.UnlinkExternalIssueRQ; - import java.util.List; import java.util.Set; @@ -29,10 +28,12 @@ */ public interface ExternalTicketHandler { - void linkExternalTickets(String submitter, List<IssueEntity> issueEntities, List<Issue.ExternalSystemIssue> tickets); + void linkExternalTickets(String submitter, List<IssueEntity> issueEntities, + List<Issue.ExternalSystemIssue> tickets); - void unlinkExternalTickets(List<TestItem> items, UnlinkExternalIssueRQ request); + void unlinkExternalTickets(List<TestItem> items, UnlinkExternalIssueRQ request); - void updateLinking(String submitter, IssueEntity newEntity, Set<Issue.ExternalSystemIssue> externalTickets); + void updateLinking(String submitter, IssueEntity newEntity, + Set<Issue.ExternalSystemIssue> externalTickets); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/FinishTestItemHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/FinishTestItemHandler.java index affd7e71f8..52a1671278 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/FinishTestItemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/FinishTestItemHandler.java @@ -28,15 +28,16 @@ */ public interface FinishTestItemHandler { - /** - * Updates {@link com.epam.ta.reportportal.entity.item.TestItem} instance - * - * @param user RQ principal - * @param projectDetails Project Details - * @param testItemId Test item ID - * @param finishExecutionRQ Request with finish Test Item data - * @return OperationCompletionRS - */ - OperationCompletionRS finishTestItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, String testItemId, - FinishTestItemRQ finishExecutionRQ); + /** + * Updates {@link com.epam.ta.reportportal.entity.item.TestItem} instance + * + * @param user RQ principal + * @param projectDetails Project Details + * @param testItemId Test item ID + * @param finishExecutionRQ Request with finish Test Item data + * @return OperationCompletionRS + */ + OperationCompletionRS finishTestItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, String testItemId, + FinishTestItemRQ finishExecutionRQ); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/GetTestItemHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/GetTestItemHandler.java index 19b44c52c1..a85cdc9a22 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/GetTestItemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/GetTestItemHandler.java @@ -26,11 +26,10 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.TestItemResource; import com.epam.ta.reportportal.ws.model.statistics.StatisticsResource; -import org.springframework.data.domain.Pageable; - -import javax.annotation.Nullable; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; +import org.springframework.data.domain.Pageable; /** * GET operations for {@link TestItem} @@ -40,125 +39,147 @@ */ public interface GetTestItemHandler { - /** - * Get {@link TestItem} instance - * - * @param testItemId {@link TestItem#uuid} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - * @return {@link TestItemResource} - */ - TestItemResource getTestItem(String testItemId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); - - /** - * Gets {@link TestItem} instances - * - * @param filter {@link Filter} - * @param pageable {@link Pageable} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - * @return {@link Iterable} of the {@link TestItemResource} - */ - Iterable<TestItemResource> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, @Nullable Long launchId, @Nullable Long filterId, boolean isLatest, int launchesLimit); - - /** - * Gets {@link TestItem} instances - * - * @param filter {@link Filter} - * @param pageable {@link Pageable} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - * @return {@link Iterable} of the {@link TestItemResource} - */ - Iterable<TestItemResource> getTestItemsByProvider(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params); - - /** - * Gets accumulated statistics of items by data provider - * - * @param filter {@link Filter} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @return Accumulated statistics - */ - StatisticsResource getStatisticsByProvider(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> providerParams); - - /** - * Get tickets that contains a term as a part inside for specified launch - * - * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} - * @param term part of {@link com.epam.ta.reportportal.entity.bts.Ticket#ticketId} to search - * @return {@link List} of {@link com.epam.ta.reportportal.entity.bts.Ticket#ticketId} - */ - List<String> getTicketIds(Long launchId, String term); - - /** - * Get tickets that contains a term as a part inside for specified project - * - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param term part of {@link Ticket#getTicketId()} to search - * @return {@link List} of {@link Ticket#getTicketId()} - */ - List<String> getTicketIds(ReportPortalUser.ProjectDetails projectDetails, String term); - - /** - * Get specified attribute keys of all test items and launches for project with provided id - * - * @param launchFilterId {@link UserFilter#getId()} fo the {@link com.epam.ta.reportportal.commons.querygen.FilterTarget#LAUNCH_TARGET} - * @param isLatest Flag defines whether all or latest launches launches will be included in the query condition - * @param launchesLimit Launches limit - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - * @param keyPart Part of the {@link ItemAttribute#getKey()} to search - * @return {@link List} of the {@link ItemAttribute#getKey()} - */ - List<String> getAttributeKeys(Long launchFilterId, boolean isLatest, int launchesLimit, ReportPortalUser.ProjectDetails projectDetails, - String keyPart); - - /** - * Get specified attribute keys - * - * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} - * @param value part of the {@link com.epam.ta.reportportal.entity.ItemAttribute#key} to search - * @return {@link List} of the {@link com.epam.ta.reportportal.entity.ItemAttribute#key} - */ - List<String> getAttributeKeys(Long launchId, String value); - - /** - * Get specified attribute values - * - * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} - * @param value part of the {@link com.epam.ta.reportportal.entity.ItemAttribute#value} to search - * @return {@link List} of the {@link com.epam.ta.reportportal.entity.ItemAttribute#value} - */ - List<String> getAttributeValues(Long launchId, String key, String value); - - /** - * Get attributes keys of test items under launches with provided name - * under {@link com.epam.ta.reportportal.entity.project.Project} specified by `projectDetails` - * - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param launchName {@link Launch#getName()} - * @param keyPart part of the {@link ItemAttribute#getKey()} to search - * @return {@link List} of the {@link ItemAttribute#getKey()} - */ - List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, String launchName, String keyPart); - - /** - * Get attributes values of test items under launches with provided name - * under {@link com.epam.ta.reportportal.entity.project.Project} specified by `projectDetails` - * - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param launchName {@link Launch#getName()} - * @param key {@link ItemAttribute#getKey()} - * @param valuePart part of the {@link ItemAttribute#getValue()} to search - * @return {@link List} of the {@link ItemAttribute#getValue()} - */ - List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String launchName, String key, String valuePart); - - /** - * @param ids array of the {@link com.epam.ta.reportportal.entity.launch.Launch#id} - * @return {@link List} of the {@link TestItemResource} - */ - List<TestItemResource> getTestItems(Long[] ids, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Get {@link TestItem} instance + * + * @param testItemId {@link TestItem#uuid} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @return {@link TestItemResource} + */ + TestItemResource getTestItem(String testItemId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); + + /** + * Gets {@link TestItem} instances + * + * @param filter {@link Filter} + * @param pageable {@link Pageable} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @param launchId Launch id + * @param filterId Filter id + * @param isLatest true if + * @param launchesLimit response limit + * @return {@link Iterable} of the {@link TestItemResource} + */ + Iterable<TestItemResource> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, @Nullable Long launchId, @Nullable Long filterId, boolean isLatest, + int launchesLimit); + + /** + * Gets {@link TestItem} instances + * + * @param filter {@link Filter} + * @param pageable {@link Pageable} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @return {@link Iterable} of the {@link TestItemResource} + */ + Iterable<TestItemResource> getTestItemsByProvider(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params); + + /** + * Gets accumulated statistics of items by data provider + * + * @param filter {@link Filter} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @return Accumulated statistics + */ + StatisticsResource getStatisticsByProvider(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> providerParams); + + /** + * Get tickets that contains a term as a part inside for specified launch + * + * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} + * @param term part of {@link com.epam.ta.reportportal.entity.bts.Ticket#ticketId} to search + * @return {@link List} of {@link com.epam.ta.reportportal.entity.bts.Ticket#ticketId} + */ + List<String> getTicketIds(Long launchId, String term); + + /** + * Get tickets that contains a term as a part inside for specified project + * + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param term part of {@link Ticket#getTicketId()} to search + * @return {@link List} of {@link Ticket#getTicketId()} + */ + List<String> getTicketIds(ReportPortalUser.ProjectDetails projectDetails, String term); + + /** + * Get specified attribute keys of all test items and launches for project with provided id + * + * @param launchFilterId {@link UserFilter#getId()} fo the + * {@link + * com.epam.ta.reportportal.commons.querygen.FilterTarget#LAUNCH_TARGET} + * @param isLatest Flag defines whether all or latest launches launches will be included in + * the query condition + * @param launchesLimit Launches limit + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param keyPart Part of the {@link ItemAttribute#getKey()} to search + * @return {@link List} of the {@link ItemAttribute#getKey()} + */ + List<String> getAttributeKeys(Long launchFilterId, boolean isLatest, int launchesLimit, + ReportPortalUser.ProjectDetails projectDetails, + String keyPart); + + /** + * Get specified attribute keys + * + * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} + * @param value part of the {@link com.epam.ta.reportportal.entity.ItemAttribute#key} to + * search + * @return {@link List} of the {@link com.epam.ta.reportportal.entity.ItemAttribute#key} + */ + List<String> getAttributeKeys(Long launchId, String value); + + /** + * Get specified attribute values + * + * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} + * @param key Attribute key to search + * @param value part of the {@link com.epam.ta.reportportal.entity.ItemAttribute#value} to + * search + * @return {@link List} of the {@link com.epam.ta.reportportal.entity.ItemAttribute#value} + */ + List<String> getAttributeValues(Long launchId, String key, String value); + + /** + * Get attributes keys of test items under launches with provided name under + * {@link com.epam.ta.reportportal.entity.project.Project} specified by `projectDetails` + * + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param launchName {@link Launch#getName()} + * @param keyPart part of the {@link ItemAttribute#getKey()} to search + * @return {@link List} of the {@link ItemAttribute#getKey()} + */ + List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, String launchName, + String keyPart); + + /** + * Get attributes values of test items under launches with provided name under + * {@link com.epam.ta.reportportal.entity.project.Project} specified by `projectDetails` + * + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param launchName {@link Launch#getName()} + * @param key {@link ItemAttribute#getKey()} + * @param valuePart part of the {@link ItemAttribute#getValue()} to search + * @return {@link List} of the {@link ItemAttribute#getValue()} + */ + List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String launchName, + String key, String valuePart); + + /** + * @param ids array of the {@link com.epam.ta.reportportal.entity.launch.Launch#id} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @return {@link List} of the {@link TestItemResource} + */ + List<TestItemResource> getTestItems(Long[] ids, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/StartTestItemHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/StartTestItemHandler.java index 0ff27ea33e..af72cf97a3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/StartTestItemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/StartTestItemHandler.java @@ -27,21 +27,26 @@ */ public interface StartTestItemHandler { - /** - * Start Root item operation - * - * @param projectDetails Project Details - * @param rq Item details - * @return ItemID and uniqueID of test item - */ - ItemCreatedRS startRootItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq); + /** + * Start Root item operation + * + * @param user {@link ReportPortalUser} + * @param projectDetails Project Details + * @param rq Item details + * @return ItemID and uniqueID of test item + */ + ItemCreatedRS startRootItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, + StartTestItemRQ rq); - /** - * Start child item operation - * - * @param projectDetails Project Details - * @param rq Item details - * @return ItemID and uniqueID of test item - */ - ItemCreatedRS startChildItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq, String parentId); + /** + * Start child item operation + * + * @param user {@link ReportPortalUser} + * @param projectDetails Project Details + * @param rq Item details + * @param parentId Id of parrent test item + * @return ItemID and uniqueID of test item + */ + ItemCreatedRS startChildItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq, String parentId); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/TestItemService.java b/src/main/java/com/epam/ta/reportportal/core/item/TestItemService.java index b271b1f7cd..3a35654534 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/TestItemService.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/TestItemService.java @@ -16,50 +16,51 @@ package com.epam.ta.reportportal.core.item; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Optional; - -import static java.util.Optional.ofNullable; - /** * @author Konstantin Antipin */ @Service public class TestItemService { - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - @Autowired - public TestItemService(TestItemRepository testItemRepository, LaunchRepository launchRepository) { - this.testItemRepository = testItemRepository; - this.launchRepository = launchRepository; - } + @Autowired + public TestItemService(TestItemRepository testItemRepository, LaunchRepository launchRepository) { + this.testItemRepository = testItemRepository; + this.launchRepository = launchRepository; + } - public Launch getEffectiveLaunch(TestItem testItem) { + public Launch getEffectiveLaunch(TestItem testItem) { - return ofNullable(testItem.getRetryOf()).map(retryParentId -> { - TestItem retryParent = testItemRepository.findById(retryParentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, testItem.getRetryOf())); - return getLaunch(retryParent); - }).orElseGet(() -> getLaunch(testItem)).orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND)); - } + return ofNullable(testItem.getRetryOf()).map(retryParentId -> { + TestItem retryParent = testItemRepository.findById(retryParentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, + testItem.getRetryOf())); + return getLaunch(retryParent); + }).orElseGet(() -> getLaunch(testItem)) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND)); + } - private Optional<Launch> getLaunch(TestItem testItem) { - return ofNullable(testItem.getLaunchId()).map(launchRepository::findById) - .orElseGet(() -> ofNullable(testItem.getParentId()).flatMap(testItemRepository::findById) - .map(TestItem::getLaunchId) - .map(launchRepository::findById) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND))); - } + private Optional<Launch> getLaunch(TestItem testItem) { + return ofNullable(testItem.getLaunchId()).map(launchRepository::findById) + .orElseGet(() -> ofNullable(testItem.getParentId()).flatMap(testItemRepository::findById) + .map(TestItem::getLaunchId) + .map(launchRepository::findById) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND))); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/UpdateTestItemHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/UpdateTestItemHandler.java index c8a1870baa..8cb6dcbac9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/UpdateTestItemHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/UpdateTestItemHandler.java @@ -23,7 +23,6 @@ import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.item.ExternalIssueRQ; import com.epam.ta.reportportal.ws.model.item.UpdateTestItemRQ; - import java.util.List; /** @@ -33,46 +32,53 @@ */ public interface UpdateTestItemHandler { - /** - * Define TestItem issue (or list of issues) - * - * @param projectDetails Project Details - * @param defineIssue issues request data - * @param user user - * @return list of defined issues for specified test items - */ - List<Issue> defineTestItemsIssues(ReportPortalUser.ProjectDetails projectDetails, DefineIssueRQ defineIssue, ReportPortalUser user); + /** + * Define TestItem issue (or list of issues) + * + * @param projectDetails Project Details + * @param defineIssue issues request data + * @param user user + * @return list of defined issues for specified test items + */ + List<Issue> defineTestItemsIssues(ReportPortalUser.ProjectDetails projectDetails, + DefineIssueRQ defineIssue, ReportPortalUser user); - /** - * Update specified test item - * - * @param projectDetails Project Details - * @param itemId test item ID - * @param rq update test item request data - * @param user request principal name - * @return OperationCompletionRS - */ - OperationCompletionRS updateTestItem(ReportPortalUser.ProjectDetails projectDetails, Long itemId, UpdateTestItemRQ rq, - ReportPortalUser user); + /** + * Update specified test item + * + * @param projectDetails Project Details + * @param itemId test item ID + * @param rq update test item request data + * @param user request principal name + * @return OperationCompletionRS + */ + OperationCompletionRS updateTestItem(ReportPortalUser.ProjectDetails projectDetails, Long itemId, + UpdateTestItemRQ rq, + ReportPortalUser user); - /** - * Add or remove external system issue link directly to the {@link com.epam.ta.reportportal.entity.item.TestItem} - * - * @param request {@link ExternalIssueRQ} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - * @return {@link List} of the {@link OperationCompletionRS} - */ - List<OperationCompletionRS> processExternalIssues(ExternalIssueRQ request, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Add or remove external system issue link directly to the + * {@link com.epam.ta.reportportal.entity.item.TestItem} + * + * @param request {@link ExternalIssueRQ} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + * @return {@link List} of the {@link OperationCompletionRS} + */ + List<OperationCompletionRS> processExternalIssues(ExternalIssueRQ request, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Resets items issue to default state - * - * @param itemIds The {@link List} of the {@link com.epam.ta.reportportal.entity.item.TestItemResults#itemId} - * @param projectId Project id - */ - void resetItemsIssue(List<Long> itemIds, Long projectId, ReportPortalUser user); + /** + * Resets items issue to default state + * + * @param itemIds The {@link List} of the + * {@link com.epam.ta.reportportal.entity.item.TestItemResults#itemId} + * @param projectId Project id + * @param user {@link ReportPortalUser} + */ + void resetItemsIssue(List<Long> itemIds, Long projectId, ReportPortalUser user); - OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, ReportPortalUser.ProjectDetails projectDetails); + OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, + ReportPortalUser.ProjectDetails projectDetails); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/UpdateUniqueId.java b/src/main/java/com/epam/ta/reportportal/core/item/UpdateUniqueId.java index 3cfb987f0f..96a07e9194 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/UpdateUniqueId.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/UpdateUniqueId.java @@ -25,191 +25,191 @@ */ @Service class UpdateUniqueId { - // - // private static final Logger LOGGER = LoggerFactory.getLogger(UpdateUniqueId.class); - // - // private static final String COLLECTION = "generationCheckpoint"; - // private static final String CHECKPOINT = "checkpoint"; - // private static final String CHECKPOINT_ID = "testItemId"; - // - // private static final int BATCH_SIZE = 100; - // - // private static final String SECRET = "auto:"; - // - // //launches cache - // private static final Cache<String, Launch> launchCache = Caffeine.newBuilder().maximumSize(200).build(); - // - // @Autowired - // private MongoOperations mongoOperations; - // - // @Autowired - // private TestItemRepository testItemRepository; - // - // private static final AtomicBoolean STARTED = new AtomicBoolean(); - // - // @EventListener - // public void onContextRefresh(ContextRefreshedEvent event) { - // if (STARTED.compareAndSet(false, true)) { - // if (mongoOperations.collectionExists(COLLECTION)) { - // Executors.newSingleThreadExecutor().execute(this::generateForAll); - // } - // } - // } - // - // private void generateForAll() { - // long forUpdate = mongoOperations.count(testItemQuery(), TestItem.class); - // long update = 0; - // boolean isOk; - // String checkpoint = getLastCheckpoint(); - // //potential endless loop - // do { - // try (CloseableIterator<TestItem> itemIterator = getItemIterator(checkpoint)) { - // List<TestItem> testItems = new ArrayList<>(BATCH_SIZE); - // int counter = 0; - // while (itemIterator.hasNext()) { - // TestItem testItem = itemIterator.next(); - // if (testItem != null) { - // boolean isRemoved = removeIfInvalid(testItem); - // if (!isRemoved) { - // if (checkpoint == null) { - // checkpoint = testItem.getId(); - // } - // String uniqueId = generate(testItem); - // testItem.setUniqueId(uniqueId); - // testItems.add(testItem); - // if (testItems.size() == BATCH_SIZE || !itemIterator.hasNext()) { - // createCheckpoint(checkpoint); - // updateTestItems(testItems); - // counter++; - // if (counter == 1000) { - // LOGGER.info("Generated uniqueId for " + update + " items. " + "It is " + ((update / (float) forUpdate) - // * 100) + "% done"); - // counter = 0; - // } - // update += testItems.size(); - // testItems = new ArrayList<>(BATCH_SIZE); - // checkpoint = null; - // } - // } - // } - // } - // isOk = true; - // } catch (Exception e) { - // LOGGER.warn("Potential endless loop in reason of: ", e); - // //continue generating uniqueId - // isOk = false; - // } - // } while (!isOk); - // STARTED.set(false); - // mongoOperations.getCollection(COLLECTION).drop(); - // launchCache.cleanUp(); - // LOGGER.info("Generating uniqueId is done!"); - // indexUniqueIds(); - // - // } - // - // private void indexUniqueIds() { - // mongoOperations.indexOps(mongoOperations.getCollectionName(TestItem.class)) - // .ensureIndex(new Index().on("uniqueId", Sort.Direction.ASC)); - // } - // - // private void updateTestItems(List<TestItem> testItems) { - // BulkOperations bulk = mongoOperations.bulkOps(BulkOperations.BulkMode.UNORDERED, TestItem.class); - // testItems.forEach(it -> { - // Update update = new Update(); - // update.set("uniqueId", it.getUniqueId()); - // bulk.updateOne(query(where("_id").is(it.getId())), update); - // }); - // bulk.execute(); - // } - // - // private boolean removeIfInvalid(TestItem item) { - // String launchRef = item.getLaunchRef(); - // if (launchRef == null) { - // mongoOperations.remove(query(where("_id").is(item.getId()))); - // } - // - // Launch launch = mongoOperations.findOne(launchQuery(launchRef), Launch.class); - // if (launch == null) { - // testItemRepository.delete(item.getId()); - // return true; - // } else { - // boolean exists = mongoOperations.exists(query(where("_id").is(launch.getProjectRef())), Project.class); - // if (!exists) { - // mongoOperations.remove(query(where("_id").is(launchRef)), Launch.class); - // return true; - // } - // } - // return false; - // } - // - // public String generate(TestItem testItem) { - // String forEncoding = prepareForEncoding(testItem); - // return SECRET + DigestUtils.md5Hex(forEncoding); - // } - // - // private String prepareForEncoding(TestItem testItem) { - // // using cache for launches - // Launch launch = launchCache.get(testItem.getLaunchRef(), - // k -> mongoOperations.findOne(launchQuery(testItem.getLaunchRef()), Launch.class) - // ); - // - // String launchName = launch.getName(); - // String projectName = launch.getProjectRef(); - // - // List<String> pathNames = getPathNames(testItem.getPath()); - // String itemName = testItem.getName(); - // StringJoiner joiner = new StringJoiner(";"); - // joiner.add(SECRET).add(projectName).add(launchName); - // if (!CollectionUtils.isEmpty(pathNames)) { - // joiner.add(pathNames.stream().collect(Collectors.joining(","))); - // } - // joiner.add(itemName); - // List<Parameter> parameters = testItem.getParameters(); - // if (!CollectionUtils.isEmpty(parameters)) { - // joiner.add(parameters.stream() - // .map(parameter -> (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + parameter.getValue()) - // .collect(Collectors.joining(","))); - // } - // return joiner.toString(); - // } - // - // private CloseableIterator<TestItem> getItemIterator(String checkpoint) { - // Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC, "_id")); - // Query query = new Query().with(sort).noCursorTimeout(); - // if (checkpoint != null) { - // query.addCriteria(where("_id").gte(new ObjectId(checkpoint))); - // } - // query.fields().include("name").include("path").include("launchRef").include("parameters"); - // return mongoOperations.stream(query, TestItem.class); - // } - // - // private List<String> getPathNames(List<String> path) { - // Map<String, String> names = testItemRepository.findPathNames(path); - // return path.stream().map(names::get).collect(Collectors.toList()); - // } - // - // private Query launchQuery(String launchId) { - // Query query = query((where("_id").is(launchId))); - // query.fields().include("name"); - // query.fields().include("projectRef"); - // return query; - // } - // - // private Query testItemQuery() { - // Query query = new Query(); - // query.fields().include("name").include("path").include("launchRef").include("parameters"); - // return query; - // } - // - // private String getLastCheckpoint() { - // DBObject checkpoint = mongoOperations.getCollection(COLLECTION).findOne(new BasicDBObject("_id", CHECKPOINT)); - // return checkpoint == null ? null : (String) checkpoint.get(CHECKPOINT_ID); - // } - // - // private void createCheckpoint(String logId) { - // BasicDBObject checkpoint = new BasicDBObject("_id", CHECKPOINT).append(CHECKPOINT_ID, logId); - // mongoOperations.getCollection(COLLECTION).save(checkpoint); - // } + // + // private static final Logger LOGGER = LoggerFactory.getLogger(UpdateUniqueId.class); + // + // private static final String COLLECTION = "generationCheckpoint"; + // private static final String CHECKPOINT = "checkpoint"; + // private static final String CHECKPOINT_ID = "testItemId"; + // + // private static final int BATCH_SIZE = 100; + // + // private static final String SECRET = "auto:"; + // + // //launches cache + // private static final Cache<String, Launch> launchCache = Caffeine.newBuilder().maximumSize(200).build(); + // + // @Autowired + // private MongoOperations mongoOperations; + // + // @Autowired + // private TestItemRepository testItemRepository; + // + // private static final AtomicBoolean STARTED = new AtomicBoolean(); + // + // @EventListener + // public void onContextRefresh(ContextRefreshedEvent event) { + // if (STARTED.compareAndSet(false, true)) { + // if (mongoOperations.collectionExists(COLLECTION)) { + // Executors.newSingleThreadExecutor().execute(this::generateForAll); + // } + // } + // } + // + // private void generateForAll() { + // long forUpdate = mongoOperations.count(testItemQuery(), TestItem.class); + // long update = 0; + // boolean isOk; + // String checkpoint = getLastCheckpoint(); + // //potential endless loop + // do { + // try (CloseableIterator<TestItem> itemIterator = getItemIterator(checkpoint)) { + // List<TestItem> testItems = new ArrayList<>(BATCH_SIZE); + // int counter = 0; + // while (itemIterator.hasNext()) { + // TestItem testItem = itemIterator.next(); + // if (testItem != null) { + // boolean isRemoved = removeIfInvalid(testItem); + // if (!isRemoved) { + // if (checkpoint == null) { + // checkpoint = testItem.getId(); + // } + // String uniqueId = generate(testItem); + // testItem.setUniqueId(uniqueId); + // testItems.add(testItem); + // if (testItems.size() == BATCH_SIZE || !itemIterator.hasNext()) { + // createCheckpoint(checkpoint); + // updateTestItems(testItems); + // counter++; + // if (counter == 1000) { + // LOGGER.info("Generated uniqueId for " + update + " items. " + "It is " + ((update / (float) forUpdate) + // * 100) + "% done"); + // counter = 0; + // } + // update += testItems.size(); + // testItems = new ArrayList<>(BATCH_SIZE); + // checkpoint = null; + // } + // } + // } + // } + // isOk = true; + // } catch (Exception e) { + // LOGGER.warn("Potential endless loop in reason of: ", e); + // //continue generating uniqueId + // isOk = false; + // } + // } while (!isOk); + // STARTED.set(false); + // mongoOperations.getCollection(COLLECTION).drop(); + // launchCache.cleanUp(); + // LOGGER.info("Generating uniqueId is done!"); + // indexUniqueIds(); + // + // } + // + // private void indexUniqueIds() { + // mongoOperations.indexOps(mongoOperations.getCollectionName(TestItem.class)) + // .ensureIndex(new Index().on("uniqueId", Sort.Direction.ASC)); + // } + // + // private void updateTestItems(List<TestItem> testItems) { + // BulkOperations bulk = mongoOperations.bulkOps(BulkOperations.BulkMode.UNORDERED, TestItem.class); + // testItems.forEach(it -> { + // Update update = new Update(); + // update.set("uniqueId", it.getUniqueId()); + // bulk.updateOne(query(where("_id").is(it.getId())), update); + // }); + // bulk.execute(); + // } + // + // private boolean removeIfInvalid(TestItem item) { + // String launchRef = item.getLaunchRef(); + // if (launchRef == null) { + // mongoOperations.remove(query(where("_id").is(item.getId()))); + // } + // + // Launch launch = mongoOperations.findOne(launchQuery(launchRef), Launch.class); + // if (launch == null) { + // testItemRepository.delete(item.getId()); + // return true; + // } else { + // boolean exists = mongoOperations.exists(query(where("_id").is(launch.getProjectRef())), Project.class); + // if (!exists) { + // mongoOperations.remove(query(where("_id").is(launchRef)), Launch.class); + // return true; + // } + // } + // return false; + // } + // + // public String generate(TestItem testItem) { + // String forEncoding = prepareForEncoding(testItem); + // return SECRET + DigestUtils.md5Hex(forEncoding); + // } + // + // private String prepareForEncoding(TestItem testItem) { + // // using cache for launches + // Launch launch = launchCache.get(testItem.getLaunchRef(), + // k -> mongoOperations.findOne(launchQuery(testItem.getLaunchRef()), Launch.class) + // ); + // + // String launchName = launch.getName(); + // String projectName = launch.getProjectRef(); + // + // List<String> pathNames = getPathNames(testItem.getPath()); + // String itemName = testItem.getName(); + // StringJoiner joiner = new StringJoiner(";"); + // joiner.add(SECRET).add(projectName).add(launchName); + // if (!CollectionUtils.isEmpty(pathNames)) { + // joiner.add(pathNames.stream().collect(Collectors.joining(","))); + // } + // joiner.add(itemName); + // List<Parameter> parameters = testItem.getParameters(); + // if (!CollectionUtils.isEmpty(parameters)) { + // joiner.add(parameters.stream() + // .map(parameter -> (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + parameter.getValue()) + // .collect(Collectors.joining(","))); + // } + // return joiner.toString(); + // } + // + // private CloseableIterator<TestItem> getItemIterator(String checkpoint) { + // Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC, "_id")); + // Query query = new Query().with(sort).noCursorTimeout(); + // if (checkpoint != null) { + // query.addCriteria(where("_id").gte(new ObjectId(checkpoint))); + // } + // query.fields().include("name").include("path").include("launchRef").include("parameters"); + // return mongoOperations.stream(query, TestItem.class); + // } + // + // private List<String> getPathNames(List<String> path) { + // Map<String, String> names = testItemRepository.findPathNames(path); + // return path.stream().map(names::get).collect(Collectors.toList()); + // } + // + // private Query launchQuery(String launchId) { + // Query query = query((where("_id").is(launchId))); + // query.fields().include("name"); + // query.fields().include("projectRef"); + // return query; + // } + // + // private Query testItemQuery() { + // Query query = new Query(); + // query.fields().include("name").include("path").include("launchRef").include("parameters"); + // return query; + // } + // + // private String getLastCheckpoint() { + // DBObject checkpoint = mongoOperations.getCollection(COLLECTION).findOne(new BasicDBObject("_id", CHECKPOINT)); + // return checkpoint == null ? null : (String) checkpoint.get(CHECKPOINT_ID); + // } + // + // private void createCheckpoint(String logId) { + // BasicDBObject checkpoint = new BasicDBObject("_id", CHECKPOINT).append(CHECKPOINT_ID, logId); + // mongoOperations.getCollection(COLLECTION).save(checkpoint); + // } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/history/ITestItemsHistoryService.java b/src/main/java/com/epam/ta/reportportal/core/item/history/ITestItemsHistoryService.java index 011bdafe9b..5df86ae3cb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/history/ITestItemsHistoryService.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/history/ITestItemsHistoryService.java @@ -19,49 +19,49 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.TestItemHistoryElement; - import java.util.List; /** - * Define interface for loading and validating additional data( launches and - * test Items) which should be used for loading test items history. + * Define interface for loading and validating additional data( launches and test Items) which + * should be used for loading test items history. * * @author Aliaksei_Makayed */ public interface ITestItemsHistoryService { - /** - * Load launches for which history should be loaded - * - * @param quantity - count items in history - * @param startingLaunchId - first initial launch in history - * @param projectName - name of project - * @param showBrokenLaunches - <b>boolean</b> should in_progress and interrupted launches - * been included in history:<br> - * <code>true</code> - if history should contain all launch - * statuses<br> - * <code>false</code> - if history should contain only passed and - * failed launches - * @return - */ - List<Launch> loadLaunches(int quantity, Long startingLaunchId, String projectName, boolean showBrokenLaunches); + /** + * Load launches for which history should be loaded + * + * @param quantity - count items in history + * @param startingLaunchId - first initial launch in history + * @param projectName - name of project + * @param showBrokenLaunches - <b>boolean</b> should in_progress and interrupted launches been + * included in history:<br> + * <code>true</code> - if history should contain all launch + * statuses<br> + * <code>false</code> - if history should contain only passed and + * failed launches + * @return {@link List} of {@link Launch} - list of founded launches + */ + List<Launch> loadLaunches(int quantity, Long startingLaunchId, String projectName, + boolean showBrokenLaunches); - /** - * Build ui representation of launch history - * - * @param launch History launch - * @param testItems History test items - * @return {@link TestItemHistoryElement} - */ - TestItemHistoryElement buildHistoryElement(Launch launch, List<TestItem> testItems); + /** + * Build ui representation of launch history + * + * @param launch History launch + * @param testItems History test items + * @return {@link TestItemHistoryElement} + */ + TestItemHistoryElement buildHistoryElement(Launch launch, List<TestItem> testItems); - /** - * Validate size of history depth - * - * @param historyDepth history depth - */ - void validateHistoryDepth(int historyDepth); + /** + * Validate size of history depth + * + * @param historyDepth history depth + */ + void validateHistoryDepth(int historyDepth); - void validateItems(List<TestItem> itemsForHistory, List<String> ids, String projectName); + void validateItems(List<TestItem> itemsForHistory, List<String> ids, String projectName); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/history/TestItemsHistoryHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/history/TestItemsHistoryHandler.java index 55ddbd4b1b..0b6ccb81cd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/history/TestItemsHistoryHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/history/TestItemsHistoryHandler.java @@ -18,8 +18,8 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Queryable; -import com.epam.ta.reportportal.ws.model.TestItemHistoryElement; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; +import com.epam.ta.reportportal.ws.model.TestItemHistoryElement; import org.springframework.data.domain.Pageable; /** @@ -29,17 +29,19 @@ */ public interface TestItemsHistoryHandler { - /** - * Get history for {@link com.epam.ta.reportportal.entity.item.TestItem}s according to input parameters - * - * @param projectDetails - project details - * @param filter - filter - * @param pageable - paging parameters object - * @param historyRequestParams - {@link HistoryRequestParams} - * @param user - {@link ReportPortalUser} - * @return {@link Iterable} of {@link TestItemHistoryElement} - */ - Iterable<TestItemHistoryElement> getItemsHistory(ReportPortalUser.ProjectDetails projectDetails, Queryable filter, Pageable pageable, - HistoryRequestParams historyRequestParams, ReportPortalUser user); + /** + * Get history for {@link com.epam.ta.reportportal.entity.item.TestItem}s according to input + * parameters + * + * @param projectDetails - project details + * @param filter - filter + * @param pageable - paging parameters object + * @param historyRequestParams - {@link HistoryRequestParams} + * @param user - {@link ReportPortalUser} + * @return {@link Iterable} of {@link TestItemHistoryElement} + */ + Iterable<TestItemHistoryElement> getItemsHistory(ReportPortalUser.ProjectDetails projectDetails, + Queryable filter, Pageable pageable, + HistoryRequestParams historyRequestParams, ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/identity/IdentityUtil.java b/src/main/java/com/epam/ta/reportportal/core/item/identity/IdentityUtil.java index a6e1367e04..225c02851d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/identity/IdentityUtil.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/identity/IdentityUtil.java @@ -3,7 +3,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -13,48 +12,50 @@ */ public class IdentityUtil { - private IdentityUtil() { - //static only - } - - /** - * Parse {@link TestItem#getPath()} and get all ids excluding id of the provided {@link TestItem} - * - * @param testItem {@link TestItem} - * @return {@link List} with ids parsed from {@link TestItem#getPath()} - */ - public static List<Long> getParentIds(TestItem testItem) { - return getIds(testItem.getPath(), false); - } - - /** - * * Parse {@link TestItem#getPath()} and get all ids including id of the provided {@link TestItem} - * - * @param testItem {@link TestItem} - * @return {@link List} with ids parsed from {@link TestItem#getPath()} - */ - public static List<Long> getItemTreeIds(TestItem testItem) { - return getIds(testItem.getPath(), true); - } - - /** - * * Parse {@link TestItem#getPath()} and get all ids including id of the provided {@link TestItem} - * - * @param path {@link TestItem#getPath()} - * @return {@link List} with ids parsed from {@link TestItem#getPath()} - */ - public static List<Long> getItemTreeIds(String path) { - return getIds(path, true); - } - - private static List<Long> getIds(String path, boolean includeLast) { - String[] ids = path.split("\\."); - return Stream.of(ids).limit(includeLast ? ids.length : ids.length - 1).map(id -> { - try { - return Long.parseLong(id); - } catch (NumberFormatException e) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Incorrect path value: " + id); - } - }).collect(Collectors.toList()); - } + private IdentityUtil() { + //static only + } + + /** + * Parse {@link TestItem#getPath()} and get all ids excluding id of the provided {@link TestItem} + * + * @param testItem {@link TestItem} + * @return {@link List} with ids parsed from {@link TestItem#getPath()} + */ + public static List<Long> getParentIds(TestItem testItem) { + return getIds(testItem.getPath(), false); + } + + /** + * * Parse {@link TestItem#getPath()} and get all ids including id of the provided + * {@link TestItem} + * + * @param testItem {@link TestItem} + * @return {@link List} with ids parsed from {@link TestItem#getPath()} + */ + public static List<Long> getItemTreeIds(TestItem testItem) { + return getIds(testItem.getPath(), true); + } + + /** + * * Parse {@link TestItem#getPath()} and get all ids including id of the provided + * {@link TestItem} + * + * @param path {@link TestItem#getPath()} + * @return {@link List} with ids parsed from {@link TestItem#getPath()} + */ + public static List<Long> getItemTreeIds(String path) { + return getIds(path, true); + } + + private static List<Long> getIds(String path, boolean includeLast) { + String[] ids = path.split("\\."); + return Stream.of(ids).limit(includeLast ? ids.length : ids.length - 1).map(id -> { + try { + return Long.parseLong(id); + } catch (NumberFormatException e) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Incorrect path value: " + id); + } + }).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGenerator.java b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGenerator.java index 6080561d1b..2c1db6258a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGenerator.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.item.identity; import com.epam.ta.reportportal.entity.item.TestItem; - import java.util.List; /** @@ -25,5 +24,5 @@ */ public interface TestCaseHashGenerator { - Integer generate(TestItem item, List<Long> parentIds, Long projectId); + Integer generate(TestItem item, List<Long> parentIds, Long projectId); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGeneratorImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGeneratorImpl.java index b0d54e665a..70837272e5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGeneratorImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestCaseHashGeneratorImpl.java @@ -20,12 +20,11 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.google.api.client.util.Lists; import com.google.common.base.Strings; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; - import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -33,36 +32,38 @@ @Service public class TestCaseHashGeneratorImpl implements TestCaseHashGenerator { - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - public TestCaseHashGeneratorImpl(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } + public TestCaseHashGeneratorImpl(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } - @Override - public Integer generate(TestItem item, List<Long> parentIds, Long projectId) { - return prepare(item, parentIds, projectId).hashCode(); - } + @Override + public Integer generate(TestItem item, List<Long> parentIds, Long projectId) { + return prepare(item, parentIds, projectId).hashCode(); + } - private String prepare(TestItem item, List<Long> parentIds, Long projectId) { - List<CharSequence> elements = Lists.newArrayList(); + private String prepare(TestItem item, List<Long> parentIds, Long projectId) { + List<CharSequence> elements = Lists.newArrayList(); - elements.add(projectId.toString()); - getPathNames(parentIds).stream().filter(StringUtils::isNotEmpty).forEach(elements::add); - elements.add(item.getName()); - item.getParameters() - .stream() - .map(parameter -> (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + parameter.getValue()) - .forEach(elements::add); + elements.add(projectId.toString()); + getPathNames(parentIds).stream().filter(StringUtils::isNotEmpty).forEach(elements::add); + elements.add(item.getName()); + item.getParameters() + .stream() + .map(parameter -> + (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + + parameter.getValue()) + .forEach(elements::add); - return String.join(";", elements); - } + return String.join(";", elements); + } - private List<String> getPathNames(List<Long> parentIds) { - return testItemRepository.findAllById(parentIds) - .stream() - .sorted(Comparator.comparingLong(TestItem::getItemId)) - .map(TestItem::getName) - .collect(Collectors.toList()); - } + private List<String> getPathNames(List<Long> parentIds) { + return testItemRepository.findAllById(parentIds) + .stream() + .sorted(Comparator.comparingLong(TestItem::getItemId)) + .map(TestItem::getName) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestItemUniqueIdGenerator.java b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestItemUniqueIdGenerator.java index 7ef810967e..ac1cad69ed 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/identity/TestItemUniqueIdGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/identity/TestItemUniqueIdGenerator.java @@ -21,73 +21,73 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.google.common.base.Strings; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** - * Generates the unique identifier for test item based - * on Base64 encoding and includes information about project, - * name of item's launch, full path of item's parent names, - * item name and parameters. + * Generates the unique identifier for test item based on Base64 encoding and includes information + * about project, name of item's launch, full path of item's parent names, item name and + * parameters. * * @author Pavel_Bortnik */ @Service public class TestItemUniqueIdGenerator implements UniqueIdGenerator { - private static final String TRAIT = "auto:"; + private static final String TRAIT = "auto:"; - private TestItemRepository testItemRepository; + private TestItemRepository testItemRepository; - @Autowired - public void setTestItemRepository(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } + @Autowired + public void setTestItemRepository(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } - @Override - public String generate(TestItem testItem, List<Long> parentIds, Launch launch) { - String forEncoding = prepareForEncoding(testItem, parentIds, launch); - return TRAIT + DigestUtils.md5Hex(forEncoding); - } + @Override + public String generate(TestItem testItem, List<Long> parentIds, Launch launch) { + String forEncoding = prepareForEncoding(testItem, parentIds, launch); + return TRAIT + DigestUtils.md5Hex(forEncoding); + } - @Override - public boolean validate(String encoded) { - return !Strings.isNullOrEmpty(encoded) && encoded.startsWith(TRAIT); - } + @Override + public boolean validate(String encoded) { + return !Strings.isNullOrEmpty(encoded) && encoded.startsWith(TRAIT); + } - private String prepareForEncoding(TestItem testItem, List<Long> parentIds, Launch launch) { - Long projectId = launch.getProjectId(); - String launchName = launch.getName(); - List<String> pathNames = getPathNames(parentIds); - String itemName = testItem.getName(); - StringJoiner joiner = new StringJoiner(";"); - joiner.add(projectId.toString()).add(launchName); - if (!CollectionUtils.isEmpty(pathNames)) { - joiner.add(String.join(";", pathNames)); - } - joiner.add(itemName); - Set<Parameter> parameters = testItem.getParameters(); - if (!CollectionUtils.isEmpty(parameters)) { - joiner.add(parameters.stream() - .map(parameter -> (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + parameter.getValue()) - .collect(Collectors.joining(","))); - } - return joiner.toString(); - } + private String prepareForEncoding(TestItem testItem, List<Long> parentIds, Launch launch) { + Long projectId = launch.getProjectId(); + String launchName = launch.getName(); + List<String> pathNames = getPathNames(parentIds); + String itemName = testItem.getName(); + StringJoiner joiner = new StringJoiner(";"); + joiner.add(projectId.toString()).add(launchName); + if (!CollectionUtils.isEmpty(pathNames)) { + joiner.add(String.join(";", pathNames)); + } + joiner.add(itemName); + Set<Parameter> parameters = testItem.getParameters(); + if (!CollectionUtils.isEmpty(parameters)) { + joiner.add(parameters.stream() + .map(parameter -> + (!Strings.isNullOrEmpty(parameter.getKey()) ? parameter.getKey() + "=" : "") + + parameter.getValue()) + .collect(Collectors.joining(","))); + } + return joiner.toString(); + } - private List<String> getPathNames(List<Long> parentIds) { - return testItemRepository.findAllById(parentIds) - .stream() - .sorted(Comparator.comparingLong(TestItem::getItemId)) - .map(TestItem::getName) - .collect(Collectors.toList()); - } + private List<String> getPathNames(List<Long> parentIds) { + return testItemRepository.findAllById(parentIds) + .stream() + .sorted(Comparator.comparingLong(TestItem::getItemId)) + .map(TestItem::getName) + .collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/identity/UniqueIdGenerator.java b/src/main/java/com/epam/ta/reportportal/core/item/identity/UniqueIdGenerator.java index 5d0aea3228..2e54282f32 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/identity/UniqueIdGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/identity/UniqueIdGenerator.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; - import java.util.List; /** @@ -29,21 +28,22 @@ */ public interface UniqueIdGenerator { - /** - * Generates the unique identifier for test item - * - * @param testItem source for id - * @param parentIds all {@link TestItem} ancestors' ids - * @return unique id - */ - String generate(TestItem testItem, List<Long> parentIds, Launch launch); + /** + * Generates the unique identifier for test item + * + * @param testItem source for id + * @param launch {@link Launch} + * @param parentIds all {@link TestItem} ancestors' ids + * @return unique id + */ + String generate(TestItem testItem, List<Long> parentIds, Launch launch); - /** - * Validate if string has been generated automatically - * - * @param encoded encoded - * @return true if it has been generated automatically - */ - boolean validate(String encoded); + /** + * Validate if string has been generated automatically + * + * @param encoded encoded + * @return true if it has been generated automatically + */ + boolean validate(String encoded); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImpl.java index 8ee7e15d19..38b6dc7fb9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImpl.java @@ -16,10 +16,25 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_IS_NOT_FINISHED; +import static com.epam.ta.reportportal.ws.model.ErrorType.TEST_ITEM_IS_NOT_FINISHED; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; + +import com.epam.reportportal.events.ElementsDeletedEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; +import com.epam.ta.reportportal.core.ElementsCounterService; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.item.DeleteTestItemHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.core.remover.ContentRemover; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -35,23 +50,19 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.google.common.collect.Sets; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toSet; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; /** * Default implementation of {@link DeleteTestItemHandler} @@ -62,139 +73,180 @@ @Service public class DeleteTestItemHandlerImpl implements DeleteTestItemHandler { - private final TestItemRepository testItemRepository; - - private final ContentRemover<Long> itemContentRemover; - - private final LogIndexer logIndexer; - - private final LaunchRepository launchRepository; - - private final AttachmentRepository attachmentRepository; - - @Autowired - public DeleteTestItemHandlerImpl(TestItemRepository testItemRepository, ContentRemover<Long> itemContentRemover, LogIndexer logIndexer, LaunchRepository launchRepository, - AttachmentRepository attachmentRepository) { - this.testItemRepository = testItemRepository; - this.itemContentRemover = itemContentRemover; - this.logIndexer = logIndexer; - this.launchRepository = launchRepository; - this.attachmentRepository = attachmentRepository; - } - - @Override - public OperationCompletionRS deleteTestItem(Long itemId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - TestItem item = testItemRepository.findById(itemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); - Launch launch = launchRepository.findById(item.getLaunchId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, item.getLaunchId())); - - validate(item, launch, user, projectDetails); - Optional<Long> parentId = ofNullable(item.getParentId()); - - Set<Long> itemsForRemove = Sets.newHashSet(testItemRepository.selectAllDescendantsIds(item.getPath())); - itemsForRemove.forEach(itemContentRemover::remove); - - itemContentRemover.remove(item.getItemId()); - testItemRepository.deleteById(item.getItemId()); - - launch.setHasRetries(launchRepository.hasRetries(launch.getId())); - parentId.flatMap(testItemRepository::findById) - .ifPresent(p -> p.setHasChildren(testItemRepository.hasChildren(p.getItemId(), p.getPath()))); - - logIndexer.indexItemsRemoveAsync(projectDetails.getProjectId(), itemsForRemove); - attachmentRepository.moveForDeletionByItems(itemsForRemove); - - return COMPOSE_DELETE_RESPONSE.apply(item.getItemId()); - } - - @Override - public List<OperationCompletionRS> deleteTestItems(Collection<Long> ids, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - List<TestItem> items = testItemRepository.findAllById(ids); - - List<Launch> launches = launchRepository.findAllById(items.stream() - .map(TestItem::getLaunchId) - .filter(Objects::nonNull) - .collect(Collectors.toSet())); - Map<Long, List<TestItem>> launchItemMap = items.stream().collect(Collectors.groupingBy(TestItem::getLaunchId)); - launches.forEach(launch -> launchItemMap.get(launch.getId()).forEach(item -> validate(item, launch, user, projectDetails))); - - Map<Long, PathName> descendantsMapping = testItemRepository.selectPathNames(items); - - Set<Long> idsToDelete = Sets.newHashSet(descendantsMapping.keySet()); - - descendantsMapping.forEach((key, value) -> value.getItemPaths().forEach(ip -> { - if (idsToDelete.contains(ip.getId())) { - idsToDelete.remove(key); - } - })); - - List<TestItem> parentsToUpdate = testItemRepository.findAllById(items.stream() - .filter(it -> idsToDelete.contains(it.getItemId())) - .map(TestItem::getParentId) - .filter(Objects::nonNull) - .collect(toList())); - - Set<Long> removedItems = testItemRepository.findAllById(idsToDelete) - .stream() - .map(TestItem::getPath) - .collect(toList()) - .stream() - .flatMap(path -> testItemRepository.selectAllDescendantsIds(path).stream()) - .collect(toSet()); - - idsToDelete.forEach(itemContentRemover::remove); - testItemRepository.deleteAllByItemIdIn(idsToDelete); - - launches.forEach(it -> it.setHasRetries(launchRepository.hasRetries(it.getId()))); - - parentsToUpdate.forEach(it -> it.setHasChildren(testItemRepository.hasChildren(it.getItemId(), it.getPath()))); - - if (CollectionUtils.isNotEmpty(removedItems)) { - logIndexer.indexItemsRemoveAsync(projectDetails.getProjectId(), removedItems); - attachmentRepository.moveForDeletionByItems(removedItems); - } - - return idsToDelete.stream().map(COMPOSE_DELETE_RESPONSE).collect(toList()); - } - - private static final Function<Long, OperationCompletionRS> COMPOSE_DELETE_RESPONSE = it -> { - String message = formattedSupplier("Test Item with ID = '{}' has been successfully deleted.", it).get(); - return new OperationCompletionRS(message); - }; - - /** - * Validate {@link ReportPortalUser} credentials, {@link TestItemResults#getStatus()}, - * {@link Launch#getStatus()} and {@link Launch} affiliation to the {@link com.epam.ta.reportportal.entity.project.Project} - * - * @param testItem {@link TestItem} - * @param user {@link ReportPortalUser} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - */ - private void validate(TestItem testItem, Launch launch, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Deleting testItem '{}' is not under specified project '{}'", - testItem.getItemId(), - projectDetails.getProjectId() - ) - ); - if (projectDetails.getProjectRole().lowerThan(ProjectRole.PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, "You are not a launch owner."); - } - } - expect(testItem.getRetryOf(), Objects::isNull).verify(ErrorType.RETRIES_HANDLER_ERROR, - Suppliers.formattedSupplier("Unable to delete test item ['{}'] because it is a retry", testItem.getItemId()).get() - ); - expect(testItem.getItemResults().getStatus(), not(it -> it.equals(StatusEnum.IN_PROGRESS))).verify(TEST_ITEM_IS_NOT_FINISHED, - formattedSupplier("Unable to delete test item ['{}'] in progress state", testItem.getItemId()) - ); - expect(launch.getStatus(), not(it -> it.equals(StatusEnum.IN_PROGRESS))).verify(LAUNCH_IS_NOT_FINISHED, - formattedSupplier("Unable to delete test item ['{}'] under launch ['{}'] with 'In progress' state", - testItem.getItemId(), - launch.getId() - ) - ); - } + private final TestItemRepository testItemRepository; + + private final ContentRemover<Long> itemContentRemover; + + private final LogIndexer logIndexer; + + private final LaunchRepository launchRepository; + + private final AttachmentRepository attachmentRepository; + + private final ApplicationEventPublisher eventPublisher; + + private final ElementsCounterService elementsCounterService; + + private final LogService logService; + + @Autowired + public DeleteTestItemHandlerImpl(TestItemRepository testItemRepository, + ContentRemover<Long> itemContentRemover, LogIndexer logIndexer, + LaunchRepository launchRepository, AttachmentRepository attachmentRepository, + ApplicationEventPublisher eventPublisher, + ElementsCounterService elementsCounterService, LogService logService) { + this.testItemRepository = testItemRepository; + this.itemContentRemover = itemContentRemover; + this.logIndexer = logIndexer; + this.launchRepository = launchRepository; + this.attachmentRepository = attachmentRepository; + this.eventPublisher = eventPublisher; + this.elementsCounterService = elementsCounterService; + this.logService = logService; + } + + @Override + public OperationCompletionRS deleteTestItem(Long itemId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + TestItem item = testItemRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); + Launch launch = launchRepository.findById(item.getLaunchId()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, item.getLaunchId())); + + validate(item, launch, user, projectDetails); + Optional<Long> parentId = ofNullable(item.getParentId()); + + Set<Long> itemsForRemove = Sets.newHashSet( + testItemRepository.selectAllDescendantsIds(item.getPath())); + itemsForRemove.forEach(itemContentRemover::remove); + + eventPublisher.publishEvent(new ElementsDeletedEvent(item, + projectDetails.getProjectId(), + elementsCounterService.countNumberOfItemElements(item) + )); + logService.deleteLogMessageByTestItemSet(projectDetails.getProjectId(), itemsForRemove); + itemContentRemover.remove(item.getItemId()); + testItemRepository.deleteById(item.getItemId()); + + launch.setHasRetries(launchRepository.hasRetries(launch.getId())); + parentId.flatMap(testItemRepository::findById) + .ifPresent( + p -> p.setHasChildren(testItemRepository.hasChildren(p.getItemId(), p.getPath()))); + + logIndexer.indexItemsRemoveAsync(projectDetails.getProjectId(), itemsForRemove); + attachmentRepository.moveForDeletionByItems(itemsForRemove); + + return COMPOSE_DELETE_RESPONSE.apply(item.getItemId()); + } + + @Override + public List<OperationCompletionRS> deleteTestItems(Collection<Long> ids, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + List<TestItem> items = testItemRepository.findAllById(ids); + + List<Launch> launches = launchRepository.findAllById(items.stream() + .map(TestItem::getLaunchId) + .filter(Objects::nonNull) + .collect(Collectors.toSet())); + Map<Long, List<TestItem>> launchItemMap = items.stream() + .collect(Collectors.groupingBy(TestItem::getLaunchId)); + launches.forEach(launch -> launchItemMap.get(launch.getId()) + .forEach(item -> validate(item, launch, user, projectDetails))); + + Map<Long, PathName> descendantsMapping = testItemRepository.selectPathNames(items); + + Set<Long> idsToDelete = Sets.newHashSet(descendantsMapping.keySet()); + + descendantsMapping.forEach((key, value) -> value.getItemPaths().forEach(ip -> { + if (idsToDelete.contains(ip.getId())) { + idsToDelete.remove(key); + } + })); + + List<TestItem> parentsToUpdate = testItemRepository.findAllById(items.stream() + .filter(it -> idsToDelete.contains(it.getItemId())) + .map(TestItem::getParentId) + .filter(Objects::nonNull) + .collect(toList())); + + Set<Long> removedItems = testItemRepository.findAllById(idsToDelete) + .stream() + .map(TestItem::getPath) + .collect(toList()) + .stream() + .flatMap(path -> testItemRepository.selectAllDescendantsIds(path).stream()) + .collect(toSet()); + + idsToDelete.forEach(itemContentRemover::remove); + eventPublisher.publishEvent(new ElementsDeletedEvent( + items, + projectDetails.getProjectId(), + elementsCounterService.countNumberOfItemElements(items) + )); + logService.deleteLogMessageByTestItemSet(projectDetails.getProjectId(), removedItems); + testItemRepository.deleteAllByItemIdIn(idsToDelete); + + launches.forEach(it -> it.setHasRetries(launchRepository.hasRetries(it.getId()))); + + parentsToUpdate.forEach( + it -> it.setHasChildren(testItemRepository.hasChildren(it.getItemId(), it.getPath()))); + + if (CollectionUtils.isNotEmpty(removedItems)) { + logIndexer.indexItemsRemoveAsync(projectDetails.getProjectId(), removedItems); + attachmentRepository.moveForDeletionByItems(removedItems); + } + + return idsToDelete.stream().map(COMPOSE_DELETE_RESPONSE).collect(toList()); + } + + private static final Function<Long, OperationCompletionRS> COMPOSE_DELETE_RESPONSE = it -> { + String message = formattedSupplier("Test Item with ID = '{}' has been successfully deleted.", + it).get(); + return new OperationCompletionRS(message); + }; + + /** + * Validate {@link ReportPortalUser} credentials, {@link TestItemResults#getStatus()}, + * {@link Launch#getStatus()} and {@link Launch} affiliation to the + * {@link com.epam.ta.reportportal.entity.project.Project} + * + * @param testItem {@link TestItem} + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + */ + private void validate(TestItem testItem, Launch launch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + formattedSupplier("Deleting testItem '{}' is not under specified project '{}'", + testItem.getItemId(), + projectDetails.getProjectId() + ) + ); + if (projectDetails.getProjectRole().lowerThan(ProjectRole.PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, + "You are not a launch owner."); + } + } + expect(testItem.getRetryOf(), Objects::isNull).verify(ErrorType.RETRIES_HANDLER_ERROR, + Suppliers.formattedSupplier("Unable to delete test item ['{}'] because it is a retry", + testItem.getItemId()).get() + ); + expect(testItem.getItemResults().getStatus(), + not(it -> it.equals(StatusEnum.IN_PROGRESS))).verify(TEST_ITEM_IS_NOT_FINISHED, + formattedSupplier("Unable to delete test item ['{}'] in progress state", + testItem.getItemId()) + ); + expect(launch.getStatus(), not(it -> it.equals(StatusEnum.IN_PROGRESS))).verify( + LAUNCH_IS_NOT_FINISHED, + formattedSupplier( + "Unable to delete test item ['{}'] under launch ['{}'] with 'In progress' state", + testItem.getItemId(), + launch.getId() + ) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/ExternalTicketHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/ExternalTicketHandlerImpl.java index 3e410375db..03377e97ba 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/ExternalTicketHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/ExternalTicketHandlerImpl.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.item.impl; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.core.item.ExternalTicketHandler; import com.epam.ta.reportportal.dao.TicketRepository; import com.epam.ta.reportportal.entity.bts.Ticket; @@ -24,18 +28,17 @@ import com.epam.ta.reportportal.ws.converter.converters.TicketConverter; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.item.UnlinkExternalIssueRQ; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.*; - -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toSet; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -43,92 +46,101 @@ @Component public class ExternalTicketHandlerImpl implements ExternalTicketHandler { - @Autowired - private TicketRepository ticketRepository; + @Autowired + private TicketRepository ticketRepository; - @Override - public void linkExternalTickets(String submitter, List<IssueEntity> issueEntities, List<Issue.ExternalSystemIssue> tickets) { - List<Ticket> existedTickets = collectExistedTickets(tickets); - Set<Ticket> ticketsFromRq = collectTickets(tickets, submitter); - linkTickets(issueEntities, existedTickets, ticketsFromRq); - } + @Override + public void linkExternalTickets(String submitter, List<IssueEntity> issueEntities, + List<Issue.ExternalSystemIssue> tickets) { + List<Ticket> existedTickets = collectExistedTickets(tickets); + Set<Ticket> ticketsFromRq = collectTickets(tickets, submitter); + linkTickets(issueEntities, existedTickets, ticketsFromRq); + } - @Override - public void unlinkExternalTickets(List<TestItem> items, UnlinkExternalIssueRQ request) { - items.forEach(testItem -> { - IssueEntity issue = testItem.getItemResults().getIssue(); - if (issue.getTickets().removeIf(it -> request.getTicketIds().contains(it.getTicketId()))) { - issue.setAutoAnalyzed(false); - } - }); - } + @Override + public void unlinkExternalTickets(List<TestItem> items, UnlinkExternalIssueRQ request) { + items.forEach(testItem -> { + IssueEntity issue = testItem.getItemResults().getIssue(); + if (issue.getTickets().removeIf(it -> request.getTicketIds().contains(it.getTicketId()))) { + issue.setAutoAnalyzed(false); + } + }); + } - @Override - public void updateLinking(String submitter, IssueEntity issueEntity, Set<Issue.ExternalSystemIssue> externalTickets) { - ofNullable(externalTickets).ifPresent(tickets -> { - Set<Ticket> existedTickets = collectTickets(tickets, submitter); - issueEntity.getTickets().removeIf(it -> !existedTickets.contains(it)); - issueEntity.getTickets().addAll(existedTickets); - existedTickets.stream().filter(it -> CollectionUtils.isEmpty(it.getIssues())).forEach(it -> it.getIssues().add(issueEntity)); - }); - } + @Override + public void updateLinking(String submitter, IssueEntity issueEntity, + Set<Issue.ExternalSystemIssue> externalTickets) { + ofNullable(externalTickets).ifPresent(tickets -> { + Set<Ticket> existedTickets = collectTickets(tickets, submitter); + issueEntity.getTickets().removeIf(it -> !existedTickets.contains(it)); + issueEntity.getTickets().addAll(existedTickets); + existedTickets.stream().filter(it -> CollectionUtils.isEmpty(it.getIssues())) + .forEach(it -> it.getIssues().add(issueEntity)); + }); + } - /** - * Finds tickets that are existed in db and removes them from request. - * - * @param externalIssues {@link com.epam.ta.reportportal.ws.model.issue.Issue.ExternalSystemIssue} - * @return List of existed tickets in db. - */ - private List<Ticket> collectExistedTickets(Collection<Issue.ExternalSystemIssue> externalIssues) { - if (CollectionUtils.isEmpty(externalIssues)) { - return Collections.emptyList(); - } - List<Ticket> existedTickets = ticketRepository.findByTicketIdIn(externalIssues.stream() - .map(Issue.ExternalSystemIssue::getTicketId) - .collect(toList())); - List<String> existedTicketsIds = existedTickets.stream().map(Ticket::getTicketId).collect(toList()); - externalIssues.removeIf(it -> existedTicketsIds.contains(it.getTicketId())); - return existedTickets; - } + /** + * Finds tickets that are existed in db and removes them from request. + * + * @param externalIssues {@link + * com.epam.ta.reportportal.ws.model.issue.Issue.ExternalSystemIssue} + * @return List of existed tickets in db. + */ + private List<Ticket> collectExistedTickets(Collection<Issue.ExternalSystemIssue> externalIssues) { + if (CollectionUtils.isEmpty(externalIssues)) { + return Collections.emptyList(); + } + List<Ticket> existedTickets = ticketRepository.findByTicketIdIn(externalIssues.stream() + .map(Issue.ExternalSystemIssue::getTicketId) + .collect(toList())); + List<String> existedTicketsIds = existedTickets.stream().map(Ticket::getTicketId) + .collect(toList()); + externalIssues.removeIf(it -> existedTicketsIds.contains(it.getTicketId())); + return existedTickets; + } - /** - * TODO document this - * - * @param externalIssues {@link com.epam.ta.reportportal.ws.model.issue.Issue.ExternalSystemIssue} - * @param username {@link com.epam.ta.reportportal.entity.user.User#login} - * @return {@link Set} of the {@link Ticket} - */ - private Set<Ticket> collectTickets(Collection<Issue.ExternalSystemIssue> externalIssues, String username) { - if (CollectionUtils.isEmpty(externalIssues)) { - return Collections.emptySet(); - } - return externalIssues.stream().map(it -> { - Ticket ticket; - Optional<Ticket> ticketOptional = ticketRepository.findByTicketId(it.getTicketId()); - if (ticketOptional.isPresent()) { - ticket = ticketOptional.get(); - ticket.setUrl(it.getUrl()); - ticket.setBtsProject(it.getBtsProject()); - ticket.setBtsUrl(it.getBtsUrl()); - ticket.setPluginName(it.getPluginName()); - } else { - ticket = TicketConverter.TO_TICKET.apply(it); - } - ticket.setSubmitter(username); - ticket.setSubmitDate(ofNullable(it.getSubmitDate()).map(millis -> LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), - ZoneOffset.UTC - )).orElse(LocalDateTime.now())); - return ticket; - }).collect(toSet()); - } + /** + * TODO document this + * + * @param externalIssues {@link + * com.epam.ta.reportportal.ws.model.issue.Issue.ExternalSystemIssue} + * @param username {@link com.epam.ta.reportportal.entity.user.User#login} + * @return {@link Set} of the {@link Ticket} + */ + private Set<Ticket> collectTickets(Collection<Issue.ExternalSystemIssue> externalIssues, + String username) { + if (CollectionUtils.isEmpty(externalIssues)) { + return Collections.emptySet(); + } + return externalIssues.stream().map(it -> { + Ticket ticket; + Optional<Ticket> ticketOptional = ticketRepository.findByTicketId(it.getTicketId()); + if (ticketOptional.isPresent()) { + ticket = ticketOptional.get(); + ticket.setUrl(it.getUrl()); + ticket.setBtsProject(it.getBtsProject()); + ticket.setBtsUrl(it.getBtsUrl()); + ticket.setPluginName(it.getPluginName()); + } else { + ticket = TicketConverter.TO_TICKET.apply(it); + } + ticket.setSubmitter(username); + ticket.setSubmitDate(ofNullable(it.getSubmitDate()).map( + millis -> LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), + ZoneOffset.UTC + )).orElse(LocalDateTime.now())); + return ticket; + }).collect(toSet()); + } - private void linkTickets(List<IssueEntity> issueEntities, List<Ticket> existedTickets, Set<Ticket> ticketsFromRq) { - List<Ticket> tickets = ticketRepository.saveAll(ticketsFromRq); - issueEntities.forEach(entity -> { - entity.getTickets().addAll(existedTickets); - entity.getTickets().addAll(tickets); - entity.setAutoAnalyzed(false); - }); - } + private void linkTickets(List<IssueEntity> issueEntities, List<Ticket> existedTickets, + Set<Ticket> ticketsFromRq) { + List<Ticket> tickets = ticketRepository.saveAll(ticketsFromRq); + issueEntities.forEach(entity -> { + entity.getTickets().addAll(existedTickets); + entity.getTickets().addAll(tickets); + entity.setAutoAnalyzed(false); + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImpl.java index cc0535ab99..04dd74a2b7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImpl.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; import com.epam.ta.reportportal.exception.ReportPortalException; @@ -25,18 +29,13 @@ import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.rabbit.MessageHeaders; import com.epam.ta.reportportal.ws.rabbit.RequestType; +import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; -import static java.util.Optional.ofNullable; - /** * @author Konstantin Antipin */ @@ -44,33 +43,36 @@ @Qualifier("finishTestItemHandlerAsync") public class FinishTestItemHandlerAsyncImpl implements FinishTestItemHandler { - @Autowired - @Qualifier(value = "rabbitTemplate") - AmqpTemplate amqpTemplate; + @Autowired + @Qualifier(value = "rabbitTemplate") + AmqpTemplate amqpTemplate; - @Autowired - private ReportingQueueService reportingQueueService; + @Autowired + private ReportingQueueService reportingQueueService; - @Override - public OperationCompletionRS finishTestItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, String testItemId, - FinishTestItemRQ request) { + @Override + public OperationCompletionRS finishTestItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, String testItemId, + FinishTestItemRQ request) { - // todo: may be problem - no access to repository, so no possibility to validateRoles() here - amqpTemplate.convertAndSend(EXCHANGE_REPORTING, - reportingQueueService.getReportingQueueKey(ofNullable(request.getLaunchUuid()).filter(StringUtils::isNotEmpty) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - "Launch UUID should not be null or empty." - ))), - request, - message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.FINISH_TEST); - headers.put(MessageHeaders.USERNAME, user.getUsername()); - headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); - headers.put(MessageHeaders.ITEM_ID, testItemId); - return message; - } - ); - return new OperationCompletionRS(formattedSupplier("Accepted finish request for test item ID = {}", testItemId).get()); - } + // todo: may be problem - no access to repository, so no possibility to validateRoles() here + amqpTemplate.convertAndSend(EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey( + ofNullable(request.getLaunchUuid()).filter(StringUtils::isNotEmpty) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Launch UUID should not be null or empty." + ))), + request, + message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.FINISH_TEST); + headers.put(MessageHeaders.USERNAME, user.getUsername()); + headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); + headers.put(MessageHeaders.ITEM_ID, testItemId); + return message; + } + ); + return new OperationCompletionRS( + formattedSupplier("Accepted finish request for test item ID = {}", testItemId).get()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImpl.java index d1f7347636..986cbab87c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImpl.java @@ -13,14 +13,42 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler.ATTRIBUTE_KEY_STATUS; +import static com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler.ATTRIBUTE_VALUE_INTERRUPTED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.INFO; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.INTERRUPTED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.SKIPPED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.WARN; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.fromValue; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; +import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; +import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.AMBIGUOUS_TEST_ITEM_STATUS; +import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_ITEM_NOT_ALLOWED; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.TEST_ITEM_NOT_FOUND; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; import com.epam.ta.reportportal.core.events.activity.item.TestItemStatusChangedEvent; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; import com.epam.ta.reportportal.core.hierarchy.FinishHierarchyHandler; import com.epam.ta.reportportal.core.item.ExternalTicketHandler; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; @@ -47,6 +75,13 @@ import com.epam.ta.reportportal.ws.model.activity.TestItemActivityResource; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Predicate; +import javax.annotation.Nullable; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -57,25 +92,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.annotation.Nullable; -import java.util.*; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler.ATTRIBUTE_KEY_STATUS; -import static com.epam.ta.reportportal.core.hierarchy.AbstractFinishHierarchyHandler.ATTRIBUTE_VALUE_INTERRUPTED; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.*; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; -import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; -import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; -import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.Optional.ofNullable; - /** * Default implementation of {@link FinishTestItemHandler} * @@ -86,314 +102,329 @@ @Transactional class FinishTestItemHandlerImpl implements FinishTestItemHandler { - private final TestItemRepository testItemRepository; - - private final IssueTypeHandler issueTypeHandler; - - private final FinishHierarchyHandler<TestItem> finishHierarchyHandler; - - private final LogIndexer logIndexer; - - private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; - - private final IssueEntityRepository issueEntityRepository; - - private final LaunchRepository launchRepository; - - private final ChangeStatusHandler changeStatusHandler; - - private final RetrySearcher retrySearcher; - private final RetryHandler retryHandler; - - private final ApplicationEventPublisher eventPublisher; - - private final MessageBus messageBus; - - private final ExternalTicketHandler externalTicketHandler; - - @Autowired - FinishTestItemHandlerImpl(TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, - @Qualifier("finishTestItemHierarchyHandler") FinishHierarchyHandler<TestItem> finishHierarchyHandler, LogIndexer logIndexer, - Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping, IssueEntityRepository issueEntityRepository, - ChangeStatusHandler changeStatusHandler, ApplicationEventPublisher eventPublisher, LaunchRepository launchRepository, - @Qualifier("uniqueIdRetrySearcher") RetrySearcher retrySearcher, RetryHandler retryHandler, MessageBus messageBus, - ExternalTicketHandler externalTicketHandler) { - this.testItemRepository = testItemRepository; - this.issueTypeHandler = issueTypeHandler; - this.finishHierarchyHandler = finishHierarchyHandler; - this.logIndexer = logIndexer; - this.statusChangingStrategyMapping = statusChangingStrategyMapping; - this.issueEntityRepository = issueEntityRepository; - this.launchRepository = launchRepository; - this.changeStatusHandler = changeStatusHandler; - this.eventPublisher = eventPublisher; - this.retrySearcher = retrySearcher; - this.retryHandler = retryHandler; - this.messageBus = messageBus; - this.externalTicketHandler = externalTicketHandler; - } - - @Override - public OperationCompletionRS finishTestItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, String testItemId, - FinishTestItemRQ finishExecutionRQ) { - final TestItem testItem = testItemRepository.findByUuid(testItemId) - .filter(it -> it.isHasChildren() || (!it.isHasChildren() && it.getItemResults().getStatus() == IN_PROGRESS)) - .orElseGet(() -> testItemRepository.findIdByUuidForUpdate(testItemId) - .flatMap(testItemRepository::findById) - .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, testItemId))); - - final Launch launch = retrieveLaunch(testItem); - - final TestItemResults testItemResults = processItemResults(user, - projectDetails, - launch, - testItem, - finishExecutionRQ, - testItem.isHasChildren() - ); - - final TestItem itemForUpdate = new TestItemBuilder(testItem).addDescription(finishExecutionRQ.getDescription()) - .addTestCaseId(finishExecutionRQ.getTestCaseId()) - .addAttributes(finishExecutionRQ.getAttributes()) - .addTestItemResults(testItemResults) - .get(); - - testItemRepository.save(itemForUpdate); - - if (BooleanUtils.toBoolean(finishExecutionRQ.isRetry()) || StringUtils.isNotBlank(finishExecutionRQ.getRetryOf())) { - Optional.of(testItem) - .filter(it -> !it.isHasChildren() && !it.isHasRetries() && Objects.isNull(it.getRetryOf())) - .map(TestItem::getParentId) - .flatMap(testItemRepository::findById) - .ifPresent(parentItem -> ofNullable(finishExecutionRQ.getRetryOf()).flatMap(testItemRepository::findIdByUuidForUpdate) - .ifPresentOrElse(retryParentId -> retryHandler.handleRetries(launch, itemForUpdate, retryParentId), - () -> retrySearcher.findPreviousRetry(launch, itemForUpdate, parentItem) - .ifPresent(previousRetryId -> retryHandler.handleRetries(launch, - itemForUpdate, - previousRetryId - )) - )); - } - - return new OperationCompletionRS("TestItem with ID = '" + testItemId + "' successfully finished."); - } - - /** - * If test item has descendants, it's status is resolved from statistics - * When status provided, no matter test item has or not descendants, test - * item status is resolved to provided - * - * @param testItem {@link TestItem} - * @param finishTestItemRQ {@link FinishTestItemRQ} - * @return TestItemResults {@link TestItemResults} - */ - private TestItemResults processItemResults(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, Launch launch, - TestItem testItem, FinishTestItemRQ finishTestItemRQ, boolean hasChildren) { - - validateRoles(user, projectDetails, launch); - verifyTestItem(testItem, fromValue(finishTestItemRQ.getStatus()), testItem.isHasChildren()); - - TestItemResults testItemResults; - if (hasChildren) { - testItemResults = processParentItemResult(testItem, finishTestItemRQ, launch, user, projectDetails); - } else { - testItemResults = processChildItemResult(testItem, finishTestItemRQ, user, projectDetails, launch); - } - testItemResults.setEndTime(TO_LOCAL_DATE_TIME.apply(finishTestItemRQ.getEndTime())); - return testItemResults; - } - - private Launch retrieveLaunch(TestItem testItem) { - - return ofNullable(testItem.getRetryOf()).map(retryParentId -> { - TestItem retryParent = testItemRepository.findById(retryParentId) - .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, testItem.getRetryOf())); - return getLaunch(retryParent); - }).orElseGet(() -> getLaunch(testItem)).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND)); - } - - private Optional<Launch> getLaunch(TestItem testItem) { - return ofNullable(testItem.getLaunchId()).map(launchRepository::findById) - .orElseGet(() -> ofNullable(testItem.getParentId()).flatMap(testItemRepository::findById) - .map(TestItem::getLaunchId) - .map(launchRepository::findById) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND))); - } - - /** - * Validation procedure for specified test item - * - * @param testItem Test item - * @param actualStatus Actual status of item - * @param hasChildren Does item contain children - */ - private void verifyTestItem(TestItem testItem, Optional<StatusEnum> actualStatus, boolean hasChildren) { - expect(!actualStatus.isPresent() && !hasChildren, equalTo(Boolean.FALSE)).verify(AMBIGUOUS_TEST_ITEM_STATUS, - formattedSupplier( - "There is no status provided from request and there are no descendants to check statistics for test item id '{}'", - testItem.getItemId() - ) - ); - } - - private void validateRoles(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, Launch launch) { - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); - if (!launch.isRerun() && projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(FINISH_ITEM_NOT_ALLOWED, - "You are not a launch owner." - ); - } - } - } - - private TestItemResults processParentItemResult(TestItem testItem, FinishTestItemRQ finishTestItemRQ, Launch launch, - ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - - TestItemResults testItemResults = testItem.getItemResults(); - Optional<StatusEnum> actualStatus = fromValue(finishTestItemRQ.getStatus()); - - if (testItemRepository.hasItemsInStatusByParent(testItem.getItemId(), testItem.getPath(), IN_PROGRESS.name())) { - finishHierarchyHandler.finishDescendants(testItem, - actualStatus.orElse(INTERRUPTED), - finishTestItemRQ.getEndTime(), - user, - projectDetails - ); - testItemResults.setStatus(resolveStatus(testItem.getItemId())); - } else { - testItemResults.setStatus(actualStatus.orElseGet(() -> resolveStatus(testItem.getItemId()))); - } - - testItem.getAttributes() - .removeIf(attribute -> ATTRIBUTE_KEY_STATUS.equalsIgnoreCase(attribute.getKey()) - && ATTRIBUTE_VALUE_INTERRUPTED.equalsIgnoreCase(attribute.getValue())); - - changeStatusHandler.changeParentStatus(testItem, projectDetails.getProjectId(), user); - changeStatusHandler.changeLaunchStatus(launch); - - return testItemResults; - } - - private TestItemResults processChildItemResult(TestItem testItem, FinishTestItemRQ finishTestItemRQ, ReportPortalUser user, - ReportPortalUser.ProjectDetails projectDetails, Launch launch) { - TestItemResults testItemResults = testItem.getItemResults(); - StatusEnum actualStatus = fromValue(finishTestItemRQ.getStatus()).orElse(INTERRUPTED); - Optional<IssueEntity> resolvedIssue = resolveIssue(user, - actualStatus, - testItem, - finishTestItemRQ.getIssue(), - projectDetails.getProjectId() - ); - - if (testItemResults.getStatus() == IN_PROGRESS) { - testItemResults.setStatus(actualStatus); - resolvedIssue.ifPresent(issue -> updateItemIssue(testItemResults, issue)); - ofNullable(testItem.getRetryOf()).ifPresentOrElse(retryOf -> { - }, () -> { - changeStatusHandler.changeParentStatus(testItem, projectDetails.getProjectId(), user); - changeStatusHandler.changeLaunchStatus(launch); - if (testItem.isHasRetries()) { - retryHandler.finishRetries(testItem.getItemId(), - JStatusEnum.valueOf(actualStatus.name()), - TO_LOCAL_DATE_TIME.apply(finishTestItemRQ.getEndTime()) - ); - } - }); - } else { - updateFinishedItem(testItemResults, actualStatus, resolvedIssue, testItem, user, projectDetails.getProjectId()); - } - - testItem.getAttributes() - .removeIf(attribute -> ATTRIBUTE_KEY_STATUS.equalsIgnoreCase(attribute.getKey()) - && ATTRIBUTE_VALUE_INTERRUPTED.equalsIgnoreCase(attribute.getValue())); - - return testItemResults; - } - - private StatusEnum resolveStatus(Long itemId) { - return testItemRepository.hasDescendantsNotInStatus(itemId, PASSED.name(), INFO.name(), WARN.name()) ? FAILED : PASSED; - } - - private boolean isIssueRequired(TestItem testItem, StatusEnum status) { - return Preconditions.statusIn(FAILED, SKIPPED).test(status) && !ofNullable(testItem.getRetryOf()).isPresent() - && testItem.isHasStats(); - } - - private Optional<IssueEntity> resolveIssue(ReportPortalUser user, StatusEnum status, TestItem testItem, @Nullable Issue issue, - Long projectId) { - - if (isIssueRequired(testItem, status)) { - return ofNullable(issue).map(is -> { - //in provided issue should be locator id or NOT_ISSUE value - String locator = is.getIssueType(); - if (!NOT_ISSUE_FLAG.getValue().equalsIgnoreCase(locator)) { - IssueType issueType = issueTypeHandler.defineIssueType(projectId, locator); - IssueEntity issueEntity = IssueConverter.TO_ISSUE.apply(is); - issueEntity.setIssueType(issueType); - if (!CollectionUtils.isEmpty(issue.getExternalSystemIssues())) { - externalTicketHandler.linkExternalTickets(user.getUsername(), - Lists.newArrayList(issueEntity), - new ArrayList<>(issue.getExternalSystemIssues()) - ); - } - return Optional.of(issueEntity); - } - return Optional.<IssueEntity>empty(); - }).orElseGet(() -> { - IssueEntity issueEntity = new IssueEntity(); - IssueType toInvestigate = issueTypeHandler.defineIssueType(projectId, TO_INVESTIGATE.getLocator()); - issueEntity.setIssueType(toInvestigate); - return Optional.of(issueEntity); - }); - } - return Optional.empty(); - } - - private void updateFinishedItem(TestItemResults testItemResults, StatusEnum actualStatus, Optional<IssueEntity> resolvedIssue, - TestItem testItem, ReportPortalUser user, Long projectId) { - - resolvedIssue.ifPresent(issue -> deleteOldIssueIndex(actualStatus, testItem, testItemResults, projectId)); - - if (testItemResults.getStatus() != actualStatus) { - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(testItem, projectId); - Optional<StatusChangingStrategy> statusChangingStrategy = ofNullable(statusChangingStrategyMapping.get(actualStatus)); - if (statusChangingStrategy.isPresent()) { - statusChangingStrategy.get().changeStatus(testItem, actualStatus, user); - } else { - testItemResults.setStatus(actualStatus); - } - publishUpdateActivity(before, TO_ACTIVITY_RESOURCE.apply(testItem, projectId), user); - } - - resolvedIssue.ifPresent(issue -> { - updateItemIssue(testItemResults, issue); - if (ITEM_CAN_BE_INDEXED.test(testItem)) { - eventPublisher.publishEvent(new ItemFinishedEvent(testItem.getItemId(), testItem.getLaunchId(), projectId)); - } - }); - } - - private void publishUpdateActivity(TestItemActivityResource before, TestItemActivityResource after, ReportPortalUser user) { - messageBus.publishActivity(new TestItemStatusChangedEvent(before, after, user.getUserId(), user.getUsername())); - } - - private void deleteOldIssueIndex(StatusEnum actualStatus, TestItem testItem, TestItemResults testItemResults, Long projectId) { - if (actualStatus == PASSED || ITEM_CAN_BE_INDEXED.test(testItem)) { - ofNullable(testItemResults.getIssue()).ifPresent(issue -> logIndexer.indexItemsRemoveAsync(projectId, - Collections.singletonList(testItem.getItemId()) - )); - } - } - - private void updateItemIssue(TestItemResults testItemResults, IssueEntity resolvedIssue) { - issueEntityRepository.findById(testItemResults.getItemId()).ifPresent(issueEntity -> { - issueEntity.setTestItemResults(null); - issueEntityRepository.delete(issueEntity); - testItemResults.setIssue(null); - }); - resolvedIssue.setTestItemResults(testItemResults); - issueEntityRepository.save(resolvedIssue); - testItemResults.setIssue(resolvedIssue); - } + private final TestItemRepository testItemRepository; + + private final IssueTypeHandler issueTypeHandler; + + private final FinishHierarchyHandler<TestItem> finishHierarchyHandler; + + private final LogIndexer logIndexer; + + private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; + + private final IssueEntityRepository issueEntityRepository; + + private final LaunchRepository launchRepository; + + private final ChangeStatusHandler changeStatusHandler; + + private final RetrySearcher retrySearcher; + private final RetryHandler retryHandler; + + private final ApplicationEventPublisher eventPublisher; + + private final MessageBus messageBus; + + private final ExternalTicketHandler externalTicketHandler; + + @Autowired + FinishTestItemHandlerImpl(TestItemRepository testItemRepository, + IssueTypeHandler issueTypeHandler, @Qualifier("finishTestItemHierarchyHandler") + FinishHierarchyHandler<TestItem> finishHierarchyHandler, LogIndexer logIndexer, + Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping, + IssueEntityRepository issueEntityRepository, ChangeStatusHandler changeStatusHandler, + ApplicationEventPublisher eventPublisher, LaunchRepository launchRepository, + @Qualifier("uniqueIdRetrySearcher") RetrySearcher retrySearcher, RetryHandler retryHandler, + MessageBus messageBus, ExternalTicketHandler externalTicketHandler) { + this.testItemRepository = testItemRepository; + this.issueTypeHandler = issueTypeHandler; + this.finishHierarchyHandler = finishHierarchyHandler; + this.logIndexer = logIndexer; + this.statusChangingStrategyMapping = statusChangingStrategyMapping; + this.issueEntityRepository = issueEntityRepository; + this.launchRepository = launchRepository; + this.changeStatusHandler = changeStatusHandler; + this.eventPublisher = eventPublisher; + this.retrySearcher = retrySearcher; + this.retryHandler = retryHandler; + this.messageBus = messageBus; + this.externalTicketHandler = externalTicketHandler; + } + + @Override + public OperationCompletionRS finishTestItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, String testItemId, + FinishTestItemRQ finishExecutionRQ) { + final TestItem testItem = testItemRepository.findByUuid(testItemId).filter( + it -> it.isHasChildren() || (!it.isHasChildren() + && it.getItemResults().getStatus() == IN_PROGRESS)).orElseGet( + () -> testItemRepository.findIdByUuidForUpdate(testItemId) + .flatMap(testItemRepository::findById) + .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, testItemId))); + + final Launch launch = retrieveLaunch(testItem); + + final TestItemResults testItemResults = + processItemResults(user, projectDetails, launch, testItem, finishExecutionRQ, + testItem.isHasChildren() + ); + + final TestItem itemForUpdate = + new TestItemBuilder(testItem).addDescription(finishExecutionRQ.getDescription()) + .addTestCaseId(finishExecutionRQ.getTestCaseId()) + .overwriteAttributesValues(finishExecutionRQ.getAttributes()) + .addTestItemResults(testItemResults).get(); + + testItemRepository.save(itemForUpdate); + + if (BooleanUtils.toBoolean(finishExecutionRQ.isRetry()) || StringUtils.isNotBlank( + finishExecutionRQ.getRetryOf())) { + Optional.of(testItem).filter( + it -> !it.isHasChildren() && !it.isHasRetries() && Objects.isNull(it.getRetryOf())) + .map(TestItem::getParentId).flatMap(testItemRepository::findById).ifPresent( + parentItem -> ofNullable(finishExecutionRQ.getRetryOf()).flatMap( + testItemRepository::findIdByUuidForUpdate).ifPresentOrElse( + retryParentId -> retryHandler.handleRetries(launch, itemForUpdate, retryParentId), + () -> retrySearcher.findPreviousRetry(launch, itemForUpdate, parentItem).ifPresent( + previousRetryId -> retryHandler.handleRetries(launch, itemForUpdate, + previousRetryId + )) + )); + } + eventPublisher.publishEvent( + new TestItemFinishedEvent(itemForUpdate, projectDetails.getProjectId())); + + return new OperationCompletionRS( + "TestItem with ID = '" + testItemId + "' successfully finished."); + } + + /** + * If test item has descendants, it's status is resolved from statistics When status provided, no + * matter test item has or not descendants, test item status is resolved to provided + * + * @param testItem {@link TestItem} + * @param finishTestItemRQ {@link FinishTestItemRQ} + * @return TestItemResults {@link TestItemResults} + */ + private TestItemResults processItemResults(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, Launch launch, TestItem testItem, + FinishTestItemRQ finishTestItemRQ, boolean hasChildren) { + + validateRoles(user, projectDetails, launch); + verifyTestItem(testItem, fromValue(finishTestItemRQ.getStatus()), testItem.isHasChildren()); + + TestItemResults testItemResults; + if (hasChildren) { + testItemResults = + processParentItemResult(testItem, finishTestItemRQ, launch, user, projectDetails); + } else { + testItemResults = + processChildItemResult(testItem, finishTestItemRQ, user, projectDetails, launch); + } + testItemResults.setEndTime(TO_LOCAL_DATE_TIME.apply(finishTestItemRQ.getEndTime())); + return testItemResults; + } + + private Launch retrieveLaunch(TestItem testItem) { + + return ofNullable(testItem.getRetryOf()).map(retryParentId -> { + TestItem retryParent = testItemRepository.findById(retryParentId) + .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, testItem.getRetryOf())); + return getLaunch(retryParent); + }).orElseGet(() -> getLaunch(testItem)) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND)); + } + + private Optional<Launch> getLaunch(TestItem testItem) { + return ofNullable(testItem.getLaunchId()).map(launchRepository::findById).orElseGet( + () -> ofNullable(testItem.getParentId()).flatMap(testItemRepository::findById) + .map(TestItem::getLaunchId).map(launchRepository::findById) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND))); + } + + /** + * Validation procedure for specified test item + * + * @param testItem Test item + * @param actualStatus Actual status of item + * @param hasChildren Does item contain children + */ + private void verifyTestItem(TestItem testItem, Optional<StatusEnum> actualStatus, + boolean hasChildren) { + expect(actualStatus.isEmpty() && !hasChildren, equalTo(Boolean.FALSE)).verify( + AMBIGUOUS_TEST_ITEM_STATUS, formattedSupplier( + "There is no status provided from request and there are no descendants to check statistics for test item id '{}'", + testItem.getItemId() + )); + } + + private void validateRoles(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, + Launch launch) { + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); + if (!launch.isRerun() && projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify( + FINISH_ITEM_NOT_ALLOWED, "You are not a launch owner."); + } + } + } + + private TestItemResults processParentItemResult(TestItem testItem, + FinishTestItemRQ finishTestItemRQ, Launch launch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + + TestItemResults testItemResults = testItem.getItemResults(); + Optional<StatusEnum> actualStatus = fromValue(finishTestItemRQ.getStatus()); + + if (testItemRepository.hasItemsInStatusByParent(testItem.getItemId(), testItem.getPath(), + IN_PROGRESS.name() + )) { + finishHierarchyHandler.finishDescendants(testItem, actualStatus.orElse(INTERRUPTED), + finishTestItemRQ.getEndTime(), user, projectDetails + ); + } + + testItemResults.setStatus(actualStatus.orElseGet(() -> resolveStatus(testItem.getItemId()))); + + testItem.getAttributes().removeIf( + attribute -> ATTRIBUTE_KEY_STATUS.equalsIgnoreCase(attribute.getKey()) + && ATTRIBUTE_VALUE_INTERRUPTED.equalsIgnoreCase(attribute.getValue())); + + changeStatusHandler.changeParentStatus(testItem, projectDetails.getProjectId(), user); + changeStatusHandler.changeLaunchStatus(launch); + + return testItemResults; + } + + private TestItemResults processChildItemResult(TestItem testItem, + FinishTestItemRQ finishTestItemRQ, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, Launch launch) { + TestItemResults testItemResults = testItem.getItemResults(); + StatusEnum actualStatus = fromValue(finishTestItemRQ.getStatus()).orElse(INTERRUPTED); + Optional<IssueEntity> resolvedIssue = + resolveIssue(user, actualStatus, testItem, finishTestItemRQ.getIssue(), + projectDetails.getProjectId() + ); + + if (testItemResults.getStatus() == IN_PROGRESS) { + testItemResults.setStatus(actualStatus); + resolvedIssue.ifPresent(issue -> updateItemIssue(testItemResults, issue)); + ofNullable(testItem.getRetryOf()).ifPresentOrElse(retryOf -> { + }, () -> { + changeStatusHandler.changeParentStatus(testItem, projectDetails.getProjectId(), user); + changeStatusHandler.changeLaunchStatus(launch); + if (testItem.isHasRetries()) { + retryHandler.finishRetries(testItem.getItemId(), JStatusEnum.valueOf(actualStatus.name()), + TO_LOCAL_DATE_TIME.apply(finishTestItemRQ.getEndTime()) + ); + } + }); + } else { + updateFinishedItem(testItemResults, actualStatus, resolvedIssue, testItem, user, + projectDetails.getProjectId() + ); + } + + testItem.getAttributes().removeIf( + attribute -> ATTRIBUTE_KEY_STATUS.equalsIgnoreCase(attribute.getKey()) + && ATTRIBUTE_VALUE_INTERRUPTED.equalsIgnoreCase(attribute.getValue())); + + return testItemResults; + } + + private StatusEnum resolveStatus(Long itemId) { + return testItemRepository.hasDescendantsNotInStatus(itemId, PASSED.name(), INFO.name(), + WARN.name() + ) ? FAILED : PASSED; + } + + private boolean isIssueRequired(TestItem testItem, StatusEnum status) { + return Preconditions.statusIn(FAILED, SKIPPED).test(status) && ofNullable( + testItem.getRetryOf()).isEmpty() && testItem.isHasStats(); + } + + private Optional<IssueEntity> resolveIssue(ReportPortalUser user, StatusEnum status, + TestItem testItem, @Nullable Issue issue, Long projectId) { + + if (isIssueRequired(testItem, status)) { + return ofNullable(issue).map(is -> { + //in provided issue should be locator id or NOT_ISSUE value + String locator = is.getIssueType(); + if (!NOT_ISSUE_FLAG.getValue().equalsIgnoreCase(locator)) { + IssueType issueType = issueTypeHandler.defineIssueType(projectId, locator); + IssueEntity issueEntity = IssueConverter.TO_ISSUE.apply(is); + issueEntity.setIssueType(issueType); + if (!CollectionUtils.isEmpty(issue.getExternalSystemIssues())) { + externalTicketHandler.linkExternalTickets(user.getUsername(), + Lists.newArrayList(issueEntity), new ArrayList<>(issue.getExternalSystemIssues()) + ); + } + return Optional.of(issueEntity); + } + return Optional.<IssueEntity>empty(); + }).orElseGet(() -> { + IssueEntity issueEntity = new IssueEntity(); + IssueType toInvestigate = + issueTypeHandler.defineIssueType(projectId, TO_INVESTIGATE.getLocator()); + issueEntity.setIssueType(toInvestigate); + return Optional.of(issueEntity); + }); + } + return Optional.empty(); + } + + private void updateFinishedItem(TestItemResults testItemResults, StatusEnum actualStatus, + Optional<IssueEntity> resolvedIssue, TestItem testItem, ReportPortalUser user, + Long projectId) { + + resolvedIssue.ifPresent( + issue -> deleteOldIssueIndex(actualStatus, testItem, testItemResults, projectId)); + + if (testItemResults.getStatus() != actualStatus) { + TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(testItem, projectId); + Optional<StatusChangingStrategy> statusChangingStrategy = + ofNullable(statusChangingStrategyMapping.get(actualStatus)); + if (statusChangingStrategy.isPresent()) { + statusChangingStrategy.get().changeStatus(testItem, actualStatus, user, false); + } else { + testItemResults.setStatus(actualStatus); + } + publishUpdateActivity(before, TO_ACTIVITY_RESOURCE.apply(testItem, projectId), user); + } + + resolvedIssue.ifPresent(issue -> { + updateItemIssue(testItemResults, issue); + if (ITEM_CAN_BE_INDEXED.test(testItem)) { + eventPublisher.publishEvent( + new IssueResolvedEvent(testItem.getItemId(), testItem.getLaunchId(), projectId)); + } + }); + } + + private void publishUpdateActivity(TestItemActivityResource before, + TestItemActivityResource after, ReportPortalUser user) { + messageBus.publishActivity( + new TestItemStatusChangedEvent(before, after, user.getUserId(), user.getUsername())); + } + + private void deleteOldIssueIndex(StatusEnum actualStatus, TestItem testItem, + TestItemResults testItemResults, Long projectId) { + if (actualStatus == PASSED || ITEM_CAN_BE_INDEXED.test(testItem)) { + ofNullable(testItemResults.getIssue()).ifPresent( + issue -> logIndexer.indexItemsRemoveAsync(projectId, + Collections.singletonList(testItem.getItemId()) + )); + } + } + + private void updateItemIssue(TestItemResults testItemResults, IssueEntity resolvedIssue) { + issueEntityRepository.findById(testItemResults.getItemId()).ifPresent(issueEntity -> { + issueEntity.setTestItemResults(null); + issueEntityRepository.delete(issueEntity); + testItemResults.setIssue(null); + }); + resolvedIssue.setTestItemResults(testItemResults); + issueEntityRepository.save(resolvedIssue); + testItemResults.setIssue(resolvedIssue); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandler.java index ece6bf1b63..e8b4553b21 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandler.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.issue.IssueType; @@ -23,41 +28,39 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; - /** * @author Pavel Bortnik */ @Service public class IssueTypeHandler { - private TestItemRepository testItemRepository; - - @Autowired - public void setTestItemRepository(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } - - /** - * Verifies that provided test item issue type is valid, and test item - * domain object could be processed correctly - * - * @param locator Issue locator - * @param projectId Project id - * @return verified issue type - */ - public IssueType defineIssueType(Long projectId, String locator) { - return testItemRepository.selectIssueTypeByLocator( - projectId, - ofNullable(locator).map(EntityUtils::normalizeId).orElseThrow(() -> new ReportPortalException("Locator should not be null")) - ).orElseThrow(() -> new ReportPortalException(FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, formattedSupplier( - "Invalid test item issue type definition '{}' is requested. Valid issue types' locators are: {}", - locator, - testItemRepository.selectIssueLocatorsByProject(projectId).stream().map(IssueType::getLocator).collect(toList()) - ))); - } + private TestItemRepository testItemRepository; + + @Autowired + public void setTestItemRepository(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } + + /** + * Verifies that provided test item issue type is valid, and test item domain object could be + * processed correctly + * + * @param locator Issue locator + * @param projectId Project id + * @return verified issue type + */ + public IssueType defineIssueType(Long projectId, String locator) { + return testItemRepository.selectIssueTypeByLocator( + projectId, + ofNullable(locator).map(EntityUtils::normalizeId) + .orElseThrow(() -> new ReportPortalException("Locator should not be null")) + ).orElseThrow( + () -> new ReportPortalException(FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, formattedSupplier( + "Invalid test item issue type definition '{}' is requested. Valid issue types' locators are: {}", + locator, + testItemRepository.selectIssueLocatorsByProject(projectId).stream() + .map(IssueType::getLocator).collect(toList()) + ))); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidator.java index 3c258bf82d..5e98ea0eff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidator.java @@ -24,17 +24,19 @@ */ public interface LaunchAccessValidator { - /** - * @param launch {@link com.epam.ta.reportportal.entity.launch.Launch} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - */ - void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * @param launch {@link com.epam.ta.reportportal.entity.launch.Launch} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + */ + void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#getId()} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - * @param user {@link ReportPortalUser} - */ - void validate(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#getId()} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param user {@link ReportPortalUser} + */ + void validate(Long launchId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImpl.java index 655cbe7a9c..5ccf992ff4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImpl.java @@ -16,21 +16,22 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.entity.project.ProjectRole.OPERATOR; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.springframework.stereotype.Service; - import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.entity.project.ProjectRole.OPERATOR; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -38,32 +39,38 @@ @Service public class LaunchAccessValidatorImpl implements LaunchAccessValidator { - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - public LaunchAccessValidatorImpl(LaunchRepository launchRepository) { - this.launchRepository = launchRepository; - } + public LaunchAccessValidatorImpl(LaunchRepository launchRepository) { + this.launchRepository = launchRepository; + } - @Override - //TODO separate project validation from launch state validation (mode) - public void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Specified launch with id '{}' not referenced to specified project with id '{}'", - launch.getId(), - projectDetails.getProjectId() - ) - ); - expect(projectDetails.getProjectRole() == OPERATOR && launch.getMode() == LaunchModeEnum.DEBUG, - Predicate.isEqual(false) - ).verify(ACCESS_DENIED); - } - } + @Override + //TODO separate project validation from launch state validation (mode) + public void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + formattedSupplier( + "Specified launch with id '{}' not referenced to specified project with id '{}'", + launch.getId(), + projectDetails.getProjectId() + ) + ); + expect( + projectDetails.getProjectRole() == OPERATOR && launch.getMode() == LaunchModeEnum.DEBUG, + Predicate.isEqual(false) + ).verify(ACCESS_DENIED); + } + } - @Override - public void validate(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - Launch launch = launchRepository.findById(launchId).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); - validate(launch, projectDetails, user); - } + @Override + public void validate(Long launchId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); + validate(launch, projectDetails, user); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImpl.java index 4a63bbe195..ffa9eef04d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.StartTestItemHandler; import com.epam.ta.reportportal.util.ReportingQueueService; @@ -23,17 +25,14 @@ import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; import com.epam.ta.reportportal.ws.rabbit.MessageHeaders; import com.epam.ta.reportportal.ws.rabbit.RequestType; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; - /** * @author Konstantin Antipin */ @@ -41,58 +40,60 @@ @Qualifier("startTestItemHandlerAsync") class StartTestItemHandlerAsyncImpl implements StartTestItemHandler { - @Autowired - @Qualifier(value = "rabbitTemplate") - AmqpTemplate amqpTemplate; + @Autowired + @Qualifier(value = "rabbitTemplate") + AmqpTemplate amqpTemplate; - @Autowired - private ReportingQueueService reportingQueueService; + @Autowired + private ReportingQueueService reportingQueueService; - @Override - public ItemCreatedRS startRootItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ request) { + @Override + public ItemCreatedRS startRootItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ request) { - // todo: may be problem - no access to repository, so no possibility to validateRoles() here - request.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); - amqpTemplate.convertAndSend(EXCHANGE_REPORTING, - reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), - request, - message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_TEST); - headers.put(MessageHeaders.USERNAME, user.getUsername()); - headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); - headers.put(MessageHeaders.PARENT_ITEM_ID, ""); - return message; - } - ); + // todo: may be problem - no access to repository, so no possibility to validateRoles() here + request.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); + amqpTemplate.convertAndSend(EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), + request, + message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_TEST); + headers.put(MessageHeaders.USERNAME, user.getUsername()); + headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); + headers.put(MessageHeaders.PARENT_ITEM_ID, ""); + return message; + } + ); - ItemCreatedRS response = new ItemCreatedRS(); - response.setId(request.getUuid()); - return response; - } + ItemCreatedRS response = new ItemCreatedRS(); + response.setId(request.getUuid()); + return response; + } - @Override - public ItemCreatedRS startChildItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ request, - String parentId) { + @Override + public ItemCreatedRS startChildItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ request, + String parentId) { - // todo: may be problem - no access to repository, so no possibility to validateRoles() here - request.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); - amqpTemplate.convertAndSend( - EXCHANGE_REPORTING, - reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), - request, - message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_TEST); - headers.put(MessageHeaders.USERNAME, user.getUsername()); - headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); - headers.put(MessageHeaders.PARENT_ITEM_ID, parentId); - return message; - } - ); + // todo: may be problem - no access to repository, so no possibility to validateRoles() here + request.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); + amqpTemplate.convertAndSend( + EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), + request, + message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_TEST); + headers.put(MessageHeaders.USERNAME, user.getUsername()); + headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); + headers.put(MessageHeaders.PARENT_ITEM_ID, parentId); + return message; + } + ); - ItemCreatedRS response = new ItemCreatedRS(); - response.setId(request.getUuid()); - return response; - } + ItemCreatedRS response = new ItemCreatedRS(); + response.setId(request.getUuid()); + return response; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImpl.java index 7051a0f020..c53070507f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImpl.java @@ -16,6 +16,16 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.CHILD_START_TIME_EARLIER_THAN_PARENT; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.TEST_ITEM_NOT_FOUND; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.BooleanUtils.isTrue; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.StartTestItemHandler; @@ -36,6 +46,9 @@ import com.epam.ta.reportportal.ws.converter.builders.TestItemBuilder; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -46,16 +59,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.BooleanUtils.isTrue; - /** * Start Test Item operation default implementation * @@ -67,153 +70,168 @@ @Transactional class StartTestItemHandlerImpl implements StartTestItemHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(StartTestItemHandlerImpl.class); - - private final TestItemRepository testItemRepository; - - private final LaunchRepository launchRepository; - - private final UniqueIdGenerator uniqueIdGenerator; - - private final TestCaseHashGenerator testCaseHashGenerator; - - private final RerunHandler rerunHandler; - - private final List<ParentItemValidator> parentItemValidators; - - private final RetrySearcher retrySearcher; - private final RetryHandler retryHandler; - - @Autowired - public StartTestItemHandlerImpl(TestItemRepository testItemRepository, LaunchRepository launchRepository, - UniqueIdGenerator uniqueIdGenerator, TestCaseHashGenerator testCaseHashGenerator, RerunHandler rerunHandler, - List<ParentItemValidator> parentItemValidators, @Qualifier("uniqueIdRetrySearcher") RetrySearcher retrySearcher, - RetryHandler retryHandler) { - this.testItemRepository = testItemRepository; - this.launchRepository = launchRepository; - this.uniqueIdGenerator = uniqueIdGenerator; - this.testCaseHashGenerator = testCaseHashGenerator; - this.rerunHandler = rerunHandler; - this.parentItemValidators = parentItemValidators; - this.retrySearcher = retrySearcher; - this.retryHandler = retryHandler; - } - - @Override - public ItemCreatedRS startRootItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq) { - Launch launch = launchRepository.findByUuid(rq.getLaunchUuid()) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, rq.getLaunchUuid())); - validate(user, projectDetails, rq, launch); - - if (launch.isRerun()) { - Optional<ItemCreatedRS> rerunCreatedRs = rerunHandler.handleRootItem(rq, launch); - if (rerunCreatedRs.isPresent()) { - return rerunCreatedRs.get(); - } - } - - TestItem item = new TestItemBuilder().addStartItemRequest(rq).addAttributes(rq.getAttributes()).addLaunchId(launch.getId()).get(); - testItemRepository.save(item); - generateUniqueId(launch, item, String.valueOf(item.getItemId())); - - LOGGER.debug("Created new root TestItem {}", item.getUuid()); - return new ItemCreatedRS(item.getUuid(), item.getUniqueId()); - } - - @Override - public ItemCreatedRS startChildItem(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq, - String parentId) { - boolean isRetry = BooleanUtils.toBoolean(rq.isRetry()) || StringUtils.isNotBlank(rq.getRetryOf()); - - Launch launch = launchRepository.findByUuid(rq.getLaunchUuid()) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, rq.getLaunchUuid())); - - if (launch.isRerun()) { - Optional<ItemCreatedRS> rerunCreatedRs = rerunHandler.handleChildItem(rq, launch, parentId); - if (rerunCreatedRs.isPresent()) { - return rerunCreatedRs.get(); - } - } - - final TestItem parentItem; - if (isRetry) { - // Lock for test - Long lockedParentId = testItemRepository.findIdByUuidForUpdate(parentId) - .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, parentId)); - parentItem = testItemRepository.getOne(lockedParentId); - } else { - parentItem = testItemRepository.findByUuid(parentId) - .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, parentId)); - } - - parentItemValidators.forEach(v -> v.validate(rq, parentItem)); - - TestItem item = new TestItemBuilder().addStartItemRequest(rq).addAttributes(rq.getAttributes()).addLaunchId(launch.getId()).get(); - - if (isRetry) { - ofNullable(rq.getRetryOf()).flatMap(testItemRepository::findIdByUuidForUpdate).ifPresentOrElse(retryParentId -> { - saveChildItem(launch, item, parentItem); - retryHandler.handleRetries(launch, item, retryParentId); - }, () -> retrySearcher.findPreviousRetry(launch, item, parentItem).ifPresentOrElse(previousRetryId -> { - saveChildItem(launch, item, parentItem); - retryHandler.handleRetries(launch, item, previousRetryId); - }, () -> saveChildItem(launch, item, parentItem))); - } else { - saveChildItem(launch, item, parentItem); - } - - LOGGER.debug("Created new child TestItem {} with root {}", item.getUuid(), parentId); - - if (rq.isHasStats() && !parentItem.isHasChildren()) { - parentItem.setHasChildren(true); - } - - return new ItemCreatedRS(item.getUuid(), item.getUniqueId()); - } - - private TestItem saveChildItem(Launch launch, TestItem childItem, TestItem parentItem) { - childItem.setParentId(parentItem.getItemId()); - testItemRepository.save(childItem); - generateUniqueId(launch, childItem, parentItem.getPath() + "." + childItem.getItemId()); - return childItem; - } - - /** - * Generates and sets {@link TestItem#getUniqueId()} and {@link TestItem#getTestCaseId()} if they are empty - * - * @param launch {@link Launch} of {@link TestItem} - * @param item {@link TestItem} - * @param path {@link TestItem} path - */ - private void generateUniqueId(Launch launch, TestItem item, String path) { - item.setPath(path); - if (Objects.isNull(item.getUniqueId())) { - item.setUniqueId(uniqueIdGenerator.generate(item, IdentityUtil.getParentIds(item), launch)); - } - if (Objects.isNull(item.getTestCaseId())) { - item.setTestCaseHash(testCaseHashGenerator.generate(item, IdentityUtil.getParentIds(item), launch.getProjectId())); - } - } - - /** - * Validate {@link ReportPortalUser} credentials, {@link Launch#getStatus()} - * and {@link Launch} affiliation to the {@link Project} - * - * @param user {@link ReportPortalUser} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - * @param rq {@link StartTestItemRQ} - * @param launch {@link Launch} - */ - private void validate(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq, Launch launch) { - if (!UserRole.ADMINISTRATOR.equals(user.getUserRole())) { - expect(projectDetails.getProjectId(), equalTo(launch.getProjectId())).verify(ACCESS_DENIED); - } - expect(rq.getStartTime(), Preconditions.sameTimeOrLater(launch.getStartTime())).verify(CHILD_START_TIME_EARLIER_THAN_PARENT, - rq.getStartTime(), - launch.getStartTime(), - launch.getId() - ); - expect(isTrue(BooleanUtils.toBoolean(rq.isRetry())), equalTo(false)).verify(BAD_REQUEST_ERROR, "Root test item can't be a retry."); - } + private static final Logger LOGGER = LoggerFactory.getLogger(StartTestItemHandlerImpl.class); + + private final TestItemRepository testItemRepository; + + private final LaunchRepository launchRepository; + + private final UniqueIdGenerator uniqueIdGenerator; + + private final TestCaseHashGenerator testCaseHashGenerator; + + private final RerunHandler rerunHandler; + + private final List<ParentItemValidator> parentItemValidators; + + private final RetrySearcher retrySearcher; + private final RetryHandler retryHandler; + + @Autowired + public StartTestItemHandlerImpl(TestItemRepository testItemRepository, + LaunchRepository launchRepository, + UniqueIdGenerator uniqueIdGenerator, TestCaseHashGenerator testCaseHashGenerator, + RerunHandler rerunHandler, + List<ParentItemValidator> parentItemValidators, + @Qualifier("uniqueIdRetrySearcher") RetrySearcher retrySearcher, + RetryHandler retryHandler) { + this.testItemRepository = testItemRepository; + this.launchRepository = launchRepository; + this.uniqueIdGenerator = uniqueIdGenerator; + this.testCaseHashGenerator = testCaseHashGenerator; + this.rerunHandler = rerunHandler; + this.parentItemValidators = parentItemValidators; + this.retrySearcher = retrySearcher; + this.retryHandler = retryHandler; + } + + @Override + public ItemCreatedRS startRootItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq) { + Launch launch = launchRepository.findByUuid(rq.getLaunchUuid()) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, rq.getLaunchUuid())); + validate(user, projectDetails, rq, launch); + + if (launch.isRerun()) { + Optional<ItemCreatedRS> rerunCreatedRs = rerunHandler.handleRootItem(rq, launch); + if (rerunCreatedRs.isPresent()) { + return rerunCreatedRs.get(); + } + } + + TestItem item = new TestItemBuilder().addStartItemRequest(rq).addAttributes(rq.getAttributes()) + .addLaunchId(launch.getId()).get(); + testItemRepository.save(item); + generateUniqueId(launch, item, String.valueOf(item.getItemId())); + + LOGGER.debug("Created new root TestItem {}", item.getUuid()); + return new ItemCreatedRS(item.getUuid(), item.getUniqueId()); + } + + @Override + public ItemCreatedRS startChildItem(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartTestItemRQ rq, + String parentId) { + boolean isRetry = + BooleanUtils.toBoolean(rq.isRetry()) || StringUtils.isNotBlank(rq.getRetryOf()); + + Launch launch = launchRepository.findByUuid(rq.getLaunchUuid()) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, rq.getLaunchUuid())); + + if (launch.isRerun()) { + Optional<ItemCreatedRS> rerunCreatedRs = rerunHandler.handleChildItem(rq, launch, parentId); + if (rerunCreatedRs.isPresent()) { + return rerunCreatedRs.get(); + } + } + + final TestItem parentItem; + if (isRetry) { + // Lock for test + Long lockedParentId = testItemRepository.findIdByUuidForUpdate(parentId) + .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, parentId)); + parentItem = testItemRepository.getOne(lockedParentId); + } else { + parentItem = testItemRepository.findByUuid(parentId) + .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, parentId)); + } + + parentItemValidators.forEach(v -> v.validate(rq, parentItem)); + + TestItem item = new TestItemBuilder().addStartItemRequest(rq).addAttributes(rq.getAttributes()) + .addLaunchId(launch.getId()).get(); + + if (isRetry) { + ofNullable(rq.getRetryOf()).flatMap(testItemRepository::findIdByUuidForUpdate) + .ifPresentOrElse(retryParentId -> { + saveChildItem(launch, item, parentItem); + retryHandler.handleRetries(launch, item, retryParentId); + }, () -> retrySearcher.findPreviousRetry(launch, item, parentItem) + .ifPresentOrElse(previousRetryId -> { + saveChildItem(launch, item, parentItem); + retryHandler.handleRetries(launch, item, previousRetryId); + }, () -> saveChildItem(launch, item, parentItem))); + } else { + saveChildItem(launch, item, parentItem); + } + + LOGGER.debug("Created new child TestItem {} with root {}", item.getUuid(), parentId); + + if (rq.isHasStats() && !parentItem.isHasChildren()) { + parentItem.setHasChildren(true); + } + + return new ItemCreatedRS(item.getUuid(), item.getUniqueId()); + } + + private TestItem saveChildItem(Launch launch, TestItem childItem, TestItem parentItem) { + childItem.setParentId(parentItem.getItemId()); + testItemRepository.save(childItem); + generateUniqueId(launch, childItem, parentItem.getPath() + "." + childItem.getItemId()); + return childItem; + } + + /** + * Generates and sets {@link TestItem#getUniqueId()} and {@link TestItem#getTestCaseId()} if they + * are empty + * + * @param launch {@link Launch} of {@link TestItem} + * @param item {@link TestItem} + * @param path {@link TestItem} path + */ + private void generateUniqueId(Launch launch, TestItem item, String path) { + item.setPath(path); + if (Objects.isNull(item.getUniqueId())) { + item.setUniqueId(uniqueIdGenerator.generate(item, IdentityUtil.getParentIds(item), launch)); + } + if (Objects.isNull(item.getTestCaseId())) { + item.setTestCaseHash(testCaseHashGenerator.generate(item, IdentityUtil.getParentIds(item), + launch.getProjectId())); + } + } + + /** + * Validate {@link ReportPortalUser} credentials, {@link Launch#getStatus()} and {@link Launch} + * affiliation to the {@link Project} + * + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param rq {@link StartTestItemRQ} + * @param launch {@link Launch} + */ + private void validate(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, + StartTestItemRQ rq, Launch launch) { + if (!UserRole.ADMINISTRATOR.equals(user.getUserRole())) { + expect(projectDetails.getProjectId(), equalTo(launch.getProjectId())).verify(ACCESS_DENIED); + } + expect(rq.getStartTime(), Preconditions.sameTimeOrLater(launch.getStartTime())).verify( + CHILD_START_TIME_EARLIER_THAN_PARENT, + rq.getStartTime(), + launch.getStartTime(), + launch.getId() + ); + expect(isTrue(BooleanUtils.toBoolean(rq.isRetry())), equalTo(false)).verify(BAD_REQUEST_ERROR, + "Root test item can't be a retry."); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImpl.java index db88cdf8f1..e6f0742223 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImpl.java @@ -99,325 +99,351 @@ @Service public class UpdateTestItemHandlerImpl implements UpdateTestItemHandler { - public static final String INITIAL_STATUS_ATTRIBUTE_KEY = "initialStatus"; - private static final String MANUALLY_CHANGED_STATUS_ATTRIBUTE_KEY = "manually"; + public static final String INITIAL_STATUS_ATTRIBUTE_KEY = "initialStatus"; + private static final String MANUALLY_CHANGED_STATUS_ATTRIBUTE_KEY = "manually"; - private final TestItemService testItemService; - - private final ProjectRepository projectRepository; + private final TestItemService testItemService; - private final TestItemRepository testItemRepository; + private final ProjectRepository projectRepository; - private final ExternalTicketHandler externalTicketHandler; + private final TestItemRepository testItemRepository; - private final IssueTypeHandler issueTypeHandler; - - private final MessageBus messageBus; - - private final LogIndexerService logIndexerService; - - private final IssueEntityRepository issueEntityRepository; - - private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; - - @Autowired - public UpdateTestItemHandlerImpl(TestItemService testItemService, ProjectRepository projectRepository, - TestItemRepository testItemRepository, ExternalTicketHandler externalTicketHandler, IssueTypeHandler issueTypeHandler, - MessageBus messageBus, LogIndexerService logIndexerService, IssueEntityRepository issueEntityRepository, - Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping) { - this.testItemService = testItemService; - this.projectRepository = projectRepository; - this.testItemRepository = testItemRepository; - this.externalTicketHandler = externalTicketHandler; - this.issueTypeHandler = issueTypeHandler; - this.messageBus = messageBus; - this.logIndexerService = logIndexerService; - this.issueEntityRepository = issueEntityRepository; - this.statusChangingStrategyMapping = statusChangingStrategyMapping; - } - - @Override - public List<Issue> defineTestItemsIssues(ReportPortalUser.ProjectDetails projectDetails, DefineIssueRQ defineIssue, - ReportPortalUser user) { - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectId())); - - List<String> errors = new ArrayList<>(); - List<IssueDefinition> definitions = defineIssue.getIssues(); - expect(CollectionUtils.isEmpty(definitions), equalTo(false)).verify(FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION); - List<Issue> updated = new ArrayList<>(defineIssue.getIssues().size()); - List<ItemIssueTypeDefinedEvent> events = new ArrayList<>(); - List<TestItem> itemsForIndexUpdate = new ArrayList<>(); - List<Long> itemsForIndexRemove = new ArrayList<>(); - - definitions.forEach(issueDefinition -> { - try { - TestItem testItem = testItemRepository.findById(issueDefinition.getId()) - .orElseThrow(() -> new BusinessRuleViolationException(formattedSupplier( - "Cannot update issue type for test item '{}', cause it is not found.", - issueDefinition.getId() - ).get())); - - verifyTestItem(testItem, issueDefinition.getId()); - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); - - Issue issue = issueDefinition.getIssue(); - IssueType issueType = issueTypeHandler.defineIssueType(projectDetails.getProjectId(), issue.getIssueType()); - - IssueEntity issueEntity = new IssueEntityBuilder(testItem.getItemResults().getIssue()).addIssueType(issueType) - .addDescription(issue.getComment()) - .addIgnoreFlag(issue.getIgnoreAnalyzer()) - .addAutoAnalyzedFlag(issue.getAutoAnalyzed()) - .get(); - - externalTicketHandler.updateLinking(user.getUsername(), issueEntity, issueDefinition.getIssue().getExternalSystemIssues()); - - testItem.getItemResults().setIssue(issueEntity); - issueEntity.setTestItemResults(testItem.getItemResults()); - testItemRepository.save(testItem); - - if (ITEM_CAN_BE_INDEXED.test(testItem)) { - itemsForIndexUpdate.add(testItem); - } else { - itemsForIndexRemove.add(testItem.getItemId()); - } - - updated.add(IssueConverter.TO_MODEL.apply(issueEntity)); - - TestItemActivityResource after = TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); - - events.add(new ItemIssueTypeDefinedEvent(before, after, user.getUserId(), user.getUsername())); - } catch (BusinessRuleViolationException e) { - errors.add(e.getMessage()); - } - }); - expect(errors.isEmpty(), equalTo(TRUE)).verify(FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, errors.toString()); - - logIndexerService.indexDefectsUpdate(project.getId(), AnalyzerUtils.getAnalyzerConfig(project), itemsForIndexUpdate); - logIndexerService.indexItemsRemoveAsync(project.getId(), itemsForIndexRemove); - - events.forEach(messageBus::publishActivity); - return updated; - } - - @Override - public OperationCompletionRS updateTestItem(ReportPortalUser.ProjectDetails projectDetails, Long itemId, UpdateTestItemRQ rq, - ReportPortalUser user) { - TestItem testItem = testItemRepository.findById(itemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); - - validate(projectDetails, user, testItem); - - Optional<StatusEnum> providedStatus = StatusEnum.fromValue(rq.getStatus()); - if (providedStatus.isPresent() && !providedStatus.get().equals(testItem.getItemResults().getStatus())) { - expect(testItem.isHasChildren() && !testItem.getType().sameLevel(TestItemTypeEnum.STEP), equalTo(FALSE)).verify(INCORRECT_REQUEST, - "Unable to change status on test item with children" - ); - checkInitialStatusAttribute(testItem, rq); - StatusChangingStrategy strategy = statusChangingStrategyMapping.get(providedStatus.get()); - - expect(strategy, notNull()).verify(INCORRECT_REQUEST, - formattedSupplier("Actual status: '{}' cannot be changed to '{}'.", - testItem.getItemResults().getStatus(), - providedStatus.get() - ) - ); - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); - strategy.changeStatus(testItem, providedStatus.get(), user); - messageBus.publishActivity(new TestItemStatusChangedEvent(before, - TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()), - user.getUserId(), - user.getUsername() - )); - } - testItem = new TestItemBuilder(testItem).overwriteAttributes(rq.getAttributes()).addDescription(rq.getDescription()).get(); - testItemRepository.save(testItem); - - return COMPOSE_UPDATE_RESPONSE.apply(itemId); - } - - @Override - public List<OperationCompletionRS> processExternalIssues(ExternalIssueRQ request, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - List<String> errors = new ArrayList<>(); - - List<TestItem> testItems = testItemRepository.findAllById(request.getTestItemIds()); - - testItems.forEach(testItem -> { - try { - verifyTestItem(testItem, testItem.getItemId()); - } catch (Exception e) { - errors.add(e.getMessage()); - } - }); - expect(errors.isEmpty(), equalTo(TRUE)).verify(FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, errors.toString()); - - List<TestItemActivityResource> before = testItems.stream() - .map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) - .collect(Collectors.toList()); - - if (LinkExternalIssueRQ.class.equals(request.getClass())) { - LinkExternalIssueRQ linkRequest = (LinkExternalIssueRQ) request; - externalTicketHandler.linkExternalTickets(user.getUsername(), - testItems.stream().map(it -> it.getItemResults().getIssue()).collect(Collectors.toList()), - linkRequest.getIssues() - ); + private final ExternalTicketHandler externalTicketHandler; + + private final IssueTypeHandler issueTypeHandler; + + private final MessageBus messageBus; + + private final LogIndexerService logIndexerService; + + private final IssueEntityRepository issueEntityRepository; + + private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; + + @Autowired + public UpdateTestItemHandlerImpl(TestItemService testItemService, + ProjectRepository projectRepository, TestItemRepository testItemRepository, + ExternalTicketHandler externalTicketHandler, IssueTypeHandler issueTypeHandler, + MessageBus messageBus, LogIndexerService logIndexerService, + IssueEntityRepository issueEntityRepository, + Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping) { + this.testItemService = testItemService; + this.projectRepository = projectRepository; + this.testItemRepository = testItemRepository; + this.externalTicketHandler = externalTicketHandler; + this.issueTypeHandler = issueTypeHandler; + this.messageBus = messageBus; + this.logIndexerService = logIndexerService; + this.issueEntityRepository = issueEntityRepository; + this.statusChangingStrategyMapping = statusChangingStrategyMapping; + } + + @Override + public List<Issue> defineTestItemsIssues(ReportPortalUser.ProjectDetails projectDetails, + DefineIssueRQ defineIssue, ReportPortalUser user) { + Project project = projectRepository.findById(projectDetails.getProjectId()).orElseThrow( + () -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectId())); + + List<String> errors = new ArrayList<>(); + List<IssueDefinition> definitions = defineIssue.getIssues(); + expect(CollectionUtils.isEmpty(definitions), equalTo(false)).verify( + FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION); + List<Issue> updated = new ArrayList<>(defineIssue.getIssues().size()); + List<ItemIssueTypeDefinedEvent> events = new ArrayList<>(); + List<TestItem> itemsForIndexUpdate = new ArrayList<>(); + List<Long> itemsForIndexRemove = new ArrayList<>(); + + definitions.forEach(issueDefinition -> { + try { + TestItem testItem = testItemRepository.findById(issueDefinition.getId()) + .orElseThrow(() -> new BusinessRuleViolationException(formattedSupplier( + "Cannot update issue type for test item '{}', cause it is not found.", + issueDefinition.getId() + ).get())); + + verifyTestItem(testItem, issueDefinition.getId()); + TestItemActivityResource before = + TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); + + Issue issue = issueDefinition.getIssue(); + IssueType issueType = + issueTypeHandler.defineIssueType(projectDetails.getProjectId(), issue.getIssueType()); + + IssueEntity issueEntity = + new IssueEntityBuilder(testItem.getItemResults().getIssue()).addIssueType(issueType) + .addDescription(issue.getComment()).addIgnoreFlag(issue.getIgnoreAnalyzer()) + .addAutoAnalyzedFlag(issue.getAutoAnalyzed()).get(); + + externalTicketHandler.updateLinking( + user.getUsername(), issueEntity, issueDefinition.getIssue().getExternalSystemIssues()); + + testItem.getItemResults().setIssue(issueEntity); + issueEntity.setTestItemResults(testItem.getItemResults()); + testItemRepository.save(testItem); + + if (ITEM_CAN_BE_INDEXED.test(testItem)) { + itemsForIndexUpdate.add(testItem); + } else { + itemsForIndexRemove.add(testItem.getItemId()); + } + + updated.add(IssueConverter.TO_MODEL.apply(issueEntity)); + + TestItemActivityResource after = + TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); + + events.add( + new ItemIssueTypeDefinedEvent(before, after, user.getUserId(), user.getUsername())); + } catch (BusinessRuleViolationException e) { + errors.add(e.getMessage()); + } + }); + expect(errors.isEmpty(), equalTo(TRUE)).verify( + FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, errors.toString()); + + if (CollectionUtils.isNotEmpty(itemsForIndexUpdate)) { + logIndexerService.indexDefectsUpdate( + project.getId(), AnalyzerUtils.getAnalyzerConfig(project), itemsForIndexUpdate); + } + if (CollectionUtils.isNotEmpty(itemsForIndexRemove)) { + logIndexerService.indexItemsRemoveAsync(project.getId(), itemsForIndexRemove); + } + + events.forEach(messageBus::publishActivity); + return updated; + } + + @Override + public OperationCompletionRS updateTestItem(ReportPortalUser.ProjectDetails projectDetails, + Long itemId, UpdateTestItemRQ rq, ReportPortalUser user) { + TestItem testItem = testItemRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); + + validate(projectDetails, user, testItem); + + Optional<StatusEnum> providedStatus = StatusEnum.fromValue(rq.getStatus()); + if (providedStatus.isPresent() && !providedStatus.get() + .equals(testItem.getItemResults().getStatus())) { + expect(testItem.isHasChildren() && !testItem.getType().sameLevel(TestItemTypeEnum.STEP), + equalTo(FALSE) + ).verify(INCORRECT_REQUEST, "Unable to change status on test item with children"); + checkInitialStatusAttribute(testItem, rq); + StatusChangingStrategy strategy = statusChangingStrategyMapping.get(providedStatus.get()); + + expect(strategy, notNull()).verify(INCORRECT_REQUEST, + formattedSupplier("Actual status: '{}' cannot be changed to '{}'.", + testItem.getItemResults().getStatus(), providedStatus.get() + ) + ); + TestItemActivityResource before = + TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()); + strategy.changeStatus(testItem, providedStatus.get(), user, true); + messageBus.publishActivity(new TestItemStatusChangedEvent(before, + TO_ACTIVITY_RESOURCE.apply(testItem, projectDetails.getProjectId()), user.getUserId(), + user.getUsername() + )); + } + testItem = new TestItemBuilder(testItem).overwriteAttributes(rq.getAttributes()) + .addDescription(rq.getDescription()).get(); + testItemRepository.save(testItem); + + return COMPOSE_UPDATE_RESPONSE.apply(itemId); + } + + @Override + public List<OperationCompletionRS> processExternalIssues(ExternalIssueRQ request, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + List<String> errors = new ArrayList<>(); + + List<TestItem> testItems = testItemRepository.findAllById(request.getTestItemIds()); + + testItems.forEach(testItem -> { + try { + verifyTestItem(testItem, testItem.getItemId()); + } catch (Exception e) { + errors.add(e.getMessage()); + } + }); + expect(errors.isEmpty(), equalTo(TRUE)).verify( + FAILED_TEST_ITEM_ISSUE_TYPE_DEFINITION, errors.toString()); + + List<TestItemActivityResource> before = + testItems.stream().map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) + .collect(Collectors.toList()); + + if (LinkExternalIssueRQ.class.equals(request.getClass())) { + LinkExternalIssueRQ linkRequest = (LinkExternalIssueRQ) request; + externalTicketHandler.linkExternalTickets(user.getUsername(), + testItems.stream().map(it -> it.getItemResults().getIssue()).collect(Collectors.toList()), + linkRequest.getIssues() + ); } if (UnlinkExternalIssueRQ.class.equals(request.getClass())) { externalTicketHandler.unlinkExternalTickets(testItems, (UnlinkExternalIssueRQ) request); } testItemRepository.saveAll(testItems); - List<TestItemActivityResource> after = testItems.stream() - .map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) - .collect(Collectors.toList()); + List<TestItemActivityResource> after = + testItems.stream().map(it -> TO_ACTIVITY_RESOURCE.apply(it, projectDetails.getProjectId())) + .collect(Collectors.toList()); before.forEach(it -> messageBus.publishActivity(new LinkTicketEvent(it, after.stream().filter(t -> t.getId().equals(it.getId())).findFirst().get(), - user.getUserId(), - user.getUsername(), - false + user.getUserId(), user.getUsername(), false ))); return testItems.stream().map(TestItem::getItemId).map(COMPOSE_UPDATE_RESPONSE) .collect(toList()); } - private static final Function<Long, OperationCompletionRS> COMPOSE_UPDATE_RESPONSE = it -> { - String message = formattedSupplier("TestItem with ID = '{}' successfully updated.", it).get(); - return new OperationCompletionRS(message); - }; - - private void checkInitialStatusAttribute(TestItem item, UpdateTestItemRQ request) { - Runnable addInitialStatusAttribute = () -> { - ItemAttribute initialStatusAttribute = new ItemAttribute(INITIAL_STATUS_ATTRIBUTE_KEY, - item.getItemResults().getStatus().getExecutionCounterField(), - true - ); - initialStatusAttribute.setTestItem(item); - item.getAttributes().add(initialStatusAttribute); - }; - - Consumer<ItemAttribute> removeManuallyStatusAttributeIfSameAsInitial = statusAttribute -> extractAttributeResource(request.getAttributes(), - MANUALLY_CHANGED_STATUS_ATTRIBUTE_KEY - ).filter(it -> it.getValue() - .equalsIgnoreCase(statusAttribute.getValue())).ifPresent(it -> request.getAttributes().remove(it)); - - extractAttribute(item.getAttributes(), INITIAL_STATUS_ATTRIBUTE_KEY).ifPresentOrElse(removeManuallyStatusAttributeIfSameAsInitial, - addInitialStatusAttribute - ); - } - - @Override - public void resetItemsIssue(List<Long> itemIds, Long projectId, ReportPortalUser user) { - itemIds.forEach(itemId -> { - TestItem item = testItemRepository.findById(itemId).orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, itemId)); - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(item, projectId); - - IssueType issueType = issueTypeHandler.defineIssueType(projectId, TestItemIssueGroup.TO_INVESTIGATE.getLocator()); - IssueEntity issueEntity = new IssueEntityBuilder(issueEntityRepository.findById(itemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.ISSUE_TYPE_NOT_FOUND, itemId))).addIssueType(issueType) - .addAutoAnalyzedFlag(false) - .get(); - issueEntityRepository.save(issueEntity); - item.getItemResults().setIssue(issueEntity); - - TestItemActivityResource after = TO_ACTIVITY_RESOURCE.apply(item, projectId); - if (!StringUtils.equalsIgnoreCase(before.getIssueTypeLongName(), after.getIssueTypeLongName())) { - ItemIssueTypeDefinedEvent event = new ItemIssueTypeDefinedEvent(before, after, user.getUserId(), user.getUsername()); - messageBus.publishActivity(event); - } - }); - } - - @Override - public OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, ReportPortalUser.ProjectDetails projectDetails) { - expect(projectRepository.existsById(projectDetails.getProjectId()), equalTo(TRUE)).verify(PROJECT_NOT_FOUND, - projectDetails.getProjectId() - ); - - List<TestItem> items = testItemRepository.findAllById(bulkUpdateRq.getIds()); - items.forEach(it -> ItemInfoUtils.updateDescription(bulkUpdateRq.getDescription(), it.getDescription()) - .ifPresent(it::setDescription)); - - bulkUpdateRq.getAttributes().forEach(it -> { - switch (it.getAction()) { - case DELETE: { - items.forEach(item -> { - ItemAttribute toDelete = ItemInfoUtils.findAttributeByResource(item.getAttributes(), it.getFrom()); - item.getAttributes().remove(toDelete); - }); - break; - } - case UPDATE: { - items.forEach(item -> ItemInfoUtils.updateAttribute(item.getAttributes(), it)); - break; - } - case CREATE: { - items.stream().filter(item -> ItemInfoUtils.containsAttribute(item.getAttributes(), it.getTo())).forEach(item -> { - ItemAttribute itemAttribute = ItemAttributeConverter.FROM_RESOURCE.apply(it.getTo()); - itemAttribute.setTestItem(item); - item.getAttributes().add(itemAttribute); - }); - break; - } - } - }); - - return new OperationCompletionRS("Attributes successfully updated"); - } - - /** - * Validates test item access ability. - * - * @param projectDetails Project - * @param user User - * @param testItem Test Item - */ - private void validate(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, TestItem testItem) { - Launch launch = testItemService.getEffectiveLaunch(testItem); - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED, - "Launch is not under the specified project." - ); - if (projectDetails.getProjectRole().lowerThan(ProjectRole.PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, "You are not a launch owner."); - } - } - } - - /** - * Complex of domain verification for test item. Verifies that test item - * domain object could be processed correctly. - * - * @param id - test item id - * @throws BusinessRuleViolationException when business rule violation - */ - private void verifyTestItem(TestItem item, Long id) throws BusinessRuleViolationException { - expect(item.getItemResults(), - notNull(), - formattedSupplier("Test item results were not found for test item with id = '{}", item.getItemId()) - ).verify(); - - expect(item.getItemResults().getStatus(), - not(status -> Stream.of(StatusEnum.values()).filter(StatusEnum::isPositive).anyMatch(s -> s == status)), - formattedSupplier("Issue status update cannot be applied on {} test items, cause it is not allowed.", - item.getItemResults().getStatus() - ) - ).verify(); - - expect(item.isHasChildren(), - equalTo(FALSE), - formattedSupplier("It is not allowed to update issue type for items with descendants. Test item '{}' has descendants.", id) - ).verify(); - - expect(item.getItemResults().getIssue(), - notNull(), - formattedSupplier("Cannot update issue type for test item '{}', cause there is no info about actual issue type value.", id) - ).verify(); - - expect(item.getItemResults().getIssue().getIssueType(), - notNull(), - formattedSupplier("Cannot update issue type for test item {}, cause it's actual issue type value is not provided.", id) - ).verify(); - } + private static final Function<Long, OperationCompletionRS> COMPOSE_UPDATE_RESPONSE = it -> { + String message = formattedSupplier("TestItem with ID = '{}' successfully updated.", it).get(); + return new OperationCompletionRS(message); + }; + + private void checkInitialStatusAttribute(TestItem item, UpdateTestItemRQ request) { + Runnable addInitialStatusAttribute = () -> { + ItemAttribute initialStatusAttribute = new ItemAttribute(INITIAL_STATUS_ATTRIBUTE_KEY, + item.getItemResults().getStatus().getExecutionCounterField(), true + ); + initialStatusAttribute.setTestItem(item); + item.getAttributes().add(initialStatusAttribute); + }; + + Consumer<ItemAttribute> removeManuallyStatusAttributeIfSameAsInitial = + statusAttribute -> extractAttributeResource(request.getAttributes(), + MANUALLY_CHANGED_STATUS_ATTRIBUTE_KEY + ).filter(it -> it.getValue().equalsIgnoreCase(statusAttribute.getValue())) + .ifPresent(it -> request.getAttributes().remove(it)); + + extractAttribute(item.getAttributes(), INITIAL_STATUS_ATTRIBUTE_KEY).ifPresentOrElse( + removeManuallyStatusAttributeIfSameAsInitial, addInitialStatusAttribute); + } + + @Override + public void resetItemsIssue(List<Long> itemIds, Long projectId, ReportPortalUser user) { + itemIds.forEach(itemId -> { + TestItem item = testItemRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(TEST_ITEM_NOT_FOUND, itemId)); + TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(item, projectId); + + IssueType issueType = issueTypeHandler.defineIssueType(projectId, + TestItemIssueGroup.TO_INVESTIGATE.getLocator() + ); + IssueEntity issueEntity = new IssueEntityBuilder(issueEntityRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.ISSUE_TYPE_NOT_FOUND, + itemId + ))).addIssueType(issueType).addAutoAnalyzedFlag(false).get(); + issueEntityRepository.save(issueEntity); + item.getItemResults().setIssue(issueEntity); + + TestItemActivityResource after = TO_ACTIVITY_RESOURCE.apply(item, projectId); + if (!StringUtils.equalsIgnoreCase( + before.getIssueTypeLongName(), after.getIssueTypeLongName())) { + ItemIssueTypeDefinedEvent event = + new ItemIssueTypeDefinedEvent(before, after, user.getUserId(), user.getUsername()); + messageBus.publishActivity(event); + } + }); + } + + @Override + public OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, + ReportPortalUser.ProjectDetails projectDetails) { + expect(projectRepository.existsById(projectDetails.getProjectId()), equalTo(TRUE)).verify( + PROJECT_NOT_FOUND, projectDetails.getProjectId()); + + List<TestItem> items = testItemRepository.findAllById(bulkUpdateRq.getIds()); + items.forEach( + it -> ItemInfoUtils.updateDescription(bulkUpdateRq.getDescription(), it.getDescription()) + .ifPresent(it::setDescription)); + + bulkUpdateRq.getAttributes().forEach(it -> { + switch (it.getAction()) { + case DELETE: { + items.forEach(item -> { + ItemAttribute toDelete = + ItemInfoUtils.findAttributeByResource(item.getAttributes(), it.getFrom()); + item.getAttributes().remove(toDelete); + }); + break; + } + case UPDATE: { + items.forEach(item -> ItemInfoUtils.updateAttribute(item.getAttributes(), it)); + break; + } + case CREATE: { + items.stream() + .filter(item -> ItemInfoUtils.containsAttribute(item.getAttributes(), it.getTo())) + .forEach(item -> { + ItemAttribute itemAttribute = + ItemAttributeConverter.FROM_RESOURCE.apply(it.getTo()); + itemAttribute.setTestItem(item); + item.getAttributes().add(itemAttribute); + }); + break; + } + } + }); + + return new OperationCompletionRS("Attributes successfully updated"); + } + + /** + * Validates test item access ability. + * + * @param projectDetails Project + * @param user User + * @param testItem Test Item + */ + private void validate(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + TestItem testItem) { + Launch launch = testItemService.getEffectiveLaunch(testItem); + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED, + "Launch is not under the specified project." + ); + if (projectDetails.getProjectRole().lowerThan(ProjectRole.PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify( + ACCESS_DENIED, "You are not a launch owner."); + } + } + } + + /** + * Complex of domain verification for test item. Verifies that test item + * domain object could be processed correctly. + * + * @param id - test item id + * @throws BusinessRuleViolationException when business rule violation + */ + private void verifyTestItem(TestItem item, Long id) throws BusinessRuleViolationException { + expect(item.getItemResults(), notNull(), + formattedSupplier("Test item results were not found for test item with id = '{}", + item.getItemId() + ) + ).verify(); + + expect(item.getItemResults().getStatus(), + not(status -> Stream.of(StatusEnum.values()).filter(StatusEnum::isPositive) + .anyMatch(s -> s == status)), formattedSupplier( + "Issue status update cannot be applied on {} test items, cause it is not allowed.", + item.getItemResults().getStatus() + ) + ).verify(); + + expect(item.isHasChildren(), equalTo(FALSE), formattedSupplier( + "It is not allowed to update issue type for items with descendants. Test item '{}' has descendants.", + id + )).verify(); + + expect(item.getItemResults().getIssue(), notNull(), formattedSupplier( + "Cannot update issue type for test item '{}', cause there is no info about actual issue type value.", + id + )).verify(); + + expect(item.getItemResults().getIssue().getIssueType(), notNull(), formattedSupplier( + "Cannot update issue type for test item {}, cause it's actual issue type value is not provided.", + id + )).verify(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/FilterUpdater.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/FilterUpdater.java index 231694b8b7..468259be4b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/FilterUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/FilterUpdater.java @@ -23,5 +23,5 @@ */ public interface FilterUpdater { - void update(Queryable filter); + void update(Queryable filter); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacer.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacer.java index 69b7b97809..91db1dde4d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacer.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacer.java @@ -16,20 +16,19 @@ package com.epam.ta.reportportal.core.item.impl.filter.updater; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE_ID; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.dao.IssueTypeRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE_ID; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -37,32 +36,35 @@ @Service public class IssueTypeConditionReplacer implements FilterUpdater { - private final IssueTypeRepository issueTypeRepository; + private final IssueTypeRepository issueTypeRepository; - @Autowired - public IssueTypeConditionReplacer(IssueTypeRepository issueTypeRepository) { - this.issueTypeRepository = issueTypeRepository; - } + @Autowired + public IssueTypeConditionReplacer(IssueTypeRepository issueTypeRepository) { + this.issueTypeRepository = issueTypeRepository; + } - @Override - public void update(Queryable filter) { - // Added to fix performance issue. - List<String> issueTypeLocators = filter.getFilterConditions() - .stream() - .map(ConvertibleCondition::getAllConditions) - .flatMap(List::stream) - .filter(c -> CRITERIA_ISSUE_TYPE.equals(c.getSearchCriteria()) && !c.isNegative() && Condition.IN.equals(c.getCondition())) - .map(FilterCondition::getValue) - .flatMap(c -> Stream.of(c.split(","))) - .collect(Collectors.toList()); + @Override + public void update(Queryable filter) { + // Added to fix performance issue. + List<String> issueTypeLocators = filter.getFilterConditions() + .stream() + .map(ConvertibleCondition::getAllConditions) + .flatMap(List::stream) + .filter(c -> CRITERIA_ISSUE_TYPE.equals(c.getSearchCriteria()) && !c.isNegative() + && Condition.IN.equals(c.getCondition())) + .map(FilterCondition::getValue) + .flatMap(c -> Stream.of(c.split(","))) + .collect(Collectors.toList()); - String issueTypeIdsString = issueTypeRepository.getIssueTypeIdsByLocators(issueTypeLocators) - .stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); + String issueTypeIdsString = issueTypeRepository.getIssueTypeIdsByLocators(issueTypeLocators) + .stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); - FilterCondition oldIssueTypeCondition = new FilterCondition(Condition.IN, false, null, CRITERIA_ISSUE_TYPE); - FilterCondition issueTypeIdCondition = new FilterCondition(Condition.IN, false, issueTypeIdsString, CRITERIA_ISSUE_TYPE_ID); - filter.replaceSearchCriteria(oldIssueTypeCondition, issueTypeIdCondition); - } + FilterCondition oldIssueTypeCondition = new FilterCondition(Condition.IN, false, null, + CRITERIA_ISSUE_TYPE); + FilterCondition issueTypeIdCondition = new FilterCondition(Condition.IN, false, + issueTypeIdsString, CRITERIA_ISSUE_TYPE_ID); + filter.replaceSearchCriteria(oldIssueTypeCondition, issueTypeIdCondition); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/ItemHistoryBaselineEnum.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/ItemHistoryBaselineEnum.java index dc95c21ab9..2d15572b67 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/ItemHistoryBaselineEnum.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/ItemHistoryBaselineEnum.java @@ -17,55 +17,57 @@ package com.epam.ta.reportportal.core.item.impl.history; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; - import java.util.Arrays; import java.util.Comparator; import java.util.Optional; import java.util.function.Predicate; /** - * Enum for {@link com.epam.ta.reportportal.entity.item.history.TestItemHistory} retrieving type resolving. + * Enum for {@link com.epam.ta.reportportal.entity.item.history.TestItemHistory} retrieving type + * resolving. * * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public enum ItemHistoryBaselineEnum { - COMPARING(1, - historyRequestParams -> historyRequestParams.getHistoryType() - .map(HistoryRequestParams.HistoryTypeEnum.COMPARING::equals) - .orElse(Boolean.FALSE) - ), - FILTER(2, historyRequestParams -> historyRequestParams.getFilterParams().isPresent()), - ITEM(3, historyRequestParams -> historyRequestParams.getParentId().isPresent() || historyRequestParams.getItemId().isPresent()), - LAUNCH(4, historyRequestParams -> historyRequestParams.getLaunchId().isPresent()); + COMPARING(1, + historyRequestParams -> historyRequestParams.getHistoryType() + .map(HistoryRequestParams.HistoryTypeEnum.COMPARING::equals) + .orElse(Boolean.FALSE) + ), + FILTER(2, historyRequestParams -> historyRequestParams.getFilterParams().isPresent()), + ITEM(3, historyRequestParams -> historyRequestParams.getParentId().isPresent() + || historyRequestParams.getItemId().isPresent()), + LAUNCH(4, historyRequestParams -> historyRequestParams.getLaunchId().isPresent()); - private final int priority; - private final Predicate<HistoryRequestParams> baseLinePredicate; + private final int priority; + private final Predicate<HistoryRequestParams> baseLinePredicate; - /** - * {@link ItemHistoryBaselineEnum} is resolved using {@link Predicate}, - * types ordered by `priority` field in ascending order, first matched type is returned. - * - * @param historyRequestParams {@link HistoryRequestParams} - * @return {@link Optional} with {@link ItemHistoryBaselineEnum} - */ - public static Optional<ItemHistoryBaselineEnum> resolveType(HistoryRequestParams historyRequestParams) { - return Arrays.stream(ItemHistoryBaselineEnum.values()) - .sorted(Comparator.comparingInt(ItemHistoryBaselineEnum::getPriority)) - .filter(v -> v.getBaseLinePredicate().test(historyRequestParams)) - .findFirst(); - } + /** + * {@link ItemHistoryBaselineEnum} is resolved using {@link Predicate}, types ordered by + * `priority` field in ascending order, first matched type is returned. + * + * @param historyRequestParams {@link HistoryRequestParams} + * @return {@link Optional} with {@link ItemHistoryBaselineEnum} + */ + public static Optional<ItemHistoryBaselineEnum> resolveType( + HistoryRequestParams historyRequestParams) { + return Arrays.stream(ItemHistoryBaselineEnum.values()) + .sorted(Comparator.comparingInt(ItemHistoryBaselineEnum::getPriority)) + .filter(v -> v.getBaseLinePredicate().test(historyRequestParams)) + .findFirst(); + } - ItemHistoryBaselineEnum(int priority, Predicate<HistoryRequestParams> baseLinePredicate) { - this.priority = priority; - this.baseLinePredicate = baseLinePredicate; - } + ItemHistoryBaselineEnum(int priority, Predicate<HistoryRequestParams> baseLinePredicate) { + this.priority = priority; + this.baseLinePredicate = baseLinePredicate; + } - public int getPriority() { - return priority; - } + public int getPriority() { + return priority; + } - public Predicate<HistoryRequestParams> getBaseLinePredicate() { - return baseLinePredicate; - } + public Predicate<HistoryRequestParams> getBaseLinePredicate() { + return baseLinePredicate; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImpl.java index 02ce4b8c28..2540a28565 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImpl.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.item.impl.history; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_STATS; +import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_LOAD_TEST_ITEM_HISTORY; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_HISTORY_DEPTH_BOUND; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_HISTORY_DEPTH_BOUND; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.CompositeFilter; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -39,6 +50,11 @@ import com.epam.ta.reportportal.ws.model.TestItemHistoryElement; import com.epam.ta.reportportal.ws.model.TestItemResource; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Predicate; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -47,21 +63,6 @@ import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_STATS; -import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_LOAD_TEST_ITEM_HISTORY; -import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_HISTORY_DEPTH_BOUND; -import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_HISTORY_DEPTH_BOUND; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.*; - /** * Creating items history based on {@link TestItem#getTestCaseId()} field * @@ -70,107 +71,123 @@ @Service public class TestItemsHistoryHandlerImpl implements TestItemsHistoryHandler { - @Value("${rp.environment.variable.history.old}") - private boolean oldHistory; - - private final TestItemRepository testItemRepository; - private final HistoryProviderFactory historyProviderFactory; - private final List<ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource>> resourceUpdaterProviders; - - @Autowired - public TestItemsHistoryHandlerImpl(TestItemRepository testItemRepository, HistoryProviderFactory historyProviderFactory, - List<ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource>> resourceUpdaterProviders) { - this.testItemRepository = testItemRepository; - this.historyProviderFactory = historyProviderFactory; - this.resourceUpdaterProviders = resourceUpdaterProviders; - } - - @Override - public Iterable<TestItemHistoryElement> getItemsHistory(ReportPortalUser.ProjectDetails projectDetails, Queryable filter, - Pageable pageable, HistoryRequestParams historyRequestParams, ReportPortalUser user) { - - validateHistoryDepth(historyRequestParams.getHistoryDepth()); - - CompositeFilter itemHistoryFilter = new CompositeFilter(Operator.AND, - filter, - Filter.builder() - .withTarget(filter.getTarget().getClazz()) - .withCondition(FilterCondition.builder() - .eq(CRITERIA_PROJECT_ID, String.valueOf(projectDetails.getProjectId())) - .build()) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, LaunchModeEnum.DEFAULT.name()).build()) - .withCondition(FilterCondition.builder().eq(CRITERIA_HAS_STATS, String.valueOf(Boolean.TRUE)).build()) - .build() - ); - - Page<TestItemHistory> testItemHistoryPage = historyProviderFactory.getProvider(historyRequestParams) - .orElseThrow(() -> new ReportPortalException(UNABLE_LOAD_TEST_ITEM_HISTORY, - "Unable to find suitable history baseline provider" - )) - .provide(itemHistoryFilter, pageable, historyRequestParams, projectDetails, user, !oldHistory); - - return buildHistoryElements( - oldHistory ? TestItemResource::getUniqueId : testItemResource -> String.valueOf(testItemResource.getTestCaseHash()), - testItemHistoryPage, - projectDetails.getProjectId(), - pageable - ); - - } - - private void validateHistoryDepth(int historyDepth) { - Predicate<Integer> greaterThan = t -> t > MIN_HISTORY_DEPTH_BOUND; - Predicate<Integer> lessThan = t -> t < MAX_HISTORY_DEPTH_BOUND; - String historyDepthMessage = Suppliers.formattedSupplier("Items history depth should be greater than '{}' and lower than '{}'", - MIN_HISTORY_DEPTH_BOUND, - MAX_HISTORY_DEPTH_BOUND - ) - .get(); - BusinessRule.expect(historyDepth, greaterThan.and(lessThan)).verify(UNABLE_LOAD_TEST_ITEM_HISTORY, historyDepthMessage); - } - - private Iterable<TestItemHistoryElement> buildHistoryElements(Function<TestItemResource, String> groupingFunction, - Page<TestItemHistory> testItemHistoryPage, Long projectId, Pageable pageable) { - - List<TestItem> testItems = testItemRepository.findAllById(testItemHistoryPage.getContent() - .stream() - .flatMap(history -> history.getItemIds().stream()) - .collect(toList())); - - List<ResourceUpdater<TestItemResource>> resourceUpdaters = getResourceUpdaters(projectId, testItems); - - Map<String, Map<Long, TestItemResource>> itemsMapping = testItems.stream().map(item -> { - TestItemResource testItemResource = TestItemConverter.TO_RESOURCE.apply(item); - resourceUpdaters.forEach(updater -> updater.updateResource(testItemResource)); - return testItemResource; - }).collect(groupingBy(groupingFunction, toMap(TestItemResource::getItemId, res -> res))); - - List<TestItemHistoryElement> testItemHistoryElements = testItemHistoryPage.getContent() - .stream() - .map(history -> ofNullable(itemsMapping.get(history.getGroupingField())).map(mapping -> { - TestItemHistoryElement historyResource = new TestItemHistoryElement(); - historyResource.setGroupingField(history.getGroupingField()); - List<TestItemResource> resources = Lists.newArrayList(); - ofNullable(history.getItemIds()).ifPresent(itemIds -> itemIds.forEach(itemId -> ofNullable(mapping.get(itemId)).ifPresent( - resources::add))); - historyResource.setResources(resources); - return historyResource; - })) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(toList()); - - return PagedResourcesAssembler.<TestItemHistoryElement>pageConverter().apply(PageableExecutionUtils.getPage(testItemHistoryElements, - pageable, - testItemHistoryPage::getTotalElements - )); - - } - - private List<ResourceUpdater<TestItemResource>> getResourceUpdaters(Long projectId, List<TestItem> testItems) { - return resourceUpdaterProviders.stream() - .map(retriever -> retriever.retrieve(TestItemUpdaterContent.of(projectId, testItems))) - .collect(toList()); - - } + @Value("${rp.environment.variable.history.old}") + private boolean oldHistory; + + private final TestItemRepository testItemRepository; + private final HistoryProviderFactory historyProviderFactory; + private final List<ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource>> resourceUpdaterProviders; + + @Autowired + public TestItemsHistoryHandlerImpl(TestItemRepository testItemRepository, + HistoryProviderFactory historyProviderFactory, + List<ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource>> resourceUpdaterProviders) { + this.testItemRepository = testItemRepository; + this.historyProviderFactory = historyProviderFactory; + this.resourceUpdaterProviders = resourceUpdaterProviders; + } + + @Override + public Iterable<TestItemHistoryElement> getItemsHistory( + ReportPortalUser.ProjectDetails projectDetails, Queryable filter, + Pageable pageable, HistoryRequestParams historyRequestParams, ReportPortalUser user) { + + validateHistoryDepth(historyRequestParams.getHistoryDepth()); + + CompositeFilter itemHistoryFilter = new CompositeFilter(Operator.AND, + filter, + Filter.builder() + .withTarget(filter.getTarget().getClazz()) + .withCondition(FilterCondition.builder() + .eq(CRITERIA_PROJECT_ID, String.valueOf(projectDetails.getProjectId())) + .build()) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, LaunchModeEnum.DEFAULT.name()) + .build()) + .withCondition( + FilterCondition.builder().eq(CRITERIA_HAS_STATS, String.valueOf(Boolean.TRUE)) + .build()) + .build() + ); + + Page<TestItemHistory> testItemHistoryPage = historyProviderFactory.getProvider( + historyRequestParams) + .orElseThrow(() -> new ReportPortalException(UNABLE_LOAD_TEST_ITEM_HISTORY, + "Unable to find suitable history baseline provider" + )) + .provide(itemHistoryFilter, pageable, historyRequestParams, projectDetails, user, + !oldHistory); + + return buildHistoryElements( + oldHistory ? TestItemResource::getUniqueId + : testItemResource -> String.valueOf(testItemResource.getTestCaseHash()), + testItemHistoryPage, + projectDetails.getProjectId(), + pageable + ); + + } + + private void validateHistoryDepth(int historyDepth) { + Predicate<Integer> greaterThan = t -> t > MIN_HISTORY_DEPTH_BOUND; + Predicate<Integer> lessThan = t -> t < MAX_HISTORY_DEPTH_BOUND; + String historyDepthMessage = Suppliers.formattedSupplier( + "Items history depth should be greater than '{}' and lower than '{}'", + MIN_HISTORY_DEPTH_BOUND, + MAX_HISTORY_DEPTH_BOUND + ) + .get(); + BusinessRule.expect(historyDepth, greaterThan.and(lessThan)) + .verify(UNABLE_LOAD_TEST_ITEM_HISTORY, historyDepthMessage); + } + + private Iterable<TestItemHistoryElement> buildHistoryElements( + Function<TestItemResource, String> groupingFunction, + Page<TestItemHistory> testItemHistoryPage, Long projectId, Pageable pageable) { + + List<TestItem> testItems = testItemRepository.findAllById(testItemHistoryPage.getContent() + .stream() + .flatMap(history -> history.getItemIds().stream()) + .collect(toList())); + + List<ResourceUpdater<TestItemResource>> resourceUpdaters = getResourceUpdaters(projectId, + testItems); + + Map<String, Map<Long, TestItemResource>> itemsMapping = testItems.stream().map(item -> { + TestItemResource testItemResource = TestItemConverter.TO_RESOURCE.apply(item); + resourceUpdaters.forEach(updater -> updater.updateResource(testItemResource)); + return testItemResource; + }).collect(groupingBy(groupingFunction, toMap(TestItemResource::getItemId, res -> res))); + + List<TestItemHistoryElement> testItemHistoryElements = testItemHistoryPage.getContent() + .stream() + .map(history -> ofNullable(itemsMapping.get(history.getGroupingField())).map(mapping -> { + TestItemHistoryElement historyResource = new TestItemHistoryElement(); + historyResource.setGroupingField(history.getGroupingField()); + List<TestItemResource> resources = Lists.newArrayList(); + ofNullable(history.getItemIds()).ifPresent( + itemIds -> itemIds.forEach(itemId -> ofNullable(mapping.get(itemId)).ifPresent( + resources::add))); + historyResource.setResources(resources); + return historyResource; + })) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + + return PagedResourcesAssembler.<TestItemHistoryElement>pageConverter() + .apply(PageableExecutionUtils.getPage(testItemHistoryElements, + pageable, + testItemHistoryPage::getTotalElements + )); + + } + + private List<ResourceUpdater<TestItemResource>> getResourceUpdaters(Long projectId, + List<TestItem> testItems) { + return resourceUpdaterProviders.stream() + .map(retriever -> retriever.retrieve(TestItemUpdaterContent.of(projectId, testItems))) + .collect(toList()); + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/param/HistoryRequestParams.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/param/HistoryRequestParams.java index cbff81424a..368db777c4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/param/HistoryRequestParams.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/param/HistoryRequestParams.java @@ -16,110 +16,118 @@ package com.epam.ta.reportportal.core.item.impl.history.param; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.Arrays; import java.util.Optional; -import static java.util.Optional.ofNullable; - /** - * NULL-safe container for {@link com.epam.ta.reportportal.ws.controller.TestItemController#getItemsHistory} request params + * NULL-safe container for + * {@link com.epam.ta.reportportal.ws.controller.TestItemController#getItemsHistory} request params * * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class HistoryRequestParams { - private int historyDepth; - private Long parentId; - private Long itemId; - private Long launchId; - private HistoryTypeEnum historyType; - private FilterParams filterParams; - - private HistoryRequestParams(int historyDepth, Long parentId, Long itemId, Long launchId, String historyType, Long filterId, - int launchesLimit, boolean isLatest) { - this.historyDepth = historyDepth; - this.parentId = parentId; - this.itemId = itemId; - this.launchId = launchId; - ofNullable(historyType).ifPresent(type -> this.historyType = HistoryTypeEnum.fromValue(historyType) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Wrong history type - '{}'", historyType).get() - ))); - ofNullable(filterId).ifPresent(id -> this.filterParams = FilterParams.of(filterId, launchesLimit, isLatest)); - } - - public enum HistoryTypeEnum { - TABLE, - LINE, - COMPARING; - - public static Optional<HistoryTypeEnum> fromValue(String type) { - return Arrays.stream(HistoryTypeEnum.values()).filter(v -> v.name().equalsIgnoreCase(type)).findFirst(); - } - } - - /** - * Container for {@link com.epam.ta.reportportal.ws.controller.TestItemController#getItemsHistory} launch's filter-related request params - */ - public static final class FilterParams { - private Long filterId; - private int launchesLimit; - private boolean isLatest; - - private FilterParams(Long filterId, int launchesLimit, boolean isLatest) { - this.filterId = filterId; - this.launchesLimit = launchesLimit; - this.isLatest = isLatest; - } - - public Long getFilterId() { - return filterId; - } - - public int getLaunchesLimit() { - return launchesLimit; - } - - public boolean isLatest() { - return isLatest; - } - - public static FilterParams of(Long filterId, int launchesLimit, boolean isLatest) { - return new FilterParams(filterId, launchesLimit, isLatest); - } - - } - - public int getHistoryDepth() { - return historyDepth; - } - - public Optional<FilterParams> getFilterParams() { - return ofNullable(filterParams); - } - - public Optional<Long> getParentId() { - return ofNullable(parentId); - } - - public Optional<Long> getItemId() { - return ofNullable(itemId); - } - - public Optional<Long> getLaunchId() { - return ofNullable(launchId); - } - - public Optional<HistoryTypeEnum> getHistoryType() { - return ofNullable(historyType); - } - - public static HistoryRequestParams of(int historyDepth, Long parentId, Long itemId, Long launchId, String historyType, Long filterId, - int launchesLimit, boolean isLatest) { - return new HistoryRequestParams(historyDepth, parentId, itemId, launchId, historyType, filterId, launchesLimit, isLatest); - } + private int historyDepth; + private Long parentId; + private Long itemId; + private Long launchId; + private HistoryTypeEnum historyType; + private FilterParams filterParams; + + private HistoryRequestParams(int historyDepth, Long parentId, Long itemId, Long launchId, + String historyType, Long filterId, + int launchesLimit, boolean isLatest) { + this.historyDepth = historyDepth; + this.parentId = parentId; + this.itemId = itemId; + this.launchId = launchId; + ofNullable(historyType).ifPresent( + type -> this.historyType = HistoryTypeEnum.fromValue(historyType) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Wrong history type - '{}'", historyType).get() + ))); + ofNullable(filterId).ifPresent( + id -> this.filterParams = FilterParams.of(filterId, launchesLimit, isLatest)); + } + + public enum HistoryTypeEnum { + TABLE, + LINE, + COMPARING; + + public static Optional<HistoryTypeEnum> fromValue(String type) { + return Arrays.stream(HistoryTypeEnum.values()).filter(v -> v.name().equalsIgnoreCase(type)) + .findFirst(); + } + } + + /** + * Container for {@link com.epam.ta.reportportal.ws.controller.TestItemController#getItemsHistory} + * launch's filter-related request params + */ + public static final class FilterParams { + + private Long filterId; + private int launchesLimit; + private boolean isLatest; + + private FilterParams(Long filterId, int launchesLimit, boolean isLatest) { + this.filterId = filterId; + this.launchesLimit = launchesLimit; + this.isLatest = isLatest; + } + + public Long getFilterId() { + return filterId; + } + + public int getLaunchesLimit() { + return launchesLimit; + } + + public boolean isLatest() { + return isLatest; + } + + public static FilterParams of(Long filterId, int launchesLimit, boolean isLatest) { + return new FilterParams(filterId, launchesLimit, isLatest); + } + + } + + public int getHistoryDepth() { + return historyDepth; + } + + public Optional<FilterParams> getFilterParams() { + return ofNullable(filterParams); + } + + public Optional<Long> getParentId() { + return ofNullable(parentId); + } + + public Optional<Long> getItemId() { + return ofNullable(itemId); + } + + public Optional<Long> getLaunchId() { + return ofNullable(launchId); + } + + public Optional<HistoryTypeEnum> getHistoryType() { + return ofNullable(historyType); + } + + public static HistoryRequestParams of(int historyDepth, Long parentId, Long itemId, Long launchId, + String historyType, Long filterId, + int launchesLimit, boolean isLatest) { + return new HistoryRequestParams(historyDepth, parentId, itemId, launchId, historyType, filterId, + launchesLimit, isLatest); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProvider.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProvider.java index 063e58086f..9218c40f36 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProvider.java @@ -18,8 +18,8 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Queryable; -import com.epam.ta.reportportal.entity.item.history.TestItemHistory; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; +import com.epam.ta.reportportal.entity.item.history.TestItemHistory; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -30,14 +30,18 @@ */ public interface HistoryProvider { - /** - * @param filter - {@link Queryable} - * @param pageable - {@link Pageable} - * @param historyRequestParams - {@link HistoryRequestParams} - * @param projectDetails - {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param user - {@link ReportPortalUser} - * @return {@link Page} with {@link TestItemHistory} content - */ - Page<TestItemHistory> provide(Queryable filter, Pageable pageable, HistoryRequestParams historyRequestParams, - ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash); + /** + * @param filter - {@link Queryable} + * @param pageable - {@link Pageable} + * @param historyRequestParams - {@link HistoryRequestParams} + * @param projectDetails - + * {@link + * com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param user - {@link ReportPortalUser} + * @param usingHash - true if need use hash + * @return {@link Page} with {@link TestItemHistory} content + */ + Page<TestItemHistory> provide(Queryable filter, Pageable pageable, + HistoryRequestParams historyRequestParams, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProviderFactory.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProviderFactory.java index 2612bf338b..d0a8fd83c8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProviderFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/HistoryProviderFactory.java @@ -18,11 +18,10 @@ import com.epam.ta.reportportal.core.item.impl.history.ItemHistoryBaselineEnum; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -30,14 +29,16 @@ @Service public class HistoryProviderFactory { - private Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping; + private Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping; - @Autowired - public HistoryProviderFactory(Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping) { - this.historyProviderMapping = historyProviderMapping; - } + @Autowired + public HistoryProviderFactory( + Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping) { + this.historyProviderMapping = historyProviderMapping; + } - public Optional<HistoryProvider> getProvider(HistoryRequestParams historyRequestParams) { - return ItemHistoryBaselineEnum.resolveType(historyRequestParams).map(this.historyProviderMapping::get); - } + public Optional<HistoryProvider> getProvider(HistoryRequestParams historyRequestParams) { + return ItemHistoryBaselineEnum.resolveType(historyRequestParams) + .map(this.historyProviderMapping::get); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/config/ItemHistoryProviderConfiguration.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/config/ItemHistoryProviderConfiguration.java index 6d2c2c6011..f36b3dce7b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/config/ItemHistoryProviderConfiguration.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/config/ItemHistoryProviderConfiguration.java @@ -16,12 +16,14 @@ package com.epam.ta.reportportal.core.item.impl.history.provider.config; -import com.epam.ta.reportportal.core.item.impl.history.provider.impl.ComparingBaselineHistoryProvider; -import com.epam.ta.reportportal.core.item.impl.history.provider.impl.FilterBaselineHistoryProvider; import com.epam.ta.reportportal.core.item.impl.history.ItemHistoryBaselineEnum; import com.epam.ta.reportportal.core.item.impl.history.provider.HistoryProvider; +import com.epam.ta.reportportal.core.item.impl.history.provider.impl.ComparingBaselineHistoryProvider; +import com.epam.ta.reportportal.core.item.impl.history.provider.impl.FilterBaselineHistoryProvider; import com.epam.ta.reportportal.core.item.impl.history.provider.impl.LaunchBaselineHistoryProvider; import com.epam.ta.reportportal.core.item.impl.history.provider.impl.TestItemBaselineHistoryProvider; +import java.util.HashMap; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -29,30 +31,31 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.HashMap; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Configuration public class ItemHistoryProviderConfiguration implements ApplicationContextAware { - private ApplicationContext applicationContext; - - @Autowired - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Bean(name = "historyProviderMapping") - public Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping() { - Map<ItemHistoryBaselineEnum, HistoryProvider> mapping = new HashMap<>(); - mapping.put(ItemHistoryBaselineEnum.COMPARING, applicationContext.getBean(ComparingBaselineHistoryProvider.class)); - mapping.put(ItemHistoryBaselineEnum.FILTER, applicationContext.getBean(FilterBaselineHistoryProvider.class)); - mapping.put(ItemHistoryBaselineEnum.ITEM, applicationContext.getBean(TestItemBaselineHistoryProvider.class)); - mapping.put(ItemHistoryBaselineEnum.LAUNCH, applicationContext.getBean(LaunchBaselineHistoryProvider.class)); - return mapping; - } + private ApplicationContext applicationContext; + + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Bean(name = "historyProviderMapping") + public Map<ItemHistoryBaselineEnum, HistoryProvider> historyProviderMapping() { + Map<ItemHistoryBaselineEnum, HistoryProvider> mapping = new HashMap<>(); + mapping.put(ItemHistoryBaselineEnum.COMPARING, + applicationContext.getBean(ComparingBaselineHistoryProvider.class)); + mapping.put(ItemHistoryBaselineEnum.FILTER, + applicationContext.getBean(FilterBaselineHistoryProvider.class)); + mapping.put(ItemHistoryBaselineEnum.ITEM, + applicationContext.getBean(TestItemBaselineHistoryProvider.class)); + mapping.put(ItemHistoryBaselineEnum.LAUNCH, + applicationContext.getBean(LaunchBaselineHistoryProvider.class)); + return mapping; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/LaunchBaselineHistoryProvider.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/LaunchBaselineHistoryProvider.java index 29e8a66af3..ec7c80627b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/LaunchBaselineHistoryProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/LaunchBaselineHistoryProvider.java @@ -32,48 +32,51 @@ import org.springframework.stereotype.Service; /** - * Required for retrieving {@link TestItemHistory} content using {@link Launch#getId()} as baseline for {@link TestItemHistory} selection. + * Required for retrieving {@link TestItemHistory} content using {@link Launch#getId()} as baseline + * for {@link TestItemHistory} selection. * * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class LaunchBaselineHistoryProvider implements HistoryProvider { - private final LaunchRepository launchRepository; - private final LaunchAccessValidator launchAccessValidator; - private final TestItemRepository testItemRepository; + private final LaunchRepository launchRepository; + private final LaunchAccessValidator launchAccessValidator; + private final TestItemRepository testItemRepository; - public LaunchBaselineHistoryProvider(LaunchRepository launchRepository, LaunchAccessValidator launchAccessValidator, - TestItemRepository testItemRepository) { - this.launchRepository = launchRepository; - this.launchAccessValidator = launchAccessValidator; - this.testItemRepository = testItemRepository; - } + public LaunchBaselineHistoryProvider(LaunchRepository launchRepository, + LaunchAccessValidator launchAccessValidator, + TestItemRepository testItemRepository) { + this.launchRepository = launchRepository; + this.launchAccessValidator = launchAccessValidator; + this.testItemRepository = testItemRepository; + } - @Override - public Page<TestItemHistory> provide(Queryable filter, Pageable pageable, HistoryRequestParams historyRequestParams, - ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { - return historyRequestParams.getLaunchId().map(launchId -> { - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); - launchAccessValidator.validate(launch.getId(), projectDetails, user); + @Override + public Page<TestItemHistory> provide(Queryable filter, Pageable pageable, + HistoryRequestParams historyRequestParams, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { + return historyRequestParams.getLaunchId().map(launchId -> { + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); + launchAccessValidator.validate(launch.getId(), projectDetails, user); - return historyRequestParams.getHistoryType() - .filter(HistoryRequestParams.HistoryTypeEnum.LINE::equals) - .map(type -> testItemRepository.loadItemsHistoryPage(filter, - pageable, - projectDetails.getProjectId(), - launch.getName(), - historyRequestParams.getHistoryDepth(), - usingHash - )) - .orElseGet(() -> testItemRepository.loadItemsHistoryPage(filter, - pageable, - projectDetails.getProjectId(), - historyRequestParams.getHistoryDepth(), - usingHash - )); - }).orElseGet(() -> Page.empty(pageable)); - } + return historyRequestParams.getHistoryType() + .filter(HistoryRequestParams.HistoryTypeEnum.LINE::equals) + .map(type -> testItemRepository.loadItemsHistoryPage(filter, + pageable, + projectDetails.getProjectId(), + launch.getName(), + historyRequestParams.getHistoryDepth(), + usingHash + )) + .orElseGet(() -> testItemRepository.loadItemsHistoryPage(filter, + pageable, + projectDetails.getProjectId(), + historyRequestParams.getHistoryDepth(), + usingHash + )); + }).orElseGet(() -> Page.empty(pageable)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/TestItemBaselineHistoryProvider.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/TestItemBaselineHistoryProvider.java index d451333c3c..b1512142d9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/TestItemBaselineHistoryProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/history/provider/impl/TestItemBaselineHistoryProvider.java @@ -16,8 +16,16 @@ package com.epam.ta.reportportal.core.item.impl.history.provider.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_CHILDREN; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PARENT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.item.impl.LaunchAccessValidator; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; @@ -28,6 +36,8 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; @@ -35,11 +45,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.*; - /** * * Required for retrieving {@link TestItemHistory} content. * @@ -48,95 +53,100 @@ @Service public class TestItemBaselineHistoryProvider implements HistoryProvider { - private final TestItemService testItemService; - private final LaunchAccessValidator launchAccessValidator; - private final TestItemRepository testItemRepository; + private final TestItemService testItemService; + private final LaunchAccessValidator launchAccessValidator; + private final TestItemRepository testItemRepository; - @Autowired - public TestItemBaselineHistoryProvider(TestItemService testItemService, LaunchAccessValidator launchAccessValidator, - TestItemRepository testItemRepository) { - this.testItemService = testItemService; - this.launchAccessValidator = launchAccessValidator; - this.testItemRepository = testItemRepository; - } + @Autowired + public TestItemBaselineHistoryProvider(TestItemService testItemService, + LaunchAccessValidator launchAccessValidator, + TestItemRepository testItemRepository) { + this.testItemService = testItemService; + this.launchAccessValidator = launchAccessValidator; + this.testItemRepository = testItemRepository; + } - @Override - public Page<TestItemHistory> provide(Queryable filter, Pageable pageable, HistoryRequestParams historyRequestParams, - ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { + @Override + public Page<TestItemHistory> provide(Queryable filter, Pageable pageable, + HistoryRequestParams historyRequestParams, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { - return historyRequestParams.getParentId() - .map(parentId -> loadHistory(resolveFilter(filter, parentId), - pageable, - parentId, - historyRequestParams, - projectDetails, - user, - usingHash - )) - .orElseGet(() -> historyRequestParams.getItemId() - .map(itemId -> loadHistory(filter, pageable, itemId, historyRequestParams, projectDetails, user, usingHash)) - .orElseGet(() -> Page.empty(pageable))); - } + return historyRequestParams.getParentId() + .map(parentId -> loadHistory(resolveFilter(filter, parentId), + pageable, + parentId, + historyRequestParams, + projectDetails, + user, + usingHash + )) + .orElseGet(() -> historyRequestParams.getItemId() + .map(itemId -> loadHistory(filter, pageable, itemId, historyRequestParams, + projectDetails, user, usingHash)) + .orElseGet(() -> Page.empty(pageable))); + } - /** - * Replace {@link Condition#EQUALS} for parent item by {@link Condition#UNDER} - * if descendants with {@link TestItem#isHasChildren()} == 'false' should be selected - * - * @param filter {@link Queryable} - * @param parentId Id of the parent {@link TestItem} which descendants' history should be built - * @return Updated {@link Queryable} - */ - private Queryable resolveFilter(Queryable filter, Long parentId) { - return filter.getFilterConditions() - .stream() - .flatMap(c -> c.getAllConditions().stream()) - .filter(c -> CRITERIA_HAS_CHILDREN.equalsIgnoreCase(c.getSearchCriteria()) && !BooleanUtils.toBoolean(c.getValue())) - .findFirst() - .map(notHasChildren -> updateParentFilter(filter, parentId)) - .orElse(filter); - } + /** + * Replace {@link Condition#EQUALS} for parent item by {@link Condition#UNDER} if descendants with + * {@link TestItem#isHasChildren()} == 'false' should be selected + * + * @param filter {@link Queryable} + * @param parentId Id of the parent {@link TestItem} which descendants' history should be built + * @return Updated {@link Queryable} + */ + private Queryable resolveFilter(Queryable filter, Long parentId) { + return filter.getFilterConditions() + .stream() + .flatMap(c -> c.getAllConditions().stream()) + .filter(c -> CRITERIA_HAS_CHILDREN.equalsIgnoreCase(c.getSearchCriteria()) + && !BooleanUtils.toBoolean(c.getValue())) + .findFirst() + .map(notHasChildren -> updateParentFilter(filter, parentId)) + .orElse(filter); + } - private Queryable updateParentFilter(Queryable parentFilter, Long parentId) { - TestItem parent = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); - List<ConvertibleCondition> resultConditions = parentFilter.getFilterConditions() - .stream() - .filter(c -> c.getAllConditions() - .stream() - .noneMatch(fc -> CRITERIA_PARENT_ID.equalsIgnoreCase(fc.getSearchCriteria()) - && Condition.EQUALS.equals(fc.getCondition()))) - .collect(Collectors.toList()); - resultConditions.add(FilterCondition.builder() - .withOperator(Operator.AND) - .withCondition(Condition.UNDER) - .withSearchCriteria(CRITERIA_PATH) - .withValue(String.valueOf(parent.getPath())) - .build()); - return new Filter(parentFilter.getTarget().getClazz(), resultConditions); - } + private Queryable updateParentFilter(Queryable parentFilter, Long parentId) { + TestItem parent = testItemRepository.findById(parentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); + List<ConvertibleCondition> resultConditions = parentFilter.getFilterConditions() + .stream() + .filter(c -> c.getAllConditions() + .stream() + .noneMatch(fc -> CRITERIA_PARENT_ID.equalsIgnoreCase(fc.getSearchCriteria()) + && Condition.EQUALS.equals(fc.getCondition()))) + .collect(Collectors.toList()); + resultConditions.add(FilterCondition.builder() + .withOperator(Operator.AND) + .withCondition(Condition.UNDER) + .withSearchCriteria(CRITERIA_PATH) + .withValue(String.valueOf(parent.getPath())) + .build()); + return new Filter(parentFilter.getTarget().getClazz(), resultConditions); + } - private Page<TestItemHistory> loadHistory(Queryable filter, Pageable pageable, Long itemId, HistoryRequestParams historyRequestParams, - ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { - TestItem testItem = testItemRepository.findById(itemId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); - Launch launch = testItemService.getEffectiveLaunch(testItem); - launchAccessValidator.validate(launch.getId(), projectDetails, user); + private Page<TestItemHistory> loadHistory(Queryable filter, Pageable pageable, Long itemId, + HistoryRequestParams historyRequestParams, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, boolean usingHash) { + TestItem testItem = testItemRepository.findById(itemId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemId)); + Launch launch = testItemService.getEffectiveLaunch(testItem); + launchAccessValidator.validate(launch.getId(), projectDetails, user); - return historyRequestParams.getHistoryType() - .filter(HistoryRequestParams.HistoryTypeEnum.LINE::equals) - .map(type -> testItemRepository.loadItemsHistoryPage(filter, - pageable, - projectDetails.getProjectId(), - launch.getName(), - historyRequestParams.getHistoryDepth(), - usingHash - )) - .orElseGet(() -> testItemRepository.loadItemsHistoryPage(filter, - pageable, - projectDetails.getProjectId(), - historyRequestParams.getHistoryDepth(), - usingHash - )); + return historyRequestParams.getHistoryType() + .filter(HistoryRequestParams.HistoryTypeEnum.LINE::equals) + .map(type -> testItemRepository.loadItemsHistoryPage(filter, + pageable, + projectDetails.getProjectId(), + launch.getName(), + historyRequestParams.getHistoryDepth(), + usingHash + )) + .orElseGet(() -> testItemRepository.loadItemsHistoryPage(filter, + pageable, + projectDetails.getProjectId(), + historyRequestParams.getHistoryDepth(), + usingHash + )); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/AbstractLaunchMergeStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/AbstractLaunchMergeStrategy.java index 46b5484a5c..30c5adb73c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/AbstractLaunchMergeStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/AbstractLaunchMergeStrategy.java @@ -16,6 +16,15 @@ package com.epam.ta.reportportal.core.item.impl.merge.strategy; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -39,157 +48,170 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.collect.Sets; - -import java.util.*; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; -import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; -import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractLaunchMergeStrategy implements LaunchMergeStrategy { - protected final LaunchRepository launchRepository; - - private final TestItemRepository testItemRepository; - private final LogRepository logRepository; - private final AttachmentRepository attachmentRepository; - private final TestItemUniqueIdGenerator identifierGenerator; - - protected AbstractLaunchMergeStrategy(LaunchRepository launchRepository, TestItemRepository testItemRepository, - LogRepository logRepository, AttachmentRepository attachmentRepository, TestItemUniqueIdGenerator identifierGenerator) { - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; - this.attachmentRepository = attachmentRepository; - this.identifierGenerator = identifierGenerator; - } - - protected Launch createNewLaunch(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ rq, - List<Launch> launchesList) { - Launch newLaunch = createResultedLaunch(projectDetails.getProjectId(), user.getUserId(), rq, launchesList); - boolean isNameChanged = !newLaunch.getName().equals(launchesList.get(0).getName()); - updateChildrenOfLaunches(newLaunch, rq.getLaunches(), rq.isExtendSuitesDescription(), isNameChanged); - - return newLaunch; - } - - /** - * Create launch that will be the result of merge - * - * @param projectId {@link Project#getId()} - * @param userId {@link ReportPortalUser#getUserId()} - * @param mergeLaunchesRQ {@link MergeLaunchesRQ} - * @param launches {@link List} of the {@link Launch} - * @return launch - */ - private Launch createResultedLaunch(Long projectId, Long userId, MergeLaunchesRQ mergeLaunchesRQ, List<Launch> launches) { - Date startTime = ofNullable(mergeLaunchesRQ.getStartTime()).orElse(EntityUtils.TO_DATE.apply(launches.stream() - .min(Comparator.comparing(Launch::getStartTime)) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Invalid launches")) - .getStartTime())); - Date endTime = ofNullable(mergeLaunchesRQ.getEndTime()).orElse(EntityUtils.TO_DATE.apply(launches.stream() - .max(Comparator.comparing(Launch::getEndTime)) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Invalid launches")) - .getEndTime())); - expect(endTime, time -> !time.before(startTime)).verify(FINISH_TIME_EARLIER_THAN_START_TIME, - TO_LOCAL_DATE_TIME.apply(endTime), - startTime, - projectId - ); - - StartLaunchRQ startRQ = new StartLaunchRQ(); - startRQ.setMode(ofNullable(mergeLaunchesRQ.getMode()).orElse(Mode.DEFAULT)); - startRQ.setDescription(ofNullable(mergeLaunchesRQ.getDescription()).orElse(launches.stream() - .map(Launch::getDescription) - .collect(joining("\n\n")))); - startRQ.setName(ofNullable(mergeLaunchesRQ.getName()).orElse( - "Merged: " + launches.stream().map(Launch::getName).distinct().collect(joining(", ")))); - startRQ.setStartTime(startTime); - Launch launch = new LaunchBuilder().addStartRQ(startRQ) - .addProject(projectId) - .addStatus(IN_PROGRESS.name()) - .addUserId(userId) - .addEndTime(endTime) - .get(); - launch.setHasRetries(launches.stream().anyMatch(Launch::isHasRetries)); - - launchRepository.save(launch); - launchRepository.refresh(launch); - mergeAttributes(mergeLaunchesRQ.getAttributes(), launches, launch); - return launch; - } - - /** - * Merges launches attributes. Collect all system attributes from existed launches - * and all unique not system attributes from request(if preset, or from exited launches if not) to resulted launch. - * - * @param attributesFromRq {@link Set} of attributes from request - * @param launchesToMerge {@link List} of {@link Launch} to be merged - * @param resultedLaunch {@link Launch} - result of merge - */ - - private void mergeAttributes(Set<ItemAttributeResource> attributesFromRq, List<Launch> launchesToMerge, Launch resultedLaunch) { - Set<ItemAttribute> mergedAttributes = Sets.newHashSet(); - - if (attributesFromRq == null) { - mergedAttributes.addAll(launchesToMerge.stream() - .map(Launch::getAttributes) - .flatMap(Collection::stream) - .peek(it -> it.setLaunch(resultedLaunch)) - .collect(Collectors.toSet())); - } else { - mergedAttributes.addAll(launchesToMerge.stream() - .map(Launch::getAttributes) - .flatMap(Collection::stream) - .filter(ItemAttribute::isSystem) - .peek(it -> it.setLaunch(resultedLaunch)) - .collect(Collectors.toSet())); - mergedAttributes.addAll(attributesFromRq.stream() - .map(FROM_RESOURCE) - .peek(attr -> attr.setLaunch(resultedLaunch)) - .collect(Collectors.toSet())); - } - resultedLaunch.setAttributes(mergedAttributes); - } - - /** - * Update test-items of specified launches with new LaunchID - * - * @param newLaunch {@link Launch} - * @param launches {@link Set} of the {@link Launch} - * @param extendDescription additional description for suite indicator - * @param isNameChanged launch name change indicator - */ - private void updateChildrenOfLaunches(Launch newLaunch, Set<Long> launches, boolean extendDescription, boolean isNameChanged) { - List<TestItem> testItems = launches.stream().peek(id -> { - logRepository.updateLaunchIdByLaunchId(id, newLaunch.getId()); - attachmentRepository.updateLaunchIdByProjectIdAndLaunchId(newLaunch.getProjectId(), id, newLaunch.getId()); - }).flatMap(id -> { - Launch launch = launchRepository.findById(id).orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, id)); - return testItemRepository.findTestItemsByLaunchId(launch.getId()).stream().peek(testItem -> { - testItem.setLaunchId(newLaunch.getId()); - if (isNameChanged && identifierGenerator.validate(testItem.getUniqueId())) { - testItem.setUniqueId(identifierGenerator.generate(testItem, IdentityUtil.getParentIds(testItem), newLaunch)); - } - if (testItem.getType().sameLevel(TestItemTypeEnum.SUITE)) { - // Add launch reference description for top level items - Supplier<String> newDescription = Suppliers.formattedSupplier( - ((null != testItem.getDescription()) ? testItem.getDescription() : "") + (extendDescription ? - "\r\n@launch '{} #{}'" : - ""), launch.getName(), launch.getNumber()); - testItem.setDescription(newDescription.get()); - } - }); - }).collect(toList()); - testItemRepository.saveAll(testItems); - } + + protected final LaunchRepository launchRepository; + + private final TestItemRepository testItemRepository; + private final LogRepository logRepository; + private final AttachmentRepository attachmentRepository; + private final TestItemUniqueIdGenerator identifierGenerator; + + protected AbstractLaunchMergeStrategy(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + LogRepository logRepository, AttachmentRepository attachmentRepository, + TestItemUniqueIdGenerator identifierGenerator) { + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.logRepository = logRepository; + this.attachmentRepository = attachmentRepository; + this.identifierGenerator = identifierGenerator; + } + + protected Launch createNewLaunch(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, MergeLaunchesRQ rq, + List<Launch> launchesList) { + Launch newLaunch = createResultedLaunch(projectDetails.getProjectId(), user.getUserId(), rq, + launchesList); + boolean isNameChanged = !newLaunch.getName().equals(launchesList.get(0).getName()); + updateChildrenOfLaunches(newLaunch, rq.getLaunches(), rq.isExtendSuitesDescription(), + isNameChanged); + + return newLaunch; + } + + /** + * Create launch that will be the result of merge + * + * @param projectId {@link Project#getId()} + * @param userId {@link ReportPortalUser#getUserId()} + * @param mergeLaunchesRQ {@link MergeLaunchesRQ} + * @param launches {@link List} of the {@link Launch} + * @return launch + */ + private Launch createResultedLaunch(Long projectId, Long userId, MergeLaunchesRQ mergeLaunchesRQ, + List<Launch> launches) { + Date startTime = ofNullable(mergeLaunchesRQ.getStartTime()).orElse( + EntityUtils.TO_DATE.apply(launches.stream() + .min(Comparator.comparing(Launch::getStartTime)) + .orElseThrow( + () -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Invalid launches")) + .getStartTime())); + Date endTime = ofNullable(mergeLaunchesRQ.getEndTime()).orElse( + EntityUtils.TO_DATE.apply(launches.stream() + .max(Comparator.comparing(Launch::getEndTime)) + .orElseThrow( + () -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Invalid launches")) + .getEndTime())); + expect(endTime, time -> !time.before(startTime)).verify(FINISH_TIME_EARLIER_THAN_START_TIME, + TO_LOCAL_DATE_TIME.apply(endTime), + startTime, + projectId + ); + + StartLaunchRQ startRQ = new StartLaunchRQ(); + startRQ.setMode(ofNullable(mergeLaunchesRQ.getMode()).orElse(Mode.DEFAULT)); + startRQ.setDescription(ofNullable(mergeLaunchesRQ.getDescription()).orElse(launches.stream() + .map(Launch::getDescription) + .collect(joining("\n\n")))); + startRQ.setName(ofNullable(mergeLaunchesRQ.getName()).orElse( + "Merged: " + launches.stream().map(Launch::getName).distinct().collect(joining(", ")))); + startRQ.setStartTime(startTime); + Launch launch = new LaunchBuilder().addStartRQ(startRQ) + .addProject(projectId) + .addStatus(IN_PROGRESS.name()) + .addUserId(userId) + .addEndTime(endTime) + .get(); + launch.setHasRetries(launches.stream().anyMatch(Launch::isHasRetries)); + + launchRepository.save(launch); + launchRepository.refresh(launch); + mergeAttributes(mergeLaunchesRQ.getAttributes(), launches, launch); + return launch; + } + + /** + * Merges launches attributes. Collect all system attributes from existed launches and all unique + * not system attributes from request(if preset, or from exited launches if not) to resulted + * launch. + * + * @param attributesFromRq {@link Set} of attributes from request + * @param launchesToMerge {@link List} of {@link Launch} to be merged + * @param resultedLaunch {@link Launch} - result of merge + */ + + private void mergeAttributes(Set<ItemAttributeResource> attributesFromRq, + List<Launch> launchesToMerge, Launch resultedLaunch) { + Set<ItemAttribute> mergedAttributes = Sets.newHashSet(); + + if (attributesFromRq == null) { + mergedAttributes.addAll(launchesToMerge.stream() + .map(Launch::getAttributes) + .flatMap(Collection::stream) + .peek(it -> it.setLaunch(resultedLaunch)) + .collect(Collectors.toSet())); + } else { + mergedAttributes.addAll(launchesToMerge.stream() + .map(Launch::getAttributes) + .flatMap(Collection::stream) + .filter(ItemAttribute::isSystem) + .peek(it -> it.setLaunch(resultedLaunch)) + .collect(Collectors.toSet())); + mergedAttributes.addAll(attributesFromRq.stream() + .map(FROM_RESOURCE) + .peek(attr -> attr.setLaunch(resultedLaunch)) + .collect(Collectors.toSet())); + } + resultedLaunch.setAttributes(mergedAttributes); + } + + /** + * Update test-items of specified launches with new LaunchID + * + * @param newLaunch {@link Launch} + * @param launches {@link Set} of the {@link Launch} + * @param extendDescription additional description for suite indicator + * @param isNameChanged launch name change indicator + */ + private void updateChildrenOfLaunches(Launch newLaunch, Set<Long> launches, + boolean extendDescription, boolean isNameChanged) { + List<TestItem> testItems = launches.stream().peek(id -> { + logRepository.updateLaunchIdByLaunchId(id, newLaunch.getId()); + attachmentRepository.updateLaunchIdByProjectIdAndLaunchId(newLaunch.getProjectId(), id, + newLaunch.getId()); + }).flatMap(id -> { + Launch launch = launchRepository.findById(id) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, id)); + return testItemRepository.findTestItemsByLaunchId(launch.getId()).stream().peek(testItem -> { + testItem.setLaunchId(newLaunch.getId()); + if (isNameChanged && identifierGenerator.validate(testItem.getUniqueId())) { + testItem.setUniqueId( + identifierGenerator.generate(testItem, IdentityUtil.getParentIds(testItem), + newLaunch)); + } + if (testItem.getType().sameLevel(TestItemTypeEnum.SUITE)) { + // Add launch reference description for top level items + Supplier<String> newDescription = Suppliers.formattedSupplier( + ((null != testItem.getDescription()) ? testItem.getDescription() : "") + ( + extendDescription ? + "\r\n@launch '{} #{}'" : + ""), launch.getName(), launch.getNumber()); + testItem.setDescription(newDescription.get()); + } + }); + }).collect(toList()); + testItemRepository.saveAll(testItems); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicLaunchMergeStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicLaunchMergeStrategy.java index 30d87abb6a..c38fb183e2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicLaunchMergeStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicLaunchMergeStrategy.java @@ -24,7 +24,6 @@ import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; - import java.util.List; /** @@ -32,26 +31,30 @@ */ public class BasicLaunchMergeStrategy extends AbstractLaunchMergeStrategy { - private final StatisticsCalculationFactory statisticsCalculationFactory; + private final StatisticsCalculationFactory statisticsCalculationFactory; - public BasicLaunchMergeStrategy(LaunchRepository launchRepository, TestItemRepository testItemRepository, - LogRepository logRepository, AttachmentRepository attachmentRepository, TestItemUniqueIdGenerator identifierGenerator, - StatisticsCalculationFactory statisticsCalculationFactory) { - super(launchRepository, testItemRepository, logRepository, attachmentRepository, identifierGenerator); - this.statisticsCalculationFactory = statisticsCalculationFactory; - } + public BasicLaunchMergeStrategy(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + LogRepository logRepository, AttachmentRepository attachmentRepository, + TestItemUniqueIdGenerator identifierGenerator, + StatisticsCalculationFactory statisticsCalculationFactory) { + super(launchRepository, testItemRepository, logRepository, attachmentRepository, + identifierGenerator); + this.statisticsCalculationFactory = statisticsCalculationFactory; + } - @Override - public Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ rq, - List<Launch> launchesList) { + @Override + public Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + MergeLaunchesRQ rq, + List<Launch> launchesList) { - Launch newLaunch = createNewLaunch(projectDetails, user, rq, launchesList); + Launch newLaunch = createNewLaunch(projectDetails, user, rq, launchesList); - newLaunch.setStatistics(statisticsCalculationFactory.getStrategy(MergeStrategyType.BASIC) - .recalculateLaunchStatistics(newLaunch, launchesList)); + newLaunch.setStatistics(statisticsCalculationFactory.getStrategy(MergeStrategyType.BASIC) + .recalculateLaunchStatistics(newLaunch, launchesList)); - launchRepository.save(newLaunch); - return newLaunch; + launchRepository.save(newLaunch); + return newLaunch; - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicStatisticsCalculationStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicStatisticsCalculationStrategy.java index 34c3bc088e..cce94ad14b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicStatisticsCalculationStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/BasicStatisticsCalculationStrategy.java @@ -16,32 +16,32 @@ package com.epam.ta.reportportal.core.item.impl.merge.strategy; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toMap; + import com.epam.ta.reportportal.core.item.merge.StatisticsCalculationStrategy; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.statistics.Statistics; - import java.util.Collection; import java.util.Set; import java.util.stream.Collectors; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toMap; - /** * @author Ivan Budaev */ public class BasicStatisticsCalculationStrategy implements StatisticsCalculationStrategy { - @Override - public Set<Statistics> recalculateLaunchStatistics(Launch newLaunch, Collection<Launch> launches) { - return launches.stream() - .filter(l -> ofNullable(l.getStatistics()).isPresent()) - .flatMap(l -> l.getStatistics().stream()) - .filter(s -> ofNullable(s.getStatisticsField()).isPresent()) - .collect(toMap(Statistics::getStatisticsField, Statistics::getCounter, Integer::sum)) - .entrySet() - .stream() - .map(entry -> new Statistics(entry.getKey(), entry.getValue(), newLaunch.getId())) - .collect(Collectors.toSet()); - } + @Override + public Set<Statistics> recalculateLaunchStatistics(Launch newLaunch, + Collection<Launch> launches) { + return launches.stream() + .filter(l -> ofNullable(l.getStatistics()).isPresent()) + .flatMap(l -> l.getStatistics().stream()) + .filter(s -> ofNullable(s.getStatisticsField()).isPresent()) + .collect(toMap(Statistics::getStatisticsField, Statistics::getCounter, Integer::sum)) + .entrySet() + .stream() + .map(entry -> new Statistics(entry.getKey(), entry.getValue(), newLaunch.getId())) + .collect(Collectors.toSet()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/DeepLaunchMergeStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/DeepLaunchMergeStrategy.java index b292ed9450..5eeb57ecf9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/DeepLaunchMergeStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/DeepLaunchMergeStrategy.java @@ -24,7 +24,6 @@ import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; - import java.util.List; /** @@ -32,19 +31,22 @@ */ public class DeepLaunchMergeStrategy extends AbstractLaunchMergeStrategy { - public DeepLaunchMergeStrategy(LaunchRepository launchRepository, TestItemRepository testItemRepository, LogRepository logRepository, - AttachmentRepository attachmentRepository, TestItemUniqueIdGenerator identifierGenerator) { - super(launchRepository, testItemRepository, logRepository, attachmentRepository, identifierGenerator); - } + public DeepLaunchMergeStrategy(LaunchRepository launchRepository, + TestItemRepository testItemRepository, LogRepository logRepository, + AttachmentRepository attachmentRepository, TestItemUniqueIdGenerator identifierGenerator) { + super(launchRepository, testItemRepository, logRepository, attachmentRepository, + identifierGenerator); + } - @Override - public Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ rq, - List<Launch> launchesList) { + @Override + public Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + MergeLaunchesRQ rq, + List<Launch> launchesList) { - Launch newLaunch = createNewLaunch(projectDetails, user, rq, launchesList); - launchRepository.mergeLaunchTestItems(newLaunch.getId()); - launchRepository.save(newLaunch); - launchRepository.refresh(newLaunch); - return newLaunch; - } + Launch newLaunch = createNewLaunch(projectDetails, user, rq, launchesList); + launchRepository.mergeLaunchTestItems(newLaunch.getId()); + launchRepository.save(newLaunch); + launchRepository.refresh(newLaunch); + return newLaunch; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/LaunchMergeFactory.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/LaunchMergeFactory.java index 660c5dc912..d74cf24ee3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/LaunchMergeFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/LaunchMergeFactory.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.item.impl.merge.strategy; import com.epam.ta.reportportal.core.item.merge.LaunchMergeStrategy; - import java.util.Map; /** @@ -25,13 +24,13 @@ */ public class LaunchMergeFactory { - private Map<MergeStrategyType, LaunchMergeStrategy> mergeStrategyMapping; + private Map<MergeStrategyType, LaunchMergeStrategy> mergeStrategyMapping; - public LaunchMergeFactory(Map<MergeStrategyType, LaunchMergeStrategy> mergeStrategyMapping) { - this.mergeStrategyMapping = mergeStrategyMapping; - } + public LaunchMergeFactory(Map<MergeStrategyType, LaunchMergeStrategy> mergeStrategyMapping) { + this.mergeStrategyMapping = mergeStrategyMapping; + } - public LaunchMergeStrategy getLaunchMergeStrategy(MergeStrategyType type) { - return mergeStrategyMapping.get(type); - } + public LaunchMergeStrategy getLaunchMergeStrategy(MergeStrategyType type) { + return mergeStrategyMapping.get(type); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/MergeStrategyType.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/MergeStrategyType.java index 73acc5ac46..c0bce9cdde 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/MergeStrategyType.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/MergeStrategyType.java @@ -22,10 +22,11 @@ * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public enum MergeStrategyType { - DEEP, - BASIC; + DEEP, + BASIC; - public static MergeStrategyType fromValue(String value) { - return Arrays.stream(MergeStrategyType.values()).filter(type -> type.name().equalsIgnoreCase(value)).findFirst().orElse(null); - } + public static MergeStrategyType fromValue(String value) { + return Arrays.stream(MergeStrategyType.values()) + .filter(type -> type.name().equalsIgnoreCase(value)).findFirst().orElse(null); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/StatisticsCalculationFactory.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/StatisticsCalculationFactory.java index 864d6551ac..8cf98d6bde 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/StatisticsCalculationFactory.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/merge/strategy/StatisticsCalculationFactory.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.item.impl.merge.strategy; import com.epam.ta.reportportal.core.item.merge.StatisticsCalculationStrategy; - import java.util.Map; /** @@ -25,13 +24,14 @@ */ public class StatisticsCalculationFactory { - private final Map<MergeStrategyType, StatisticsCalculationStrategy> calculationStrategyMapping; + private final Map<MergeStrategyType, StatisticsCalculationStrategy> calculationStrategyMapping; - public StatisticsCalculationFactory(Map<MergeStrategyType, StatisticsCalculationStrategy> calculationStrategyMapping) { - this.calculationStrategyMapping = calculationStrategyMapping; - } + public StatisticsCalculationFactory( + Map<MergeStrategyType, StatisticsCalculationStrategy> calculationStrategyMapping) { + this.calculationStrategyMapping = calculationStrategyMapping; + } - public StatisticsCalculationStrategy getStrategy(MergeStrategyType type) { - return this.calculationStrategyMapping.get(type); - } + public StatisticsCalculationStrategy getStrategy(MergeStrategyType type) { + return this.calculationStrategyMapping.get(type); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderHandler.java index 23b21b0543..dca3f45162 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderHandler.java @@ -20,21 +20,22 @@ import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.statistics.Statistics; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; - import java.util.Map; import java.util.Set; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public interface DataProviderHandler { - Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params); + Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params); - Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params); + Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderType.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderType.java index 1c6465047c..b14d173a9b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderType.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/DataProviderType.java @@ -16,32 +16,33 @@ package com.epam.ta.reportportal.core.item.impl.provider; -import javax.annotation.Nullable; import java.util.Arrays; import java.util.Optional; +import javax.annotation.Nullable; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public enum DataProviderType { - WIDGET_BASED("widget"), - LAUNCH_BASED("launch"), - FILTER_BASED("filter"), - CLUSTER_BASED("cluster"), - BASELINE_BASED("baseline"); + WIDGET_BASED("widget"), + LAUNCH_BASED("launch"), + FILTER_BASED("filter"), + CLUSTER_BASED("cluster"), + BASELINE_BASED("baseline"); - private final String type; + private final String type; - DataProviderType(String type) { - this.type = type; - } + DataProviderType(String type) { + this.type = type; + } - public String getType() { - return this.type; - } + public String getType() { + return this.type; + } - public static Optional<DataProviderType> findByName(@Nullable String name) { - return Arrays.stream(DataProviderType.values()).filter(type -> type.getType().equalsIgnoreCase(name)).findAny(); - } + public static Optional<DataProviderType> findByName(@Nullable String name) { + return Arrays.stream(DataProviderType.values()) + .filter(type -> type.getType().equalsIgnoreCase(name)).findAny(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/ProviderTypeConfig.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/ProviderTypeConfig.java index ccd682c3db..67e25422b2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/ProviderTypeConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/ProviderTypeConfig.java @@ -16,9 +16,14 @@ package com.epam.ta.reportportal.core.item.impl.provider; -import com.epam.ta.reportportal.core.item.impl.provider.impl.*; +import com.epam.ta.reportportal.core.item.impl.provider.impl.BaselineLaunchDataProvider; +import com.epam.ta.reportportal.core.item.impl.provider.impl.CumulativeTestItemDataProviderImpl; +import com.epam.ta.reportportal.core.item.impl.provider.impl.DelegatingClusterDataProviderHandler; +import com.epam.ta.reportportal.core.item.impl.provider.impl.LaunchDataProviderHandlerImpl; +import com.epam.ta.reportportal.core.item.impl.provider.impl.MaterializedWidgetProviderHandlerImpl; import com.epam.ta.reportportal.entity.widget.WidgetType; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -26,44 +31,48 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Configuration public class ProviderTypeConfig { - private ApplicationContext applicationContext; + private ApplicationContext applicationContext; - @Autowired - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @Bean - public DelegatingClusterDataProviderHandler delegatingClusterDataProviderHandler( - @Value("${rp.environment.variable.cluster.item.page-size}") Integer maxPageSize, - @Autowired LaunchDataProviderHandlerImpl launchDataProviderHandler) { - return new DelegatingClusterDataProviderHandler(maxPageSize, launchDataProviderHandler); - } + @Bean + public DelegatingClusterDataProviderHandler delegatingClusterDataProviderHandler( + @Value("${rp.environment.variable.cluster.item.page-size}") Integer maxPageSize, + @Autowired LaunchDataProviderHandlerImpl launchDataProviderHandler) { + return new DelegatingClusterDataProviderHandler(maxPageSize, launchDataProviderHandler); + } - @Bean("testItemDataProviders") - public Map<DataProviderType, DataProviderHandler> testItemDataProviders() { - return ImmutableMap.<DataProviderType, DataProviderHandler>builder() - .put(DataProviderType.WIDGET_BASED, applicationContext.getBean(MaterializedWidgetProviderHandlerImpl.class)) - .put(DataProviderType.LAUNCH_BASED, applicationContext.getBean(LaunchDataProviderHandlerImpl.class)) - .put(DataProviderType.FILTER_BASED, applicationContext.getBean(FilterDataProviderImpl.class)) - .put(DataProviderType.CLUSTER_BASED,applicationContext.getBean(DelegatingClusterDataProviderHandler.class)) - .put(DataProviderType.BASELINE_BASED,applicationContext.getBean(BaselineLaunchDataProvider.class)) - .build(); - } + @Bean("testItemDataProviders") + public Map<DataProviderType, DataProviderHandler> testItemDataProviders() { + return ImmutableMap.<DataProviderType, DataProviderHandler>builder() + .put(DataProviderType.WIDGET_BASED, + applicationContext.getBean(MaterializedWidgetProviderHandlerImpl.class)) + .put(DataProviderType.LAUNCH_BASED, + applicationContext.getBean(LaunchDataProviderHandlerImpl.class)) + .put(DataProviderType.FILTER_BASED, + applicationContext.getBean(FilterDataProviderImpl.class)) + .put(DataProviderType.CLUSTER_BASED, + applicationContext.getBean(DelegatingClusterDataProviderHandler.class)) + .put(DataProviderType.BASELINE_BASED, + applicationContext.getBean(BaselineLaunchDataProvider.class)) + .build(); + } - @Bean("testItemWidgetDataProviders") - public Map<WidgetType, DataProviderHandler> testItemWidgetDataProviders() { - return ImmutableMap.<WidgetType, DataProviderHandler>builder() - .put(WidgetType.CUMULATIVE, applicationContext.getBean(CumulativeTestItemDataProviderImpl.class)) - .build(); - } + @Bean("testItemWidgetDataProviders") + public Map<WidgetType, DataProviderHandler> testItemWidgetDataProviders() { + return ImmutableMap.<WidgetType, DataProviderHandler>builder() + .put(WidgetType.CUMULATIVE, + applicationContext.getBean(CumulativeTestItemDataProviderImpl.class)) + .build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/BaselineLaunchDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/BaselineLaunchDataProvider.java index 8a68e550f4..1173a2da6f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/BaselineLaunchDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/BaselineLaunchDataProvider.java @@ -16,8 +16,13 @@ package com.epam.ta.reportportal.core.item.impl.provider.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.CompositeFilter; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.item.impl.LaunchAccessValidator; import com.epam.ta.reportportal.core.item.impl.filter.updater.FilterUpdater; import com.epam.ta.reportportal.core.item.impl.provider.DataProviderHandler; @@ -27,82 +32,89 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ControllerUtils; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class BaselineLaunchDataProvider implements DataProviderHandler { - private static final String LAUNCH_ID_PARAM = "launchId"; - private static final String BASELINE_LAUNCH_ID_PARAM = "baselineLaunchId"; - private final LaunchAccessValidator launchAccessValidator; - private final TestItemRepository testItemRepository; - private final FilterUpdater filterUpdater; + private static final String LAUNCH_ID_PARAM = "launchId"; + private static final String BASELINE_LAUNCH_ID_PARAM = "baselineLaunchId"; + + private final LaunchAccessValidator launchAccessValidator; + private final TestItemRepository testItemRepository; + private final FilterUpdater filterUpdater; - @Autowired - public BaselineLaunchDataProvider(LaunchAccessValidator launchAccessValidator, TestItemRepository testItemRepository, - FilterUpdater filterUpdater) { - this.launchAccessValidator = launchAccessValidator; - this.testItemRepository = testItemRepository; - this.filterUpdater = filterUpdater; - } + @Autowired + public BaselineLaunchDataProvider(LaunchAccessValidator launchAccessValidator, + TestItemRepository testItemRepository, + FilterUpdater filterUpdater) { + this.launchAccessValidator = launchAccessValidator; + this.testItemRepository = testItemRepository; + this.filterUpdater = filterUpdater; + } - @Override - public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params) { - final Queryable targetFilter = getLaunchIdFilter(LAUNCH_ID_PARAM, params, projectDetails, user); - final Queryable baselineFilter = getLaunchIdFilter(BASELINE_LAUNCH_ID_PARAM, params, projectDetails, user); - filterUpdater.update(filter); + @Override + public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params) { + final Queryable targetFilter = getLaunchIdFilter(LAUNCH_ID_PARAM, params, projectDetails, user); + final Queryable baselineFilter = getLaunchIdFilter(BASELINE_LAUNCH_ID_PARAM, params, + projectDetails, user); + filterUpdater.update(filter); - return testItemRepository.findAllNotFromBaseline(joinFilters(targetFilter, filter), joinFilters(baselineFilter, filter), pageable); - } + return testItemRepository.findAllNotFromBaseline(joinFilters(targetFilter, filter), + joinFilters(baselineFilter, filter), pageable); + } - @Override - public Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - final Queryable targetFilter = getLaunchIdFilter(LAUNCH_ID_PARAM, params, projectDetails, user); - final Queryable baselineFilter = getLaunchIdFilter(BASELINE_LAUNCH_ID_PARAM, params, projectDetails, user); - filterUpdater.update(filter); - return testItemRepository.accumulateStatisticsByFilterNotFromBaseline(joinFilters(targetFilter, filter), - joinFilters(baselineFilter, filter) - ); - } + @Override + public Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params) { + final Queryable targetFilter = getLaunchIdFilter(LAUNCH_ID_PARAM, params, projectDetails, user); + final Queryable baselineFilter = getLaunchIdFilter(BASELINE_LAUNCH_ID_PARAM, params, + projectDetails, user); + filterUpdater.update(filter); + return testItemRepository.accumulateStatisticsByFilterNotFromBaseline( + joinFilters(targetFilter, filter), + joinFilters(baselineFilter, filter) + ); + } - private Queryable getLaunchIdFilter(String key, Map<String, String> params, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - final Long launchId = getLaunchId(key, params); - launchAccessValidator.validate(launchId, projectDetails, user); - return getLaunchIdFilter(launchId); - } + private Queryable getLaunchIdFilter(String key, Map<String, String> params, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + final Long launchId = getLaunchId(key, params); + launchAccessValidator.validate(launchId, projectDetails, user); + return getLaunchIdFilter(launchId); + } - private Long getLaunchId(String key, Map<String, String> params) { - return Optional.ofNullable(params.get(key)) - .map(ControllerUtils::safeParseLong) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - "Launch id must be provided for baseline items provider" - )); - } + private Long getLaunchId(String key, Map<String, String> params) { + return Optional.ofNullable(params.get(key)) + .map(ControllerUtils::safeParseLong) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Launch id must be provided for baseline items provider" + )); + } - private Queryable getLaunchIdFilter(Long launchId) { - return Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) - .build(); - } + private Queryable getLaunchIdFilter(Long launchId) { + return Filter.builder() + .withTarget(TestItem.class) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) + .build(); + } - private Queryable joinFilters(Queryable... filters) { - return new CompositeFilter(Operator.AND, filters); - } + private Queryable joinFilters(Queryable... filters) { + return new CompositeFilter(Operator.AND, filters); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/CumulativeTestItemDataProviderImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/CumulativeTestItemDataProviderImpl.java index 26051b8572..8b06c0881c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/CumulativeTestItemDataProviderImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/CumulativeTestItemDataProviderImpl.java @@ -16,8 +16,17 @@ package com.epam.ta.reportportal.core.item.impl.provider.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_LEVEL_ATTRIBUTE; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.CompositeFilter; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.item.impl.provider.DataProviderHandler; import com.epam.ta.reportportal.dao.TestItemRepository; @@ -25,6 +34,9 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; @@ -33,56 +45,53 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_LEVEL_ATTRIBUTE; -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component public class CumulativeTestItemDataProviderImpl implements DataProviderHandler { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Autowired - private TestItemRepository testItemRepository; + @Autowired + private TestItemRepository testItemRepository; - @Override - public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params) { - filter = updateFilter(filter, params); - return testItemRepository.findByFilter(filter, pageable); + @Override + public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params) { + filter = updateFilter(filter, params); + return testItemRepository.findByFilter(filter, pageable); - } + } - @Override - public Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - filter = updateFilter(filter, params); - return testItemRepository.accumulateStatisticsByFilter(filter); - } + @Override + public Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params) { + filter = updateFilter(filter, params); + return testItemRepository.accumulateStatisticsByFilter(filter); + } - public Queryable updateFilter(Queryable filter, Map<String, String> providerParams) { - String compositeAttribute = providerParams.get(DEFAULT_FILTER_PREFIX + Condition.HAS_FILTER + CRITERIA_LEVEL_ATTRIBUTE); - BusinessRule.expect(compositeAttribute, it -> !StringUtils.isEmpty(it)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Level attributes must be provided for widget based items provider"); - List<Long> redirectLaunchIds = widgetContentRepository.getCumulativeLevelRedirectLaunchIds(providerParams.get(VIEW_NAME), - compositeAttribute - ); - if (CollectionUtils.isNotEmpty(redirectLaunchIds)) { - Queryable launchesBasedFilter = Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().in(CRITERIA_LAUNCH_ID, redirectLaunchIds).build()) - .build(); - return new CompositeFilter(Operator.AND, filter, launchesBasedFilter); - } - return filter; - } + public Queryable updateFilter(Queryable filter, Map<String, String> providerParams) { + String compositeAttribute = providerParams.get( + DEFAULT_FILTER_PREFIX + Condition.HAS_FILTER + CRITERIA_LEVEL_ATTRIBUTE); + BusinessRule.expect(compositeAttribute, it -> !StringUtils.isEmpty(it)) + .verify(ErrorType.BAD_REQUEST_ERROR, + "Level attributes must be provided for widget based items provider"); + List<Long> redirectLaunchIds = widgetContentRepository.getCumulativeLevelRedirectLaunchIds( + providerParams.get(VIEW_NAME), + compositeAttribute + ); + if (CollectionUtils.isNotEmpty(redirectLaunchIds)) { + Queryable launchesBasedFilter = Filter.builder() + .withTarget(TestItem.class) + .withCondition( + FilterCondition.builder().in(CRITERIA_LAUNCH_ID, redirectLaunchIds).build()) + .build(); + return new CompositeFilter(Operator.AND, filter, launchesBasedFilter); + } + return filter; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/DelegatingClusterDataProviderHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/DelegatingClusterDataProviderHandler.java index 58bbeefee9..d05d1ff697 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/DelegatingClusterDataProviderHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/DelegatingClusterDataProviderHandler.java @@ -23,54 +23,56 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.BooleanUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import java.util.Map; -import java.util.Set; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class DelegatingClusterDataProviderHandler implements DataProviderHandler { - public static final String CLUSTER_ID_PARAM = "clusterId"; + public static final String CLUSTER_ID_PARAM = "clusterId"; - private final Integer maxPageSize; - private final DataProviderHandler delegate; + private final Integer maxPageSize; + private final DataProviderHandler delegate; - public DelegatingClusterDataProviderHandler(Integer maxPageSize, DataProviderHandler dataProviderHandler) { - this.maxPageSize = maxPageSize; - this.delegate = dataProviderHandler; - } + public DelegatingClusterDataProviderHandler(Integer maxPageSize, + DataProviderHandler dataProviderHandler) { + this.maxPageSize = maxPageSize; + this.delegate = dataProviderHandler; + } - @Override - public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params) { - validateClusterCondition(filter); - validatePageSize(pageable); - return delegate.getTestItems(filter, pageable, projectDetails, user, params); - } + @Override + public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params) { + validateClusterCondition(filter); + validatePageSize(pageable); + return delegate.getTestItems(filter, pageable, projectDetails, user, params); + } - @Override - public Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - validateClusterCondition(filter); - return delegate.accumulateStatistics(filter, projectDetails, user, params); - } + @Override + public Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params) { + validateClusterCondition(filter); + return delegate.accumulateStatistics(filter, projectDetails, user, params); + } - private void validateClusterCondition(Queryable filter) { - final boolean hasClusterIdCondition = filter.getFilterConditions() - .stream() - .flatMap(c -> c.getAllConditions().stream()) - .anyMatch(c -> c.getSearchCriteria().contains(CLUSTER_ID_PARAM)); - BusinessRule.expect(hasClusterIdCondition, BooleanUtils::isTrue) - .verify(ErrorType.BAD_REQUEST_ERROR, "Cluster id condition not provided"); - } + private void validateClusterCondition(Queryable filter) { + final boolean hasClusterIdCondition = filter.getFilterConditions() + .stream() + .flatMap(c -> c.getAllConditions().stream()) + .anyMatch(c -> c.getSearchCriteria().contains(CLUSTER_ID_PARAM)); + BusinessRule.expect(hasClusterIdCondition, BooleanUtils::isTrue) + .verify(ErrorType.BAD_REQUEST_ERROR, "Cluster id condition not provided"); + } - private void validatePageSize(Pageable pageable) { - BusinessRule.expect(pageable.getPageSize(), pageSize -> pageSize <= maxPageSize) - .verify(ErrorType.BAD_REQUEST_ERROR, "Max page size: " + maxPageSize); - } + private void validatePageSize(Pageable pageable) { + BusinessRule.expect(pageable.getPageSize(), pageSize -> pageSize <= maxPageSize) + .verify(ErrorType.BAD_REQUEST_ERROR, "Max page size: " + maxPageSize); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/LaunchDataProviderHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/LaunchDataProviderHandlerImpl.java index 52a71ffdd7..c3eb72781d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/LaunchDataProviderHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/provider/impl/LaunchDataProviderHandlerImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.item.impl.provider.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.CompositeFilter; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -30,64 +32,65 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ControllerUtils; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component public class LaunchDataProviderHandlerImpl implements DataProviderHandler { - private static final String LAUNCH_ID_PARAM = "launchId"; + private static final String LAUNCH_ID_PARAM = "launchId"; - @Autowired - private LaunchAccessValidator launchAccessValidator; + @Autowired + private LaunchAccessValidator launchAccessValidator; - @Autowired - private TestItemRepository testItemRepository; + @Autowired + private TestItemRepository testItemRepository; - @Autowired - private FilterUpdater filterUpdater; + @Autowired + private FilterUpdater filterUpdater; - @Override - public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params) { - filter = updateFilter(filter, projectDetails, user, params); - return testItemRepository.findByFilter(filter, pageable); - } + @Override + public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params) { + filter = updateFilter(filter, projectDetails, user, params); + return testItemRepository.findByFilter(filter, pageable); + } - @Override - public Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - filter = updateFilter(filter, projectDetails, user, params); - return testItemRepository.accumulateStatisticsByFilter(filter); - } + @Override + public Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params) { + filter = updateFilter(filter, projectDetails, user, params); + return testItemRepository.accumulateStatisticsByFilter(filter); + } - private Queryable updateFilter(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - Long launchId = Optional.ofNullable(params.get(LAUNCH_ID_PARAM)) - .map(ControllerUtils::safeParseLong) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - "Launch id must be provided for launch based items provider" - )); - launchAccessValidator.validate(launchId, projectDetails, user); - Queryable launchBasedFilter = Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) - .build(); + private Queryable updateFilter(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, + Map<String, String> params) { + Long launchId = Optional.ofNullable(params.get(LAUNCH_ID_PARAM)) + .map(ControllerUtils::safeParseLong) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Launch id must be provided for launch based items provider" + )); + launchAccessValidator.validate(launchId, projectDetails, user); + Queryable launchBasedFilter = Filter.builder() + .withTarget(TestItem.class) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) + .build(); - filterUpdater.update(filter); + filterUpdater.update(filter); - return new CompositeFilter(Operator.AND, filter, launchBasedFilter); - } + return new CompositeFilter(Operator.AND, filter, launchBasedFilter); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcher.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcher.java index 1d58955f60..4567eec46a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcher.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcher.java @@ -1,9 +1,9 @@ package com.epam.ta.reportportal.core.item.impl.rerun; import com.epam.ta.reportportal.commons.querygen.Queryable; - import java.util.Optional; public interface RerunSearcher { - Optional<Long> findItem(Queryable filter); + + Optional<Long> findItem(Queryable filter); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcherImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcherImpl.java index ecba145523..4a7a5bf3de 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcherImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/rerun/RerunSearcherImpl.java @@ -1,25 +1,24 @@ package com.epam.ta.reportportal.core.item.impl.rerun; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; + import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.dao.TestItemRepository; +import java.util.Optional; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Optional; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; - @Service public class RerunSearcherImpl implements RerunSearcher { - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - public RerunSearcherImpl(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } + public RerunSearcherImpl(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } - @Override - public Optional<Long> findItem(Queryable filter) { - return testItemRepository.findIdByFilter(filter, Sort.by(Sort.Order.desc(CRITERIA_START_TIME))); - } + @Override + public Optional<Long> findItem(Queryable filter) { + return testItemRepository.findIdByFilter(filter, Sort.by(Sort.Order.desc(CRITERIA_START_TIME))); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/DefaultRetryHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/DefaultRetryHandler.java index 96b07a0d7d..cdfd718ca6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/DefaultRetryHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/DefaultRetryHandler.java @@ -8,11 +8,10 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.jooq.enums.JStatusEnum; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.stereotype.Service; - import java.time.LocalDateTime; import java.util.Objects; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -20,56 +19,59 @@ @Service public class DefaultRetryHandler implements RetryHandler { - private final TestItemRepository testItemRepository; - private final LaunchRepository launchRepository; - private final ApplicationEventPublisher eventPublisher; + private final TestItemRepository testItemRepository; + private final LaunchRepository launchRepository; + private final ApplicationEventPublisher eventPublisher; - public DefaultRetryHandler(TestItemRepository testItemRepository, LaunchRepository launchRepository, - ApplicationEventPublisher eventPublisher) { - this.testItemRepository = testItemRepository; - this.launchRepository = launchRepository; - this.eventPublisher = eventPublisher; - } + public DefaultRetryHandler(TestItemRepository testItemRepository, + LaunchRepository launchRepository, + ApplicationEventPublisher eventPublisher) { + this.testItemRepository = testItemRepository; + this.launchRepository = launchRepository; + this.eventPublisher = eventPublisher; + } - @Override - public void handleRetries(Launch launch, TestItem newRetryParent, Long previousParent) { - handleRetries(launch, previousParent, newRetryParent); - eventPublisher.publishEvent(ItemRetryEvent.of(launch.getProjectId(), launch.getId(), newRetryParent.getItemId())); - } + @Override + public void handleRetries(Launch launch, TestItem newRetryParent, Long previousParent) { + handleRetries(launch, previousParent, newRetryParent); + eventPublisher.publishEvent( + ItemRetryEvent.of(launch.getProjectId(), launch.getId(), newRetryParent.getItemId())); + } - @Override - public void finishRetries(Long retryParentId, JStatusEnum status, LocalDateTime endTime) { - testItemRepository.updateStatusAndEndTimeByRetryOfId(retryParentId, - JStatusEnum.IN_PROGRESS, - JStatusEnum.valueOf(status.name()), - endTime - ); - } + @Override + public void finishRetries(Long retryParentId, JStatusEnum status, LocalDateTime endTime) { + testItemRepository.updateStatusAndEndTimeByRetryOfId(retryParentId, + JStatusEnum.IN_PROGRESS, + JStatusEnum.valueOf(status.name()), + endTime + ); + } - /** - * Handles retry items with new explicitly provided parent - * - * @param launch {@link Launch} - * @param retryParent {@link TestItem#getItemId()} - * @param newRetryParent {@link TestItem} - */ - private void handleRetries(Launch launch, Long retryParent, TestItem newRetryParent) { - validateNewParent(retryParent, newRetryParent); - testItemRepository.handleRetry(retryParent, newRetryParent.getItemId()); - updateLaunchRetriesState(launch); - } + /** + * Handles retry items with new explicitly provided parent + * + * @param launch {@link Launch} + * @param retryParent {@link TestItem#getItemId()} + * @param newRetryParent {@link TestItem} + */ + private void handleRetries(Launch launch, Long retryParent, TestItem newRetryParent) { + validateNewParent(retryParent, newRetryParent); + testItemRepository.handleRetry(retryParent, newRetryParent.getItemId()); + updateLaunchRetriesState(launch); + } - private void validateNewParent(Long prevRetryParent, TestItem newRetryParent) { - BusinessRule.expect(newRetryParent, i -> !i.getItemId().equals(prevRetryParent)) - .verify(ErrorType.RETRIES_HANDLER_ERROR, "Previous and new parent 'id' should not be equal"); - BusinessRule.expect(newRetryParent, i -> Objects.isNull(i.getRetryOf())) - .verify(ErrorType.RETRIES_HANDLER_ERROR, "Parent item should not be a retry"); - } + private void validateNewParent(Long prevRetryParent, TestItem newRetryParent) { + BusinessRule.expect(newRetryParent, i -> !i.getItemId().equals(prevRetryParent)) + .verify(ErrorType.RETRIES_HANDLER_ERROR, + "Previous and new parent 'id' should not be equal"); + BusinessRule.expect(newRetryParent, i -> Objects.isNull(i.getRetryOf())) + .verify(ErrorType.RETRIES_HANDLER_ERROR, "Parent item should not be a retry"); + } - private void updateLaunchRetriesState(Launch launch) { - if (!launch.isHasRetries()) { - launch.setHasRetries(launchRepository.hasRetries(launch.getId())); - } - } + private void updateLaunchRetriesState(Launch launch) { + if (!launch.isHasRetries()) { + launch.setHasRetries(launchRepository.hasRetries(launch.getId())); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetryHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetryHandler.java index f8345e3571..614e52348e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetryHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetryHandler.java @@ -3,7 +3,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.jooq.enums.JStatusEnum; - import java.time.LocalDateTime; /** @@ -11,7 +10,7 @@ */ public interface RetryHandler { - void handleRetries(Launch launch, TestItem newRetryParent, Long previousParent); + void handleRetries(Launch launch, TestItem newRetryParent, Long previousParent); - void finishRetries(Long retryParentId, JStatusEnum status, LocalDateTime endTime); + void finishRetries(Long retryParentId, JStatusEnum status, LocalDateTime endTime); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetrySearcher.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetrySearcher.java index f8fee5a0a4..f81d7d8dfd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetrySearcher.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/RetrySearcher.java @@ -2,11 +2,10 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; - import java.util.Optional; public interface RetrySearcher { - Optional<Long> findPreviousRetry(Launch launch, TestItem newItem, TestItem parentItem); + Optional<Long> findPreviousRetry(Launch launch, TestItem newItem, TestItem parentItem); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/UniqueIdRetrySearcher.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/UniqueIdRetrySearcher.java index e875439180..74b79c555d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/UniqueIdRetrySearcher.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/retry/UniqueIdRetrySearcher.java @@ -1,16 +1,15 @@ package com.epam.ta.reportportal.core.item.impl.retry; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.item.identity.IdentityUtil; import com.epam.ta.reportportal.core.item.identity.UniqueIdGenerator; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; -import org.springframework.stereotype.Service; - import java.util.Objects; import java.util.Optional; - -import static java.util.Optional.ofNullable; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -18,28 +17,32 @@ @Service("uniqueIdRetrySearcher") public class UniqueIdRetrySearcher implements RetrySearcher { - private final UniqueIdGenerator uniqueIdGenerator; - private final TestItemRepository testItemRepository; + private final UniqueIdGenerator uniqueIdGenerator; + private final TestItemRepository testItemRepository; - public UniqueIdRetrySearcher(UniqueIdGenerator uniqueIdGenerator, TestItemRepository testItemRepository) { - this.uniqueIdGenerator = uniqueIdGenerator; - this.testItemRepository = testItemRepository; - } + public UniqueIdRetrySearcher(UniqueIdGenerator uniqueIdGenerator, + TestItemRepository testItemRepository) { + this.uniqueIdGenerator = uniqueIdGenerator; + this.testItemRepository = testItemRepository; + } - @Override - public Optional<Long> findPreviousRetry(Launch launch, TestItem newItem, TestItem parentItem) { - if (Objects.isNull(newItem.getUniqueId())) { - newItem.setUniqueId(uniqueIdGenerator.generate(newItem, IdentityUtil.getItemTreeIds(parentItem), launch)); - } - return ofNullable(newItem.getItemId()).map(itemId -> testItemRepository.findLatestIdByUniqueIdAndLaunchIdAndParentIdAndItemIdNotEqual( - newItem.getUniqueId(), - launch.getId(), - parentItem.getItemId(), - itemId - )) - .orElseGet(() -> testItemRepository.findLatestIdByUniqueIdAndLaunchIdAndParentId(newItem.getUniqueId(), - launch.getId(), - parentItem.getItemId() - )); - } + @Override + public Optional<Long> findPreviousRetry(Launch launch, TestItem newItem, TestItem parentItem) { + if (Objects.isNull(newItem.getUniqueId())) { + newItem.setUniqueId( + uniqueIdGenerator.generate(newItem, IdentityUtil.getItemTreeIds(parentItem), launch)); + } + return ofNullable(newItem.getItemId()).map( + itemId -> testItemRepository.findLatestIdByUniqueIdAndLaunchIdAndParentIdAndItemIdNotEqual( + newItem.getUniqueId(), + launch.getId(), + parentItem.getItemId(), + itemId + )) + .orElseGet(() -> testItemRepository.findLatestIdByUniqueIdAndLaunchIdAndParentId( + newItem.getUniqueId(), + launch.getId(), + parentItem.getItemId() + )); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/AbstractStatusChangingStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/AbstractStatusChangingStrategy.java index f59ce34cea..0fe5d2600f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/AbstractStatusChangingStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/AbstractStatusChangingStrategy.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.item.impl.status; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.INFO; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.WARN; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -24,7 +35,11 @@ import com.epam.ta.reportportal.core.events.activity.item.TestItemStatusChangedEvent; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.IssueEntityRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.item.issue.IssueEntity; @@ -35,147 +50,150 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.activity.TestItemActivityResource; import com.google.common.collect.Lists; - import java.util.Collections; import java.util.List; import java.util.Optional; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.*; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; -import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public abstract class AbstractStatusChangingStrategy implements StatusChangingStrategy { - private final TestItemService testItemService; - - private final ProjectRepository projectRepository; - private final LaunchRepository launchRepository; - private final IssueTypeHandler issueTypeHandler; - private final MessageBus messageBus; - - protected final TestItemRepository testItemRepository; - protected final IssueEntityRepository issueEntityRepository; - protected final LogRepository logRepository; - protected final LogIndexer logIndexer; - - protected AbstractStatusChangingStrategy(TestItemService testItemService, ProjectRepository projectRepository, - LaunchRepository launchRepository, TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, - MessageBus messageBus, IssueEntityRepository issueEntityRepository, LogRepository logRepository, LogIndexer logIndexer) { - this.testItemService = testItemService; - this.projectRepository = projectRepository; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.issueTypeHandler = issueTypeHandler; - this.messageBus = messageBus; - this.issueEntityRepository = issueEntityRepository; - this.logRepository = logRepository; - this.logIndexer = logIndexer; - } - - protected abstract void updateStatus(Project project, Launch launch, TestItem testItem, StatusEnum providedStatus, - ReportPortalUser user); - - protected abstract StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem); - - @Override - public void changeStatus(TestItem testItem, StatusEnum providedStatus, ReportPortalUser user) { - BusinessRule.expect(testItem.getItemResults().getStatus(), currentStatus -> !IN_PROGRESS.equals(currentStatus)) - .verify(INCORRECT_REQUEST, Suppliers.formattedSupplier("Unable to update status of test item = '{}' because of '{}' status", - testItem.getItemId(), - testItem.getItemResults().getStatus() - ).get()); - if (providedStatus == testItem.getItemResults().getStatus()) { - return; - } - - Launch launch = testItemService.getEffectiveLaunch(testItem); - Project project = projectRepository.findById(launch.getProjectId()) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, launch.getProjectId())); - - updateStatus(project, launch, testItem, providedStatus, user); - } - - protected void addToInvestigateIssue(TestItem testItem, Long projectId) { - IssueEntity issueEntity = new IssueEntity(); - IssueType toInvestigate = issueTypeHandler.defineIssueType(projectId, TO_INVESTIGATE.getLocator()); - issueEntity.setIssueType(toInvestigate); - issueEntity.setTestItemResults(testItem.getItemResults()); - issueEntityRepository.save(issueEntity); - testItem.getItemResults().setIssue(issueEntity); - } - - protected List<Long> changeParentsStatuses(TestItem testItem, Launch launch, boolean issueRequired, ReportPortalUser user) { - List<Long> updatedParents = Lists.newArrayList(); - - Long parentId = testItem.getParentId(); - while (parentId != null) { - - TestItem parent = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, testItem.getParentId())); - - StatusEnum currentParentStatus = parent.getItemResults().getStatus(); - if (!StatusEnum.IN_PROGRESS.equals(currentParentStatus)) { - - StatusEnum newParentStatus = evaluateParentItemStatus(parent, testItem); - if (!currentParentStatus.equals(newParentStatus)) { - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(parent, launch.getProjectId()); - parent.getItemResults().setStatus(newParentStatus); - updateItem(parent, launch.getProjectId(), issueRequired).ifPresent(updatedParents::add); - publishUpdateActivity(before, TO_ACTIVITY_RESOURCE.apply(parent, launch.getProjectId()), user); - } else { - return updatedParents; - } - - } else { - return updatedParents; - } - - parentId = parent.getParentId(); - } - - if (launch.getStatus() != IN_PROGRESS) { - launch.setStatus(launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), - StatusEnum.PASSED.name(), - INFO.name(), - WARN.name() - ) ? FAILED : PASSED); - } - - return updatedParents; - } - - private Optional<Long> updateItem(TestItem parent, Long projectId, boolean issueRequired) { - if (parent.isHasStats() && !parent.isHasChildren()) { - updateIssue(parent, projectId, issueRequired); - return Optional.of(parent.getItemId()); - } - return Optional.empty(); - } - - private void updateIssue(TestItem parent, Long projectId, boolean issueRequired) { - if (issueRequired) { - if (ofNullable(parent.getItemResults().getIssue()).isEmpty()) { - addToInvestigateIssue(parent, projectId); - } - } else { - ofNullable(parent.getItemResults().getIssue()).ifPresent(issue -> { - issue.setTestItemResults(null); - issueEntityRepository.delete(issue); - parent.getItemResults().setIssue(null); - logIndexer.indexItemsRemoveAsync(projectId, Collections.singletonList(parent.getItemId())); - }); - } - } - - private void publishUpdateActivity(TestItemActivityResource before, TestItemActivityResource after, ReportPortalUser user) { - messageBus.publishActivity(new TestItemStatusChangedEvent(before, after, user.getUserId(), user.getUsername())); - } + private final TestItemService testItemService; + + private final ProjectRepository projectRepository; + private final LaunchRepository launchRepository; + private final IssueTypeHandler issueTypeHandler; + private final MessageBus messageBus; + + protected final TestItemRepository testItemRepository; + protected final IssueEntityRepository issueEntityRepository; + protected final LogRepository logRepository; + protected final LogIndexer logIndexer; + + protected AbstractStatusChangingStrategy(TestItemService testItemService, + ProjectRepository projectRepository, LaunchRepository launchRepository, + TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, + MessageBus messageBus, IssueEntityRepository issueEntityRepository, + LogRepository logRepository, LogIndexer logIndexer) { + this.testItemService = testItemService; + this.projectRepository = projectRepository; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.issueTypeHandler = issueTypeHandler; + this.messageBus = messageBus; + this.issueEntityRepository = issueEntityRepository; + this.logRepository = logRepository; + this.logIndexer = logIndexer; + } + + protected abstract void updateStatus(Project project, Launch launch, TestItem testItem, + StatusEnum providedStatus, ReportPortalUser user, boolean updateParents); + + protected abstract StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem); + + @Override + public void changeStatus(TestItem testItem, StatusEnum providedStatus, ReportPortalUser user, + boolean updateParents) { + BusinessRule.expect(testItem.getItemResults().getStatus(), + currentStatus -> !IN_PROGRESS.equals(currentStatus) + ).verify( + INCORRECT_REQUEST, Suppliers.formattedSupplier( + "Unable to update status of test item = '{}' because of '{}' status", + testItem.getItemId(), testItem.getItemResults().getStatus() + ).get()); + if (providedStatus == testItem.getItemResults().getStatus()) { + return; + } + + Launch launch = testItemService.getEffectiveLaunch(testItem); + Project project = projectRepository.findById(launch.getProjectId()) + .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, launch.getProjectId())); + + updateStatus(project, launch, testItem, providedStatus, user, updateParents); + } + + protected void addToInvestigateIssue(TestItem testItem, Long projectId) { + IssueEntity issueEntity = new IssueEntity(); + IssueType toInvestigate = + issueTypeHandler.defineIssueType(projectId, TO_INVESTIGATE.getLocator()); + issueEntity.setIssueType(toInvestigate); + issueEntity.setTestItemResults(testItem.getItemResults()); + issueEntityRepository.save(issueEntity); + testItem.getItemResults().setIssue(issueEntity); + } + + protected List<Long> changeParentsStatuses(TestItem testItem, Launch launch, + boolean issueRequired, ReportPortalUser user) { + List<Long> updatedParents = Lists.newArrayList(); + + Long parentId = testItem.getParentId(); + while (parentId != null) { + + TestItem parent = testItemRepository.findById(parentId).orElseThrow( + () -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, testItem.getParentId())); + + StatusEnum currentParentStatus = parent.getItemResults().getStatus(); + if (!StatusEnum.IN_PROGRESS.equals(currentParentStatus)) { + + StatusEnum newParentStatus = evaluateParentItemStatus(parent, testItem); + if (!currentParentStatus.equals(newParentStatus)) { + TestItemActivityResource before = + TO_ACTIVITY_RESOURCE.apply(parent, launch.getProjectId()); + parent.getItemResults().setStatus(newParentStatus); + updateItem(parent, launch.getProjectId(), issueRequired).ifPresent(updatedParents::add); + publishUpdateActivity(before, TO_ACTIVITY_RESOURCE.apply(parent, launch.getProjectId()), + user + ); + } else { + return updatedParents; + } + + } else { + return updatedParents; + } + + parentId = parent.getParentId(); + } + + if (launch.getStatus() != IN_PROGRESS) { + launch.setStatus( + launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), StatusEnum.PASSED.name(), + INFO.name(), WARN.name() + ) ? FAILED : PASSED); + } + + return updatedParents; + } + + private Optional<Long> updateItem(TestItem parent, Long projectId, boolean issueRequired) { + if (parent.isHasStats() && !parent.isHasChildren()) { + updateIssue(parent, projectId, issueRequired); + return Optional.of(parent.getItemId()); + } + return Optional.empty(); + } + + private void updateIssue(TestItem parent, Long projectId, boolean issueRequired) { + if (issueRequired) { + if (ofNullable(parent.getItemResults().getIssue()).isEmpty()) { + addToInvestigateIssue(parent, projectId); + } + } else { + ofNullable(parent.getItemResults().getIssue()).ifPresent(issue -> { + issue.setTestItemResults(null); + issueEntityRepository.delete(issue); + parent.getItemResults().setIssue(null); + logIndexer.indexItemsRemoveAsync(projectId, Collections.singletonList(parent.getItemId())); + }); + } + } + + private void publishUpdateActivity(TestItemActivityResource before, + TestItemActivityResource after, ReportPortalUser user) { + messageBus.publishActivity( + new TestItemStatusChangedEvent(before, after, user.getUserId(), user.getUsername())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandler.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandler.java index 1da3afbfee..d282963d37 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandler.java @@ -25,7 +25,7 @@ */ public interface ChangeStatusHandler { - void changeParentStatus(TestItem childItem, Long projectId, ReportPortalUser user); + void changeParentStatus(TestItem childItem, Long projectId, ReportPortalUser user); - void changeLaunchStatus(Launch launch); + void changeLaunchStatus(Launch launch); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java index 9a95751cc2..9d4eef2b72 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.item.impl.status; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.INFO; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.WARN; +import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.events.activity.item.TestItemStatusChangedEvent; @@ -29,15 +36,10 @@ import com.epam.ta.reportportal.jooq.enums.JStatusEnum; import com.epam.ta.reportportal.ws.model.activity.TestItemActivityResource; import com.google.common.collect.Lists; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.Optional; - -import static com.epam.ta.reportportal.entity.enums.StatusEnum.*; -import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; -import static java.util.Optional.ofNullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -45,82 +47,91 @@ @Service public class ChangeStatusHandlerImpl implements ChangeStatusHandler { - private final TestItemRepository testItemRepository; - private final IssueEntityRepository issueEntityRepository; - private final MessageBus messageBus; - private final LaunchRepository launchRepository; - private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; + private final TestItemRepository testItemRepository; + private final IssueEntityRepository issueEntityRepository; + private final MessageBus messageBus; + private final LaunchRepository launchRepository; + private final Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; - @Autowired - public ChangeStatusHandlerImpl(TestItemRepository testItemRepository, IssueEntityRepository issueEntityRepository, - MessageBus messageBus, LaunchRepository launchRepository, - Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping) { - this.testItemRepository = testItemRepository; - this.issueEntityRepository = issueEntityRepository; - this.messageBus = messageBus; - this.launchRepository = launchRepository; - this.statusChangingStrategyMapping = statusChangingStrategyMapping; - } + @Autowired + public ChangeStatusHandlerImpl(TestItemRepository testItemRepository, + IssueEntityRepository issueEntityRepository, + MessageBus messageBus, LaunchRepository launchRepository, + Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping) { + this.testItemRepository = testItemRepository; + this.issueEntityRepository = issueEntityRepository; + this.messageBus = messageBus; + this.launchRepository = launchRepository; + this.statusChangingStrategyMapping = statusChangingStrategyMapping; + } - @Override - public void changeParentStatus(TestItem childItem, Long projectId, ReportPortalUser user) { - ofNullable(childItem.getParentId()).flatMap(testItemRepository::findById).ifPresent(parent -> { - if (parent.isHasChildren()) { - ofNullable(parent.getItemResults().getIssue()).map(IssueEntity::getIssueId).ifPresent(issueEntityRepository::deleteById); - } - if (isParentStatusUpdateRequired(parent)) { - StatusEnum resolvedStatus = resolveStatus(parent.getItemId()); - if (parent.getItemResults().getStatus() != resolvedStatus) { - TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(parent, projectId); - changeStatus(parent, resolvedStatus, user); - messageBus.publishActivity(new TestItemStatusChangedEvent(before, - TO_ACTIVITY_RESOURCE.apply(parent, projectId), - user.getUserId(), - user.getUsername() - )); - changeParentStatus(parent, projectId, user); - } + @Override + public void changeParentStatus(TestItem childItem, Long projectId, ReportPortalUser user) { + ofNullable(childItem.getParentId()).flatMap(testItemRepository::findById).ifPresent(parent -> { + if (parent.isHasChildren()) { + ofNullable(parent.getItemResults().getIssue()).map(IssueEntity::getIssueId) + .ifPresent(issueEntityRepository::deleteById); + } + if (isParentStatusUpdateRequired(parent)) { + StatusEnum resolvedStatus = resolveStatus(parent.getItemId()); + if (parent.getItemResults().getStatus() != resolvedStatus) { + TestItemActivityResource before = TO_ACTIVITY_RESOURCE.apply(parent, projectId); + changeStatus(parent, resolvedStatus, user); + messageBus.publishActivity(new TestItemStatusChangedEvent(before, + TO_ACTIVITY_RESOURCE.apply(parent, projectId), + user.getUserId(), + user.getUsername() + )); + changeParentStatus(parent, projectId, user); + } - } - }); - } + } + }); + } - private boolean isParentStatusUpdateRequired(TestItem parent) { - return parent.getItemResults().getStatus() != StatusEnum.IN_PROGRESS - && !testItemRepository.hasItemsInStatusByParent(parent.getItemId(), parent.getPath(), StatusEnum.IN_PROGRESS.name()); - } + private boolean isParentStatusUpdateRequired(TestItem parent) { + return parent.getItemResults().getStatus() != StatusEnum.IN_PROGRESS + && parent.getItemResults().getStatus() != PASSED + && parent.getItemResults().getStatus() != FAILED + && !testItemRepository.hasItemsInStatusByParent(parent.getItemId(), parent.getPath(), + StatusEnum.IN_PROGRESS.name()); + } - private StatusEnum resolveStatus(Long itemId) { - return testItemRepository.hasDescendantsNotInStatus(itemId, StatusEnum.PASSED.name(), INFO.name(), WARN.name()) ? - FAILED : - PASSED; - } + private StatusEnum resolveStatus(Long itemId) { + return + testItemRepository.hasDescendantsNotInStatus(itemId, StatusEnum.PASSED.name(), INFO.name(), + WARN.name()) ? + FAILED : + PASSED; + } - private void changeStatus(TestItem parent, StatusEnum resolvedStatus, ReportPortalUser user) { - if (parent.isHasChildren() || !parent.isHasStats()) { - parent.getItemResults().setStatus(resolvedStatus); - } else { - Optional<StatusChangingStrategy> statusChangingStrategy = ofNullable(statusChangingStrategyMapping.get(resolvedStatus)); - if (statusChangingStrategy.isPresent()) { - statusChangingStrategy.get().changeStatus(parent, resolvedStatus, user); - } else { - parent.getItemResults().setStatus(resolvedStatus); - } - } + private void changeStatus(TestItem parent, StatusEnum resolvedStatus, ReportPortalUser user) { + if (parent.isHasChildren() || !parent.isHasStats()) { + parent.getItemResults().setStatus(resolvedStatus); + } else { + Optional<StatusChangingStrategy> statusChangingStrategy = ofNullable( + statusChangingStrategyMapping.get(resolvedStatus)); + if (statusChangingStrategy.isPresent()) { + statusChangingStrategy.get().changeStatus(parent, resolvedStatus, user, false); + } else { + parent.getItemResults().setStatus(resolvedStatus); + } + } - } + } - @Override - public void changeLaunchStatus(Launch launch) { - if (launch.getStatus() != StatusEnum.IN_PROGRESS) { - if (!launchRepository.hasItemsInStatuses(launch.getId(), Lists.newArrayList(JStatusEnum.IN_PROGRESS))) { - StatusEnum launchStatus = launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), - StatusEnum.PASSED.name(), - INFO.name(), - WARN.name() - ) ? FAILED : PASSED; - launch.setStatus(launchStatus); - } - } - } + @Override + public void changeLaunchStatus(Launch launch) { + if (launch.getStatus() != StatusEnum.IN_PROGRESS) { + if (!launchRepository.hasItemsInStatuses(launch.getId(), + Lists.newArrayList(JStatusEnum.IN_PROGRESS))) { + StatusEnum launchStatus = launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), + StatusEnum.PASSED.name(), + INFO.name(), + WARN.name() + ) ? FAILED : PASSED; + launch.setStatus(launchStatus); + } + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/StatusChangingStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/StatusChangingStrategy.java index 61c8b09ef0..45758d4685 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/StatusChangingStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/StatusChangingStrategy.java @@ -26,5 +26,6 @@ */ public interface StatusChangingStrategy { - void changeStatus(TestItem testItem, StatusEnum providedStatus, ReportPortalUser user); + void changeStatus(TestItem testItem, StatusEnum providedStatus, ReportPortalUser user, + boolean updateParents); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToFailedStatusChangingStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToFailedStatusChangingStrategy.java index 43f93bd2b1..f1fb3a84a8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToFailedStatusChangingStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToFailedStatusChangingStrategy.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.item.impl.status; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -24,19 +27,20 @@ import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.IssueEntityRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.project.Project; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - +import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -45,46 +49,47 @@ @Service public class ToFailedStatusChangingStrategy extends AbstractStatusChangingStrategy { - @Autowired - public ToFailedStatusChangingStrategy(TestItemService testItemService, ProjectRepository projectRepository, - LaunchRepository launchRepository, TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, - MessageBus messageBus, IssueEntityRepository issueEntityRepository, LogRepository logRepository, LogIndexer logIndexer) { - super( - testItemService, - projectRepository, - launchRepository, - testItemRepository, - issueTypeHandler, - messageBus, - issueEntityRepository, - logRepository, - logIndexer - ); - } + @Autowired + public ToFailedStatusChangingStrategy(TestItemService testItemService, + ProjectRepository projectRepository, LaunchRepository launchRepository, + TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, + MessageBus messageBus, IssueEntityRepository issueEntityRepository, + LogRepository logRepository, LogIndexer logIndexer) { + super(testItemService, projectRepository, launchRepository, testItemRepository, + issueTypeHandler, messageBus, issueEntityRepository, logRepository, logIndexer + ); + } - @Override - protected void updateStatus(Project project, Launch launch, TestItem testItem, StatusEnum providedStatus, ReportPortalUser user) { - BusinessRule.expect(providedStatus, statusIn(StatusEnum.FAILED)).verify( - INCORRECT_REQUEST, - Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' is allowed", providedStatus, StatusEnum.FAILED).get() - ); + @Override + protected void updateStatus(Project project, Launch launch, TestItem testItem, + StatusEnum providedStatus, ReportPortalUser user, boolean updateParents) { + BusinessRule.expect(providedStatus, statusIn(StatusEnum.FAILED)).verify(INCORRECT_REQUEST, + Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' is allowed", providedStatus, + StatusEnum.FAILED + ).get() + ); - testItem.getItemResults().setStatus(providedStatus); - if (Objects.isNull(testItem.getRetryOf())) { - if (testItem.getItemResults().getIssue() == null && testItem.isHasStats()) { - addToInvestigateIssue(testItem, project.getId()); - } + testItem.getItemResults().setStatus(providedStatus); + if (Objects.isNull(testItem.getRetryOf())) { + if (testItem.getItemResults().getIssue() == null && testItem.isHasStats()) { + addToInvestigateIssue(testItem, project.getId()); + } - List<Long> itemsToReindex = changeParentsStatuses(testItem, launch, true, user); - itemsToReindex.add(testItem.getItemId()); - logIndexer.indexItemsRemove(project.getId(), itemsToReindex); - logIndexer.indexItemsLogs(project.getId(), launch.getId(), itemsToReindex, AnalyzerUtils.getAnalyzerConfig(project)); - } - } + List<Long> itemsToReindex = new ArrayList<>(); + if (updateParents) { + itemsToReindex = changeParentsStatuses(testItem, launch, true, user); + } + itemsToReindex.add(testItem.getItemId()); + logIndexer.indexItemsRemove(project.getId(), itemsToReindex); + logIndexer.indexItemsLogs(project.getId(), launch.getId(), itemsToReindex, + AnalyzerUtils.getAnalyzerConfig(project) + ); + } + } - @Override - protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { - return StatusEnum.FAILED; - } + @Override + protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { + return StatusEnum.FAILED; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToPassedStatusChangingStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToPassedStatusChangingStrategy.java index 34f7b07d98..babcc18e7e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToPassedStatusChangingStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToPassedStatusChangingStrategy.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.item.impl.status; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -23,22 +27,21 @@ import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.IssueEntityRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.project.Project; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static java.util.Optional.ofNullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -47,58 +50,53 @@ @Service public class ToPassedStatusChangingStrategy extends AbstractStatusChangingStrategy { - @Autowired - protected ToPassedStatusChangingStrategy(TestItemService testItemService, ProjectRepository projectRepository, - LaunchRepository launchRepository, IssueTypeHandler issueTypeHandler, MessageBus messageBus, - IssueEntityRepository issueEntityRepository, LogRepository logRepository, LogIndexer logIndexer, - TestItemRepository testItemRepository) { - super(testItemService, - projectRepository, - launchRepository, - testItemRepository, - issueTypeHandler, - messageBus, - issueEntityRepository, - logRepository, - logIndexer - ); - } + @Autowired + protected ToPassedStatusChangingStrategy(TestItemService testItemService, + ProjectRepository projectRepository, LaunchRepository launchRepository, + IssueTypeHandler issueTypeHandler, MessageBus messageBus, + IssueEntityRepository issueEntityRepository, LogRepository logRepository, + LogIndexer logIndexer, TestItemRepository testItemRepository) { + super(testItemService, projectRepository, launchRepository, testItemRepository, + issueTypeHandler, messageBus, issueEntityRepository, logRepository, logIndexer + ); + } - @Override - protected void updateStatus(Project project, Launch launch, TestItem testItem, StatusEnum providedStatus, ReportPortalUser user) { - BusinessRule.expect(providedStatus, statusIn(StatusEnum.PASSED, StatusEnum.INFO, StatusEnum.WARN)) - .verify(INCORRECT_REQUEST, - Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' are allowed", - providedStatus, - Stream.of(StatusEnum.PASSED, StatusEnum.INFO, StatusEnum.WARN) - .map(StatusEnum::name) - .collect(Collectors.joining(", ")) - ).get() - ); + @Override + protected void updateStatus(Project project, Launch launch, TestItem testItem, + StatusEnum providedStatus, ReportPortalUser user, boolean updateParents) { + BusinessRule.expect(providedStatus, + statusIn(StatusEnum.PASSED, StatusEnum.INFO, StatusEnum.WARN) + ).verify(INCORRECT_REQUEST, + Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' are allowed", + providedStatus, + Stream.of(StatusEnum.PASSED, StatusEnum.INFO, StatusEnum.WARN).map(StatusEnum::name) + .collect(Collectors.joining(", ")) + ).get() + ); - testItem.getItemResults().setStatus(providedStatus); - if (Objects.isNull(testItem.getRetryOf())) { - ofNullable(testItem.getItemResults().getIssue()).ifPresent(issue -> { - issue.setTestItemResults(null); - issueEntityRepository.delete(issue); - testItem.getItemResults().setIssue(null); - logIndexer.indexItemsRemoveAsync(project.getId(), Collections.singletonList(testItem.getItemId())); - }); + testItem.getItemResults().setStatus(providedStatus); + if (Objects.isNull(testItem.getRetryOf())) { + ofNullable(testItem.getItemResults().getIssue()).ifPresent(issue -> { + issue.setTestItemResults(null); + issueEntityRepository.delete(issue); + testItem.getItemResults().setIssue(null); + logIndexer.indexItemsRemoveAsync(project.getId(), + Collections.singletonList(testItem.getItemId()) + ); + }); - changeParentsStatuses(testItem, launch, false, user); - } - } + if (updateParents) { + changeParentsStatuses(testItem, launch, false, user); + } + } + } - @Override - protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { - return testItemRepository.hasDescendantsNotInStatusExcludingById(parentItem.getItemId(), - childItem.getItemId(), - StatusEnum.PASSED.name(), - StatusEnum.INFO.name(), - StatusEnum.WARN.name() - ) ? - StatusEnum.FAILED : - StatusEnum.PASSED; - } + @Override + protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { + return testItemRepository.hasDescendantsNotInStatusExcludingById(parentItem.getItemId(), + childItem.getItemId(), StatusEnum.PASSED.name(), StatusEnum.INFO.name(), + StatusEnum.WARN.name() + ) ? StatusEnum.FAILED : StatusEnum.PASSED; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToSkippedStatusChangingStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToSkippedStatusChangingStrategy.java index f50b5a3d8d..863896daff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToSkippedStatusChangingStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ToSkippedStatusChangingStrategy.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.item.impl.status; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -24,24 +29,24 @@ import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.IssueEntityRepository; +import com.epam.ta.reportportal.dao.ItemAttributeRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.project.Project; -import org.apache.commons.lang3.BooleanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -50,72 +55,74 @@ @Service public class ToSkippedStatusChangingStrategy extends AbstractStatusChangingStrategy { - public static final String SKIPPED_ISSUE_KEY = "skippedIssue"; - - private final ItemAttributeRepository itemAttributeRepository; - - @Autowired - protected ToSkippedStatusChangingStrategy(TestItemService testItemService, ProjectRepository projectRepository, - LaunchRepository launchRepository, TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, - MessageBus messageBus, IssueEntityRepository issueEntityRepository, LogRepository logRepository, LogIndexer logIndexer, - ItemAttributeRepository itemAttributeRepository) { - super(testItemService, - projectRepository, - launchRepository, - testItemRepository, - issueTypeHandler, - messageBus, - issueEntityRepository, - logRepository, - logIndexer - ); - this.itemAttributeRepository = itemAttributeRepository; - } - - @Override - protected void updateStatus(Project project, Launch launch, TestItem testItem, StatusEnum providedStatus, ReportPortalUser user) { - BusinessRule.expect(providedStatus, statusIn(StatusEnum.SKIPPED)) - .verify(INCORRECT_REQUEST, - Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' is allowed", providedStatus, StatusEnum.SKIPPED) - .get() - ); - - testItem.getItemResults().setStatus(providedStatus); - - if (Objects.isNull(testItem.getRetryOf())) { - Optional<ItemAttribute> skippedIssueAttribute = itemAttributeRepository.findByLaunchIdAndKeyAndSystem(testItem.getLaunchId(), - SKIPPED_ISSUE_KEY, - true - ); - - boolean issueRequired = skippedIssueAttribute.isPresent() && BooleanUtils.toBoolean(skippedIssueAttribute.get().getValue()); - - if (issueRequired) { - if (testItem.getItemResults().getIssue() == null && testItem.isHasStats()) { - addToInvestigateIssue(testItem, project.getId()); - } - } else { - ofNullable(testItem.getItemResults().getIssue()).map(issue -> { - issue.setTestItemResults(null); - testItem.getItemResults().setIssue(null); - return issue.getIssueId(); - }).ifPresent(issueEntityRepository::deleteById); - } - - List<Long> itemsToReindex = changeParentsStatuses(testItem, launch, true, user); - itemsToReindex.add(testItem.getItemId()); - logIndexer.indexLaunchesRemove(project.getId(), itemsToReindex); - - if (!issueRequired) { - itemsToReindex.remove(itemsToReindex.size() - 1); - } - - logIndexer.indexItemsLogs(project.getId(), launch.getId(), itemsToReindex, AnalyzerUtils.getAnalyzerConfig(project)); - } - } - - @Override - protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { - return FAILED; - } + public static final String SKIPPED_ISSUE_KEY = "skippedIssue"; + + private final ItemAttributeRepository itemAttributeRepository; + + @Autowired + protected ToSkippedStatusChangingStrategy(TestItemService testItemService, + ProjectRepository projectRepository, LaunchRepository launchRepository, + TestItemRepository testItemRepository, IssueTypeHandler issueTypeHandler, + MessageBus messageBus, IssueEntityRepository issueEntityRepository, + LogRepository logRepository, LogIndexer logIndexer, + ItemAttributeRepository itemAttributeRepository) { + super(testItemService, projectRepository, launchRepository, testItemRepository, + issueTypeHandler, messageBus, issueEntityRepository, logRepository, logIndexer + ); + this.itemAttributeRepository = itemAttributeRepository; + } + + @Override + protected void updateStatus(Project project, Launch launch, TestItem testItem, + StatusEnum providedStatus, ReportPortalUser user, boolean updateParents) { + BusinessRule.expect(providedStatus, statusIn(StatusEnum.SKIPPED)).verify(INCORRECT_REQUEST, + Suppliers.formattedSupplier("Incorrect status - '{}', only '{}' is allowed", providedStatus, + StatusEnum.SKIPPED + ).get() + ); + + testItem.getItemResults().setStatus(providedStatus); + + if (Objects.isNull(testItem.getRetryOf())) { + Optional<ItemAttribute> skippedIssueAttribute = + itemAttributeRepository.findByLaunchIdAndKeyAndSystem(testItem.getLaunchId(), + SKIPPED_ISSUE_KEY, true + ); + + boolean issueRequired = skippedIssueAttribute.isPresent() && BooleanUtils.toBoolean( + skippedIssueAttribute.get().getValue()); + + if (issueRequired) { + if (testItem.getItemResults().getIssue() == null && testItem.isHasStats()) { + addToInvestigateIssue(testItem, project.getId()); + } + } else { + ofNullable(testItem.getItemResults().getIssue()).map(issue -> { + issue.setTestItemResults(null); + testItem.getItemResults().setIssue(null); + return issue.getIssueId(); + }).ifPresent(issueEntityRepository::deleteById); + } + + List<Long> itemsToReindex = new ArrayList<>(); + if (updateParents) { + itemsToReindex = changeParentsStatuses(testItem, launch, true, user); + } + itemsToReindex.add(testItem.getItemId()); + logIndexer.indexItemsRemove(project.getId(), itemsToReindex); + + if (!issueRequired) { + itemsToReindex.remove(itemsToReindex.size() - 1); + } + + logIndexer.indexItemsLogs(project.getId(), launch.getId(), itemsToReindex, + AnalyzerUtils.getAnalyzerConfig(project) + ); + } + } + + @Override + protected StatusEnum evaluateParentItemStatus(TestItem parentItem, TestItem childItem) { + return FAILED; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/merge/LaunchMergeStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/merge/LaunchMergeStrategy.java index 6c5658321b..aa786bbf44 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/merge/LaunchMergeStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/merge/LaunchMergeStrategy.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; - import java.util.List; /** @@ -27,6 +26,7 @@ */ public interface LaunchMergeStrategy { - Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ rq, - List<Launch> launchesList); + Launch mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + MergeLaunchesRQ rq, + List<Launch> launchesList); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/merge/StatisticsCalculationStrategy.java b/src/main/java/com/epam/ta/reportportal/core/item/merge/StatisticsCalculationStrategy.java index e184bc4627..0518440372 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/merge/StatisticsCalculationStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/merge/StatisticsCalculationStrategy.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.statistics.Statistics; - import java.util.Collection; import java.util.Set; @@ -27,5 +26,5 @@ */ public interface StatisticsCalculationStrategy { - Set<Statistics> recalculateLaunchStatistics(Launch newLaunch, Collection<Launch> launches); + Set<Statistics> recalculateLaunchStatistics(Launch newLaunch, Collection<Launch> launches); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/utils/DefaultLaunchFilterProvider.java b/src/main/java/com/epam/ta/reportportal/core/item/utils/DefaultLaunchFilterProvider.java index fa66acb1fa..b1fdecff05 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/utils/DefaultLaunchFilterProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/utils/DefaultLaunchFilterProvider.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.item.utils; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -33,60 +39,58 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class DefaultLaunchFilterProvider { - public static Pair<Queryable, Pageable> createDefaultLaunchQueryablePair(ReportPortalUser.ProjectDetails projectDetails, - UserFilter userFilter, int launchesLimit) { - Queryable launchFilter = createLaunchFilter(projectDetails, userFilter); - Pageable launchPageable = createLaunchPageable(userFilter, launchesLimit); - return Pair.of(launchFilter, launchPageable); - } + public static Pair<Queryable, Pageable> createDefaultLaunchQueryablePair( + ReportPortalUser.ProjectDetails projectDetails, + UserFilter userFilter, int launchesLimit) { + Queryable launchFilter = createLaunchFilter(projectDetails, userFilter); + Pageable launchPageable = createLaunchPageable(userFilter, launchesLimit); + return Pair.of(launchFilter, launchPageable); + } - private static Filter createLaunchFilter(ReportPortalUser.ProjectDetails projectDetails, UserFilter launchFilter) { + private static Filter createLaunchFilter(ReportPortalUser.ProjectDetails projectDetails, + UserFilter launchFilter) { - validateLaunchFilterTarget(launchFilter); + validateLaunchFilterTarget(launchFilter); - Filter filter = Filter.builder() - .withTarget(launchFilter.getTargetClass().getClassObject()) - .withCondition(FilterCondition.builder().eq(CRITERIA_PROJECT_ID, String.valueOf(projectDetails.getProjectId())).build()) - .withCondition(FilterCondition.builder() - .withCondition(Condition.NOT_EQUALS) - .withSearchCriteria(CRITERIA_LAUNCH_STATUS) - .withValue(StatusEnum.IN_PROGRESS.name()) - .build()) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, Mode.DEFAULT.toString()).build()) - .build(); - filter.getFilterConditions().addAll(launchFilter.getFilterCondition()); - return filter; - } + Filter filter = Filter.builder() + .withTarget(launchFilter.getTargetClass().getClassObject()) + .withCondition(FilterCondition.builder() + .eq(CRITERIA_PROJECT_ID, String.valueOf(projectDetails.getProjectId())).build()) + .withCondition(FilterCondition.builder() + .withCondition(Condition.NOT_EQUALS) + .withSearchCriteria(CRITERIA_LAUNCH_STATUS) + .withValue(StatusEnum.IN_PROGRESS.name()) + .build()) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, Mode.DEFAULT.toString()).build()) + .build(); + filter.getFilterConditions().addAll(launchFilter.getFilterCondition()); + return filter; + } - private static void validateLaunchFilterTarget(UserFilter launchFilter) { - BusinessRule.expect(launchFilter, f -> ObjectType.Launch.equals(f.getTargetClass())) - .verify(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Incorrect filter target - '{}'. Allowed: '{}'", - launchFilter.getTargetClass(), - ObjectType.Launch - ) - ); - } + private static void validateLaunchFilterTarget(UserFilter launchFilter) { + BusinessRule.expect(launchFilter, f -> ObjectType.Launch.equals(f.getTargetClass())) + .verify(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Incorrect filter target - '{}'. Allowed: '{}'", + launchFilter.getTargetClass(), + ObjectType.Launch + ) + ); + } - private static Pageable createLaunchPageable(UserFilter launchFilter, int launchesLimit) { + private static Pageable createLaunchPageable(UserFilter launchFilter, int launchesLimit) { - BusinessRule.expect(launchesLimit, limit -> limit > 0) - .verify(ErrorType.BAD_REQUEST_ERROR, "Launches limit should be greater than 0"); + BusinessRule.expect(launchesLimit, limit -> limit > 0) + .verify(ErrorType.BAD_REQUEST_ERROR, "Launches limit should be greater than 0"); - Sort sort = ofNullable(launchFilter.getFilterSorts()).map(sorts -> Sort.by(sorts.stream() - .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) - .collect(toList()))).orElseGet(Sort::unsorted); - return PageRequest.of(0, launchesLimit, sort); - } + Sort sort = ofNullable(launchFilter.getFilterSorts()).map(sorts -> Sort.by(sorts.stream() + .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) + .collect(toList()))).orElseGet(Sort::unsorted); + return PageRequest.of(0, launchesLimit, sort); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/NestedStepConditionValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/NestedStepConditionValidator.java index b1fa30dbf5..87338a1f1d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/NestedStepConditionValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/NestedStepConditionValidator.java @@ -1,31 +1,33 @@ package com.epam.ta.reportportal.core.item.validator.parent; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import org.springframework.core.Ordered; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; - @Service public class NestedStepConditionValidator implements ParentItemValidator, Ordered { - @Override - public void validate(StartTestItemRQ rq, TestItem parent) { - if (!parent.isHasStats()) { - expect(rq.isHasStats(), equalTo(Boolean.FALSE)).verify(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Unable to add a not nested step item, because parent item with ID = '{}' is a nested step", - parent.getItemId() - ) - .get() - ); - } - } - @Override - public int getOrder() { - return 1; - } + @Override + public void validate(StartTestItemRQ rq, TestItem parent) { + if (!parent.isHasStats()) { + expect(rq.isHasStats(), equalTo(Boolean.FALSE)).verify(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier( + "Unable to add a not nested step item, because parent item with ID = '{}' is a nested step", + parent.getItemId() + ) + .get() + ); + } + } + + @Override + public int getOrder() { + return 1; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/ParentItemValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/ParentItemValidator.java index a0aa192353..ef29f979df 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/ParentItemValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/ParentItemValidator.java @@ -21,11 +21,11 @@ public interface ParentItemValidator { - /** - * Verifies if the start of a child item is allowed. - * - * @param rq Start child item request - * @param parent Parent item - */ - void validate(StartTestItemRQ rq, TestItem parent); + /** + * Verifies if the start of a child item is allowed. + * + * @param rq Start child item request + * @param parent Parent item + */ + void validate(StartTestItemRQ rq, TestItem parent); } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/PathLengthValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/PathLengthValidator.java new file mode 100644 index 0000000000..774e87f54c --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/PathLengthValidator.java @@ -0,0 +1,48 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.item.validator.parent; + +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + +import com.epam.ta.reportportal.commons.Predicates; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Service; + +/** + * @author Andrei Piankouski + */ +@Service +public class PathLengthValidator implements ParentItemValidator, Ordered { + + private static final int MAX_PATH_LENGTH = 64; + + @Override + public void validate(StartTestItemRQ rq, TestItem parent) { + expect(parent.getPath().split("\\.").length >= MAX_PATH_LENGTH, + Predicates.equalTo(false)).verify(BAD_REQUEST_ERROR, + "Exceeded nesting limit for test item. Max limit is " + MAX_PATH_LENGTH + "." + ); + } + + @Override + public int getOrder() { + return 4; + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/RetryConditionValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/RetryConditionValidator.java index 9a75ffc174..485eabcec5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/RetryConditionValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/RetryConditionValidator.java @@ -1,25 +1,27 @@ package com.epam.ta.reportportal.core.item.validator.parent; +import static com.epam.ta.reportportal.commons.Predicates.isNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_TO_SAVE_CHILD_ITEM_FOR_THE_RETRY; + import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import org.springframework.core.Ordered; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.Predicates.isNull; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.UNABLE_TO_SAVE_CHILD_ITEM_FOR_THE_RETRY; - @Service public class RetryConditionValidator implements ParentItemValidator, Ordered { - @Override - public void validate(StartTestItemRQ rq, TestItem parent) { - if (rq.isHasStats()) { - expect(parent.getRetryOf(), isNull()::test).verify(UNABLE_TO_SAVE_CHILD_ITEM_FOR_THE_RETRY, parent.getItemId()); - } - } - @Override - public int getOrder() { - return 2; - } + @Override + public void validate(StartTestItemRQ rq, TestItem parent) { + if (rq.isHasStats()) { + expect(parent.getRetryOf(), isNull()::test).verify(UNABLE_TO_SAVE_CHILD_ITEM_FOR_THE_RETRY, + parent.getItemId()); + } + } + + @Override + public int getOrder() { + return 2; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/StartTimeConditionValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/StartTimeConditionValidator.java index fba612e821..ed453d8b9e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/StartTimeConditionValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/parent/StartTimeConditionValidator.java @@ -1,27 +1,29 @@ package com.epam.ta.reportportal.core.item.validator.parent; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.ws.model.ErrorType.CHILD_START_TIME_EARLIER_THAN_PARENT; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import org.springframework.core.Ordered; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.ws.model.ErrorType.CHILD_START_TIME_EARLIER_THAN_PARENT; - @Service public class StartTimeConditionValidator implements ParentItemValidator, Ordered { - @Override - public void validate(StartTestItemRQ rq, TestItem parent) { - expect(rq.getStartTime(), Preconditions.sameTimeOrLater(parent.getStartTime())).verify(CHILD_START_TIME_EARLIER_THAN_PARENT, - rq.getStartTime(), - parent.getStartTime(), - parent.getItemId() - ); - } - @Override - public int getOrder() { - return 3; - } + @Override + public void validate(StartTestItemRQ rq, TestItem parent) { + expect(rq.getStartTime(), Preconditions.sameTimeOrLater(parent.getStartTime())).verify( + CHILD_START_TIME_EARLIER_THAN_PARENT, + rq.getStartTime(), + parent.getStartTime(), + parent.getItemId() + ); + } + + @Override + public int getOrder() { + return 3; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidator.java index 0f4e0cfcc1..8248b7c1d9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidator.java @@ -27,18 +27,18 @@ @Service public class NotNestedStepValidator implements TestItemValidator, Ordered { - @Override - public boolean validate(TestItem item) { - return item.isHasStats(); - } + @Override + public boolean validate(TestItem item) { + return item.isHasStats(); + } - @Override - public String provide(TestItem item) { - return Suppliers.formattedSupplier("Test item = {} is a nested step", item.getItemId()).get(); - } + @Override + public String provide(TestItem item) { + return Suppliers.formattedSupplier("Test item = {} is a nested step", item.getItemId()).get(); + } - @Override - public int getOrder() { - return 1; - } + @Override + public int getOrder() { + return 1; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidator.java index c4fda95cc0..2816b0304f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidator.java @@ -18,29 +18,28 @@ import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.item.TestItem; +import java.util.Objects; import org.springframework.core.Ordered; import org.springframework.stereotype.Service; -import java.util.Objects; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class NotRetryValidator implements TestItemValidator, Ordered { - @Override - public boolean validate(TestItem item) { - return Objects.isNull(item.getRetryOf()) && Objects.nonNull(item.getLaunchId()); - } + @Override + public boolean validate(TestItem item) { + return Objects.isNull(item.getRetryOf()) && Objects.nonNull(item.getLaunchId()); + } - @Override - public String provide(TestItem item) { - return Suppliers.formattedSupplier("Test item = {} is a retry", item.getItemId()).get(); - } + @Override + public String provide(TestItem item) { + return Suppliers.formattedSupplier("Test item = {} is a retry", item.getItemId()).get(); + } - @Override - public int getOrder() { - return 2; - } + @Override + public int getOrder() { + return 2; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/TestItemValidator.java b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/TestItemValidator.java index 52d1747d7c..97e1f28963 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/validator/state/TestItemValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/validator/state/TestItemValidator.java @@ -24,5 +24,5 @@ */ public interface TestItemValidator extends MessageProvider<TestItem> { - boolean validate(TestItem item); + boolean validate(TestItem item); } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/GetJasperReportHandler.java b/src/main/java/com/epam/ta/reportportal/core/jasper/GetJasperReportHandler.java index a25a69caf1..7cc882eb43 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/GetJasperReportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/GetJasperReportHandler.java @@ -17,11 +17,10 @@ package com.epam.ta.reportportal.core.jasper; import com.epam.ta.reportportal.entity.jasper.ReportFormat; -import net.sf.jasperreports.engine.JRDataSource; -import net.sf.jasperreports.engine.JasperPrint; - import java.io.OutputStream; import java.util.Map; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JasperPrint; /** * Get export reports utilities @@ -30,36 +29,37 @@ */ public interface GetJasperReportHandler<T> { - /** - * Generate rendered report representation. - * - * @param params Parameters for Jasper view - * @param dataSource Data for Jasper view - * @return {@link JasperPrint} - */ - JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource); + /** + * Generate rendered report representation. + * + * @param params Parameters for Jasper view + * @param dataSource Data for Jasper view + * @return {@link JasperPrint} + */ + JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource); - /** - * Finds report format and checks whether it's valid - * - * @param format ReportFormat - */ - ReportFormat getReportFormat(String format); + /** + * Finds report format and checks whether it's valid + * + * @param format ReportFormat + * @return {@link ReportFormat} + */ + ReportFormat getReportFormat(String format); - /** - * Convert rendered report to output stream. - * - * @param format Report format - * @param outputStream Stream report should be written to - * @param jasperPrint Report Data - */ - void writeReport(ReportFormat format, OutputStream outputStream, JasperPrint jasperPrint); + /** + * Convert rendered report to output stream. + * + * @param format Report format + * @param outputStream Stream report should be written to + * @param jasperPrint Report Data + */ + void writeReport(ReportFormat format, OutputStream outputStream, JasperPrint jasperPrint); - /** - * Convert entity parameters for {@link JasperPrint} creation - * - * @param entity Entity for report parameters retrieving - * @return {@link Map} with Jasper column name as KEY and Launch parameter as VALUE - */ - Map<String, Object> convertParams(T entity); + /** + * Convert entity parameters for {@link JasperPrint} creation + * + * @param entity Entity for report parameters retrieving + * @return {@link Map} with Jasper column name as KEY and Launch parameter as VALUE + */ + Map<String, Object> convertParams(T entity); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/JasperReportRender.java b/src/main/java/com/epam/ta/reportportal/core/jasper/JasperReportRender.java index 3cab70cd1e..935bc98258 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/JasperReportRender.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/JasperReportRender.java @@ -15,9 +15,19 @@ */ package com.epam.ta.reportportal.core.jasper; +import static com.google.common.base.Preconditions.checkArgument; + import com.epam.ta.reportportal.entity.jasper.ReportType; import com.google.common.collect.ImmutableMap; -import net.sf.jasperreports.engine.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperCompileManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; +import net.sf.jasperreports.engine.JasperReport; import net.sf.jasperreports.engine.design.JasperDesign; import net.sf.jasperreports.engine.xml.JRXmlLoader; import org.slf4j.Logger; @@ -27,61 +37,59 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkArgument; - /** * Jasper Report render based on provided JRXML template.<br> * * @author Andrei_Ramanchuk - * @author Andrei Varabyeu - * Performance improvements. Load JasperReport only once since it is immutable + * @author Andrei Varabyeu Performance improvements. Load JasperReport only once since it is + * immutable */ @Service("jasperRender") public class JasperReportRender { - private static final Logger LOGGER = LoggerFactory.getLogger(JasperReportRender.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JasperReportRender.class); - private static final String PROJECTS_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/projects.jrxml"; - private static final String USERS_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/users.jrxml"; - private static final String LAUNCH_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/report.jrxml"; - private static final Map<ReportType, String> reportTypeTemplatePathMapping = ImmutableMap.<ReportType, String>builder().put(ReportType.PROJECT, - PROJECTS_REPORT_JRXML_TEMPLATE - ) - .put(ReportType.USER, USERS_REPORT_JRXML_TEMPLATE) - .put(ReportType.LAUNCH, LAUNCH_REPORT_JRXML_TEMPLATE) - .build(); + private static final String PROJECTS_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/projects.jrxml"; + private static final String USERS_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/users.jrxml"; + private static final String LAUNCH_REPORT_JRXML_TEMPLATE = "classpath:/templates/report/report.jrxml"; + private static final Map<ReportType, String> reportTypeTemplatePathMapping = ImmutableMap.<ReportType, String>builder() + .put(ReportType.PROJECT, + PROJECTS_REPORT_JRXML_TEMPLATE + ) + .put(ReportType.USER, USERS_REPORT_JRXML_TEMPLATE) + .put(ReportType.LAUNCH, LAUNCH_REPORT_JRXML_TEMPLATE) + .build(); - private final Map<ReportType, JasperReport> reportTemplatesMapping; + private final Map<ReportType, JasperReport> reportTemplatesMapping; - @Autowired - public JasperReportRender(ResourceLoader resourceLoader) throws JRException, IOException { + @Autowired + public JasperReportRender(ResourceLoader resourceLoader) throws JRException, IOException { - ImmutableMap.Builder<ReportType, JasperReport> reportTypeJasperReportBuilder = ImmutableMap.builder(); + ImmutableMap.Builder<ReportType, JasperReport> reportTypeJasperReportBuilder = ImmutableMap.builder(); - for (Map.Entry<ReportType, String> entry : reportTypeTemplatePathMapping.entrySet()) { - Resource reportTemplate = resourceLoader.getResource(entry.getValue()); - checkArgument(reportTemplate.exists()); - //TODO investigate stream closing requirement - InputStream inputStream = reportTemplate.getInputStream(); + for (Map.Entry<ReportType, String> entry : reportTypeTemplatePathMapping.entrySet()) { + Resource reportTemplate = resourceLoader.getResource(entry.getValue()); + checkArgument(reportTemplate.exists()); + //TODO investigate stream closing requirement + InputStream inputStream = reportTemplate.getInputStream(); - JasperDesign jasperDesign = JRXmlLoader.load(inputStream); - reportTypeJasperReportBuilder.put(entry.getKey(), JasperCompileManager.compileReport(jasperDesign)); - } + JasperDesign jasperDesign = JRXmlLoader.load(inputStream); + reportTypeJasperReportBuilder.put(entry.getKey(), + JasperCompileManager.compileReport(jasperDesign)); + } - reportTemplatesMapping = reportTypeJasperReportBuilder.build(); + reportTemplatesMapping = reportTypeJasperReportBuilder.build(); - } + } - public JasperPrint generateReportPrint(ReportType reportType, Map<String, Object> params, JRDataSource datasource) { - try { - return JasperFillManager.fillReport(reportTemplatesMapping.get(reportType), params, datasource); - } catch (JRException e) { - LOGGER.error("Unable to generate Report", e); - return new JasperPrint(); - } - } + public JasperPrint generateReportPrint(ReportType reportType, Map<String, Object> params, + JRDataSource datasource) { + try { + return JasperFillManager.fillReport(reportTemplatesMapping.get(reportType), params, + datasource); + } catch (JRException e) { + LOGGER.error("Unable to generate Report", e); + return new JasperPrint(); + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/TestItemPojo.java b/src/main/java/com/epam/ta/reportportal/core/jasper/TestItemPojo.java index 2182fca10e..e36f902f0d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/TestItemPojo.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/TestItemPojo.java @@ -15,192 +15,211 @@ */ package com.epam.ta.reportportal.core.jasper; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.EMPTY_STRING; +import static com.epam.ta.reportportal.core.jasper.util.ExportUtils.COMMENT_PREFIX; +import static com.epam.ta.reportportal.core.jasper.util.ExportUtils.DESCRIPTION_PREFIX; +import static com.epam.ta.reportportal.core.jasper.util.ExportUtils.adjustName; +import static com.epam.ta.reportportal.core.jasper.util.ExportUtils.getStatisticsCounter; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_NO_DEFECT_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_FAILED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_SKIPPED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.statistics.Statistics; - import java.time.Duration; +import java.util.Objects; import java.util.Optional; import java.util.Set; -import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.EMPTY_STRING; -import static com.epam.ta.reportportal.core.jasper.util.ExportUtils.*; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static java.util.Optional.ofNullable; - /** * Jasper Reports collection {@link TestItem} POJO * * @author Andrei_Ramanchuk */ public class TestItemPojo { - private String type; - private String name; - private String status; - private Double duration; - private Integer total; - private Integer passed; - private Integer failed; - private Integer skipped; - private Integer automationBug; - private Integer productBug; - private Integer systemIssue; - private Integer noDefect; - private Integer toInvestigate; - - public TestItemPojo(TestItem input) { - this.type = input.getType().name(); - Optional<String> issueDescription = Optional.empty(); - if (input.getItemResults().getIssue() != null) { - issueDescription = ofNullable(input.getItemResults().getIssue().getIssueDescription()).map(it -> COMMENT_PREFIX + it); - } - - Optional<String> description = ofNullable(input.getDescription()).map(it -> DESCRIPTION_PREFIX + it); - - this.name = adjustName(input) + description.orElse(EMPTY_STRING) + issueDescription.orElse(EMPTY_STRING); - this.status = input.getItemResults().getStatus().name(); - - this.duration = Duration.between(input.getStartTime(), input.getItemResults().getEndTime()).toMillis() - / (double) org.apache.commons.lang3.time.DateUtils.MILLIS_PER_SECOND; - - Set<Statistics> statistics = input.getItemResults().getStatistics(); - - this.total = getStatisticsCounter(statistics, EXECUTIONS_TOTAL); - this.passed = getStatisticsCounter(statistics, EXECUTIONS_PASSED); - this.failed = getStatisticsCounter(statistics, EXECUTIONS_FAILED); - this.skipped = getStatisticsCounter(statistics, EXECUTIONS_SKIPPED); - - this.automationBug = getStatisticsCounter(statistics, DEFECTS_AUTOMATION_BUG_TOTAL); - this.productBug = getStatisticsCounter(statistics, DEFECTS_PRODUCT_BUG_TOTAL); - this.systemIssue = getStatisticsCounter(statistics, DEFECTS_SYSTEM_ISSUE_TOTAL); - this.noDefect = getStatisticsCounter(statistics, DEFECTS_NO_DEFECT_TOTAL); - this.toInvestigate = getStatisticsCounter(statistics, DEFECTS_TO_INVESTIGATE_TOTAL); - } - - public void setType(String value) { - this.type = value; - } - - public String getType() { - return type; - } - - public void setName(String value) { - this.name = value; - } - - public String getName() { - return name; - } - - public void setStatus(String value) { - this.status = value; - } - - public String getStatus() { - return status; - } - - public void setTotal(Integer value) { - this.total = value; - } - - public Integer getTotal() { - return total; - } - - public void setPased(Integer value) { - this.passed = value; - } - - public Integer getPassed() { - return passed; - } - - public void setFailed(Integer value) { - this.failed = value; - } - - public Integer getFailed() { - return failed; - } - - public void setSkipped(Integer value) { - this.skipped = value; - } - - public Integer getSkipped() { - return skipped; - } - - public void setAutomationBug(Integer value) { - this.automationBug = value; - } - - public Integer getAutomationBug() { - return automationBug; - } - - public void setProductBug(Integer value) { - this.productBug = value; - } - - public Integer getProductBug() { - return productBug; - } - - public void setSystemIssue(Integer value) { - this.systemIssue = value; - } - - public Integer getSystemIssue() { - return systemIssue; - } - - public void setNoDefect(Integer value) { - this.noDefect = value; - } - - public Integer getNoDefect() { - return noDefect; - } - - public void setToInvestigate(Integer value) { - this.toInvestigate = value; - } - - public Integer getToInvestigate() { - return toInvestigate; - } - - public Double getDuration() { - return duration; - } - - public void setDuration(Double duration) { - this.duration = duration; - } - - public void setPassed(Integer passed) { - this.passed = passed; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("TestItemPojo{"); - sb.append("type='").append(type).append('\''); - sb.append(", name='").append(name).append('\''); - sb.append(", status='").append(status).append('\''); - sb.append(", duration=").append(duration); - sb.append(", total=").append(total); - sb.append(", passed=").append(passed); - sb.append(", failed=").append(failed); - sb.append(", skipped=").append(skipped); - sb.append(", automationBug=").append(automationBug); - sb.append(", productBug=").append(productBug); - sb.append(", systemIssue=").append(systemIssue); - sb.append(", noDefect=").append(noDefect); - sb.append(", toInvestigate=").append(toInvestigate); - sb.append('}'); - return sb.toString(); - } + + private String type; + private String name; + private String status; + private Double duration; + private Integer total; + private Integer passed; + private Integer failed; + private Integer skipped; + private Integer automationBug; + private Integer productBug; + private Integer systemIssue; + private Integer noDefect; + private Integer toInvestigate; + + private static final Double EMPTY_DURATION = 0D; + + public TestItemPojo(TestItem input) { + this.type = input.getType().name(); + Optional<String> issueDescription = Optional.empty(); + if (input.getItemResults().getIssue() != null) { + issueDescription = ofNullable(input.getItemResults().getIssue().getIssueDescription()).map( + it -> COMMENT_PREFIX + it); + } + + Optional<String> description = ofNullable(input.getDescription()).map( + it -> DESCRIPTION_PREFIX + it); + + this.name = adjustName(input) + description.orElse(EMPTY_STRING) + issueDescription.orElse( + EMPTY_STRING); + this.status = input.getItemResults().getStatus().name(); + + this.duration = Objects.nonNull(input.getItemResults().getEndTime()) ? + Duration.between(input.getStartTime(), input.getItemResults().getEndTime()).toMillis() + / (double) org.apache.commons.lang3.time.DateUtils.MILLIS_PER_SECOND : + EMPTY_DURATION; + + Set<Statistics> statistics = input.getItemResults().getStatistics(); + + this.total = getStatisticsCounter(statistics, EXECUTIONS_TOTAL); + this.passed = getStatisticsCounter(statistics, EXECUTIONS_PASSED); + this.failed = getStatisticsCounter(statistics, EXECUTIONS_FAILED); + this.skipped = getStatisticsCounter(statistics, EXECUTIONS_SKIPPED); + + this.automationBug = getStatisticsCounter(statistics, DEFECTS_AUTOMATION_BUG_TOTAL); + this.productBug = getStatisticsCounter(statistics, DEFECTS_PRODUCT_BUG_TOTAL); + this.systemIssue = getStatisticsCounter(statistics, DEFECTS_SYSTEM_ISSUE_TOTAL); + this.noDefect = getStatisticsCounter(statistics, DEFECTS_NO_DEFECT_TOTAL); + this.toInvestigate = getStatisticsCounter(statistics, DEFECTS_TO_INVESTIGATE_TOTAL); + } + + public void setType(String value) { + this.type = value; + } + + public String getType() { + return type; + } + + public void setName(String value) { + this.name = value; + } + + public String getName() { + return name; + } + + public void setStatus(String value) { + this.status = value; + } + + public String getStatus() { + return status; + } + + public void setTotal(Integer value) { + this.total = value; + } + + public Integer getTotal() { + return total; + } + + public void setPased(Integer value) { + this.passed = value; + } + + public Integer getPassed() { + return passed; + } + + public void setFailed(Integer value) { + this.failed = value; + } + + public Integer getFailed() { + return failed; + } + + public void setSkipped(Integer value) { + this.skipped = value; + } + + public Integer getSkipped() { + return skipped; + } + + public void setAutomationBug(Integer value) { + this.automationBug = value; + } + + public Integer getAutomationBug() { + return automationBug; + } + + public void setProductBug(Integer value) { + this.productBug = value; + } + + public Integer getProductBug() { + return productBug; + } + + public void setSystemIssue(Integer value) { + this.systemIssue = value; + } + + public Integer getSystemIssue() { + return systemIssue; + } + + public void setNoDefect(Integer value) { + this.noDefect = value; + } + + public Integer getNoDefect() { + return noDefect; + } + + public void setToInvestigate(Integer value) { + this.toInvestigate = value; + } + + public Integer getToInvestigate() { + return toInvestigate; + } + + public Double getDuration() { + return duration; + } + + public void setDuration(Double duration) { + this.duration = duration; + } + + public void setPassed(Integer passed) { + this.passed = passed; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("TestItemPojo{"); + sb.append("type='").append(type).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append(", status='").append(status).append('\''); + sb.append(", duration=").append(duration); + sb.append(", total=").append(total); + sb.append(", passed=").append(passed); + sb.append(", failed=").append(failed); + sb.append(", skipped=").append(skipped); + sb.append(", automationBug=").append(automationBug); + sb.append(", productBug=").append(productBug); + sb.append(", systemIssue=").append(systemIssue); + sb.append(", noDefect=").append(noDefect); + sb.append(", toInvestigate=").append(toInvestigate); + sb.append('}'); + return sb.toString(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/LaunchReportConstants.java b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/LaunchReportConstants.java index ec4828f5b7..046321f8d5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/LaunchReportConstants.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/LaunchReportConstants.java @@ -21,30 +21,30 @@ */ public final class LaunchReportConstants { - /* Defined fields in JRXML template */ - public final static String LAUNCH_NAME = "LAUNCH_NAME"; - public final static String LAUNCH_DESC = "LAUNCH_DESCRIPTION"; - public final static String LAUNCH_TAGS = "LAUNCH_TAGS"; - public final static String DURATION = "LAUNCH_DURATION"; - public final static String OWNER = "LAUNCH_OWNER"; + /* Defined fields in JRXML template */ + public final static String LAUNCH_NAME = "LAUNCH_NAME"; + public final static String LAUNCH_DESC = "LAUNCH_DESCRIPTION"; + public final static String LAUNCH_TAGS = "LAUNCH_TAGS"; + public final static String DURATION = "LAUNCH_DURATION"; + public final static String OWNER = "LAUNCH_OWNER"; - /* Launch statistics fields */ - // TODO could be inject in report as DataSource - public final static String TOTAL = "TOTAL"; - public final static String PASSED = "PASSED"; - public final static String FAILED = "FAILED"; - public final static String SKIPPED = "SKIPPED"; - public final static String AB = "AB"; - public final static String PB = "PB"; - public final static String SI = "SI"; - public final static String ND = "ND"; - public final static String TI = "TI"; + /* Launch statistics fields */ + // TODO could be inject in report as DataSource + public final static String TOTAL = "TOTAL"; + public final static String PASSED = "PASSED"; + public final static String FAILED = "FAILED"; + public final static String SKIPPED = "SKIPPED"; + public final static String AB = "AB"; + public final static String PB = "PB"; + public final static String SI = "SI"; + public final static String ND = "ND"; + public final static String TI = "TI"; - /* Data sets */ - public final static String TEST_ITEMS = "TEST_ITEMS"; + /* Data sets */ + public final static String TEST_ITEMS = "TEST_ITEMS"; - public LaunchReportConstants() { + public LaunchReportConstants() { - //static only - } + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/ProjectReportConstants.java b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/ProjectReportConstants.java index 92c3631ba8..09261b81d7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/ProjectReportConstants.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/ProjectReportConstants.java @@ -21,15 +21,15 @@ */ public final class ProjectReportConstants { - public static final String PROJECT_TYPE = "Project type"; - public static final String PROJECT_NAME = "Project name"; - public static final String ORGANIZATION = "Organization"; - public static final String MEMBERS = "Members"; - public static final String LAUNCHES = "Launches"; - public static final String LAST_LAUNCH_DATE = "Last launch date"; + public static final String PROJECT_TYPE = "Project type"; + public static final String PROJECT_NAME = "Project name"; + public static final String ORGANIZATION = "Organization"; + public static final String MEMBERS = "Members"; + public static final String LAUNCHES = "Launches"; + public static final String LAST_LAUNCH_DATE = "Last launch date"; - private ProjectReportConstants() { + private ProjectReportConstants() { - //static only - } + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/UserReportConstants.java b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/UserReportConstants.java index 4247de7f81..49eae54d8b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/constants/UserReportConstants.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/constants/UserReportConstants.java @@ -21,15 +21,15 @@ */ public final class UserReportConstants { - public static final String FULL_NAME = "Full name"; - public static final String TYPE = "Type"; - public static final String LOGIN = "Login"; - public static final String EMAIL = "Email"; - public static final String LAST_LOGIN = "Last login"; - public static final String PROJECTS_AND_ROLES = "Projects and Roles"; + public static final String FULL_NAME = "Full name"; + public static final String TYPE = "Type"; + public static final String LOGIN = "Login"; + public static final String EMAIL = "Email"; + public static final String LAST_LOGIN = "Last login"; + public static final String PROJECTS_AND_ROLES = "Projects and Roles"; - private UserReportConstants() { + private UserReportConstants() { - //static only - } + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/AbstractJasperReportHandler.java b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/AbstractJasperReportHandler.java index 9292842043..73773ec557 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/AbstractJasperReportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/AbstractJasperReportHandler.java @@ -15,27 +15,33 @@ */ package com.epam.ta.reportportal.core.jasper.impl; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.jasper.GetJasperReportHandler; import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.io.OutputStream; +import java.util.Set; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JasperExportManager; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.export.HtmlExporter; import net.sf.jasperreports.engine.export.JRCsvExporter; import net.sf.jasperreports.engine.export.JRXlsExporter; -import net.sf.jasperreports.export.*; +import net.sf.jasperreports.export.HtmlExporterOutput; +import net.sf.jasperreports.export.SimpleCsvExporterConfiguration; +import net.sf.jasperreports.export.SimpleExporterInput; +import net.sf.jasperreports.export.SimpleHtmlExporterOutput; +import net.sf.jasperreports.export.SimpleHtmlReportConfiguration; +import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput; +import net.sf.jasperreports.export.SimpleWriterExporterOutput; +import net.sf.jasperreports.export.SimpleXlsReportConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.OutputStream; -import java.util.Set; - -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; - /** * Jasper Reports provider. Basic implementation of * {@link com.epam.ta.reportportal.core.jasper.GetJasperReportHandler} @@ -43,85 +49,88 @@ * @author Andrei_Ramanchuk */ public abstract class AbstractJasperReportHandler<T> implements GetJasperReportHandler<T> { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractJasperReportHandler.class); - - private final String unsupportedReportFormatExceptionMessage; - - public AbstractJasperReportHandler(String unsupportedReportFormatExceptionMessage) { - - this.unsupportedReportFormatExceptionMessage = unsupportedReportFormatExceptionMessage; - } - - @Override - public ReportFormat getReportFormat(String view) { - ReportFormat reportFormat = ReportFormat.findByName(view) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Unexpected report format: {}", view) - )); - - BusinessRule.expect(reportFormat, getAvailableReportFormats()::contains) - .verify(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier(unsupportedReportFormatExceptionMessage, reportFormat.name()) - ); - - return reportFormat; - } - - @Override - public void writeReport(ReportFormat format, OutputStream outputStream, JasperPrint jasperPrint) { - try { - switch (format) { - case PDF: - JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream); - break; - case HTML: - HtmlExporter exporter = new HtmlExporter(); - exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); - HtmlExporterOutput exporterOutput = new SimpleHtmlExporterOutput(outputStream); - exporter.setExporterOutput(exporterOutput); - - SimpleHtmlReportConfiguration htmlConfig = new SimpleHtmlReportConfiguration(); - htmlConfig.setWhitePageBackground(false); - htmlConfig.setRemoveEmptySpaceBetweenRows(true); - exporter.setConfiguration(htmlConfig); - exporter.exportReport(); - break; - case XLS: - SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration(); - configuration.setOnePagePerSheet(false); - configuration.setDetectCellType(true); - configuration.setCollapseRowSpan(false); - configuration.setIgnoreGraphics(true); - - JRXlsExporter exporterXLS = new JRXlsExporter(); - exporterXLS.setExporterInput(new SimpleExporterInput(jasperPrint)); - exporterXLS.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream)); - exporterXLS.setConfiguration(configuration); - exporterXLS.exportReport(); - break; - case CSV: - - JRCsvExporter jrCsvExporter = new JRCsvExporter(); - jrCsvExporter.setExporterInput(new SimpleExporterInput(jasperPrint)); - jrCsvExporter.setExporterOutput(new SimpleWriterExporterOutput(outputStream)); - SimpleCsvExporterConfiguration csvExporterConfiguration = new SimpleCsvExporterConfiguration(); - jrCsvExporter.setConfiguration(csvExporterConfiguration); - jrCsvExporter.exportReport(); - break; - default: - throw new UnsupportedOperationException(format.getValue()); - } - - } catch (JRException ex) { - LOGGER.error("Unable to generate report!", ex); - BusinessRule.fail() - .withError(ErrorType.FORBIDDEN_OPERATION, - Suppliers.formattedSupplier(" Unexpected issue during report output stream creation: {}", - ex.getLocalizedMessage() - ) - ); - } - } - - public abstract Set<ReportFormat> getAvailableReportFormats(); + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractJasperReportHandler.class); + + private final String unsupportedReportFormatExceptionMessage; + + public AbstractJasperReportHandler(String unsupportedReportFormatExceptionMessage) { + + this.unsupportedReportFormatExceptionMessage = unsupportedReportFormatExceptionMessage; + } + + @Override + public ReportFormat getReportFormat(String view) { + ReportFormat reportFormat = ReportFormat.findByName(view) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Unexpected report format: {}", view) + )); + + BusinessRule.expect(reportFormat, getAvailableReportFormats()::contains) + .verify(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier(unsupportedReportFormatExceptionMessage, + reportFormat.name()) + ); + + return reportFormat; + } + + @Override + public void writeReport(ReportFormat format, OutputStream outputStream, JasperPrint jasperPrint) { + try { + switch (format) { + case PDF: + JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream); + break; + case HTML: + HtmlExporter exporter = new HtmlExporter(); + exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + HtmlExporterOutput exporterOutput = new SimpleHtmlExporterOutput(outputStream); + exporter.setExporterOutput(exporterOutput); + + SimpleHtmlReportConfiguration htmlConfig = new SimpleHtmlReportConfiguration(); + htmlConfig.setWhitePageBackground(false); + htmlConfig.setRemoveEmptySpaceBetweenRows(true); + exporter.setConfiguration(htmlConfig); + exporter.exportReport(); + break; + case XLS: + SimpleXlsReportConfiguration configuration = new SimpleXlsReportConfiguration(); + configuration.setOnePagePerSheet(false); + configuration.setDetectCellType(true); + configuration.setCollapseRowSpan(false); + configuration.setIgnoreGraphics(true); + + JRXlsExporter exporterXLS = new JRXlsExporter(); + exporterXLS.setExporterInput(new SimpleExporterInput(jasperPrint)); + exporterXLS.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream)); + exporterXLS.setConfiguration(configuration); + exporterXLS.exportReport(); + break; + case CSV: + + JRCsvExporter jrCsvExporter = new JRCsvExporter(); + jrCsvExporter.setExporterInput(new SimpleExporterInput(jasperPrint)); + jrCsvExporter.setExporterOutput(new SimpleWriterExporterOutput(outputStream)); + SimpleCsvExporterConfiguration csvExporterConfiguration = new SimpleCsvExporterConfiguration(); + jrCsvExporter.setConfiguration(csvExporterConfiguration); + jrCsvExporter.exportReport(); + break; + default: + throw new UnsupportedOperationException(format.getValue()); + } + + } catch (JRException ex) { + LOGGER.error("Unable to generate report!", ex); + BusinessRule.fail() + .withError(ErrorType.FORBIDDEN_OPERATION, + Suppliers.formattedSupplier( + " Unexpected issue during report output stream creation: {}", + ex.getLocalizedMessage() + ) + ); + } + } + + public abstract Set<ReportFormat> getAvailableReportFormats(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/LaunchJasperReportHandler.java b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/LaunchJasperReportHandler.java index fd6137ea12..35f5dad48f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/LaunchJasperReportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/LaunchJasperReportHandler.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.jasper.impl; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_NO_DEFECT_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_FAILED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_SKIPPED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.jasper.JasperReportRender; import com.epam.ta.reportportal.core.jasper.constants.LaunchReportConstants; import com.epam.ta.reportportal.core.jasper.util.ExportUtils; @@ -24,20 +35,16 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.google.common.collect.Sets; -import net.sf.jasperreports.engine.JRDataSource; -import net.sf.jasperreports.engine.JasperPrint; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static java.util.Optional.ofNullable; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JasperPrint; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -45,60 +52,72 @@ @Service("launchJasperReportHandler") public class LaunchJasperReportHandler extends AbstractJasperReportHandler<Launch> { - private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for launch reports."; - - private final Set<ReportFormat> availableReportFormats; - - private final JasperReportRender reportRender; - - @Autowired - public LaunchJasperReportHandler(JasperReportRender reportRender) { - super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); - this.reportRender = reportRender; - availableReportFormats = Sets.immutableEnumSet(ReportFormat.HTML, ReportFormat.PDF, ReportFormat.XLS); - } - - @Override - public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { - - return reportRender.generateReportPrint(ReportType.LAUNCH, params, dataSource); - } - - @Override - public Map<String, Object> convertParams(Launch launch) { - Map<String, Object> params = new HashMap<>(); - - params.put(LaunchReportConstants.LAUNCH_NAME, launch.getName() + " #" + launch.getNumber()); - params.put(LaunchReportConstants.LAUNCH_DESC, launch.getDescription() == null ? "" : launch.getDescription()); - params.put(LaunchReportConstants.LAUNCH_TAGS, - launch.getAttributes() - .stream() - .map(it -> it.getKey() == null ? it.getValue() : it.getKey().concat(it.getValue())) - .collect(Collectors.toList()) - ); - - String duration = ofNullable(launch.getEndTime()).map(endTime -> ExportUtils.durationToShortDHMS( - Duration.between(launch.getStartTime(), endTime))).orElse(StringUtils.EMPTY); - params.put(LaunchReportConstants.DURATION, duration); - - Set<Statistics> statistics = launch.getStatistics(); - params.put(LaunchReportConstants.TOTAL, ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_TOTAL)); - params.put(LaunchReportConstants.PASSED, ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_PASSED)); - params.put(LaunchReportConstants.FAILED, ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_FAILED)); - params.put(LaunchReportConstants.SKIPPED, ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_SKIPPED)); - - params.put(LaunchReportConstants.AB, ExportUtils.getStatisticsCounter(statistics, DEFECTS_AUTOMATION_BUG_TOTAL)); - params.put(LaunchReportConstants.PB, ExportUtils.getStatisticsCounter(statistics, DEFECTS_PRODUCT_BUG_TOTAL)); - params.put(LaunchReportConstants.SI, ExportUtils.getStatisticsCounter(statistics, DEFECTS_SYSTEM_ISSUE_TOTAL)); - params.put(LaunchReportConstants.ND, ExportUtils.getStatisticsCounter(statistics, DEFECTS_NO_DEFECT_TOTAL)); - params.put(LaunchReportConstants.TI, ExportUtils.getStatisticsCounter(statistics, DEFECTS_TO_INVESTIGATE_TOTAL)); - - return params; - } - - @Override - public Set<ReportFormat> getAvailableReportFormats() { - return availableReportFormats; - } + private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for launch reports."; + + private final Set<ReportFormat> availableReportFormats; + + private final JasperReportRender reportRender; + + @Autowired + public LaunchJasperReportHandler(JasperReportRender reportRender) { + super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); + this.reportRender = reportRender; + availableReportFormats = Sets.immutableEnumSet(ReportFormat.HTML, ReportFormat.PDF, + ReportFormat.XLS); + } + + @Override + public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { + + return reportRender.generateReportPrint(ReportType.LAUNCH, params, dataSource); + } + + @Override + public Map<String, Object> convertParams(Launch launch) { + Map<String, Object> params = new HashMap<>(); + + params.put(LaunchReportConstants.LAUNCH_NAME, launch.getName() + " #" + launch.getNumber()); + params.put(LaunchReportConstants.LAUNCH_DESC, + launch.getDescription() == null ? "" : launch.getDescription()); + params.put(LaunchReportConstants.LAUNCH_TAGS, + launch.getAttributes() + .stream() + .map(it -> it.getKey() == null ? it.getValue() : it.getKey().concat(it.getValue())) + .collect(Collectors.toList()) + ); + + String duration = ofNullable(launch.getEndTime()).map( + endTime -> ExportUtils.durationToShortDHMS( + Duration.between(launch.getStartTime(), endTime))).orElse(StringUtils.EMPTY); + params.put(LaunchReportConstants.DURATION, duration); + + Set<Statistics> statistics = launch.getStatistics(); + params.put(LaunchReportConstants.TOTAL, + ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_TOTAL)); + params.put(LaunchReportConstants.PASSED, + ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_PASSED)); + params.put(LaunchReportConstants.FAILED, + ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_FAILED)); + params.put(LaunchReportConstants.SKIPPED, + ExportUtils.getStatisticsCounter(statistics, EXECUTIONS_SKIPPED)); + + params.put(LaunchReportConstants.AB, + ExportUtils.getStatisticsCounter(statistics, DEFECTS_AUTOMATION_BUG_TOTAL)); + params.put(LaunchReportConstants.PB, + ExportUtils.getStatisticsCounter(statistics, DEFECTS_PRODUCT_BUG_TOTAL)); + params.put(LaunchReportConstants.SI, + ExportUtils.getStatisticsCounter(statistics, DEFECTS_SYSTEM_ISSUE_TOTAL)); + params.put(LaunchReportConstants.ND, + ExportUtils.getStatisticsCounter(statistics, DEFECTS_NO_DEFECT_TOTAL)); + params.put(LaunchReportConstants.TI, + ExportUtils.getStatisticsCounter(statistics, DEFECTS_TO_INVESTIGATE_TOTAL)); + + return params; + } + + @Override + public Set<ReportFormat> getAvailableReportFormats() { + return availableReportFormats; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/ProjectJasperReportHandler.java b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/ProjectJasperReportHandler.java index c0e85ca925..8d058df594 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/ProjectJasperReportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/ProjectJasperReportHandler.java @@ -16,26 +16,25 @@ package com.epam.ta.reportportal.core.jasper.impl; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.EMPTY_STRING; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.jasper.JasperReportRender; import com.epam.ta.reportportal.core.jasper.constants.ProjectReportConstants; import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.jasper.ReportType; import com.epam.ta.reportportal.entity.project.ProjectInfo; import com.google.common.collect.Sets; -import net.sf.jasperreports.engine.JRDataSource; -import net.sf.jasperreports.engine.JasperPrint; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map; import java.util.Set; - -import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.EMPTY_STRING; -import static java.util.Optional.ofNullable; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JasperPrint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -43,44 +42,46 @@ @Service("projectJasperReportHandler") public class ProjectJasperReportHandler extends AbstractJasperReportHandler<ProjectInfo> { - private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for project reports."; + private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for project reports."; - private final Set<ReportFormat> availableReportFormats; + private final Set<ReportFormat> availableReportFormats; - private final JasperReportRender reportRender; + private final JasperReportRender reportRender; - @Autowired - public ProjectJasperReportHandler(JasperReportRender reportRender) { - super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); - this.reportRender = reportRender; - availableReportFormats = Sets.immutableEnumSet(ReportFormat.CSV); - } + @Autowired + public ProjectJasperReportHandler(JasperReportRender reportRender) { + super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); + this.reportRender = reportRender; + availableReportFormats = Sets.immutableEnumSet(ReportFormat.CSV); + } - @Override - public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { + @Override + public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { - return reportRender.generateReportPrint(ReportType.PROJECT, params, dataSource); - } + return reportRender.generateReportPrint(ReportType.PROJECT, params, dataSource); + } - @Override - public Map<String, Object> convertParams(ProjectInfo project) { - Map<String, Object> params = new HashMap<>(); + @Override + public Map<String, Object> convertParams(ProjectInfo project) { + Map<String, Object> params = new HashMap<>(); - params.put(ProjectReportConstants.PROJECT_TYPE, project.getProjectType()); - params.put(ProjectReportConstants.PROJECT_NAME, project.getName()); - params.put(ProjectReportConstants.ORGANIZATION, ofNullable(project.getOrganization()).orElse(EMPTY_STRING)); - params.put(ProjectReportConstants.MEMBERS, project.getUsersQuantity()); - params.put(ProjectReportConstants.LAUNCHES, project.getLaunchesQuantity()); + params.put(ProjectReportConstants.PROJECT_TYPE, project.getProjectType()); + params.put(ProjectReportConstants.PROJECT_NAME, project.getName()); + params.put(ProjectReportConstants.ORGANIZATION, + ofNullable(project.getOrganization()).orElse(EMPTY_STRING)); + params.put(ProjectReportConstants.MEMBERS, project.getUsersQuantity()); + params.put(ProjectReportConstants.LAUNCHES, project.getLaunchesQuantity()); - ofNullable(project.getLastRun()).ifPresent(lastRun -> params.put(ProjectReportConstants.LAST_LAUNCH_DATE, - DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.of(lastRun, ZoneOffset.UTC)) - )); + ofNullable(project.getLastRun()).ifPresent( + lastRun -> params.put(ProjectReportConstants.LAST_LAUNCH_DATE, + DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.of(lastRun, ZoneOffset.UTC)) + )); - return params; - } + return params; + } - @Override - public Set<ReportFormat> getAvailableReportFormats() { - return availableReportFormats; - } + @Override + public Set<ReportFormat> getAvailableReportFormats() { + return availableReportFormats; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/UserJasperReportHandler.java b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/UserJasperReportHandler.java index 26c49f1e43..53942890a4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/impl/UserJasperReportHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/impl/UserJasperReportHandler.java @@ -16,17 +16,15 @@ package com.epam.ta.reportportal.core.jasper.impl; +import static com.epam.ta.reportportal.ws.converter.builders.UserBuilder.USER_LAST_LOGIN; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.jasper.JasperReportRender; import com.epam.ta.reportportal.core.jasper.constants.UserReportConstants; import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.jasper.ReportType; import com.epam.ta.reportportal.entity.user.User; import com.google.common.collect.Sets; -import net.sf.jasperreports.engine.JRDataSource; -import net.sf.jasperreports.engine.JasperPrint; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.time.ZoneOffset; import java.time.ZonedDateTime; @@ -35,9 +33,10 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.ws.converter.builders.UserBuilder.USER_LAST_LOGIN; -import static java.util.Optional.ofNullable; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JasperPrint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -45,60 +44,64 @@ @Service("userJasperReportHandler") public class UserJasperReportHandler extends AbstractJasperReportHandler<User> { - private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for user reports."; - - private final Set<ReportFormat> availableReportFormats; - - private final JasperReportRender reportRender; - - @Autowired - public UserJasperReportHandler(JasperReportRender reportRender) { - super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); - this.reportRender = reportRender; - availableReportFormats = Sets.immutableEnumSet(ReportFormat.CSV); - } - - @Override - public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { - - return reportRender.generateReportPrint(ReportType.USER, params, dataSource); - } - - @Override - public Map<String, Object> convertParams(User user) { - Map<String, Object> params = new HashMap<>(); - - params.put(UserReportConstants.FULL_NAME, user.getFullName()); - params.put(UserReportConstants.TYPE, user.getUserType().name()); - params.put(UserReportConstants.LOGIN, user.getLogin()); - params.put(UserReportConstants.EMAIL, user.getEmail()); - - params.put(UserReportConstants.PROJECTS_AND_ROLES, user.getProjects().stream().collect(Collectors.toMap( - projectUser -> projectUser.getProject().getName(), - projectUser -> projectUser.getProjectRole().name(), - (prev, curr) -> prev - )).entrySet().stream().map(entry -> entry.getKey() + " - " + entry.getValue()).collect(Collectors.joining(", "))); - - ofNullable(user.getMetadata()).ifPresent(metadata -> ofNullable(metadata.getMetadata()).ifPresent(meta -> ofNullable(meta.get( - USER_LAST_LOGIN)).ifPresent(lastLogin -> { - try { - long epochMilli = Long.parseLong(String.valueOf(lastLogin)); - Instant instant = Instant.ofEpochMilli(epochMilli); - params.put( - UserReportConstants.LAST_LOGIN, - DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.ofInstant(instant, ZoneOffset.UTC)) - ); - } catch (NumberFormatException e) { - //do nothing, null value will be put in the result - } - - }))); - - return params; - } - - @Override - public Set<ReportFormat> getAvailableReportFormats() { - return availableReportFormats; - } + private static final String UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION = "Report format - {} is not supported for user reports."; + + private final Set<ReportFormat> availableReportFormats; + + private final JasperReportRender reportRender; + + @Autowired + public UserJasperReportHandler(JasperReportRender reportRender) { + super(UNSUPPORTED_REPORT_FORMAT_MESSAGE_EXCEPTION); + this.reportRender = reportRender; + availableReportFormats = Sets.immutableEnumSet(ReportFormat.CSV); + } + + @Override + public JasperPrint getJasperPrint(Map<String, Object> params, JRDataSource dataSource) { + + return reportRender.generateReportPrint(ReportType.USER, params, dataSource); + } + + @Override + public Map<String, Object> convertParams(User user) { + Map<String, Object> params = new HashMap<>(); + + params.put(UserReportConstants.FULL_NAME, user.getFullName()); + params.put(UserReportConstants.TYPE, user.getUserType().name()); + params.put(UserReportConstants.LOGIN, user.getLogin()); + params.put(UserReportConstants.EMAIL, user.getEmail()); + + params.put(UserReportConstants.PROJECTS_AND_ROLES, + user.getProjects().stream().collect(Collectors.toMap( + projectUser -> projectUser.getProject().getName(), + projectUser -> projectUser.getProjectRole().name(), + (prev, curr) -> prev + )).entrySet().stream().map(entry -> entry.getKey() + " - " + entry.getValue()) + .collect(Collectors.joining(", "))); + + ofNullable(user.getMetadata()).ifPresent( + metadata -> ofNullable(metadata.getMetadata()).ifPresent(meta -> ofNullable(meta.get( + USER_LAST_LOGIN)).ifPresent(lastLogin -> { + try { + long epochMilli = Long.parseLong(String.valueOf(lastLogin)); + Instant instant = Instant.ofEpochMilli(epochMilli); + params.put( + UserReportConstants.LAST_LOGIN, + DateTimeFormatter.ISO_ZONED_DATE_TIME.format( + ZonedDateTime.ofInstant(instant, ZoneOffset.UTC)) + ); + } catch (NumberFormatException e) { + //do nothing, null value will be put in the result + } + + }))); + + return params; + } + + @Override + public Set<ReportFormat> getAvailableReportFormats() { + return availableReportFormats; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/util/ExportUtils.java b/src/main/java/com/epam/ta/reportportal/core/jasper/util/ExportUtils.java index ec2ffd121c..1873869ed8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/util/ExportUtils.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/util/ExportUtils.java @@ -18,52 +18,54 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.statistics.Statistics; -import org.apache.commons.lang3.StringUtils; - import java.time.Duration; import java.util.Set; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public class ExportUtils { - private static final String SHIFT_PREFIX = " "; - public static final String COMMENT_PREFIX = "\r\n" + " DEFECT COMMENT: "; - public static final String DESCRIPTION_PREFIX = "\r\n" + " ITEM DESCRIPTION: "; - public static int getStatisticsCounter(Set<Statistics> statistics, String statisticsFieldName) { - return statistics.stream() - .filter(it -> it.getStatisticsField().getName().equals(statisticsFieldName)) - .mapToInt(Statistics::getCounter) - .findAny() - .orElse(0); - } + private static final String SHIFT_PREFIX = " "; + public static final String COMMENT_PREFIX = "\r\n" + " DEFECT COMMENT: "; + public static final String DESCRIPTION_PREFIX = "\r\n" + " ITEM DESCRIPTION: "; + + public static int getStatisticsCounter(Set<Statistics> statistics, String statisticsFieldName) { + return statistics.stream() + .filter(it -> it.getStatisticsField().getName().equals(statisticsFieldName)) + .mapToInt(Statistics::getCounter) + .findAny() + .orElse(0); + } - /** - * Add right shifting for child items depends on depth level - * - * @param input - target {@see TestItem} - * @return updated test item name with shifted name - */ - public static String adjustName(TestItem input) { - /* Sync buffer instead builder! */ - return new StringBuilder(StringUtils.repeat(SHIFT_PREFIX, input.getPath().split("\\.").length)).append(input.getName()).toString(); - } + /** + * Add right shifting for child items depends on depth level + * + * @param input - The target {@link TestItem} for which the name will be updated + * @return updated test item name with shifted name + */ + public static String adjustName(TestItem input) { + /* Sync buffer instead builder! */ + return new StringBuilder( + StringUtils.repeat(SHIFT_PREFIX, input.getPath().split("\\.").length)).append( + input.getName()).toString(); + } - /** - * Format launch duration from long to human readable format. - * - * @param duration - input duration - * @return String - formatted output - */ - public static String durationToShortDHMS(Duration duration) { - long days = duration.toDays(); - long hours = duration.toHours() - TimeUnit.DAYS.toHours(days); - long minutes = duration.toMinutes() - TimeUnit.HOURS.toMinutes(hours); - long seconds = duration.getSeconds() - TimeUnit.MINUTES.toSeconds(minutes); - return days == 0 ? - String.format("%02d:%02d:%02d", hours, minutes, seconds) : - String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds); - } + /** + * Format launch duration from long to human readable format. + * + * @param duration - input duration + * @return String - formatted output + */ + public static String durationToShortDHMS(Duration duration) { + long days = duration.toDays(); + long hours = duration.toHours() - TimeUnit.DAYS.toHours(days); + long minutes = duration.toMinutes() - TimeUnit.HOURS.toMinutes(hours); + long seconds = duration.getSeconds() - TimeUnit.MINUTES.toSeconds(minutes); + return days == 0 ? + String.format("%02d:%02d:%02d", hours, minutes, seconds) : + String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/jasper/util/JasperDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/jasper/util/JasperDataProvider.java index 685d2c344e..00e38fab2d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/jasper/util/JasperDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/jasper/util/JasperDataProvider.java @@ -15,16 +15,15 @@ */ package com.epam.ta.reportportal.core.jasper.util; +import static com.google.common.base.Preconditions.checkNotNull; + import com.epam.ta.reportportal.core.jasper.TestItemPojo; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.launch.Launch; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * Initial {@link net.sf.jasperreports.engine.JRDataSource} provider class for RP Jasper Reports @@ -34,18 +33,18 @@ @Service("jasperDataProvider") public class JasperDataProvider { - private TestItemRepository testItemRepository; + private TestItemRepository testItemRepository; - @Autowired - public JasperDataProvider(TestItemRepository testItemRepository) { - this.testItemRepository = checkNotNull(testItemRepository); - } + @Autowired + public JasperDataProvider(TestItemRepository testItemRepository) { + this.testItemRepository = checkNotNull(testItemRepository); + } - public List<TestItemPojo> getTestItemsOfLaunch(Launch launch) { - /* Get launch referred test items with SORT! */ - return testItemRepository.findTestItemsByLaunchIdOrderByStartTimeAsc(launch.getId()) - .stream() - .map(TestItemPojo::new) - .collect(Collectors.toList()); - } + public List<TestItemPojo> getTestItemsOfLaunch(Launch launch) { + /* Get launch referred test items with SORT! */ + return testItemRepository.findTestItemsByLaunchIdOrderByStartTimeAsc(launch.getId()) + .stream() + .map(TestItemPojo::new) + .collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/DeleteLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/DeleteLaunchHandler.java index 04f19fb4ad..3f65e87a77 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/DeleteLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/DeleteLaunchHandler.java @@ -30,23 +30,25 @@ public interface DeleteLaunchHandler { - /** - * Delete {@link com.epam.ta.reportportal.entity.launch.Launch} instance - * - * @param launchId ID of launch - * @param projectDetails Project Details - * @param user User - * @return OperationCompletionRS - */ - OperationCompletionRS deleteLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Delete {@link com.epam.ta.reportportal.entity.launch.Launch} instance + * + * @param launchId ID of launch + * @param projectDetails Project Details + * @param user User + * @return OperationCompletionRS + */ + OperationCompletionRS deleteLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Bul launches delete. - * - * @param deleteBulkRQ {@link DeleteBulkRQ} - * @param projectDetails Project Details - * @param user User - * @return DeleteLaunchesRS - */ - DeleteBulkRS deleteLaunches(DeleteBulkRQ deleteBulkRQ, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Bul launches delete. + * + * @param deleteBulkRQ {@link DeleteBulkRQ} + * @param projectDetails Project Details + * @param user User + * @return DeleteLaunchesRS + */ + DeleteBulkRS deleteLaunches(DeleteBulkRQ deleteBulkRQ, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/FinishLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/FinishLaunchHandler.java index d28a092e9b..a7108fb717 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/FinishLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/FinishLaunchHandler.java @@ -29,16 +29,18 @@ public interface FinishLaunchHandler { - /** - * Updates {@link Launch} instance - * - * @param launchId ID of launch - * @param finishLaunchRQ Request data - * @param projectDetails Project Details - * @param user User - * @return FinishLaunchRS - */ - FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ finishLaunchRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String baseUrl); + /** + * Updates {@link Launch} instance + * + * @param launchId ID of launch + * @param finishLaunchRQ Request data + * @param projectDetails Project Details + * @param user User + * @param baseUrl Application base url + * @return FinishLaunchRS + */ + FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ finishLaunchRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, String baseUrl); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/GetLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/GetLaunchHandler.java index 84a406c69e..3d0bc531c5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/GetLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/GetLaunchHandler.java @@ -23,12 +23,11 @@ import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; import com.epam.ta.reportportal.ws.model.launch.cluster.ClusterInfoResource; -import org.springframework.data.domain.Pageable; - -import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.springframework.data.domain.Pageable; //import com.epam.ta.reportportal.entity.widget.content.ComparisonStatisticsContent; @@ -40,133 +39,143 @@ */ public interface GetLaunchHandler { - Launch get(Long id); - - /** - * Get Launch resource by specified UUID - * - * @param launchId Launch uuid - * @param projectDetails Project Details - * @return {@link LaunchResource} - */ - LaunchResource getLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails); - - /** - * Get Launch resource by specified Name (for Jenkins Plugin) - * - * @param project Project Name - * @param pageable Page details - * @param username User name - * @return Response Data - */ - LaunchResource getLaunchByProjectName(String project, Pageable pageable, Filter filter, String username); - - /** - * Get list of Launch resources for specified project - * - * @param projectDetails Project Details - * @param filter Filter data - * @param pageable Page details - * @param userName Name of User - * @return Response Data - */ - Iterable<LaunchResource> getProjectLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable, - String userName); - - /** - * Get debug launches - * - * @param projectDetails Project Details - * @param filter Filter data - * @param pageable Page details - * @return Response Data - */ - Iterable<LaunchResource> getDebugLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable); - - /** - * Get specified launch attribute keys (auto-complete functionality) - * - * @param projectDetails Project Details - * @param value Tag prefix to be searched - * @return List of found tags - */ - List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, String value); - - /** - * Get specified launch attribute values (auto-complete functionality) - * - * @param projectDetails Project Details - * @param value Tag prefix to be searched - * @return List of found tags - */ - List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String key, String value); - - /** - * Get launch names of specified project (auto-complete functionality) - * - * @param projectDetails Project Details - * @param value Launch name prefix - * @return List of found launches - */ - List<String> getLaunchNames(ReportPortalUser.ProjectDetails projectDetails, String value); - - /** - * Get unique owners of launches in specified mode - * - * @param projectDetails Project Details - * @param value Owner name prefix - * @param mode Mode - * @return Response Data - */ - List<String> getOwners(ReportPortalUser.ProjectDetails projectDetails, String value, String mode); - - /** - * Get launches comparison info - * - * @param projectDetails Project Details - * @param ids IDs to be looked up - * @return Response Data - * // - */ - Map<String, List<ChartStatisticsContent>> getLaunchesComparisonInfo(ReportPortalUser.ProjectDetails projectDetails, Long[] ids); - - /** - * Get statuses of specified launches - * - * @param projectDetails Project Details - * @param ids Launch IDs - * @return Response Data - */ - Map<String, String> getStatuses(ReportPortalUser.ProjectDetails projectDetails, Long[] ids); - - /** - * Export Launch info according to the {@link ReportFormat} type - * - * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} - * @param reportFormat {@link ReportFormat} - * @param outputStream {@link HttpServletResponse#getOutputStream()} - * @param user Current {@link ReportPortalUser} - */ - void exportLaunch(Long launchId, ReportFormat reportFormat, OutputStream outputStream, ReportPortalUser user); - - /** - * Get latest launches - * - * @param projectDetails Project Details - * @param filter Filter data - * @param pageable Page details - * @return Response Data - */ - Iterable<LaunchResource> getLatestLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable); - - /** - * Get Launch resource by specified UUID - * - * @param launchId Launch uuid - * @param projectDetails Project Details - * @return {@link ClusterInfoResource} - */ - Iterable<ClusterInfoResource> getClusters(String launchId, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable); - - boolean hasItemsWithIssues(Launch launch); + Launch get(Long id); + + /** + * Get Launch resource by specified UUID + * + * @param launchId Launch uuid + * @param projectDetails Project Details + * @return {@link LaunchResource} + */ + LaunchResource getLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails); + + /** + * Get Launch resource by specified Name (for Jenkins Plugin) + * + * @param project Project Name + * @param pageable Page details + * @param username User name + * @param filter {@link Filter} + * @return Response Data + */ + LaunchResource getLaunchByProjectName(String project, Pageable pageable, Filter filter, + String username); + + /** + * Get list of Launch resources for specified project + * + * @param projectDetails Project Details + * @param filter Filter data + * @param pageable Page details + * @param userName Name of User + * @return Response Data + */ + Iterable<LaunchResource> getProjectLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable, + String userName); + + /** + * Get debug launches + * + * @param projectDetails Project Details + * @param filter Filter data + * @param pageable Page details + * @return Response Data + */ + Iterable<LaunchResource> getDebugLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable); + + /** + * Get specified launch attribute keys (auto-complete functionality) + * + * @param projectDetails Project Details + * @param value Tag prefix to be searched + * @return List of found tags + */ + List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, String value); + + /** + * Get specified launch attribute values (auto-complete functionality) + * + * @param projectDetails Project Details + * @param value Tag prefix to be searched + * @param key Attribute key + * @return List of found tags + */ + List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String key, + String value); + + /** + * Get launch names of specified project (auto-complete functionality) + * + * @param projectDetails Project Details + * @param value Launch name prefix + * @return List of found launches + */ + List<String> getLaunchNames(ReportPortalUser.ProjectDetails projectDetails, String value); + + /** + * Get unique owners of launches in specified mode + * + * @param projectDetails Project Details + * @param value Owner name prefix + * @param mode Mode + * @return Response Data + */ + List<String> getOwners(ReportPortalUser.ProjectDetails projectDetails, String value, String mode); + + /** + * Get launches comparison info + * + * @param projectDetails Project Details + * @param ids IDs to be looked up + * @return Response Data // + */ + Map<String, List<ChartStatisticsContent>> getLaunchesComparisonInfo( + ReportPortalUser.ProjectDetails projectDetails, Long[] ids); + + /** + * Get statuses of specified launches + * + * @param projectDetails Project Details + * @param ids Launch IDs + * @return Response Data + */ + Map<String, String> getStatuses(ReportPortalUser.ProjectDetails projectDetails, Long[] ids); + + /** + * Export Launch info according to the {@link ReportFormat} type + * + * @param launchId {@link com.epam.ta.reportportal.entity.launch.Launch#id} + * @param reportFormat {@link ReportFormat} + * @param outputStream {@link HttpServletResponse#getOutputStream()} + * @param user Current {@link ReportPortalUser} + */ + void exportLaunch(Long launchId, ReportFormat reportFormat, OutputStream outputStream, + ReportPortalUser user); + + /** + * Get latest launches + * + * @param projectDetails Project Details + * @param filter Filter data + * @param pageable Page details + * @return Response Data + */ + Iterable<LaunchResource> getLatestLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable); + + /** + * Get Launch resource by specified UUID + * + * @param launchId Launch uuid + * @param projectDetails Project Details + * @param pageable Pagination information for the results + * @return {@link ClusterInfoResource} + */ + Iterable<ClusterInfoResource> getClusters(String launchId, + ReportPortalUser.ProjectDetails projectDetails, Pageable pageable); + + boolean hasItemsWithIssues(Launch launch); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/MergeLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/MergeLaunchHandler.java index a39b33e3f8..c6026baab4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/MergeLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/MergeLaunchHandler.java @@ -27,14 +27,15 @@ */ public interface MergeLaunchHandler { - /** - * Merges launches. - * - * @param projectDetails Project Details - * @param user User - * @param mergeLaunchesRQ Request data - * @return OperationCompletionsRS - */ - LaunchResource mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ mergeLaunchesRQ); + /** + * Merges launches. + * + * @param projectDetails Project Details + * @param user User + * @param mergeLaunchesRQ Request data + * @return OperationCompletionsRS + */ + LaunchResource mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, MergeLaunchesRQ mergeLaunchesRQ); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/StartLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/StartLaunchHandler.java index 3d5ae52570..b5c551b266 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/StartLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/StartLaunchHandler.java @@ -16,17 +16,16 @@ package com.epam.ta.reportportal.core.launch; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; - import java.util.function.Predicate; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * Start Launch operation handler * @@ -34,27 +33,30 @@ */ public interface StartLaunchHandler { - /** - * Creates new launch for specified project - * - * @param user ReportPortal user - * @param projectDetails Project Details - * @param startLaunchRQ Request Data - * @return StartLaunchRS - */ - StartLaunchRS startLaunch(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ startLaunchRQ); + /** + * Creates new launch for specified project + * + * @param user ReportPortal user + * @param projectDetails Project Details + * @param startLaunchRQ Request Data + * @return StartLaunchRS + */ + StartLaunchRS startLaunch(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, + StartLaunchRQ startLaunchRQ); - /** - * Validate {@link ReportPortalUser} credentials. User with a {@link ProjectRole#CUSTOMER} role can't report - * launches in a debug mode. - * - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param startLaunchRQ {@link StartLaunchRQ} - */ - default void validateRoles(ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ startLaunchRQ) { - expect( - Mode.DEBUG.equals(startLaunchRQ.getMode()) && ProjectRole.CUSTOMER.equals(projectDetails.getProjectRole()), - Predicate.isEqual(false) - ).verify(ErrorType.FORBIDDEN_OPERATION); - } + /** + * Validate {@link ReportPortalUser} credentials. User with a {@link ProjectRole#CUSTOMER} role + * can't report launches in a debug mode. + * + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param startLaunchRQ {@link StartLaunchRQ} + */ + default void validateRoles(ReportPortalUser.ProjectDetails projectDetails, + StartLaunchRQ startLaunchRQ) { + expect( + Mode.DEBUG.equals(startLaunchRQ.getMode()) && ProjectRole.CUSTOMER.equals( + projectDetails.getProjectRole()), + Predicate.isEqual(false) + ).verify(ErrorType.FORBIDDEN_OPERATION); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/StopLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/StopLaunchHandler.java index 4ad4539657..3a85ce26b1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/StopLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/StopLaunchHandler.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.ws.model.BulkRQ; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; - import java.util.List; /** @@ -28,26 +27,28 @@ */ public interface StopLaunchHandler { - /** - * Stop Launch instance by user - * - * @param launchId ID of launch - * @param finishLaunchRQ Request data - * @param projectDetails Project Details - * @param user User - * @return OperationCompletionRS - */ - OperationCompletionRS stopLaunch(Long launchId, FinishExecutionRQ finishLaunchRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Stop Launch instance by user + * + * @param launchId ID of launch + * @param finishLaunchRQ Request data + * @param projectDetails Project Details + * @param user User + * @return OperationCompletionRS + */ + OperationCompletionRS stopLaunch(Long launchId, FinishExecutionRQ finishLaunchRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Bulk stop launches operation. - * - * @param bulkRQ Bulk request - * @param projectDetails Project Details - * @param user User - * @return OperationCompletionsRS - */ - List<OperationCompletionRS> stopLaunch(BulkRQ<Long, FinishExecutionRQ> bulkRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Bulk stop launches operation. + * + * @param bulkRQ Bulk request + * @param projectDetails Project Details + * @param user User + * @return OperationCompletionsRS + */ + List<OperationCompletionRS> stopLaunch(BulkRQ<Long, FinishExecutionRQ> bulkRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/UpdateLaunchHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/UpdateLaunchHandler.java index a212aa10e1..152b24a579 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/UpdateLaunchHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/UpdateLaunchHandler.java @@ -23,7 +23,6 @@ import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.UpdateLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.cluster.CreateClustersRQ; - import java.util.List; /** @@ -35,42 +34,47 @@ */ public interface UpdateLaunchHandler { - /** - * Update specified by id launch. - * - * @param launchId ID of Launch object - * @param projectDetails Project Details - * @param user Recipient user - * @param rq Request Data - * @return OperationCompletionRS - Response Data - */ - OperationCompletionRS updateLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - UpdateLaunchRQ rq); + /** + * Update specified by id launch. + * + * @param launchId ID of Launch object + * @param projectDetails Project Details + * @param user Recipient user + * @param rq Request Data + * @return OperationCompletionRS - Response Data + */ + OperationCompletionRS updateLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, + UpdateLaunchRQ rq); - /** - * Start launch analyzer on demand - * - * @param projectDetails Project Details - * @param analyzeLaunchRQ Launch analyze rq - * @param user User started analysis - * @return OperationCompletionRS - Response Data - */ - OperationCompletionRS startLaunchAnalyzer(AnalyzeLaunchRQ analyzeLaunchRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Start launch analyzer on demand + * + * @param projectDetails Project Details + * @param analyzeLaunchRQ Launch analyze rq + * @param user User started analysis + * @return OperationCompletionRS - Response Data + */ + OperationCompletionRS startLaunchAnalyzer(AnalyzeLaunchRQ analyzeLaunchRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - OperationCompletionRS createClusters(CreateClustersRQ createClustersRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + OperationCompletionRS createClusters(CreateClustersRQ createClustersRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Bulk launch update. - * - * @param rq Bulk request - * @param projectDetails Project Details - * @param user User - * @return OperationCompletionRS - */ - List<OperationCompletionRS> updateLaunch(BulkRQ<Long, UpdateLaunchRQ> rq, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Bulk launch update. + * + * @param rq Bulk request + * @param projectDetails Project Details + * @param user User + * @return OperationCompletionRS + */ + List<OperationCompletionRS> updateLaunch(BulkRQ<Long, UpdateLaunchRQ> rq, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, ReportPortalUser.ProjectDetails projectDetails); + OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, + ReportPortalUser.ProjectDetails projectDetails); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/ClusterGenerator.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/ClusterGenerator.java index ced3a8d491..fdb769c996 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/ClusterGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/ClusterGenerator.java @@ -23,6 +23,6 @@ */ public interface ClusterGenerator { - void generate(GenerateClustersConfig config); + void generate(GenerateClustersConfig config); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandler.java index cada826928..540de65037 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandler.java @@ -23,5 +23,5 @@ */ public interface CreateClusterHandler { - void create(ClusterData clusterData); + void create(ClusterData clusterData); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImpl.java index 1b5544a36f..51ed71cfe3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImpl.java @@ -16,21 +16,20 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.ws.converter.converters.ClusterConverter.TO_CLUSTER; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterInfoRs; import com.epam.ta.reportportal.dao.ClusterRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; +import java.util.Objects; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Objects; - -import static com.epam.ta.reportportal.ws.converter.converters.ClusterConverter.TO_CLUSTER; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @@ -38,50 +37,54 @@ @Transactional public class CreateClusterHandlerImpl implements CreateClusterHandler { - private final ClusterRepository clusterRepository; - private final LogRepository logRepository; + private final ClusterRepository clusterRepository; + private final LogRepository logRepository; - @Autowired - public CreateClusterHandlerImpl(ClusterRepository clusterRepository, LogRepository logRepository) { - this.clusterRepository = clusterRepository; - this.logRepository = logRepository; - } + @Autowired + public CreateClusterHandlerImpl(ClusterRepository clusterRepository, + LogRepository logRepository) { + this.clusterRepository = clusterRepository; + this.logRepository = logRepository; + } - @Override - public void create(ClusterData clusterData) { - ofNullable(clusterData.getClusters()).filter(CollectionUtils::isNotEmpty) - .ifPresent(clusters -> clusters.stream().filter(c -> Objects.nonNull(c.getClusterId())).forEach(clusterInfoRs -> { - final Cluster cluster = saveCluster(clusterData, clusterInfoRs); - saveItems(clusterInfoRs, cluster); - updateLogs(clusterInfoRs, cluster); - })); - } + @Override + public void create(ClusterData clusterData) { + ofNullable(clusterData.getClusters()).filter(CollectionUtils::isNotEmpty) + .ifPresent(clusters -> clusters.stream().filter(c -> Objects.nonNull(c.getClusterId())) + .forEach(clusterInfoRs -> { + final Cluster cluster = saveCluster(clusterData, clusterInfoRs); + saveItems(clusterInfoRs, cluster); + updateLogs(clusterInfoRs, cluster); + })); + } - private Cluster saveCluster(ClusterData clusterData, ClusterInfoRs clusterInfoRs) { - final Cluster cluster = clusterRepository.findByIndexIdAndLaunchId(clusterInfoRs.getClusterId(), clusterData.getLaunchId()) - .map(c -> { - c.setMessage(clusterInfoRs.getClusterMessage()); - return c; - }) - .orElseGet(() -> convertToCluster(clusterData, clusterInfoRs)); - return clusterRepository.save(cluster); - } + private Cluster saveCluster(ClusterData clusterData, ClusterInfoRs clusterInfoRs) { + final Cluster cluster = clusterRepository.findByIndexIdAndLaunchId(clusterInfoRs.getClusterId(), + clusterData.getLaunchId()) + .map(c -> { + c.setMessage(clusterInfoRs.getClusterMessage()); + return c; + }) + .orElseGet(() -> convertToCluster(clusterData, clusterInfoRs)); + return clusterRepository.save(cluster); + } - private Cluster convertToCluster(ClusterData clusterData, ClusterInfoRs clusterInfoRs) { - final Cluster cluster = TO_CLUSTER.apply(clusterInfoRs); - cluster.setProjectId(clusterData.getProject()); - cluster.setLaunchId(clusterData.getLaunchId()); - return cluster; - } + private Cluster convertToCluster(ClusterData clusterData, ClusterInfoRs clusterInfoRs) { + final Cluster cluster = TO_CLUSTER.apply(clusterInfoRs); + cluster.setProjectId(clusterData.getProject()); + cluster.setLaunchId(clusterData.getLaunchId()); + return cluster; + } - private void saveItems(ClusterInfoRs clusterInfoRs, Cluster cluster) { - ofNullable(clusterInfoRs.getItemIds()).filter(CollectionUtils::isNotEmpty) - .ifPresent(itemIds -> clusterRepository.saveClusterTestItems(cluster, itemIds)); - } + private void saveItems(ClusterInfoRs clusterInfoRs, Cluster cluster) { + ofNullable(clusterInfoRs.getItemIds()).filter(CollectionUtils::isNotEmpty) + .ifPresent(itemIds -> clusterRepository.saveClusterTestItems(cluster, itemIds)); + } - private void updateLogs(ClusterInfoRs clusterInfoRs, Cluster cluster) { - ofNullable(clusterInfoRs.getLogIds()).filter(CollectionUtils::isNotEmpty) - .ifPresent(logIds -> logRepository.updateClusterIdByIdIn(cluster.getId(), clusterInfoRs.getLogIds())); - } + private void updateLogs(ClusterInfoRs clusterInfoRs, Cluster cluster) { + ofNullable(clusterInfoRs.getLogIds()).filter(CollectionUtils::isNotEmpty) + .ifPresent(logIds -> logRepository.updateClusterIdByIdIn(cluster.getId(), + clusterInfoRs.getLogIds())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandler.java index f1a79c83bd..4292007568 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandler.java @@ -26,7 +26,7 @@ */ public interface GetClusterHandler { - Cluster getById(Long id); + Cluster getById(Long id); - Iterable<ClusterInfoResource> getResources(Launch launch, Pageable pageable); + Iterable<ClusterInfoResource> getResources(Launch launch, Pageable pageable); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandlerImpl.java index 0dbb58f37c..3bc0b38bc9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/GetClusterHandlerImpl.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.ws.converter.converters.ClusterConverter.TO_CLUSTER_INFO; + import com.epam.reportportal.extension.event.GetClusterResourcesEvent; import com.epam.ta.reportportal.dao.ClusterRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; @@ -32,48 +35,48 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static com.epam.ta.reportportal.ws.converter.converters.ClusterConverter.TO_CLUSTER_INFO; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class GetClusterHandlerImpl implements GetClusterHandler { - private final ClusterRepository clusterRepository; - private final ApplicationEventPublisher eventPublisher; + private final ClusterRepository clusterRepository; + private final ApplicationEventPublisher eventPublisher; - @Autowired - public GetClusterHandlerImpl(ClusterRepository clusterRepository, ApplicationEventPublisher eventPublisher) { - this.clusterRepository = clusterRepository; - this.eventPublisher = eventPublisher; - } + @Autowired + public GetClusterHandlerImpl(ClusterRepository clusterRepository, + ApplicationEventPublisher eventPublisher) { + this.clusterRepository = clusterRepository; + this.eventPublisher = eventPublisher; + } - @Override - public Cluster getById(Long id) { - return clusterRepository.findById(id).orElseThrow(() -> new ReportPortalException(ErrorType.CLUSTER_NOT_FOUND, id)); - } + @Override + public Cluster getById(Long id) { + return clusterRepository.findById(id) + .orElseThrow(() -> new ReportPortalException(ErrorType.CLUSTER_NOT_FOUND, id)); + } - @Override - public Iterable<ClusterInfoResource> getResources(Launch launch, Pageable pageable) { + @Override + public Iterable<ClusterInfoResource> getResources(Launch launch, Pageable pageable) { - final Pageable pageableWithSort = applySort(pageable); - final Page<Cluster> clusters = clusterRepository.findAllByLaunchId(launch.getId(), pageableWithSort); + final Pageable pageableWithSort = applySort(pageable); + final Page<Cluster> clusters = clusterRepository.findAllByLaunchId(launch.getId(), + pageableWithSort); - return getClusterResources(clusters, launch.getId()); - } + return getClusterResources(clusters, launch.getId()); + } - private Pageable applySort(Pageable pageable) { - final Sort idSort = Sort.by(Sort.Order.asc(CRITERIA_ID)); - return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), idSort); - } + private Pageable applySort(Pageable pageable) { + final Sort idSort = Sort.by(Sort.Order.asc(CRITERIA_ID)); + return PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), idSort); + } - private Iterable<ClusterInfoResource> getClusterResources(Page<Cluster> clusters, Long launchId) { - final com.epam.ta.reportportal.ws.model.Page<ClusterInfoResource> clustersPage = PagedResourcesAssembler.pageConverter( - TO_CLUSTER_INFO).apply(clusters); - eventPublisher.publishEvent(new GetClusterResourcesEvent(clustersPage.getContent(), launchId)); - return clustersPage; - } + private Iterable<ClusterInfoResource> getClusterResources(Page<Cluster> clusters, Long launchId) { + final com.epam.ta.reportportal.ws.model.Page<ClusterInfoResource> clustersPage = PagedResourcesAssembler.pageConverter( + TO_CLUSTER_INFO).apply(clusters); + eventPublisher.publishEvent(new GetClusterResourcesEvent(clustersPage.getContent(), launchId)); + return clustersPage; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarter.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarter.java index 0c6c9a4761..b5726506d9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarter.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarter.java @@ -16,41 +16,40 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getUniqueErrorConfig; + import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.epam.ta.reportportal.ws.model.project.UniqueErrorConfig; -import org.apache.commons.collections4.CollectionUtils; - import java.util.Map; - -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getAnalyzerConfig; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.getUniqueErrorConfig; +import org.apache.commons.collections4.CollectionUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class UniqueErrorAnalysisStarter { - private final ClusterGenerator clusterGenerator; + private final ClusterGenerator clusterGenerator; - public UniqueErrorAnalysisStarter(ClusterGenerator clusterGenerator) { - this.clusterGenerator = clusterGenerator; - } + public UniqueErrorAnalysisStarter(ClusterGenerator clusterGenerator) { + this.clusterGenerator = clusterGenerator; + } - public void start(ClusterEntityContext entityContext, Map<String, String> projectConfig) { + public void start(ClusterEntityContext entityContext, Map<String, String> projectConfig) { - final GenerateClustersConfig clustersConfig = new GenerateClustersConfig(); + final GenerateClustersConfig clustersConfig = new GenerateClustersConfig(); - clustersConfig.setEntityContext(entityContext); - clustersConfig.setForUpdate(CollectionUtils.isNotEmpty(entityContext.getItemIds())); + clustersConfig.setEntityContext(entityContext); + clustersConfig.setForUpdate(CollectionUtils.isNotEmpty(entityContext.getItemIds())); - final UniqueErrorConfig uniqueErrorConfig = getUniqueErrorConfig(projectConfig); - clustersConfig.setCleanNumbers(uniqueErrorConfig.isRemoveNumbers()); + final UniqueErrorConfig uniqueErrorConfig = getUniqueErrorConfig(projectConfig); + clustersConfig.setCleanNumbers(uniqueErrorConfig.isRemoveNumbers()); - final AnalyzerConfig analyzerConfig = getAnalyzerConfig(projectConfig); - clustersConfig.setAnalyzerConfig(analyzerConfig); + final AnalyzerConfig analyzerConfig = getAnalyzerConfig(projectConfig); + clustersConfig.setAnalyzerConfig(analyzerConfig); - clusterGenerator.generate(clustersConfig); - } + clusterGenerator.generate(clustersConfig); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGenerator.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGenerator.java index 1e77f1e66a..ae2e4432c2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGenerator.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; @@ -23,67 +25,69 @@ import com.epam.ta.reportportal.pipeline.PipelinePart; import com.epam.ta.reportportal.pipeline.TransactionalPipeline; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.function.Predicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class UniqueErrorGenerator implements ClusterGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(UniqueErrorGeneratorAsync.class); + private static final Logger LOGGER = LoggerFactory.getLogger(UniqueErrorGeneratorAsync.class); - private final AnalyzerStatusCache analyzerStatusCache; + private final AnalyzerStatusCache analyzerStatusCache; - private final PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor; - private final TransactionalPipeline transactionalPipeline; + private final PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor; + private final TransactionalPipeline transactionalPipeline; - @Autowired - public UniqueErrorGenerator(AnalyzerStatusCache analyzerStatusCache, - PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor, TransactionalPipeline transactionalPipeline) { - this.analyzerStatusCache = analyzerStatusCache; - this.generateClustersPipelineConstructor = generateClustersPipelineConstructor; - this.transactionalPipeline = transactionalPipeline; - } + @Autowired + public UniqueErrorGenerator(AnalyzerStatusCache analyzerStatusCache, + PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor, + TransactionalPipeline transactionalPipeline) { + this.analyzerStatusCache = analyzerStatusCache; + this.generateClustersPipelineConstructor = generateClustersPipelineConstructor; + this.transactionalPipeline = transactionalPipeline; + } - @Override - public void generate(GenerateClustersConfig config) { - fillCache(config.getEntityContext()); - generateClusters(config); - } + @Override + public void generate(GenerateClustersConfig config) { + fillCache(config.getEntityContext()); + generateClusters(config); + } - protected void fillCache(ClusterEntityContext entityContext) { - checkDuplicate(entityContext); - analyzerStatusCache.analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId(), entityContext.getProjectId()); - } + protected void fillCache(ClusterEntityContext entityContext) { + checkDuplicate(entityContext); + analyzerStatusCache.analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId(), + entityContext.getProjectId()); + } - private void checkDuplicate(ClusterEntityContext entityContext) { - expect(analyzerStatusCache.containsLaunchId(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()), - Predicate.isEqual(false) - ).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "Clusters creation is in progress."); - } + private void checkDuplicate(ClusterEntityContext entityContext) { + expect(analyzerStatusCache.containsLaunchId(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()), + Predicate.isEqual(false) + ).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "Clusters creation is in progress."); + } - protected void generateClusters(GenerateClustersConfig config) { - try { - final List<PipelinePart> pipelineParts = generateClustersPipelineConstructor.construct(config); - transactionalPipeline.run(pipelineParts); - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - } finally { - cleanCache(config.getEntityContext()); - } - } + protected void generateClusters(GenerateClustersConfig config) { + try { + final List<PipelinePart> pipelineParts = generateClustersPipelineConstructor.construct( + config); + transactionalPipeline.run(pipelineParts); + } catch (Exception ex) { + LOGGER.error(ex.getMessage(), ex); + } finally { + cleanCache(config.getEntityContext()); + } + } - protected void cleanCache(ClusterEntityContext entityContext) { - analyzerStatusCache.analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } + protected void cleanCache(ClusterEntityContext entityContext) { + analyzerStatusCache.analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsync.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsync.java index 5e81f964ed..6b311b9605 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsync.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsync.java @@ -33,25 +33,26 @@ @Service public class UniqueErrorGeneratorAsync extends UniqueErrorGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(UniqueErrorGeneratorAsync.class); + private static final Logger LOGGER = LoggerFactory.getLogger(UniqueErrorGeneratorAsync.class); - private final TaskExecutor logClusterExecutor; + private final TaskExecutor logClusterExecutor; - @Autowired - public UniqueErrorGeneratorAsync(AnalyzerStatusCache analyzerStatusCache, - PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor, TransactionalPipeline transactionalPipeline, - @Qualifier(value = "logClusterExecutor") TaskExecutor logClusterExecutor) { - super(analyzerStatusCache, generateClustersPipelineConstructor, transactionalPipeline); - this.logClusterExecutor = logClusterExecutor; - } + @Autowired + public UniqueErrorGeneratorAsync(AnalyzerStatusCache analyzerStatusCache, + PipelineConstructor<GenerateClustersConfig> generateClustersPipelineConstructor, + TransactionalPipeline transactionalPipeline, + @Qualifier(value = "logClusterExecutor") TaskExecutor logClusterExecutor) { + super(analyzerStatusCache, generateClustersPipelineConstructor, transactionalPipeline); + this.logClusterExecutor = logClusterExecutor; + } - @Override - protected void generateClusters(GenerateClustersConfig config) { - try { - logClusterExecutor.execute(() -> super.generateClusters(config)); - } catch (Exception ex) { - LOGGER.error(ex.getMessage(), ex); - cleanCache(config.getEntityContext()); - } - } + @Override + protected void generateClusters(GenerateClustersConfig config) { + try { + logClusterExecutor.execute(() -> super.generateClusters(config)); + } catch (Exception ex) { + LOGGER.error(ex.getMessage(), ex); + cleanCache(config.getEntityContext()); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/ClusterEntityContext.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/ClusterEntityContext.java index fe4ffe950e..26fec00822 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/ClusterEntityContext.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/ClusterEntityContext.java @@ -24,40 +24,40 @@ */ public class ClusterEntityContext { - private final Long launchId; - private final Long projectId; - - private final List<Long> itemIds; - - private ClusterEntityContext(Long launchId, Long projectId) { - this.launchId = launchId; - this.projectId = projectId; - this.itemIds = Collections.emptyList(); - } - - private ClusterEntityContext(Long launchId, Long projectId, List<Long> itemIds) { - this.launchId = launchId; - this.projectId = projectId; - this.itemIds = itemIds; - } - - public Long getLaunchId() { - return launchId; - } - - public Long getProjectId() { - return projectId; - } - - public List<Long> getItemIds() { - return itemIds; - } - - public static ClusterEntityContext of(Long launchId, Long projectId) { - return new ClusterEntityContext(launchId, projectId); - } - - public static ClusterEntityContext of(Long launchId, Long projectId, List<Long> itemIds) { - return new ClusterEntityContext(launchId, projectId, itemIds); - } + private final Long launchId; + private final Long projectId; + + private final List<Long> itemIds; + + private ClusterEntityContext(Long launchId, Long projectId) { + this.launchId = launchId; + this.projectId = projectId; + this.itemIds = Collections.emptyList(); + } + + private ClusterEntityContext(Long launchId, Long projectId, List<Long> itemIds) { + this.launchId = launchId; + this.projectId = projectId; + this.itemIds = itemIds; + } + + public Long getLaunchId() { + return launchId; + } + + public Long getProjectId() { + return projectId; + } + + public List<Long> getItemIds() { + return itemIds; + } + + public static ClusterEntityContext of(Long launchId, Long projectId) { + return new ClusterEntityContext(launchId, projectId); + } + + public static ClusterEntityContext of(Long launchId, Long projectId, List<Long> itemIds) { + return new ClusterEntityContext(launchId, projectId, itemIds); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/GenerateClustersConfig.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/GenerateClustersConfig.java index b77835edc0..641be39f05 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/GenerateClustersConfig.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/config/GenerateClustersConfig.java @@ -23,45 +23,45 @@ */ public class GenerateClustersConfig { - private ClusterEntityContext entityContext; + private ClusterEntityContext entityContext; - private AnalyzerConfig analyzerConfig; + private AnalyzerConfig analyzerConfig; - private boolean forUpdate; - private boolean cleanNumbers; + private boolean forUpdate; + private boolean cleanNumbers; - public GenerateClustersConfig() { - } + public GenerateClustersConfig() { + } - public ClusterEntityContext getEntityContext() { - return entityContext; - } + public ClusterEntityContext getEntityContext() { + return entityContext; + } - public void setEntityContext(ClusterEntityContext entityContext) { - this.entityContext = entityContext; - } + public void setEntityContext(ClusterEntityContext entityContext) { + this.entityContext = entityContext; + } - public AnalyzerConfig getAnalyzerConfig() { - return analyzerConfig; - } + public AnalyzerConfig getAnalyzerConfig() { + return analyzerConfig; + } - public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { - this.analyzerConfig = analyzerConfig; - } + public void setAnalyzerConfig(AnalyzerConfig analyzerConfig) { + this.analyzerConfig = analyzerConfig; + } - public boolean isForUpdate() { - return forUpdate; - } + public boolean isForUpdate() { + return forUpdate; + } - public void setForUpdate(boolean forUpdate) { - this.forUpdate = forUpdate; - } + public void setForUpdate(boolean forUpdate) { + this.forUpdate = forUpdate; + } - public boolean isCleanNumbers() { - return cleanNumbers; - } + public boolean isCleanNumbers() { + return cleanNumbers; + } - public void setCleanNumbers(boolean cleanNumbers) { - this.cleanNumbers = cleanNumbers; - } + public void setCleanNumbers(boolean cleanNumbers) { + this.cleanNumbers = cleanNumbers; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProvider.java index 8ad783824a..9a41f2c928 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProvider.java @@ -28,26 +28,27 @@ */ public class DeleteClustersPartProvider implements PipelinePartProvider<GenerateClustersConfig> { - private final ClusterRepository clusterRepository; - private final LogRepository logRepository; + private final ClusterRepository clusterRepository; + private final LogRepository logRepository; - public DeleteClustersPartProvider(ClusterRepository clusterRepository, LogRepository logRepository) { - this.clusterRepository = clusterRepository; - this.logRepository = logRepository; - } + public DeleteClustersPartProvider(ClusterRepository clusterRepository, + LogRepository logRepository) { + this.clusterRepository = clusterRepository; + this.logRepository = logRepository; + } - @Override - public PipelinePart provide(GenerateClustersConfig config) { - return () -> { - final ClusterEntityContext entityContext = config.getEntityContext(); - if (config.isForUpdate()) { - logRepository.updateClusterIdSetNullByItemIds(entityContext.getItemIds()); - clusterRepository.deleteClusterTestItemsByItemIds(entityContext.getItemIds()); - } else { - logRepository.updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); - clusterRepository.deleteClusterTestItemsByLaunchId(entityContext.getLaunchId()); - clusterRepository.deleteAllByLaunchId(entityContext.getLaunchId()); - } - }; - } + @Override + public PipelinePart provide(GenerateClustersConfig config) { + return () -> { + final ClusterEntityContext entityContext = config.getEntityContext(); + if (config.isForUpdate()) { + logRepository.updateClusterIdSetNullByItemIds(entityContext.getItemIds()); + clusterRepository.deleteClusterTestItemsByItemIds(entityContext.getItemIds()); + } else { + logRepository.updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); + clusterRepository.deleteClusterTestItemsByLaunchId(entityContext.getLaunchId()); + clusterRepository.deleteAllByLaunchId(entityContext.getLaunchId()); + } + }; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProvider.java index e0427c460a..8f908bf5a2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProvider.java @@ -22,7 +22,6 @@ import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.ClusterDataProviderResolver; import com.epam.ta.reportportal.pipeline.PipelinePart; import com.epam.ta.reportportal.pipeline.PipelinePartProvider; - import java.util.Optional; /** @@ -30,18 +29,20 @@ */ public class SaveClusterDataPartProvider implements PipelinePartProvider<GenerateClustersConfig> { - private final ClusterDataProviderResolver clusterDataProviderResolver; - private final CreateClusterHandler createClusterHandler; - - public SaveClusterDataPartProvider(ClusterDataProviderResolver clusterDataProviderResolver, CreateClusterHandler createClusterHandler) { - this.clusterDataProviderResolver = clusterDataProviderResolver; - this.createClusterHandler = createClusterHandler; - } - - @Override - public PipelinePart provide(GenerateClustersConfig config) { - final Optional<ClusterData> clusterData = clusterDataProviderResolver.resolve(config).flatMap(p -> p.provide(config)); - return () -> clusterData.ifPresent(createClusterHandler::create); - } + private final ClusterDataProviderResolver clusterDataProviderResolver; + private final CreateClusterHandler createClusterHandler; + + public SaveClusterDataPartProvider(ClusterDataProviderResolver clusterDataProviderResolver, + CreateClusterHandler createClusterHandler) { + this.clusterDataProviderResolver = clusterDataProviderResolver; + this.createClusterHandler = createClusterHandler; + } + + @Override + public PipelinePart provide(GenerateClustersConfig config) { + final Optional<ClusterData> clusterData = clusterDataProviderResolver.resolve(config) + .flatMap(p -> p.provide(config)); + return () -> clusterData.ifPresent(createClusterHandler::create); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProvider.java index 395de7c5c9..96e2399f63 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProvider.java @@ -21,38 +21,37 @@ import com.epam.ta.reportportal.dao.ItemAttributeRepository; import com.epam.ta.reportportal.pipeline.PipelinePart; import com.epam.ta.reportportal.pipeline.PipelinePartProvider; - import java.time.Instant; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ -public class SaveLastRunAttributePartProvider implements PipelinePartProvider<GenerateClustersConfig> { - - public static final String RP_CLUSTER_LAST_RUN_KEY = "rp.cluster.lastRun"; - - private final ItemAttributeRepository itemAttributeRepository; - - public SaveLastRunAttributePartProvider(ItemAttributeRepository itemAttributeRepository) { - this.itemAttributeRepository = itemAttributeRepository; - } - - @Override - public PipelinePart provide(GenerateClustersConfig config) { - return () -> { - final String lastRunDate = String.valueOf(Instant.now().toEpochMilli()); - final ClusterEntityContext entityContext = config.getEntityContext(); - itemAttributeRepository.findByLaunchIdAndKeyAndSystem(entityContext.getLaunchId(), RP_CLUSTER_LAST_RUN_KEY, true) - .ifPresentOrElse(attr -> { - attr.setValue(lastRunDate); - itemAttributeRepository.save(attr); - }, - () -> itemAttributeRepository.saveByLaunchId(entityContext.getLaunchId(), - RP_CLUSTER_LAST_RUN_KEY, - lastRunDate, - true - ) - ); - }; - } +public class SaveLastRunAttributePartProvider implements + PipelinePartProvider<GenerateClustersConfig> { + + public static final String RP_CLUSTER_LAST_RUN_KEY = "rp.cluster.lastRun"; + + private final ItemAttributeRepository itemAttributeRepository; + + public SaveLastRunAttributePartProvider(ItemAttributeRepository itemAttributeRepository) { + this.itemAttributeRepository = itemAttributeRepository; + } + + @Override + public PipelinePart provide(GenerateClustersConfig config) { + return () -> { + if (config.isForUpdate()) { + return; + } + final String lastRunDate = String.valueOf(Instant.now().toEpochMilli()); + final ClusterEntityContext entityContext = config.getEntityContext(); + itemAttributeRepository.deleteAllByLaunchIdAndKeyAndSystem(entityContext.getLaunchId(), + RP_CLUSTER_LAST_RUN_KEY, true); + itemAttributeRepository.saveByLaunchId(entityContext.getLaunchId(), + RP_CLUSTER_LAST_RUN_KEY, + lastRunDate, + true + ); + }; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerClusterDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerClusterDataProvider.java index 6dee500eae..f1fea1c8b4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerClusterDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerClusterDataProvider.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline.data; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; @@ -24,48 +26,46 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; - import java.util.Optional; import java.util.function.Predicate; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AnalyzerClusterDataProvider implements ClusterDataProvider { - private final AnalyzerServiceClient analyzerServiceClient; + private final AnalyzerServiceClient analyzerServiceClient; - public AnalyzerClusterDataProvider(AnalyzerServiceClient analyzerServiceClient) { - this.analyzerServiceClient = analyzerServiceClient; - } + public AnalyzerClusterDataProvider(AnalyzerServiceClient analyzerServiceClient) { + this.analyzerServiceClient = analyzerServiceClient; + } - protected abstract Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config); + protected abstract Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config); - @Override - public Optional<ClusterData> provide(GenerateClustersConfig config) { - expect(analyzerServiceClient.hasClients(), Predicate.isEqual(true)).verify(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer services are deployed." - ); - return getGenerateRq(config).map(analyzerServiceClient::generateClusters); - } + @Override + public Optional<ClusterData> provide(GenerateClustersConfig config) { + expect(analyzerServiceClient.hasClients(), Predicate.isEqual(true)).verify( + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "There are no analyzer services are deployed." + ); + return getGenerateRq(config).map(analyzerServiceClient::generateClusters); + } - private Optional<GenerateClustersRq> getGenerateRq(GenerateClustersConfig config) { - return prepareIndexLaunch(config).map(indexLaunch -> { - final GenerateClustersRq generateClustersRq = new GenerateClustersRq(); - generateClustersRq.setLaunch(indexLaunch); - generateClustersRq.setCleanNumbers(config.isCleanNumbers()); - generateClustersRq.setForUpdate(config.isForUpdate()); + private Optional<GenerateClustersRq> getGenerateRq(GenerateClustersConfig config) { + return prepareIndexLaunch(config).map(indexLaunch -> { + final GenerateClustersRq generateClustersRq = new GenerateClustersRq(); + generateClustersRq.setLaunch(indexLaunch); + generateClustersRq.setCleanNumbers(config.isCleanNumbers()); + generateClustersRq.setForUpdate(config.isForUpdate()); - final ClusterEntityContext entityContext = config.getEntityContext(); - generateClustersRq.setProject(entityContext.getProjectId()); + final ClusterEntityContext entityContext = config.getEntityContext(); + generateClustersRq.setProject(entityContext.getProjectId()); - final AnalyzerConfig analyzerConfig = config.getAnalyzerConfig(); - generateClustersRq.setNumberOfLogLines(analyzerConfig.getNumberOfLogLines()); + final AnalyzerConfig analyzerConfig = config.getAnalyzerConfig(); + generateClustersRq.setNumberOfLogLines(analyzerConfig.getNumberOfLogLines()); - return generateClustersRq; - }); - } + return generateClustersRq; + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProvider.java index 4066187554..a3a5cbe686 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProvider.java @@ -25,36 +25,36 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; -import org.apache.commons.collections4.CollectionUtils; - import java.util.List; import java.util.Optional; +import org.apache.commons.collections4.CollectionUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class AnalyzerItemClusterDataProvider extends AnalyzerClusterDataProvider { - private final GetLaunchHandler getLaunchHandler; - private final TestItemRepository testItemRepository; - private final LaunchPreparerService launchPreparerService; + private final GetLaunchHandler getLaunchHandler; + private final TestItemRepository testItemRepository; + private final LaunchPreparerService launchPreparerService; - public AnalyzerItemClusterDataProvider(AnalyzerServiceClient analyzerServiceClient, GetLaunchHandler getLaunchHandler, - TestItemRepository testItemRepository, LaunchPreparerService launchPreparerService) { - super(analyzerServiceClient); - this.getLaunchHandler = getLaunchHandler; - this.testItemRepository = testItemRepository; - this.launchPreparerService = launchPreparerService; - } + public AnalyzerItemClusterDataProvider(AnalyzerServiceClient analyzerServiceClient, + GetLaunchHandler getLaunchHandler, + TestItemRepository testItemRepository, LaunchPreparerService launchPreparerService) { + super(analyzerServiceClient); + this.getLaunchHandler = getLaunchHandler; + this.testItemRepository = testItemRepository; + this.launchPreparerService = launchPreparerService; + } - @Override - protected Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config) { - final ClusterEntityContext entityContext = config.getEntityContext(); - if (CollectionUtils.isEmpty(entityContext.getItemIds())) { - return Optional.empty(); - } - final Launch launch = getLaunchHandler.get(entityContext.getLaunchId()); - final List<TestItem> testItems = testItemRepository.findAllById(entityContext.getItemIds()); - return launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig()); - } + @Override + protected Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config) { + final ClusterEntityContext entityContext = config.getEntityContext(); + if (CollectionUtils.isEmpty(entityContext.getItemIds())) { + return Optional.empty(); + } + final Launch launch = getLaunchHandler.get(entityContext.getLaunchId()); + final List<TestItem> testItems = testItemRepository.findAllById(entityContext.getItemIds()); + return launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProvider.java index 98475e7ae8..cb4f1e64f4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProvider.java @@ -21,7 +21,6 @@ import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; - import java.util.Optional; /** @@ -29,16 +28,17 @@ */ public class AnalyzerLaunchClusterDataProvider extends AnalyzerClusterDataProvider { - private final LaunchPreparerService launchPreparerService; + private final LaunchPreparerService launchPreparerService; - public AnalyzerLaunchClusterDataProvider(AnalyzerServiceClient analyzerServiceClient, LaunchPreparerService launchPreparerService) { - super(analyzerServiceClient); - this.launchPreparerService = launchPreparerService; - } + public AnalyzerLaunchClusterDataProvider(AnalyzerServiceClient analyzerServiceClient, + LaunchPreparerService launchPreparerService) { + super(analyzerServiceClient); + this.launchPreparerService = launchPreparerService; + } - @Override - protected Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config) { - final ClusterEntityContext entityContext = config.getEntityContext(); - return launchPreparerService.prepare(entityContext.getLaunchId(), config.getAnalyzerConfig()); - } + @Override + protected Optional<IndexLaunch> prepareIndexLaunch(GenerateClustersConfig config) { + final ClusterEntityContext entityContext = config.getEntityContext(); + return launchPreparerService.prepare(entityContext.getLaunchId(), config.getAnalyzerConfig()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/ClusterDataProvider.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/ClusterDataProvider.java index 3b7f116ffc..a5cfb7bd56 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/ClusterDataProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/ClusterDataProvider.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; - import java.util.Optional; /** @@ -26,5 +25,5 @@ */ public interface ClusterDataProvider { - Optional<ClusterData> provide(GenerateClustersConfig config); + Optional<ClusterData> provide(GenerateClustersConfig config); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolver.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolver.java index 4371de30df..d547d35fce 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolver.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolver.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator.ClusterDataProviderEvaluator; - import java.util.List; import java.util.Optional; @@ -28,13 +27,14 @@ */ public class ClusterDataProviderResolver { - private final List<ClusterDataProviderEvaluator> evaluators; + private final List<ClusterDataProviderEvaluator> evaluators; - public ClusterDataProviderResolver(List<ClusterDataProviderEvaluator> evaluators) { - this.evaluators = evaluators; - } + public ClusterDataProviderResolver(List<ClusterDataProviderEvaluator> evaluators) { + this.evaluators = evaluators; + } - public Optional<ClusterDataProvider> resolve(GenerateClustersConfig config) { - return evaluators.stream().filter(e -> e.supports(config)).map(ClusterDataProviderEvaluator::getProvider).findFirst(); - } + public Optional<ClusterDataProvider> resolve(GenerateClustersConfig config) { + return evaluators.stream().filter(e -> e.supports(config)) + .map(ClusterDataProviderEvaluator::getProvider).findFirst(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluator.java b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluator.java index 630c0bfe56..1bad46c0b8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluator.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluator.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; - import java.util.function.Predicate; /** @@ -26,19 +25,20 @@ */ public class ClusterDataProviderEvaluator { - private final Predicate<GenerateClustersConfig> supportsPredicate; - private final ClusterDataProvider clusterDataProvider; + private final Predicate<GenerateClustersConfig> supportsPredicate; + private final ClusterDataProvider clusterDataProvider; - public ClusterDataProviderEvaluator(Predicate<GenerateClustersConfig> supportsPredicate, ClusterDataProvider clusterDataProvider) { - this.supportsPredicate = supportsPredicate; - this.clusterDataProvider = clusterDataProvider; - } + public ClusterDataProviderEvaluator(Predicate<GenerateClustersConfig> supportsPredicate, + ClusterDataProvider clusterDataProvider) { + this.supportsPredicate = supportsPredicate; + this.clusterDataProvider = clusterDataProvider; + } - public boolean supports(GenerateClustersConfig config) { - return supportsPredicate.test(config); - } + public boolean supports(GenerateClustersConfig config) { + return supportsPredicate.test(config); + } - public ClusterDataProvider getProvider() { - return clusterDataProvider; - } + public ClusterDataProvider getProvider() { + return clusterDataProvider; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImpl.java index 3d8c176b72..a1509b40f9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImpl.java @@ -16,11 +16,24 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; +import static com.epam.ta.reportportal.ws.converter.converters.LaunchConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_IS_NOT_FINISHED; + +import com.epam.reportportal.events.ElementsDeletedEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.ElementsCounterService; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.events.activity.LaunchDeletedEvent; import com.epam.ta.reportportal.core.launch.DeleteLaunchHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.core.remover.ContentRemover; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -28,24 +41,23 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.*; +import com.epam.ta.reportportal.ws.model.DeleteBulkRQ; +import com.epam.ta.reportportal.ws.model.DeleteBulkRS; +import com.epam.ta.reportportal.ws.model.ErrorRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.activity.LaunchActivityResource; +import com.google.api.client.util.Maps; import com.google.common.collect.Lists; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; -import static com.epam.ta.reportportal.ws.converter.converters.LaunchConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; /** * Default implementation of {@link com.epam.ta.reportportal.core.launch.DeleteLaunchHandler} @@ -57,100 +69,134 @@ @Service public class DeleteLaunchHandlerImpl implements DeleteLaunchHandler { - private final ContentRemover<Launch> launchContentRemover; - - private final LaunchRepository launchRepository; - - private final MessageBus messageBus; - - private final LogIndexer logIndexer; - - private final AttachmentRepository attachmentRepository; - - @Autowired - public DeleteLaunchHandlerImpl(ContentRemover<Launch> launchContentRemover, LaunchRepository launchRepository, MessageBus messageBus, - LogIndexer logIndexer, AttachmentRepository attachmentRepository) { - this.launchContentRemover = launchContentRemover; - this.launchRepository = launchRepository; - this.messageBus = messageBus; - this.logIndexer = logIndexer; - this.attachmentRepository = attachmentRepository; - } - - public OperationCompletionRS deleteLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); - validate(launch, user, projectDetails); - - logIndexer.indexLaunchesRemove(projectDetails.getProjectId(), Lists.newArrayList(launchId)); - launchContentRemover.remove(launch); - launchRepository.delete(launch); - attachmentRepository.moveForDeletionByLaunchId(launchId); - - messageBus.publishActivity(new LaunchDeletedEvent(TO_ACTIVITY_RESOURCE.apply(launch), user.getUserId(), user.getUsername())); - return new OperationCompletionRS("Launch with ID = '" + launchId + "' successfully deleted."); - } - - public DeleteBulkRS deleteLaunches(DeleteBulkRQ deleteBulkRQ, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - List<Long> notFound = Lists.newArrayList(); - List<ReportPortalException> exceptions = Lists.newArrayList(); - List<Launch> toDelete = Lists.newArrayList(); - List<Long> launchIds = Lists.newArrayList(); - - deleteBulkRQ.getIds().forEach(id -> { - Optional<Launch> optionalLaunch = launchRepository.findById(id); - if (optionalLaunch.isPresent()) { - Launch launch = optionalLaunch.get(); - try { - validate(launch, user, projectDetails); - toDelete.add(launch); - launchIds.add(id); - } catch (ReportPortalException ex) { - exceptions.add(ex); - } - } else { - notFound.add(id); - } - }); - - if (CollectionUtils.isNotEmpty(launchIds)) { - logIndexer.indexLaunchesRemove(projectDetails.getProjectId(), launchIds); - toDelete.forEach(launchContentRemover::remove); - launchRepository.deleteAll(toDelete); - attachmentRepository.moveForDeletionByLaunchIds(launchIds); - } - - toDelete.stream() - .map(TO_ACTIVITY_RESOURCE) - .forEach(it -> messageBus.publishActivity(new LaunchDeletedEvent(it, user.getUserId(), user.getUsername()))); - - return new DeleteBulkRS(launchIds, notFound, exceptions.stream().map(ex -> { - ErrorRS errorResponse = new ErrorRS(); - errorResponse.setErrorType(ex.getErrorType()); - errorResponse.setMessage(ex.getMessage()); - return errorResponse; - }).collect(Collectors.toList())); - } - - /** - * Validate user credentials and {@link Launch#getStatus()} - * - * @param launch {@link Launch} - * @param user {@link ReportPortalUser} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - */ - private void validate(Launch launch, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - expect(launch, not(l -> StatusEnum.IN_PROGRESS.equals(l.getStatus()))).verify(LAUNCH_IS_NOT_FINISHED, - formattedSupplier("Unable to delete launch '{}' in progress state", launch.getId()) - ); - if (!UserRole.ADMINISTRATOR.equals(user.getUserRole())) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Target launch '{}' not under specified project '{}'", launch.getId(), projectDetails.getProjectId()) - ); - /* Only PROJECT_MANAGER roles could delete launches */ - if (projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, "You are not launch owner."); - } - } - } + private final ContentRemover<Launch> launchContentRemover; + + private final LaunchRepository launchRepository; + + private final MessageBus messageBus; + + private final LogIndexer logIndexer; + + private final AttachmentRepository attachmentRepository; + + private final ApplicationEventPublisher eventPublisher; + + private final ElementsCounterService elementsCounterService; + + private final LogService logService; + + @Autowired + public DeleteLaunchHandlerImpl(ContentRemover<Launch> launchContentRemover, + LaunchRepository launchRepository, MessageBus messageBus, + LogIndexer logIndexer, AttachmentRepository attachmentRepository, + ApplicationEventPublisher eventPublisher, + ElementsCounterService elementsCounterService, LogService logService) { + this.launchContentRemover = launchContentRemover; + this.launchRepository = launchRepository; + this.messageBus = messageBus; + this.logIndexer = logIndexer; + this.attachmentRepository = attachmentRepository; + this.eventPublisher = eventPublisher; + this.elementsCounterService = elementsCounterService; + this.logService = logService; + } + + public OperationCompletionRS deleteLaunch(Long launchId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); + validate(launch, user, projectDetails); + final Long numberOfLaunchElements = elementsCounterService.countNumberOfLaunchElements( + launchId); + + logIndexer.indexLaunchesRemove(projectDetails.getProjectId(), Lists.newArrayList(launchId)); + launchContentRemover.remove(launch); + logService.deleteLogMessageByLaunch(projectDetails.getProjectId(), launch.getId()); + launchRepository.delete(launch); + attachmentRepository.moveForDeletionByLaunchId(launchId); + + messageBus.publishActivity( + new LaunchDeletedEvent(TO_ACTIVITY_RESOURCE.apply(launch), user.getUserId(), + user.getUsername())); + eventPublisher.publishEvent( + new ElementsDeletedEvent(launchId, launch.getProjectId(), numberOfLaunchElements)); + return new OperationCompletionRS("Launch with ID = '" + launchId + "' successfully deleted."); + } + + public DeleteBulkRS deleteLaunches(DeleteBulkRQ deleteBulkRQ, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { + List<Long> notFound = Lists.newArrayList(); + List<ReportPortalException> exceptions = Lists.newArrayList(); + Map<Launch, Long> toDelete = Maps.newHashMap(); + List<Long> launchIds = Lists.newArrayList(); + + deleteBulkRQ.getIds().forEach(id -> { + Optional<Launch> optionalLaunch = launchRepository.findById(id); + if (optionalLaunch.isPresent()) { + Launch launch = optionalLaunch.get(); + try { + validate(launch, user, projectDetails); + Long numberOfLaunchElements = elementsCounterService.countNumberOfLaunchElements( + launch.getId()); + toDelete.put(launch, numberOfLaunchElements); + launchIds.add(id); + } catch (ReportPortalException ex) { + exceptions.add(ex); + } + } else { + notFound.add(id); + } + }); + + if (CollectionUtils.isNotEmpty(launchIds)) { + logIndexer.indexLaunchesRemove(projectDetails.getProjectId(), launchIds); + toDelete.keySet().forEach(launchContentRemover::remove); + logService.deleteLogMessageByLaunchList(projectDetails.getProjectId(), launchIds); + launchRepository.deleteAll(toDelete.keySet()); + attachmentRepository.moveForDeletionByLaunchIds(launchIds); + } + + toDelete.entrySet().forEach(entry -> { + LaunchActivityResource launchActivity = TO_ACTIVITY_RESOURCE.apply(entry.getKey()); + messageBus.publishActivity( + new LaunchDeletedEvent(launchActivity, user.getUserId(), user.getUsername())); + eventPublisher.publishEvent( + new ElementsDeletedEvent(entry.getKey().getId(), entry.getKey().getProjectId(), + entry.getValue())); + }); + + return new DeleteBulkRS(launchIds, notFound, exceptions.stream().map(ex -> { + ErrorRS errorResponse = new ErrorRS(); + errorResponse.setErrorType(ex.getErrorType()); + errorResponse.setMessage(ex.getMessage()); + return errorResponse; + }).collect(Collectors.toList())); + } + + /** + * Validate user credentials and {@link Launch#getStatus()} + * + * @param launch {@link Launch} + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + */ + private void validate(Launch launch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + expect(launch, not(l -> StatusEnum.IN_PROGRESS.equals(l.getStatus()))).verify( + LAUNCH_IS_NOT_FINISHED, + formattedSupplier("Unable to delete launch '{}' in progress state", launch.getId()) + ); + if (!UserRole.ADMINISTRATOR.equals(user.getUserRole())) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + formattedSupplier("Target launch '{}' not under specified project '{}'", launch.getId(), + projectDetails.getProjectId()) + ); + /* Only PROJECT_MANAGER roles could delete launches */ + if (projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, + "You are not launch owner."); + } + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImpl.java index 97402bdcbd..04221771f3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.launch.FinishLaunchHandler; import com.epam.ta.reportportal.util.ReportingQueueService; @@ -23,15 +25,12 @@ import com.epam.ta.reportportal.ws.model.launch.FinishLaunchRS; import com.epam.ta.reportportal.ws.rabbit.MessageHeaders; import com.epam.ta.reportportal.ws.rabbit.RequestType; +import java.util.Map; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; - /** * @author Konstantin Antipin */ @@ -39,30 +38,32 @@ @Qualifier("finishLaunchHandlerAsync") public class FinishLaunchHandlerAsyncImpl implements FinishLaunchHandler { - @Autowired - @Qualifier(value = "rabbitTemplate") - AmqpTemplate amqpTemplate; + @Autowired + @Qualifier(value = "rabbitTemplate") + AmqpTemplate amqpTemplate; - @Autowired - private ReportingQueueService reportingQueueService; + @Autowired + private ReportingQueueService reportingQueueService; - @Override - public FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ request, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String baseUrl) { + @Override + public FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ request, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, String baseUrl) { - // todo: may be problem - no access to repository, so no possibility to validateRoles() here - amqpTemplate.convertAndSend(EXCHANGE_REPORTING, reportingQueueService.getReportingQueueKey(launchId), request, message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.FINISH_LAUNCH); - headers.put(MessageHeaders.USERNAME, user.getUsername()); - headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); - headers.put(MessageHeaders.LAUNCH_ID, launchId); - headers.put(MessageHeaders.BASE_URL, baseUrl); - return message; - }); + // todo: may be problem - no access to repository, so no possibility to validateRoles() here + amqpTemplate.convertAndSend(EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey(launchId), request, message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.FINISH_LAUNCH); + headers.put(MessageHeaders.USERNAME, user.getUsername()); + headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); + headers.put(MessageHeaders.LAUNCH_ID, launchId); + headers.put(MessageHeaders.BASE_URL, baseUrl); + return message; + }); - FinishLaunchRS response = new FinishLaunchRS(); - response.setId(launchId); - return response; - } + FinishLaunchRS response = new FinishLaunchRS(); + response.setId(launchId); + return response; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImpl.java index 94a02d5cb1..4e1d71a82a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImpl.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.core.launch.util.LaunchValidator.validate; +import static com.epam.ta.reportportal.core.launch.util.LaunchValidator.validateRoles; +import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.generateLaunchLink; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; + +import com.epam.reportportal.extension.event.LaunchFinishedPluginEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.hierarchy.FinishHierarchyHandler; @@ -27,6 +35,7 @@ import com.epam.ta.reportportal.ws.converter.builders.LaunchBuilder; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.launch.FinishLaunchRS; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; @@ -34,15 +43,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.launch.util.LaunchValidator.validate; -import static com.epam.ta.reportportal.core.launch.util.LaunchValidator.validateRoles; -import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.generateLaunchLink; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; -import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; - /** * Default implementation of {@link FinishLaunchHandler} * @@ -53,72 +53,78 @@ @Transactional public class FinishLaunchHandlerImpl implements FinishLaunchHandler { - private final LaunchRepository launchRepository; - private final FinishHierarchyHandler<Launch> finishHierarchyHandler; - private final ApplicationEventPublisher eventPublisher; - - @Autowired - public FinishLaunchHandlerImpl(LaunchRepository launchRepository, - @Qualifier("finishLaunchHierarchyHandler") FinishHierarchyHandler<Launch> finishHierarchyHandler, - ApplicationEventPublisher eventPublisher) { - this.launchRepository = launchRepository; - this.finishHierarchyHandler = finishHierarchyHandler; - this.eventPublisher = eventPublisher; - } - - @Override - public FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ finishLaunchRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, String baseUrl) { - Launch launch = launchRepository.findByUuid(launchId).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); - - validateRoles(launch, user, projectDetails); - validate(launch, finishLaunchRQ); - - Optional<StatusEnum> status = StatusEnum.fromValue(finishLaunchRQ.getStatus()); - - Long id = launch.getId(); - - final int finishedCount = finishHierarchyHandler.finishDescendants(launch, - status.orElse(StatusEnum.INTERRUPTED), - finishLaunchRQ.getEndTime(), - user, - projectDetails - ); - if (finishedCount > 0) { - launch.setStatus(launchRepository.hasRootItemsWithStatusNotEqual(id, - StatusEnum.PASSED.name(), - StatusEnum.INFO.name(), - StatusEnum.WARN.name() - ) ? FAILED : PASSED); - } else { - launch.setStatus(status.orElseGet(() -> launchRepository.hasRootItemsWithStatusNotEqual(id, - StatusEnum.PASSED.name(), - StatusEnum.INFO.name(), - StatusEnum.WARN.name() - ) ? FAILED : PASSED)); - } - - launch = new LaunchBuilder(launch).addDescription(buildDescription(launch.getDescription(), finishLaunchRQ.getDescription())) - .addAttributes(finishLaunchRQ.getAttributes()) - .addEndTime(finishLaunchRQ.getEndTime()) - .get(); - - LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, baseUrl); - eventPublisher.publishEvent(event); - - FinishLaunchRS response = new FinishLaunchRS(); - response.setId(launch.getUuid()); - response.setNumber(launch.getNumber()); - response.setLink(generateLaunchLink(baseUrl, projectDetails.getProjectName(), String.valueOf(launch.getId()))); - return response; - } - - private String buildDescription(String existDescription, String fromRequestDescription) { - if (null != existDescription) { - return null != fromRequestDescription ? existDescription + " " + fromRequestDescription : existDescription; - } else { - return null; - } - } + private final LaunchRepository launchRepository; + private final FinishHierarchyHandler<Launch> finishHierarchyHandler; + private final ApplicationEventPublisher eventPublisher; + + @Autowired + public FinishLaunchHandlerImpl(LaunchRepository launchRepository, + @Qualifier("finishLaunchHierarchyHandler") FinishHierarchyHandler<Launch> finishHierarchyHandler, + ApplicationEventPublisher eventPublisher) { + this.launchRepository = launchRepository; + this.finishHierarchyHandler = finishHierarchyHandler; + this.eventPublisher = eventPublisher; + } + + @Override + public FinishLaunchRS finishLaunch(String launchId, FinishExecutionRQ finishLaunchRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, String baseUrl) { + Launch launch = launchRepository.findByUuid(launchId) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); + + validateRoles(launch, user, projectDetails); + validate(launch, finishLaunchRQ); + + Optional<StatusEnum> status = StatusEnum.fromValue(finishLaunchRQ.getStatus()); + + Long id = launch.getId(); + + final int finishedCount = finishHierarchyHandler.finishDescendants(launch, + status.orElse(StatusEnum.INTERRUPTED), + finishLaunchRQ.getEndTime(), + user, + projectDetails + ); + if (finishedCount > 0) { + launch.setStatus(launchRepository.hasRootItemsWithStatusNotEqual(id, + StatusEnum.PASSED.name(), + StatusEnum.INFO.name(), + StatusEnum.WARN.name() + ) ? FAILED : PASSED); + } else { + launch.setStatus(status.orElseGet(() -> launchRepository.hasRootItemsWithStatusNotEqual(id, + StatusEnum.PASSED.name(), + StatusEnum.INFO.name(), + StatusEnum.WARN.name() + ) ? FAILED : PASSED)); + } + + launch = new LaunchBuilder(launch).addDescription( + buildDescription(launch.getDescription(), finishLaunchRQ.getDescription())) + .addAttributes(finishLaunchRQ.getAttributes()) + .addEndTime(finishLaunchRQ.getEndTime()) + .get(); + + eventPublisher.publishEvent( + new LaunchFinishedPluginEvent(launch.getId(), launch.getProjectId())); + eventPublisher.publishEvent(new LaunchFinishedEvent(launch, user, baseUrl)); + + FinishLaunchRS response = new FinishLaunchRS(); + response.setId(launch.getUuid()); + response.setNumber(launch.getNumber()); + response.setLink(generateLaunchLink(baseUrl, projectDetails.getProjectName(), + String.valueOf(launch.getId()))); + return response; + } + + private String buildDescription(String existDescription, String fromRequestDescription) { + if (null != existDescription) { + return null != fromRequestDescription ? existDescription + " " + fromRequestDescription + : existDescription; + } else { + return null; + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImpl.java index c432c07fc2..28d2093850 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImpl.java @@ -16,17 +16,57 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.commons.Preconditions.HAS_ANY_MODE; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.querygen.Condition.EQUALS; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_NO_DEFECT_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_FAILED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_SKIPPED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_FILTER_PARAMETERS; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_LAUNCH_NAME_LENGTH; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_LAUNCH_NAME_LENGTH; +import static com.epam.ta.reportportal.ws.model.launch.Mode.DEBUG; +import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; +import static java.util.Collections.singletonMap; +import static java.util.Optional.ofNullable; + import com.epam.reportportal.extension.event.GetLaunchResourceCollectionEvent; import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.ProjectFilter; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.jasper.GetJasperReportHandler; import com.epam.ta.reportportal.core.jasper.constants.LaunchReportConstants; import com.epam.ta.reportportal.core.jasper.util.JasperDataProvider; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.core.launch.cluster.GetClusterHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.ItemAttributeRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.dao.UserRepository; +import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.jasper.ReportFormat; @@ -44,6 +84,14 @@ import com.epam.ta.reportportal.ws.model.launch.cluster.ClusterInfoResource; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import net.sf.jasperreports.engine.JREmptyDataSource; import net.sf.jasperreports.engine.JasperPrint; import org.springframework.beans.factory.annotation.Autowired; @@ -55,30 +103,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.OutputStream; -import java.util.*; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Preconditions.HAS_ANY_MODE; -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.commons.Predicates.*; -import static com.epam.ta.reportportal.commons.querygen.Condition.EQUALS; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_LAUNCH_NAME_LENGTH; -import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_LAUNCH_NAME_LENGTH; -import static com.epam.ta.reportportal.ws.model.launch.Mode.DEBUG; -import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; -import static java.util.Collections.singletonMap; -import static java.util.Optional.ofNullable; - /** * Default implementation of {@link com.epam.ta.reportportal.core.launch.GetLaunchHandler} * @@ -88,281 +112,314 @@ @Service public class GetLaunchHandlerImpl implements GetLaunchHandler { - private final GetClusterHandler getClusterHandler; - private final LaunchRepository launchRepository; - private final TestItemRepository testItemRepository; - private final ItemAttributeRepository itemAttributeRepository; - private final ProjectRepository projectRepository; - private final WidgetContentRepository widgetContentRepository; - private final UserRepository userRepository; - private final JasperDataProvider dataProvider; - private final GetJasperReportHandler<Launch> jasperReportHandler; - private final LaunchConverter launchConverter; - private final ApplicationEventPublisher applicationEventPublisher; - - @Autowired - public GetLaunchHandlerImpl(GetClusterHandler getClusterHandler, LaunchRepository launchRepository, - TestItemRepository testItemRepository, ItemAttributeRepository itemAttributeRepository, ProjectRepository projectRepository, - WidgetContentRepository widgetContentRepository, UserRepository userRepository, JasperDataProvider dataProvider, - @Qualifier("launchJasperReportHandler") GetJasperReportHandler<Launch> jasperReportHandler, LaunchConverter launchConverter, - ApplicationEventPublisher applicationEventPublisher) { - this.getClusterHandler = getClusterHandler; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.itemAttributeRepository = itemAttributeRepository; - this.projectRepository = projectRepository; - this.widgetContentRepository = widgetContentRepository; - this.userRepository = userRepository; - this.dataProvider = Preconditions.checkNotNull(dataProvider); - this.jasperReportHandler = jasperReportHandler; - this.launchConverter = launchConverter; - this.applicationEventPublisher = applicationEventPublisher; - } - - @Override - public Launch get(Long id) { - return launchRepository.findById(id).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, id)); - } - - @Override - public LaunchResource getLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails) { - final Launch launch = findLaunch(launchId, projectDetails); - return getLaunchResource(launch); - } - - private Launch findLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails) { - Launch launch; - try { - launch = get(Long.parseLong(launchId)); - } catch (NumberFormatException e) { - launch = launchRepository.findByUuid(launchId).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); - } - validate(launch, projectDetails); - return launch; - } - - @Override - public LaunchResource getLaunchByProjectName(String projectName, Pageable pageable, Filter filter, String username) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - - Page<Launch> launches = launchRepository.findByFilter(ProjectFilter.of(filter, project.getId()), pageable); - expect(launches, notNull()).verify(LAUNCH_NOT_FOUND); - return getLaunchResource(launches.iterator().next()); - } - - private LaunchResource getLaunchResource(Launch launch) { - final LaunchResource launchResource = launchConverter.TO_RESOURCE.apply(launch); - applicationEventPublisher.publishEvent(new GetLaunchResourceCollectionEvent(Collections.singletonList(launchResource))); - return launchResource; - } - - @Override - public Iterable<LaunchResource> getProjectLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable, - String userName) { - validateModeConditions(filter); - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectDetails.getProjectId())); - - filter = addLaunchCommonCriteria(DEFAULT, filter); - Page<Launch> launches = launchRepository.findByFilter(ProjectFilter.of(filter, project.getId()), pageable); - return getLaunchResources(launches); - } - - /* - * Changed logic for this method: It should return DEBUG launches for - * project users, for specified user or only owner - */ - @Override - public Iterable<LaunchResource> getDebugLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable) { - validateModeConditions(filter); - filter = addLaunchCommonCriteria(DEBUG, filter); - Page<Launch> launches = launchRepository.findByFilter(ProjectFilter.of(filter, projectDetails.getProjectId()), pageable); - return getLaunchResources(launches); - } - - @Override - public List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, String value) { - return itemAttributeRepository.findLaunchAttributeKeys(projectDetails.getProjectId(), value, false); - } - - @Override - public List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String key, String value) { - return itemAttributeRepository.findLaunchAttributeValues(projectDetails.getProjectId(), key, value, false); - } - - @Override - public Iterable<LaunchResource> getLatestLaunches(ReportPortalUser.ProjectDetails projectDetails, Filter filter, Pageable pageable) { - - validateModeConditions(filter); - - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectDetails.getProjectId())); - - filter = addLaunchCommonCriteria(DEFAULT, filter); - - Page<Launch> launches = launchRepository.findAllLatestByFilter(ProjectFilter.of(filter, project.getId()), pageable); - return getLaunchResources(launches); - } - - @Override - @Transactional(readOnly = true) - public Iterable<ClusterInfoResource> getClusters(String launchId, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable) { - final Launch launch = findLaunch(launchId, projectDetails); - return getClusterHandler.getResources(launch, pageable); - } - - @Override - public boolean hasItemsWithIssues(Launch launch) { - return testItemRepository.hasItemsWithIssueByLaunch(launch.getId()); - } - - private Iterable<LaunchResource> getLaunchResources(Page<Launch> launches) { - final com.epam.ta.reportportal.ws.model.Page<LaunchResource> launchResourcePage = PagedResourcesAssembler.pageConverter( - launchConverter.TO_RESOURCE).apply(launches); - applicationEventPublisher.publishEvent(new GetLaunchResourceCollectionEvent(launchResourcePage.getContent())); - return launchResourcePage; - } - - @Override - public List<String> getLaunchNames(ReportPortalUser.ProjectDetails projectDetails, String value) { - expect(value.length() >= MIN_LAUNCH_NAME_LENGTH && value.length() <= MAX_LAUNCH_NAME_LENGTH, equalTo(true)).verify( - INCORRECT_FILTER_PARAMETERS, - formattedSupplier("Length of the launch name string '{}' is less than {} symbols or more than {} symbols", - value, - MIN_LAUNCH_NAME_LENGTH, - MAX_LAUNCH_NAME_LENGTH - ) - ); - return launchRepository.getLaunchNamesByModeExcludedByStatus(projectDetails.getProjectId(), - value, - LaunchModeEnum.DEFAULT, - StatusEnum.IN_PROGRESS - ); - } - - @Override - public List<String> getOwners(ReportPortalUser.ProjectDetails projectDetails, String value, String mode) { - expect(value.length() > 2, equalTo(true)).verify(INCORRECT_FILTER_PARAMETERS, - formattedSupplier("Length of the filtering string '{}' is less than 3 symbols", value) - ); - - LaunchModeEnum launchMode = LaunchModeEnum.findByName(mode) - .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, - formattedSupplier("Mode - {} doesn't exist.", mode) - )); - - return launchRepository.getOwnerNames(projectDetails.getProjectId(), value, launchMode.name()); - } - - @Override - public Map<String, List<ChartStatisticsContent>> getLaunchesComparisonInfo(ReportPortalUser.ProjectDetails projectDetails, Long[] ids) { - - List<String> contentFields = Lists.newArrayList(DEFECTS_AUTOMATION_BUG_TOTAL, - DEFECTS_NO_DEFECT_TOTAL, - DEFECTS_PRODUCT_BUG_TOTAL, - DEFECTS_SYSTEM_ISSUE_TOTAL, - DEFECTS_TO_INVESTIGATE_TOTAL, - EXECUTIONS_FAILED, - EXECUTIONS_PASSED, - EXECUTIONS_SKIPPED - ); - - Filter filter = Filter.builder() - .withTarget(Launch.class) - .withCondition(new FilterCondition(Condition.IN, - false, - Arrays.stream(ids).map(String::valueOf).collect(Collectors.joining(",")), - CRITERIA_ID - )) - .withCondition(new FilterCondition(EQUALS, false, String.valueOf(projectDetails.getProjectId()), CRITERIA_PROJECT_ID)) - .build(); - - List<ChartStatisticsContent> result = widgetContentRepository.launchesComparisonStatistics(filter, - contentFields, - Sort.unsorted(), - ids.length - ); - - return singletonMap(RESULT, result); - - } - - @Override - public Map<String, String> getStatuses(ReportPortalUser.ProjectDetails projectDetails, Long[] ids) { - return launchRepository.getStatuses(projectDetails.getProjectId(), ids); - } - - @Override - public void exportLaunch(Long launchId, ReportFormat reportFormat, OutputStream outputStream, ReportPortalUser user) { - - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); - expect(launch.getStatus(), not(statusIn(IN_PROGRESS))).verify(ErrorType.FORBIDDEN_OPERATION, - Suppliers.formattedSupplier("Launch '{}' has IN_PROGRESS status. Impossible to export such elements.", launchId) - ); - - String userFullName = userRepository.findById(user.getUserId()) - .map(User::getFullName) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, user.getUserId())); - - Map<String, Object> params = jasperReportHandler.convertParams(launch); - - fillWithAdditionalParams(params, launch, userFullName); - - JasperPrint jasperPrint = jasperReportHandler.getJasperPrint(params, new JREmptyDataSource()); - - jasperReportHandler.writeReport(reportFormat, outputStream, jasperPrint); - - } - - /** - * Validate user credentials and launch affiliation to the project - * - * @param launch {@link Launch} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - */ - private void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { - expect(launch.getProjectId(), Predicates.equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); - if (LaunchModeEnum.DEBUG.equals(launch.getMode())) { - expect(projectDetails.getProjectRole(), not(Predicates.equalTo(ProjectRole.CUSTOMER))).verify(ACCESS_DENIED); - } - } - - /** - * Add to filter project and mode criteria - * - * @param filter Filter to update - * @return Updated filter - */ - private Filter addLaunchCommonCriteria(Mode mode, Filter filter) { - return ofNullable(filter).orElseGet(() -> new Filter(Launch.class, Lists.newArrayList())) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, mode.name()).build()); - } - - /** - * Validate if filter doesn't contain any "mode" related conditions. - * - * @param filter - */ - private void validateModeConditions(Filter filter) { - expect(filter.getFilterConditions() - .stream() - .map(ConvertibleCondition::getAllConditions) - .flatMap(Collection::stream) - .anyMatch(HAS_ANY_MODE), equalTo(false)).verify(INCORRECT_FILTER_PARAMETERS, - "Filters for 'mode' aren't applicable for project's launches." - ); - } - - private void fillWithAdditionalParams(Map<String, Object> params, Launch launch, String userFullName) { - - Optional<String> owner = userRepository.findById(launch.getUserId()).map(User::getFullName); - - /* Check if launch owner still in system if not - setup principal */ - params.put(LaunchReportConstants.OWNER, owner.orElse(userFullName)); - - params.put(LaunchReportConstants.TEST_ITEMS, dataProvider.getTestItemsOfLaunch(launch)); - } + private final GetClusterHandler getClusterHandler; + private final LaunchRepository launchRepository; + private final TestItemRepository testItemRepository; + private final ItemAttributeRepository itemAttributeRepository; + private final ProjectRepository projectRepository; + private final WidgetContentRepository widgetContentRepository; + private final UserRepository userRepository; + private final JasperDataProvider dataProvider; + private final GetJasperReportHandler<Launch> jasperReportHandler; + private final LaunchConverter launchConverter; + private final ApplicationEventPublisher applicationEventPublisher; + + @Autowired + public GetLaunchHandlerImpl(GetClusterHandler getClusterHandler, + LaunchRepository launchRepository, + TestItemRepository testItemRepository, ItemAttributeRepository itemAttributeRepository, + ProjectRepository projectRepository, + WidgetContentRepository widgetContentRepository, UserRepository userRepository, + JasperDataProvider dataProvider, + @Qualifier("launchJasperReportHandler") GetJasperReportHandler<Launch> jasperReportHandler, + LaunchConverter launchConverter, + ApplicationEventPublisher applicationEventPublisher) { + this.getClusterHandler = getClusterHandler; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.itemAttributeRepository = itemAttributeRepository; + this.projectRepository = projectRepository; + this.widgetContentRepository = widgetContentRepository; + this.userRepository = userRepository; + this.dataProvider = Preconditions.checkNotNull(dataProvider); + this.jasperReportHandler = jasperReportHandler; + this.launchConverter = launchConverter; + this.applicationEventPublisher = applicationEventPublisher; + } + + @Override + public Launch get(Long id) { + return launchRepository.findById(id) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, id)); + } + + @Override + public LaunchResource getLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails) { + final Launch launch = findLaunch(launchId, projectDetails); + return getLaunchResource(launch); + } + + private Launch findLaunch(String launchId, ReportPortalUser.ProjectDetails projectDetails) { + Launch launch; + try { + launch = get(Long.parseLong(launchId)); + } catch (NumberFormatException e) { + launch = launchRepository.findByUuid(launchId) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); + } + validate(launch, projectDetails); + return launch; + } + + @Override + public LaunchResource getLaunchByProjectName(String projectName, Pageable pageable, Filter filter, + String username) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + + Page<Launch> launches = launchRepository.findByFilter(ProjectFilter.of(filter, project.getId()), + pageable); + expect(launches, notNull()).verify(LAUNCH_NOT_FOUND); + return getLaunchResource(launches.iterator().next()); + } + + private LaunchResource getLaunchResource(Launch launch) { + final LaunchResource launchResource = launchConverter.TO_RESOURCE.apply(launch); + applicationEventPublisher.publishEvent( + new GetLaunchResourceCollectionEvent(Collections.singletonList(launchResource))); + return launchResource; + } + + @Override + public Iterable<LaunchResource> getProjectLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable, + String userName) { + validateModeConditions(filter); + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, + projectDetails.getProjectId())); + + filter = addLaunchCommonCriteria(DEFAULT, filter); + Page<Launch> launches = launchRepository.findByFilter(ProjectFilter.of(filter, project.getId()), + pageable); + return getLaunchResources(launches); + } + + /* + * Changed logic for this method: It should return DEBUG launches for + * project users, for specified user or only owner + */ + @Override + public Iterable<LaunchResource> getDebugLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable) { + validateModeConditions(filter); + filter = addLaunchCommonCriteria(DEBUG, filter); + Page<Launch> launches = launchRepository.findByFilter( + ProjectFilter.of(filter, projectDetails.getProjectId()), pageable); + return getLaunchResources(launches); + } + + @Override + public List<String> getAttributeKeys(ReportPortalUser.ProjectDetails projectDetails, + String value) { + return itemAttributeRepository.findLaunchAttributeKeys(projectDetails.getProjectId(), value, + false); + } + + @Override + public List<String> getAttributeValues(ReportPortalUser.ProjectDetails projectDetails, String key, + String value) { + return itemAttributeRepository.findLaunchAttributeValues(projectDetails.getProjectId(), key, + value, false); + } + + @Override + public Iterable<LaunchResource> getLatestLaunches(ReportPortalUser.ProjectDetails projectDetails, + Filter filter, Pageable pageable) { + + validateModeConditions(filter); + + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, + projectDetails.getProjectId())); + + filter = addLaunchCommonCriteria(DEFAULT, filter); + + Page<Launch> launches = launchRepository.findAllLatestByFilter( + ProjectFilter.of(filter, project.getId()), pageable); + return getLaunchResources(launches); + } + + @Override + @Transactional(readOnly = true) + public Iterable<ClusterInfoResource> getClusters(String launchId, + ReportPortalUser.ProjectDetails projectDetails, Pageable pageable) { + final Launch launch = findLaunch(launchId, projectDetails); + return getClusterHandler.getResources(launch, pageable); + } + + @Override + public boolean hasItemsWithIssues(Launch launch) { + return testItemRepository.hasItemsWithIssueByLaunch(launch.getId()); + } + + private Iterable<LaunchResource> getLaunchResources(Page<Launch> launches) { + final com.epam.ta.reportportal.ws.model.Page<LaunchResource> launchResourcePage = PagedResourcesAssembler.pageConverter( + launchConverter.TO_RESOURCE).apply(launches); + applicationEventPublisher.publishEvent( + new GetLaunchResourceCollectionEvent(launchResourcePage.getContent())); + return launchResourcePage; + } + + @Override + public List<String> getLaunchNames(ReportPortalUser.ProjectDetails projectDetails, String value) { + expect(value.length() <= MAX_LAUNCH_NAME_LENGTH, equalTo(true)).verify( + INCORRECT_FILTER_PARAMETERS, + formattedSupplier("Length of the launch name string '{}' more than {} symbols", + value, + MAX_LAUNCH_NAME_LENGTH + ) + ); + return launchRepository.getLaunchNamesByModeExcludedByStatus(projectDetails.getProjectId(), + value, + LaunchModeEnum.DEFAULT, + StatusEnum.IN_PROGRESS + ); + } + + @Override + public List<String> getOwners(ReportPortalUser.ProjectDetails projectDetails, String value, + String mode) { + expect(value.length() > 2, equalTo(true)).verify(INCORRECT_FILTER_PARAMETERS, + formattedSupplier("Length of the filtering string '{}' is less than 3 symbols", value) + ); + + LaunchModeEnum launchMode = LaunchModeEnum.findByName(mode) + .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, + formattedSupplier("Mode - {} doesn't exist.", mode) + )); + + return launchRepository.getOwnerNames(projectDetails.getProjectId(), value, launchMode.name()); + } + + @Override + public Map<String, List<ChartStatisticsContent>> getLaunchesComparisonInfo( + ReportPortalUser.ProjectDetails projectDetails, Long[] ids) { + + List<String> contentFields = Lists.newArrayList(DEFECTS_AUTOMATION_BUG_TOTAL, + DEFECTS_NO_DEFECT_TOTAL, + DEFECTS_PRODUCT_BUG_TOTAL, + DEFECTS_SYSTEM_ISSUE_TOTAL, + DEFECTS_TO_INVESTIGATE_TOTAL, + EXECUTIONS_FAILED, + EXECUTIONS_PASSED, + EXECUTIONS_SKIPPED + ); + + Filter filter = Filter.builder() + .withTarget(Launch.class) + .withCondition(new FilterCondition(Condition.IN, + false, + Arrays.stream(ids).map(String::valueOf).collect(Collectors.joining(",")), + CRITERIA_ID + )) + .withCondition( + new FilterCondition(EQUALS, false, String.valueOf(projectDetails.getProjectId()), + CRITERIA_PROJECT_ID)) + .build(); + + List<ChartStatisticsContent> result = widgetContentRepository.launchesComparisonStatistics( + filter, + contentFields, + Sort.unsorted(), + ids.length + ); + + return singletonMap(RESULT, result); + + } + + @Override + public Map<String, String> getStatuses(ReportPortalUser.ProjectDetails projectDetails, + Long[] ids) { + return launchRepository.getStatuses(projectDetails.getProjectId(), ids); + } + + @Override + public void exportLaunch(Long launchId, ReportFormat reportFormat, OutputStream outputStream, + ReportPortalUser user) { + + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchId)); + expect(launch.getStatus(), not(statusIn(IN_PROGRESS))).verify(ErrorType.FORBIDDEN_OPERATION, + Suppliers.formattedSupplier( + "Launch '{}' has IN_PROGRESS status. Impossible to export such elements.", launchId) + ); + + String userFullName = userRepository.findById(user.getUserId()) + .map(User::getFullName) + .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, user.getUserId())); + + Map<String, Object> params = jasperReportHandler.convertParams(launch); + + fillWithAdditionalParams(params, launch, userFullName); + + JasperPrint jasperPrint = jasperReportHandler.getJasperPrint(params, new JREmptyDataSource()); + + jasperReportHandler.writeReport(reportFormat, outputStream, jasperPrint); + + } + + /** + * Validate user credentials and launch affiliation to the project + * + * @param launch {@link Launch} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + */ + private void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { + expect(launch.getProjectId(), Predicates.equalTo(projectDetails.getProjectId())).verify( + ACCESS_DENIED); + if (LaunchModeEnum.DEBUG.equals(launch.getMode())) { + expect(projectDetails.getProjectRole(), not(Predicates.equalTo(ProjectRole.CUSTOMER))).verify( + ACCESS_DENIED); + } + } + + /** + * Add to filter project and mode criteria + * + * @param filter Filter to update + * @return Updated filter + */ + private Filter addLaunchCommonCriteria(Mode mode, Filter filter) { + return ofNullable(filter).orElseGet(() -> new Filter(Launch.class, Lists.newArrayList())) + .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_MODE, mode.name()).build()); + } + + /** + * Validate if filter doesn't contain any "mode" related conditions. + * + * @param filter + */ + private void validateModeConditions(Filter filter) { + expect(filter.getFilterConditions() + .stream() + .map(ConvertibleCondition::getAllConditions) + .flatMap(Collection::stream) + .anyMatch(HAS_ANY_MODE), equalTo(false)).verify(INCORRECT_FILTER_PARAMETERS, + "Filters for 'mode' aren't applicable for project's launches." + ); + } + + private void fillWithAdditionalParams(Map<String, Object> params, Launch launch, + String userFullName) { + + Optional<String> owner = userRepository.findById(launch.getUserId()).map(User::getFullName); + + /* Check if launch owner still in system if not - setup principal */ + params.put(LaunchReportConstants.OWNER, owner.orElse(userFullName)); + + params.put(LaunchReportConstants.TEST_ITEMS, dataProvider.getTestItemsOfLaunch(launch)); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/MergeLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/MergeLaunchHandlerImpl.java index c6a6c5c50a..6d463d219e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/MergeLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/MergeLaunchHandlerImpl.java @@ -16,6 +16,19 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.entity.user.UserRole.ADMINISTRATOR; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_IS_NOT_FINISHED; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.UNSUPPORTED_MERGE_STRATEGY_TYPE; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -37,19 +50,12 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; +import java.util.List; +import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Set; - -import static com.epam.ta.reportportal.commons.Predicates.*; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; -import static com.epam.ta.reportportal.entity.user.UserRole.ADMINISTRATOR; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; - /** * @author Aliaksei_Makayed * @author Andrei_Ramanchuk @@ -58,102 +64,113 @@ @Service public class MergeLaunchHandlerImpl implements MergeLaunchHandler { - private final LaunchRepository launchRepository; - - private final TestItemRepository testItemRepository; - - private final ProjectRepository projectRepository; - - private final LaunchMergeFactory launchMergeFactory; - - private final LaunchConverter launchConverter; - - private final LaunchPreparerService launchPreparerService; - - private final LogIndexer logIndexer; - - @Autowired - public MergeLaunchHandlerImpl(LaunchRepository launchRepository, TestItemRepository testItemRepository, - ProjectRepository projectRepository, LaunchMergeFactory launchMergeFactory, LaunchConverter launchConverter, - LaunchPreparerService launchPreparerService, LogIndexer logIndexer) { - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.projectRepository = projectRepository; - this.launchMergeFactory = launchMergeFactory; - this.launchConverter = launchConverter; - this.launchPreparerService = launchPreparerService; - this.logIndexer = logIndexer; - } - - @Override - public LaunchResource mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, MergeLaunchesRQ rq) { - Project project = projectRepository.findById(projectDetails.getProjectId()) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectName())); - - Set<Long> launchesIds = rq.getLaunches(); - - expect(CollectionUtils.isNotEmpty(launchesIds), equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "At least one launch id should be specified for merging" - ); - - expect(launchesIds.size() > 0, equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "At least 1 launch id should be provided for merging" - ); - - List<Launch> launchesList = launchRepository.findAllById(launchesIds); - - expect(launchesIds.size(), equalTo(launchesList.size())).verify(ErrorType.BAD_REQUEST_ERROR, - "Not all launches with provided ids were found" - ); - - validateMergingLaunches(launchesList, user, projectDetails); - - MergeStrategyType type = MergeStrategyType.fromValue(rq.getMergeStrategyType()); - expect(type, notNull()).verify(UNSUPPORTED_MERGE_STRATEGY_TYPE, type); - - Launch newLaunch = launchMergeFactory.getLaunchMergeStrategy(type).mergeLaunches(projectDetails, user, rq, launchesList); - newLaunch.setStatus(StatisticsHelper.getStatusFromStatistics(newLaunch.getStatistics())); - - launchRepository.deleteAll(launchesList); - - logIndexer.indexLaunchLogs(newLaunch, AnalyzerUtils.getAnalyzerConfig(project)); - - return launchConverter.TO_RESOURCE.apply(newLaunch); - } - - /** - * Validations for merge launches request parameters and data - * - * @param launches {@link List} of the {@link Launch} - * @param user {@link ReportPortalUser} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - */ - private void validateMergingLaunches(List<Launch> launches, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - - /* - * ADMINISTRATOR and PROJECT_MANAGER+ users have permission to merge not-only-own - * launches - */ - boolean isUserValidate = !(user.getUserRole().equals(ADMINISTRATOR) || projectDetails.getProjectRole() - .sameOrHigherThan(ProjectRole.PROJECT_MANAGER)); - - launches.forEach(launch -> { - expect(launch, notNull()).verify(LAUNCH_NOT_FOUND, launch); + private final LaunchRepository launchRepository; - expect(launch.getStatus(), not(Preconditions.statusIn(IN_PROGRESS))).verify(LAUNCH_IS_NOT_FINISHED, - Suppliers.formattedSupplier("Cannot merge launch '{}' with status '{}'", launch.getId(), launch.getStatus()) - ); + private final TestItemRepository testItemRepository; - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - "Impossible to merge launches from different projects." - ); + private final ProjectRepository projectRepository; - if (isUserValidate) { - expect(launch.getUserId(), equalTo(user.getUserId())).verify(ACCESS_DENIED, - "You are not an owner of launches or have less than PROJECT_MANAGER project role." - ); - } - }); - } + private final LaunchMergeFactory launchMergeFactory; + + private final LaunchConverter launchConverter; + + private final LaunchPreparerService launchPreparerService; + + private final LogIndexer logIndexer; + + @Autowired + public MergeLaunchHandlerImpl(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + ProjectRepository projectRepository, LaunchMergeFactory launchMergeFactory, + LaunchConverter launchConverter, + LaunchPreparerService launchPreparerService, LogIndexer logIndexer) { + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.projectRepository = projectRepository; + this.launchMergeFactory = launchMergeFactory; + this.launchConverter = launchConverter; + this.launchPreparerService = launchPreparerService; + this.logIndexer = logIndexer; + } + + @Override + public LaunchResource mergeLaunches(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, MergeLaunchesRQ rq) { + Project project = projectRepository.findById(projectDetails.getProjectId()) + .orElseThrow( + () -> new ReportPortalException(PROJECT_NOT_FOUND, projectDetails.getProjectName())); + + Set<Long> launchesIds = rq.getLaunches(); + + expect(CollectionUtils.isNotEmpty(launchesIds), equalTo(true)).verify( + ErrorType.BAD_REQUEST_ERROR, + "At least one launch id should be specified for merging" + ); + + expect(launchesIds.size() > 0, equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, + "At least 1 launch id should be provided for merging" + ); + + List<Launch> launchesList = launchRepository.findAllById(launchesIds); + + expect(launchesIds.size(), equalTo(launchesList.size())).verify(ErrorType.BAD_REQUEST_ERROR, + "Not all launches with provided ids were found" + ); + + validateMergingLaunches(launchesList, user, projectDetails); + + MergeStrategyType type = MergeStrategyType.fromValue(rq.getMergeStrategyType()); + expect(type, notNull()).verify(UNSUPPORTED_MERGE_STRATEGY_TYPE, type); + + Launch newLaunch = launchMergeFactory.getLaunchMergeStrategy(type) + .mergeLaunches(projectDetails, user, rq, launchesList); + newLaunch.setStatus(StatisticsHelper.getStatusFromStatistics(newLaunch.getStatistics())); + + launchRepository.deleteAll(launchesList); + + logIndexer.indexLaunchLogs(newLaunch, AnalyzerUtils.getAnalyzerConfig(project)); + + return launchConverter.TO_RESOURCE.apply(newLaunch); + } + + /** + * Validations for merge launches request parameters and data + * + * @param launches {@link List} of the {@link Launch} + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + */ + private void validateMergingLaunches(List<Launch> launches, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + + /* + * ADMINISTRATOR and PROJECT_MANAGER+ users have permission to merge not-only-own + * launches + */ + boolean isUserValidate = !(user.getUserRole().equals(ADMINISTRATOR) + || projectDetails.getProjectRole() + .sameOrHigherThan(ProjectRole.PROJECT_MANAGER)); + + launches.forEach(launch -> { + expect(launch, notNull()).verify(LAUNCH_NOT_FOUND, launch); + + expect(launch.getStatus(), not(Preconditions.statusIn(IN_PROGRESS))).verify( + LAUNCH_IS_NOT_FINISHED, + Suppliers.formattedSupplier("Cannot merge launch '{}' with status '{}'", launch.getId(), + launch.getStatus()) + ); + + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + "Impossible to merge launches from different projects." + ); + + if (isUserValidate) { + expect(launch.getUserId(), equalTo(user.getUserId())).verify(ACCESS_DENIED, + "You are not an owner of launches or have less than PROJECT_MANAGER project role." + ); + } + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/MetadataUpdater.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/MetadataUpdater.java index 96a3b499ef..61e1470955 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/MetadataUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/MetadataUpdater.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.launch.impl; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; - import java.util.Collection; /** @@ -25,13 +24,13 @@ */ public class MetadataUpdater implements ResourceUpdater<LaunchResource> { - @Override - public void update(LaunchResource resource) { + @Override + public void update(LaunchResource resource) { - } + } - @Override - public void update(Collection<LaunchResource> resources) { + @Override + public void update(Collection<LaunchResource> resources) { - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/ResourceUpdater.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/ResourceUpdater.java index 4508e41264..3a9058e63c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/ResourceUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/ResourceUpdater.java @@ -16,8 +16,6 @@ package com.epam.ta.reportportal.core.launch.impl; -import com.epam.ta.reportportal.ws.model.launch.LaunchResource; - import java.util.Collection; /** @@ -25,7 +23,7 @@ */ public interface ResourceUpdater<T> { - void update(T resource); + void update(T resource); - void update(Collection<T> resources); + void update(Collection<T> resources); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImpl.java index f60bf87590..9f90037d19 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.launch.StartLaunchHandler; import com.epam.ta.reportportal.util.ReportingQueueService; @@ -23,16 +25,13 @@ import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; import com.epam.ta.reportportal.ws.rabbit.MessageHeaders; import com.epam.ta.reportportal.ws.rabbit.RequestType; +import java.util.Map; +import java.util.UUID; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.UUID; - -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; - /** * @author Konstantin Antipin */ @@ -40,30 +39,32 @@ @Qualifier("startLaunchHandlerAsync") public class StartLaunchHandlerAsyncImpl implements StartLaunchHandler { - @Autowired - @Qualifier(value = "rabbitTemplate") - AmqpTemplate amqpTemplate; + @Autowired + @Qualifier(value = "rabbitTemplate") + AmqpTemplate amqpTemplate; - @Autowired - private ReportingQueueService reportingQueueService; + @Autowired + private ReportingQueueService reportingQueueService; - @Override - public StartLaunchRS startLaunch(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ request) { - validateRoles(projectDetails, request); + @Override + public StartLaunchRS startLaunch(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ request) { + validateRoles(projectDetails, request); - if (request.getUuid() == null) { - request.setUuid(UUID.randomUUID().toString()); - } - amqpTemplate.convertAndSend(EXCHANGE_REPORTING, reportingQueueService.getReportingQueueKey(request.getUuid()), request, message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_LAUNCH); - headers.put(MessageHeaders.USERNAME, user.getUsername()); - headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); - return message; - }); + if (request.getUuid() == null) { + request.setUuid(UUID.randomUUID().toString()); + } + amqpTemplate.convertAndSend(EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey(request.getUuid()), request, message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.START_LAUNCH); + headers.put(MessageHeaders.USERNAME, user.getUsername()); + headers.put(MessageHeaders.PROJECT_NAME, projectDetails.getProjectName()); + return message; + }); - StartLaunchRS response = new StartLaunchRS(); - response.setId(request.getUuid()); - return response; - } + StartLaunchRS response = new StartLaunchRS(); + response.setId(request.getUuid()); + return response; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImpl.java index 421a1a2f59..43abc35b67 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ws.converter.converters.LaunchConverter.TO_ACTIVITY_RESOURCE; + import com.epam.reportportal.extension.event.StartLaunchEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; @@ -27,16 +29,13 @@ import com.epam.ta.reportportal.ws.converter.builders.LaunchBuilder; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - -import static com.epam.ta.reportportal.ws.converter.converters.LaunchConverter.TO_ACTIVITY_RESOURCE; - /** * Default implementation of {@link com.epam.ta.reportportal.core.launch.StartLaunchHandler} * @@ -47,45 +46,48 @@ @Transactional class StartLaunchHandlerImpl implements StartLaunchHandler { - private final LaunchRepository launchRepository; - private final ApplicationEventPublisher eventPublisher; - private final MessageBus messageBus; - private final RerunHandler rerunHandler; + private final LaunchRepository launchRepository; + private final ApplicationEventPublisher eventPublisher; + private final MessageBus messageBus; + private final RerunHandler rerunHandler; - @Autowired - public StartLaunchHandlerImpl(LaunchRepository launchRepository, - ApplicationEventPublisher eventPublisher, MessageBus messageBus, RerunHandler rerunHandler) { - this.launchRepository = launchRepository; - this.eventPublisher = eventPublisher; - this.messageBus = messageBus; - this.rerunHandler = rerunHandler; - } + @Autowired + public StartLaunchHandlerImpl(LaunchRepository launchRepository, + ApplicationEventPublisher eventPublisher, MessageBus messageBus, RerunHandler rerunHandler) { + this.launchRepository = launchRepository; + this.eventPublisher = eventPublisher; + this.messageBus = messageBus; + this.rerunHandler = rerunHandler; + } - @Override - @Transactional - public StartLaunchRS startLaunch(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ request) { - validateRoles(projectDetails, request); + @Override + @Transactional + public StartLaunchRS startLaunch(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, StartLaunchRQ request) { + validateRoles(projectDetails, request); - final Launch savedLaunch = Optional.of(request.isRerun()) - .filter(Boolean::booleanValue) - .map(rerun -> rerunHandler.handleLaunch(request, projectDetails.getProjectId(), user)) - .orElseGet(() -> { - Launch launch = new LaunchBuilder().addStartRQ(request) - .addAttributes(request.getAttributes()) - .addProject(projectDetails.getProjectId()) - .addUserId(user.getUserId()) - .get(); - launchRepository.save(launch); - launchRepository.refresh(launch); - return launch; - }); + final Launch savedLaunch = Optional.of(request.isRerun()) + .filter(Boolean::booleanValue) + .map(rerun -> rerunHandler.handleLaunch(request, projectDetails.getProjectId(), user)) + .orElseGet(() -> { + Launch launch = new LaunchBuilder().addStartRQ(request) + .addAttributes(request.getAttributes()) + .addProject(projectDetails.getProjectId()) + .addUserId(user.getUserId()) + .get(); + launchRepository.save(launch); + launchRepository.refresh(launch); + return launch; + }); - eventPublisher.publishEvent(new StartLaunchEvent(savedLaunch.getId())); - messageBus.publishActivity(new LaunchStartedEvent(TO_ACTIVITY_RESOURCE.apply(savedLaunch), user.getUserId(), user.getUsername())); + eventPublisher.publishEvent(new StartLaunchEvent(savedLaunch.getId())); + messageBus.publishActivity( + new LaunchStartedEvent(TO_ACTIVITY_RESOURCE.apply(savedLaunch), user.getUserId(), + user.getUsername())); - StartLaunchRS response = new StartLaunchRS(); - response.setId(savedLaunch.getUuid()); - response.setNumber(savedLaunch.getNumber()); - return response; - } + StartLaunchRS response = new StartLaunchRS(); + response.setId(savedLaunch.getUuid()); + response.setNumber(savedLaunch.getNumber()); + return response; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StopLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StopLaunchHandlerImpl.java index 696bd66074..7b87a8f0d6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/StopLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/StopLaunchHandlerImpl.java @@ -85,7 +85,8 @@ public OperationCompletionRS stopLaunch(Long launchId, FinishExecutionRQ finishL launchRepository.save(launch); testItemRepository.interruptInProgressItems(launch.getId()); - eventPublisher.publishEvent(new LaunchFinishedEvent(launch, user.getUserId(), user.getUsername())); + eventPublisher.publishEvent( + new LaunchFinishedEvent(launch, user.getUserId(), user.getUsername(), false)); return new OperationCompletionRS("Launch with ID = '" + launchId + "' successfully stopped."); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImpl.java index 9adcc092ca..d1dcac32b6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImpl.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; +import static com.epam.ta.reportportal.entity.project.ProjectUtils.getConfigParameters; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; @@ -50,24 +62,14 @@ import com.epam.ta.reportportal.ws.model.launch.cluster.CreateClustersRQ; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; -import static com.epam.ta.reportportal.entity.project.ProjectUtils.getConfigParameters; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.stream.Collectors.toList; - /** * Default implementation of {@link UpdateLaunchHandler} * @@ -77,165 +79,184 @@ @Service public class UpdateLaunchHandlerImpl implements UpdateLaunchHandler { - private final GetProjectHandler getProjectHandler; - private final GetLaunchHandler getLaunchHandler; - private final LaunchAccessValidator launchAccessValidator; - - private final LaunchRepository launchRepository; - - private final LogIndexer logIndexer; - - private final Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping; - - private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; - - @Autowired - public UpdateLaunchHandlerImpl(GetProjectHandler getProjectHandler, GetLaunchHandler getLaunchHandler, - LaunchAccessValidator launchAccessValidator, LaunchRepository launchRepository, LogIndexer logIndexer, - Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping, - @Qualifier("uniqueErrorAnalysisStarterAsync") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { - this.getProjectHandler = getProjectHandler; - this.getLaunchHandler = getLaunchHandler; - this.launchAccessValidator = launchAccessValidator; - this.launchRepository = launchRepository; - this.launchAnalysisStrategyMapping = launchAnalysisStrategyMapping; - this.logIndexer = logIndexer; - this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; - } - - @Override - public OperationCompletionRS updateLaunch(Long launchId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - UpdateLaunchRQ rq) { - Project project = getProjectHandler.get(projectDetails); - Launch launch = launchRepository.findById(launchId) - .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId.toString())); - validate(launch, user, projectDetails, rq.getMode()); - - LaunchModeEnum previousMode = launch.getMode(); - - launch = new LaunchBuilder(launch).addMode(rq.getMode()) - .addDescription(rq.getDescription()) - .overwriteAttributes(rq.getAttributes()) - .get(); - launchRepository.save(launch); - - if (!previousMode.equals(launch.getMode())) { - reindexLogs(launch, AnalyzerUtils.getAnalyzerConfig(project), project.getId()); - } - return new OperationCompletionRS("Launch with ID = '" + launch.getId() + "' successfully updated."); - } - - @Override - public List<OperationCompletionRS> updateLaunch(BulkRQ<Long, UpdateLaunchRQ> rq, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - return rq.getEntities() - .entrySet() - .stream() - .map(entry -> updateLaunch(entry.getKey(), projectDetails, user, entry.getValue())) - .collect(toList()); - } - - @Override - public OperationCompletionRS startLaunchAnalyzer(AnalyzeLaunchRQ analyzeRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - AnalyzerType analyzerType = AnalyzerType.fromString(analyzeRQ.getAnalyzerTypeName()); - launchAnalysisStrategyMapping.get(analyzerType).analyze(analyzeRQ, projectDetails, user); - return new OperationCompletionRS( - analyzerType.getName() + " analysis for launch with ID='" + analyzeRQ.getLaunchId() + "' started."); - } - - @Override - @Transactional - public OperationCompletionRS createClusters(CreateClustersRQ createClustersRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user) { - - final Launch launch = getLaunchHandler.get(createClustersRQ.getLaunchId()); - launchAccessValidator.validate(launch, projectDetails, user); - //TODO should be put inside *Validator after validators refactoring - expect(launch.getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify(INCORRECT_REQUEST, "Cannot analyze launch in progress."); - - final Project project = getProjectHandler.get(launch.getProjectId()); - - final Map<String, String> configParameters = getConfigParameters(project.getProjectAttributes()); - configParameters.put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), - String.valueOf(createClustersRQ.isRemoveNumbers()) - ); - uniqueErrorAnalysisStarter.start(ClusterEntityContext.of(launch.getId(), launch.getProjectId()), configParameters); - - return new OperationCompletionRS(Suppliers.formattedSupplier("Clusters generation for launch with ID='{}' started.", launch.getId()) - .get()); - } - - @Override - public OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, ReportPortalUser.ProjectDetails projectDetails) { - expect(getProjectHandler.exists(projectDetails.getProjectId()), Predicate.isEqual(true)).verify(PROJECT_NOT_FOUND, - projectDetails.getProjectId() - ); - - List<Launch> launches = launchRepository.findAllById(bulkUpdateRq.getIds()); - launches.forEach(it -> ItemInfoUtils.updateDescription(bulkUpdateRq.getDescription(), it.getDescription()) - .ifPresent(it::setDescription)); - - bulkUpdateRq.getAttributes().forEach(it -> { - switch (it.getAction()) { - case DELETE: { - launches.forEach(launch -> { - ItemAttribute toDelete = ItemInfoUtils.findAttributeByResource(launch.getAttributes(), it.getFrom()); - launch.getAttributes().remove(toDelete); - }); - break; - } - case UPDATE: { - launches.forEach(launch -> ItemInfoUtils.updateAttribute(launch.getAttributes(), it)); - break; - } - case CREATE: { - launches.stream() - .filter(launch -> ItemInfoUtils.containsAttribute(launch.getAttributes(), it.getTo())) - .forEach(launch -> { - ItemAttribute itemAttribute = ItemAttributeConverter.FROM_RESOURCE.apply(it.getTo()); - itemAttribute.setLaunch(launch); - launch.getAttributes().add(itemAttribute); - }); - break; - } - } - }); - - return new OperationCompletionRS("Attributes successfully updated"); - } - - /** - * If launch mode has changed - reindex items - * - * @param launch Update launch - */ - private void reindexLogs(Launch launch, AnalyzerConfig analyzerConfig, Long projectId) { - if (LaunchModeEnum.DEBUG.equals(launch.getMode())) { - logIndexer.indexLaunchesRemove(projectId, Lists.newArrayList(launch.getId())); - } else { - logIndexer.indexLaunchLogs(launch, analyzerConfig); - } - } - - /** - * Valide {@link ReportPortalUser} credentials - * - * @param launch {@link Launch} - * @param user {@link ReportPortalUser} - * @param mode {@link Launch#mode} - */ - //TODO *Validator refactoring - private void validate(Launch launch, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails, Mode mode) { - if (projectDetails.getProjectRole() == ProjectRole.CUSTOMER && null != mode) { - expect(mode, equalTo(Mode.DEFAULT)).verify(ACCESS_DENIED); - } - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); - if (projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED); - } - } - } + private final GetProjectHandler getProjectHandler; + private final GetLaunchHandler getLaunchHandler; + private final LaunchAccessValidator launchAccessValidator; + + private final LaunchRepository launchRepository; + + private final LogIndexer logIndexer; + + private final Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping; + + private final UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter; + + @Autowired + public UpdateLaunchHandlerImpl(GetProjectHandler getProjectHandler, + GetLaunchHandler getLaunchHandler, + LaunchAccessValidator launchAccessValidator, LaunchRepository launchRepository, + LogIndexer logIndexer, + Map<AnalyzerType, LaunchAnalysisStrategy> launchAnalysisStrategyMapping, + @Qualifier("uniqueErrorAnalysisStarterAsync") UniqueErrorAnalysisStarter uniqueErrorAnalysisStarter) { + this.getProjectHandler = getProjectHandler; + this.getLaunchHandler = getLaunchHandler; + this.launchAccessValidator = launchAccessValidator; + this.launchRepository = launchRepository; + this.launchAnalysisStrategyMapping = launchAnalysisStrategyMapping; + this.logIndexer = logIndexer; + this.uniqueErrorAnalysisStarter = uniqueErrorAnalysisStarter; + } + + @Override + public OperationCompletionRS updateLaunch(Long launchId, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + UpdateLaunchRQ rq) { + Project project = getProjectHandler.get(projectDetails); + Launch launch = launchRepository.findById(launchId) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId.toString())); + validate(launch, user, projectDetails, rq.getMode()); + + LaunchModeEnum previousMode = launch.getMode(); + + launch = new LaunchBuilder(launch).addMode(rq.getMode()) + .addDescription(rq.getDescription()) + .overwriteAttributes(rq.getAttributes()) + .get(); + launchRepository.save(launch); + + if (!previousMode.equals(launch.getMode())) { + reindexLogs(launch, AnalyzerUtils.getAnalyzerConfig(project), project.getId()); + } + return new OperationCompletionRS( + "Launch with ID = '" + launch.getId() + "' successfully updated."); + } + + @Override + public List<OperationCompletionRS> updateLaunch(BulkRQ<Long, UpdateLaunchRQ> rq, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + return rq.getEntities() + .entrySet() + .stream() + .map(entry -> updateLaunch(entry.getKey(), projectDetails, user, entry.getValue())) + .collect(toList()); + } + + @Override + public OperationCompletionRS startLaunchAnalyzer(AnalyzeLaunchRQ analyzeRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + AnalyzerType analyzerType = AnalyzerType.fromString(analyzeRQ.getAnalyzerTypeName()); + launchAnalysisStrategyMapping.get(analyzerType).analyze(analyzeRQ, projectDetails, user); + return new OperationCompletionRS( + analyzerType.getName() + " analysis for launch with ID='" + analyzeRQ.getLaunchId() + + "' started."); + } + + @Override + @Transactional + public OperationCompletionRS createClusters(CreateClustersRQ createClustersRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + + final Launch launch = getLaunchHandler.get(createClustersRQ.getLaunchId()); + launchAccessValidator.validate(launch, projectDetails, user); + //TODO should be put inside *Validator after validators refactoring + expect(launch.getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify(INCORRECT_REQUEST, + "Cannot analyze launch in progress."); + + final Project project = getProjectHandler.get(launch.getProjectId()); + + final Map<String, String> configParameters = getConfigParameters( + project.getProjectAttributes()); + configParameters.put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), + String.valueOf(createClustersRQ.isRemoveNumbers()) + ); + uniqueErrorAnalysisStarter.start(ClusterEntityContext.of(launch.getId(), launch.getProjectId()), + configParameters); + + return new OperationCompletionRS( + Suppliers.formattedSupplier("Clusters generation for launch with ID='{}' started.", + launch.getId()) + .get()); + } + + @Override + public OperationCompletionRS bulkInfoUpdate(BulkInfoUpdateRQ bulkUpdateRq, + ReportPortalUser.ProjectDetails projectDetails) { + expect(getProjectHandler.exists(projectDetails.getProjectId()), Predicate.isEqual(true)).verify( + PROJECT_NOT_FOUND, + projectDetails.getProjectId() + ); + + List<Launch> launches = launchRepository.findAllById(bulkUpdateRq.getIds()); + launches.forEach( + it -> ItemInfoUtils.updateDescription(bulkUpdateRq.getDescription(), it.getDescription()) + .ifPresent(it::setDescription)); + + bulkUpdateRq.getAttributes().forEach(it -> { + switch (it.getAction()) { + case DELETE: { + launches.forEach(launch -> { + ItemAttribute toDelete = ItemInfoUtils.findAttributeByResource(launch.getAttributes(), + it.getFrom()); + launch.getAttributes().remove(toDelete); + }); + break; + } + case UPDATE: { + launches.forEach(launch -> ItemInfoUtils.updateAttribute(launch.getAttributes(), it)); + break; + } + case CREATE: { + launches.stream() + .filter(launch -> ItemInfoUtils.containsAttribute(launch.getAttributes(), it.getTo())) + .forEach(launch -> { + ItemAttribute itemAttribute = ItemAttributeConverter.FROM_RESOURCE.apply( + it.getTo()); + itemAttribute.setLaunch(launch); + launch.getAttributes().add(itemAttribute); + }); + break; + } + } + }); + + return new OperationCompletionRS("Attributes successfully updated"); + } + + /** + * If launch mode has changed - reindex items + * + * @param launch Update launch + */ + private void reindexLogs(Launch launch, AnalyzerConfig analyzerConfig, Long projectId) { + if (LaunchModeEnum.DEBUG.equals(launch.getMode())) { + logIndexer.indexLaunchesRemove(projectId, Lists.newArrayList(launch.getId())); + } else { + logIndexer.indexLaunchLogs(launch, analyzerConfig); + } + } + + /** + * Valide {@link ReportPortalUser} credentials + * + * @param launch {@link Launch} + * @param user {@link ReportPortalUser} + * @param mode {@link Launch#mode} + */ + //TODO *Validator refactoring + private void validate(Launch launch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails, Mode mode) { + if (projectDetails.getProjectRole() == ProjectRole.CUSTOMER && null != mode) { + expect(mode, equalTo(Mode.DEFAULT)).verify(ACCESS_DENIED); + } + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); + if (projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED); + } + } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandler.java b/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandler.java index 3250affd61..031ac97508 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandler.java @@ -22,7 +22,6 @@ import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; - import java.util.Optional; /** @@ -30,31 +29,33 @@ */ public interface RerunHandler { - /** - * Updates launch state and return existed launch to rerun - * - * @param request Request data - * @param projectId Project ID - * @param user ReportPortal user - * @return {@link Launch} - */ - Launch handleLaunch(StartLaunchRQ request, Long projectId, ReportPortalUser user); + /** + * Updates launch state and return existed launch to rerun + * + * @param request Request data + * @param projectId Project ID + * @param user ReportPortal user + * @return {@link Launch} + */ + Launch handleLaunch(StartLaunchRQ request, Long projectId, ReportPortalUser user); - /** - * Finds root {@link TestItem} to rerun and creates retries - * - * @param request Request data - * @param launch {@link Launch} - * @return {@link ItemCreatedRS} if item is rerun, otherwise {@link Optional#empty()} - */ - Optional<ItemCreatedRS> handleRootItem(StartTestItemRQ request, Launch launch); + /** + * Finds root {@link TestItem} to rerun and creates retries + * + * @param request Request data + * @param launch {@link Launch} + * @return {@link ItemCreatedRS} if item is rerun, otherwise {@link Optional#empty()} + */ + Optional<ItemCreatedRS> handleRootItem(StartTestItemRQ request, Launch launch); - /** - * Finds child {@link TestItem} to rerun and creates retries - * - * @param request Request data - * @param launch {@link Launch} - * @return {@link ItemCreatedRS} if item is rerun, otherwise {@link Optional#empty()} - */ - Optional<ItemCreatedRS> handleChildItem(StartTestItemRQ request, Launch launch, String parentUuid); + /** + * Finds child {@link TestItem} to rerun and creates retries + * + * @param request Request data + * @param launch {@link Launch} + * @param parentUuid Parent testItem's id + * @return {@link ItemCreatedRS} if item is rerun, otherwise {@link Optional#empty()} + */ + Optional<ItemCreatedRS> handleChildItem(StartTestItemRQ request, Launch launch, + String parentUuid); } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImpl.java index 3a734dbbcd..7933d0421e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImpl.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.launch.rerun; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PARENT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_TEST_CASE_HASH; +import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.TO_LAUNCH_ATTRIBUTE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -40,24 +47,16 @@ import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.util.Pair; -import org.springframework.stereotype.Component; - import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PARENT_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_TEST_CASE_HASH; -import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.TO_LAUNCH_ATTRIBUTE; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.util.Pair; +import org.springframework.stereotype.Component; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -65,151 +64,170 @@ @Component public class RerunHandlerImpl implements RerunHandler { - private final TestItemRepository testItemRepository; - private final LaunchRepository launchRepository; - private final UniqueIdGenerator uniqueIdGenerator; - private final TestCaseHashGenerator testCaseHashGenerator; - private final ApplicationEventPublisher eventPublisher; - private final RerunSearcher rerunSearcher; - private final List<ParentItemValidator> parentItemValidators; - private final RetryHandler retryHandler; - - @Autowired - public RerunHandlerImpl(TestItemRepository testItemRepository, LaunchRepository launchRepository, UniqueIdGenerator uniqueIdGenerator, - TestCaseHashGenerator testCaseHashGenerator, ApplicationEventPublisher eventPublisher, RerunSearcher rerunSearcher, - List<ParentItemValidator> parentItemValidators, RetryHandler retryHandler) { - this.testItemRepository = testItemRepository; - this.launchRepository = launchRepository; - this.uniqueIdGenerator = uniqueIdGenerator; - this.testCaseHashGenerator = testCaseHashGenerator; - this.eventPublisher = eventPublisher; - this.rerunSearcher = rerunSearcher; - this.parentItemValidators = parentItemValidators; - this.retryHandler = retryHandler; - } - - @Override - public Launch handleLaunch(StartLaunchRQ request, Long projectId, ReportPortalUser user) { - Optional<Launch> launchOptional = StringUtils.isEmpty(request.getRerunOf()) ? - launchRepository.findLatestByNameAndProjectId(request.getName(), projectId) : - launchRepository.findByUuid(request.getRerunOf()); - Launch launch = launchOptional.orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, - ofNullable(request.getRerunOf()).orElse(request.getName()) - )); - - ofNullable(request.getMode()).map(it -> LaunchModeEnum.valueOf(it.name())).ifPresent(launch::setMode); - ofNullable(request.getDescription()).ifPresent(launch::setDescription); - launch.setStatus(StatusEnum.IN_PROGRESS); - ofNullable(request.getAttributes()).map(it -> it.stream() - .map(attr -> TO_LAUNCH_ATTRIBUTE.apply(attr, launch)) - .collect(Collectors.toSet())).ifPresent(launch::setAttributes); - ofNullable(request.getUuid()).ifPresent(launch::setUuid); - launch.setRerun(true); - return launch; - } - - @Override - public Optional<ItemCreatedRS> handleRootItem(StartTestItemRQ request, Launch launch) { - final Integer testCaseHash = getTestCaseHash(request, launch); - final Filter parentItemFilter = getRootItemFilter(launch, testCaseHash, request.getName()); - return rerunSearcher.findItem(parentItemFilter).flatMap(testItemRepository::findById).map(it -> updateRootItem(request, it)); - } - - private Integer getTestCaseHash(StartTestItemRQ request, Launch launch) { - final TestCaseIdEntry testCaseIdEntry = TestItemBuilder.processTestCaseId(request); - return ofNullable(testCaseIdEntry.getId()).map(id -> testCaseIdEntry.getHash()).orElseGet(() -> { - TestItem newItem = new TestItemBuilder().addStartItemRequest(request).get(); - return testCaseHashGenerator.generate(newItem, Collections.emptyList(), launch.getProjectId()); - }); - } - - @Override - public Optional<ItemCreatedRS> handleChildItem(StartTestItemRQ request, Launch launch, String parentUuid) { - if (!request.isHasStats()) { - return Optional.empty(); - } - - final Pair<Long, String> pathName = testItemRepository.selectPath(parentUuid) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentUuid)); - - TestItem newItem = new TestItemBuilder().addLaunchId(launch.getId()) - .addStartItemRequest(request) - .addAttributes(request.getAttributes()) - .addParentId(pathName.getFirst()) - .get(); - - if (Objects.isNull(newItem.getTestCaseId())) { - newItem.setTestCaseHash(testCaseHashGenerator.generate(newItem, - IdentityUtil.getItemTreeIds(pathName.getSecond()), - launch.getProjectId() - )); - } - - final Filter childItemFilter = getChildItemFilter(launch, newItem.getTestCaseHash(), pathName.getFirst()); - - return rerunSearcher.findItem(childItemFilter).flatMap(testItemRepository::findById).flatMap(foundItem -> { - if (!foundItem.isHasChildren()) { - final TestItem parent = testItemRepository.findIdByUuidForUpdate(parentUuid) - .map(testItemRepository::getOne) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentUuid)); - parentItemValidators.forEach(v -> v.validate(request, parent)); - return Optional.of(handleRetry(launch, newItem, foundItem, parent)); - } - - if (foundItem.getName().equals(newItem.getName())) { - return Optional.of(updateRootItem(request, foundItem)); - } - - childItemFilter.withCondition(new FilterCondition(Condition.EQUALS, false, newItem.getName(), CRITERIA_NAME)); - return rerunSearcher.findItem(childItemFilter).flatMap(testItemRepository::findById).map(it -> updateRootItem(request, it)); - }); - } - - private Filter getCommonFilter(Long launchId, Integer testCaseHash) { - return Filter.builder() - .withTarget(TestItem.class) - .withCondition(new FilterCondition(Condition.EQUALS, false, String.valueOf(launchId), CRITERIA_LAUNCH_ID)) - .withCondition(new FilterCondition(Condition.EQUALS, false, String.valueOf(testCaseHash), CRITERIA_TEST_CASE_HASH)) - .build(); - } - - private Filter getRootItemFilter(Launch launch, Integer testCaseHash, String name) { - return getCommonFilter(launch.getId(), testCaseHash).withCondition(new FilterCondition(Condition.EQUALS, - false, - name, - CRITERIA_NAME - )).withCondition(new FilterCondition(Condition.EXISTS, true, "1", CRITERIA_PARENT_ID)); - } - - private Filter getChildItemFilter(Launch launch, Integer testCaseHash, Long parentId) { - return getCommonFilter(launch.getId(), testCaseHash).withCondition(new FilterCondition(Condition.EXISTS, - false, - String.valueOf(parentId), - CRITERIA_PARENT_ID - )); - } - - private ItemCreatedRS handleRetry(Launch launch, TestItem newItem, TestItem foundItem, TestItem parentItem) { - eventPublisher.publishEvent(ItemRetryEvent.of(launch.getProjectId(), launch.getId(), foundItem.getItemId())); - testItemRepository.save(newItem); - newItem.setPath(parentItem.getPath() + "." + newItem.getItemId()); - generateUniqueId(launch, newItem); - retryHandler.handleRetries(launch, newItem, foundItem.getItemId()); - return new ItemCreatedRS(newItem.getUuid(), newItem.getUniqueId()); - } - - private void generateUniqueId(Launch launch, TestItem item) { - if (null == item.getUniqueId()) { - item.setUniqueId(uniqueIdGenerator.generate(item, IdentityUtil.getParentIds(item), launch)); - } - } - - private ItemCreatedRS updateRootItem(StartTestItemRQ request, TestItem foundItem) { - foundItem = new TestItemBuilder(foundItem).addDescription(request.getDescription()) - .overwriteAttributes(request.getAttributes()) - .addStatus(StatusEnum.IN_PROGRESS) - .get(); - ofNullable(request.getUuid()).ifPresent(foundItem::setUuid); - return new ItemCreatedRS(foundItem.getUuid(), foundItem.getUniqueId()); - } + private final TestItemRepository testItemRepository; + private final LaunchRepository launchRepository; + private final UniqueIdGenerator uniqueIdGenerator; + private final TestCaseHashGenerator testCaseHashGenerator; + private final ApplicationEventPublisher eventPublisher; + private final RerunSearcher rerunSearcher; + private final List<ParentItemValidator> parentItemValidators; + private final RetryHandler retryHandler; + + @Autowired + public RerunHandlerImpl(TestItemRepository testItemRepository, LaunchRepository launchRepository, + UniqueIdGenerator uniqueIdGenerator, + TestCaseHashGenerator testCaseHashGenerator, ApplicationEventPublisher eventPublisher, + RerunSearcher rerunSearcher, + List<ParentItemValidator> parentItemValidators, RetryHandler retryHandler) { + this.testItemRepository = testItemRepository; + this.launchRepository = launchRepository; + this.uniqueIdGenerator = uniqueIdGenerator; + this.testCaseHashGenerator = testCaseHashGenerator; + this.eventPublisher = eventPublisher; + this.rerunSearcher = rerunSearcher; + this.parentItemValidators = parentItemValidators; + this.retryHandler = retryHandler; + } + + @Override + public Launch handleLaunch(StartLaunchRQ request, Long projectId, ReportPortalUser user) { + Optional<Launch> launchOptional = StringUtils.isEmpty(request.getRerunOf()) ? + launchRepository.findLatestByNameAndProjectId(request.getName(), projectId) : + launchRepository.findByUuid(request.getRerunOf()); + Launch launch = launchOptional.orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, + ofNullable(request.getRerunOf()).orElse(request.getName()) + )); + + ofNullable(request.getMode()).map(it -> LaunchModeEnum.valueOf(it.name())) + .ifPresent(launch::setMode); + ofNullable(request.getDescription()).ifPresent(launch::setDescription); + launch.setStatus(StatusEnum.IN_PROGRESS); + ofNullable(request.getAttributes()).map(it -> it.stream() + .map(attr -> TO_LAUNCH_ATTRIBUTE.apply(attr, launch)) + .collect(Collectors.toSet())).ifPresent(launch::setAttributes); + ofNullable(request.getUuid()).ifPresent(launch::setUuid); + launch.setRerun(true); + return launch; + } + + @Override + public Optional<ItemCreatedRS> handleRootItem(StartTestItemRQ request, Launch launch) { + final Integer testCaseHash = getTestCaseHash(request, launch); + final Filter parentItemFilter = getRootItemFilter(launch, testCaseHash, request.getName()); + return rerunSearcher.findItem(parentItemFilter).flatMap(testItemRepository::findById) + .map(it -> updateRootItem(request, it)); + } + + private Integer getTestCaseHash(StartTestItemRQ request, Launch launch) { + final TestCaseIdEntry testCaseIdEntry = TestItemBuilder.processTestCaseId(request); + return ofNullable(testCaseIdEntry.getId()).map(id -> testCaseIdEntry.getHash()) + .orElseGet(() -> { + TestItem newItem = new TestItemBuilder().addStartItemRequest(request).get(); + return testCaseHashGenerator.generate(newItem, Collections.emptyList(), + launch.getProjectId()); + }); + } + + @Override + public Optional<ItemCreatedRS> handleChildItem(StartTestItemRQ request, Launch launch, + String parentUuid) { + if (!request.isHasStats()) { + return Optional.empty(); + } + + final Pair<Long, String> pathName = testItemRepository.selectPath(parentUuid) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentUuid)); + + TestItem newItem = new TestItemBuilder().addLaunchId(launch.getId()) + .addStartItemRequest(request) + .addAttributes(request.getAttributes()) + .addParentId(pathName.getFirst()) + .get(); + + if (Objects.isNull(newItem.getTestCaseId())) { + newItem.setTestCaseHash(testCaseHashGenerator.generate(newItem, + IdentityUtil.getItemTreeIds(pathName.getSecond()), + launch.getProjectId() + )); + } + + final Filter childItemFilter = getChildItemFilter(launch, newItem.getTestCaseHash(), + pathName.getFirst()); + + return rerunSearcher.findItem(childItemFilter).flatMap(testItemRepository::findById) + .flatMap(foundItem -> { + if (!foundItem.isHasChildren()) { + final TestItem parent = testItemRepository.findIdByUuidForUpdate(parentUuid) + .map(testItemRepository::getOne) + .orElseThrow( + () -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentUuid)); + parentItemValidators.forEach(v -> v.validate(request, parent)); + return Optional.of(handleRetry(launch, newItem, foundItem, parent)); + } + + if (foundItem.getName().equals(newItem.getName())) { + return Optional.of(updateRootItem(request, foundItem)); + } + + childItemFilter.withCondition( + new FilterCondition(Condition.EQUALS, false, newItem.getName(), CRITERIA_NAME)); + return rerunSearcher.findItem(childItemFilter).flatMap(testItemRepository::findById) + .map(it -> updateRootItem(request, it)); + }); + } + + private Filter getCommonFilter(Long launchId, Integer testCaseHash) { + return Filter.builder() + .withTarget(TestItem.class) + .withCondition(new FilterCondition(Condition.EQUALS, false, String.valueOf(launchId), + CRITERIA_LAUNCH_ID)) + .withCondition(new FilterCondition(Condition.EQUALS, false, String.valueOf(testCaseHash), + CRITERIA_TEST_CASE_HASH)) + .build(); + } + + private Filter getRootItemFilter(Launch launch, Integer testCaseHash, String name) { + return getCommonFilter(launch.getId(), testCaseHash).withCondition( + new FilterCondition(Condition.EQUALS, + false, + name, + CRITERIA_NAME + )).withCondition(new FilterCondition(Condition.EXISTS, true, "1", CRITERIA_PARENT_ID)); + } + + private Filter getChildItemFilter(Launch launch, Integer testCaseHash, Long parentId) { + return getCommonFilter(launch.getId(), testCaseHash).withCondition( + new FilterCondition(Condition.EQUALS, + false, + String.valueOf(parentId), + CRITERIA_PARENT_ID + )); + } + + private ItemCreatedRS handleRetry(Launch launch, TestItem newItem, TestItem foundItem, + TestItem parentItem) { + eventPublisher.publishEvent( + ItemRetryEvent.of(launch.getProjectId(), launch.getId(), foundItem.getItemId())); + testItemRepository.save(newItem); + newItem.setPath(parentItem.getPath() + "." + newItem.getItemId()); + generateUniqueId(launch, newItem); + retryHandler.handleRetries(launch, newItem, foundItem.getItemId()); + return new ItemCreatedRS(newItem.getUuid(), newItem.getUniqueId()); + } + + private void generateUniqueId(Launch launch, TestItem item) { + if (null == item.getUniqueId()) { + item.setUniqueId(uniqueIdGenerator.generate(item, IdentityUtil.getParentIds(item), launch)); + } + } + + private ItemCreatedRS updateRootItem(StartTestItemRQ request, TestItem foundItem) { + foundItem = new TestItemBuilder(foundItem).addDescription(request.getDescription()) + .overwriteAttributes(request.getAttributes()) + .addStatus(StatusEnum.IN_PROGRESS) + .get(); + ofNullable(request.getUuid()).ifPresent(foundItem::setUuid); + return new ItemCreatedRS(foundItem.getUuid(), foundItem.getUniqueId()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/util/LaunchValidator.java b/src/main/java/com/epam/ta/reportportal/core/launch/util/LaunchValidator.java index ac4c41589c..e8825eafd2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/util/LaunchValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/util/LaunchValidator.java @@ -16,6 +16,21 @@ package com.epam.ta.reportportal.core.launch.util; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.IN_PROGRESS; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.SKIPPED; +import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_LAUNCH_NOT_ALLOWED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_FINISH_STATUS; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.enums.StatusEnum; @@ -23,85 +38,83 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; - import java.util.function.Predicate; -import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.Predicates.not; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.entity.enums.StatusEnum.*; -import static com.epam.ta.reportportal.entity.project.ProjectRole.PROJECT_MANAGER; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public class LaunchValidator { - private LaunchValidator() { - //static only - } + private LaunchValidator() { + //static only + } - /** - * Validate {@link Launch#status} and value of the {@link Launch#endTime} - * - * @param launch {@link Launch} - * @param finishExecutionRQ {@link FinishExecutionRQ} - */ - public static void validate(Launch launch, FinishExecutionRQ finishExecutionRQ) { - expect(launch.getStatus(), equalTo(IN_PROGRESS)).verify(FINISH_LAUNCH_NOT_ALLOWED, - formattedSupplier("Launch '{}' already finished with status '{}'", launch.getId(), launch.getStatus()) - ); + /** + * Validate {@link Launch#status} and value of the {@link Launch#endTime} + * + * @param launch {@link Launch} + * @param finishExecutionRQ {@link FinishExecutionRQ} + */ + public static void validate(Launch launch, FinishExecutionRQ finishExecutionRQ) { + expect(launch.getStatus(), equalTo(IN_PROGRESS)).verify(FINISH_LAUNCH_NOT_ALLOWED, + formattedSupplier("Launch '{}' already finished with status '{}'", launch.getId(), + launch.getStatus()) + ); - expect(finishExecutionRQ.getEndTime(), Preconditions.sameTimeOrLater(launch.getStartTime())).verify( - FINISH_TIME_EARLIER_THAN_START_TIME, - TO_LOCAL_DATE_TIME.apply(finishExecutionRQ.getEndTime()), - launch.getStartTime(), - launch.getId() - ); - } + expect(finishExecutionRQ.getEndTime(), + Preconditions.sameTimeOrLater(launch.getStartTime())).verify( + FINISH_TIME_EARLIER_THAN_START_TIME, + TO_LOCAL_DATE_TIME.apply(finishExecutionRQ.getEndTime()), + launch.getStartTime(), + launch.getId() + ); + } - /** - * Validate {@link ReportPortalUser} credentials and {@link Launch} affiliation to the {@link Project} - * - * @param launch {@link Launch} - * @param user {@link ReportPortalUser} - * @param projectDetails {@link ReportPortalUser.ProjectDetails} - */ - public static void validateRoles(Launch launch, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - if (user.getUserRole() != UserRole.ADMINISTRATOR) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); - if (!launch.isRerun() && projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { - expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, "You are not launch owner."); - } - } - } + /** + * Validate {@link ReportPortalUser} credentials and {@link Launch} affiliation to the + * {@link Project} + * + * @param launch {@link Launch} + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + */ + public static void validateRoles(Launch launch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + if (user.getUserRole() != UserRole.ADMINISTRATOR) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(ACCESS_DENIED); + if (!launch.isRerun() && projectDetails.getProjectRole().lowerThan(PROJECT_MANAGER)) { + expect(user.getUserId(), Predicate.isEqual(launch.getUserId())).verify(ACCESS_DENIED, + "You are not launch owner."); + } + } + } - /** - * Validate {@link Launch#status} - * - * @param launch {@link Launch} - * @param providedStatus {@link StatusEnum} launch status from {@link FinishExecutionRQ} - * @param fromStatisticsStatus {@link StatusEnum} identified launch status - */ - public static void validateProvidedStatus(Launch launch, StatusEnum providedStatus, StatusEnum fromStatisticsStatus) { - /* Validate provided status */ - expect(providedStatus, not(statusIn(IN_PROGRESS, SKIPPED))).verify(INCORRECT_FINISH_STATUS, - formattedSupplier("Cannot finish launch '{}' with status '{}'", launch.getId(), providedStatus) - ); - if (PASSED.equals(providedStatus)) { - /* Validate actual launch status */ - expect(launch.getStatus(), statusIn(IN_PROGRESS, PASSED)).verify(INCORRECT_FINISH_STATUS, - formattedSupplier("Cannot finish launch '{}' with current status '{}' as 'PASSED'", launch.getId(), launch.getStatus()) - ); - expect(fromStatisticsStatus, statusIn(IN_PROGRESS, PASSED)).verify(INCORRECT_FINISH_STATUS, formattedSupplier( - "Cannot finish launch '{}' with calculated automatically status '{}' as 'PASSED'", - launch.getId(), - fromStatisticsStatus - )); - } - } + /** + * Validate {@link Launch#status} + * + * @param launch {@link Launch} + * @param providedStatus {@link StatusEnum} launch status from {@link FinishExecutionRQ} + * @param fromStatisticsStatus {@link StatusEnum} identified launch status + */ + public static void validateProvidedStatus(Launch launch, StatusEnum providedStatus, + StatusEnum fromStatisticsStatus) { + /* Validate provided status */ + expect(providedStatus, not(statusIn(IN_PROGRESS, SKIPPED))).verify(INCORRECT_FINISH_STATUS, + formattedSupplier("Cannot finish launch '{}' with status '{}'", launch.getId(), + providedStatus) + ); + if (PASSED.equals(providedStatus)) { + /* Validate actual launch status */ + expect(launch.getStatus(), statusIn(IN_PROGRESS, PASSED)).verify(INCORRECT_FINISH_STATUS, + formattedSupplier("Cannot finish launch '{}' with current status '{}' as 'PASSED'", + launch.getId(), launch.getStatus()) + ); + expect(fromStatisticsStatus, statusIn(IN_PROGRESS, PASSED)).verify(INCORRECT_FINISH_STATUS, + formattedSupplier( + "Cannot finish launch '{}' with calculated automatically status '{}' as 'PASSED'", + launch.getId(), + fromStatisticsStatus + )); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/launch/util/LinkGenerator.java b/src/main/java/com/epam/ta/reportportal/core/launch/util/LinkGenerator.java index 3511e8ce83..a62c06bb8a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/launch/util/LinkGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/launch/util/LinkGenerator.java @@ -16,37 +16,36 @@ package com.epam.ta.reportportal.core.launch.util; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.util.UriComponentsBuilder; -import javax.servlet.http.HttpServletRequest; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public final class LinkGenerator { - private static final String UI_PREFIX = "/ui/#"; - private static final String LAUNCHES = "/launches/all/"; - - private LinkGenerator() { - //static only - } - - public static String generateLaunchLink(String baseUrl, String projectName, String id) { - return StringUtils.isEmpty(baseUrl) ? null : baseUrl + UI_PREFIX + projectName + LAUNCHES + id; - } - - public static String composeBaseUrl(HttpServletRequest request) { - /* - * Use Uri components since they are aware of x-forwarded-host headers - */ - return UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) - .replacePath(null) - .replaceQuery(null) - .build() - .toUri() - .toASCIIString(); - } + private static final String UI_PREFIX = "/ui/#"; + private static final String LAUNCHES = "/launches/all/"; + + private LinkGenerator() { + //static only + } + + public static String generateLaunchLink(String baseUrl, String projectName, String id) { + return StringUtils.isEmpty(baseUrl) ? null : baseUrl + UI_PREFIX + projectName + LAUNCHES + id; + } + + public static String composeBaseUrl(HttpServletRequest request) { + /* + * Use Uri components since they are aware of x-forwarded-host headers + */ + return UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)) + .replacePath(null) + .replaceQuery(null) + .build() + .toUri() + .toASCIIString(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/CreateLogHandler.java b/src/main/java/com/epam/ta/reportportal/core/log/CreateLogHandler.java index b04f328524..4e584d1504 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/CreateLogHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/CreateLogHandler.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.log; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -23,41 +25,38 @@ import com.epam.ta.reportportal.ws.model.EntryCreatedAsyncRS; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import org.springframework.web.multipart.MultipartFile; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import org.springframework.web.multipart.MultipartFile; public interface CreateLogHandler { - /** - * Creates a new Log - * - * @param createLogRQ Log details - * @param file file with log - * @param projectDetails Project details - * @return EntryCreatedRS - */ - @Nonnull - EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ createLogRQ, @Nullable MultipartFile file, - @Nullable ReportPortalUser.ProjectDetails projectDetails); + /** + * Creates a new Log + * + * @param createLogRQ Log details + * @param file file with log + * @param projectDetails Project details + * @return EntryCreatedRS + */ + @Nonnull + EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ createLogRQ, @Nullable MultipartFile file, + @Nullable ReportPortalUser.ProjectDetails projectDetails); - /** - * Validates business rules related to test item of this log - * - * @param saveLogRQ Save log request - */ - default void validate(SaveLogRQ saveLogRQ) { - // todo : seems we need to loosen (throw out) this time check + /** + * Validates business rules related to test item of this log + * + * @param saveLogRQ Save log request + */ + default void validate(SaveLogRQ saveLogRQ) { + // todo : seems we need to loosen (throw out) this time check // expect(saveLogRQ.getLogTime(), Preconditions.sameTimeOrLater(testItem.getStartTime())).verify( // ErrorType.LOGGING_IS_NOT_ALLOWED, // Suppliers.formattedSupplier("Log has incorrect log time. Log time should be after parent item's start time.") // ); - expect(LogLevel.toCustomLogLevel(saveLogRQ.getLevel()), Predicates.notNull()).verify( - ErrorType.BAD_SAVE_LOG_REQUEST, - Suppliers.formattedSupplier("Cannot convert '{}' to valid 'LogLevel'", saveLogRQ.getLevel()) - ); - } + expect(LogLevel.toCustomLogLevel(saveLogRQ.getLevel()), Predicates.notNull()).verify( + ErrorType.BAD_SAVE_LOG_REQUEST, + Suppliers.formattedSupplier("Cannot convert '{}' to valid 'LogLevel'", saveLogRQ.getLevel()) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/DeleteLogHandler.java b/src/main/java/com/epam/ta/reportportal/core/log/DeleteLogHandler.java index f6805c24ed..d212f2129e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/DeleteLogHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/DeleteLogHandler.java @@ -21,13 +21,14 @@ public interface DeleteLogHandler { - /** - * Delete {@link com.epam.ta.reportportal.entity.log.Log} instance - * - * @param logId ID of Log - * @param projectDetails Project Details - * @param user User - * @return OperationCompletionRS - */ - OperationCompletionRS deleteLog(Long logId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Delete {@link com.epam.ta.reportportal.entity.log.Log} instance + * + * @param logId ID of Log + * @param projectDetails Project Details + * @param user User + * @return OperationCompletionRS + */ + OperationCompletionRS deleteLog(Long logId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/log/ElasticLogService.java b/src/main/java/com/epam/ta/reportportal/core/log/ElasticLogService.java new file mode 100644 index 0000000000..c836c6d521 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/log/ElasticLogService.java @@ -0,0 +1,332 @@ +package com.epam.ta.reportportal.core.log; + +import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.LOG_MESSAGE_SAVING_ROUTING_KEY; +import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.PROCESSING_EXCHANGE_NAME; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_TO_LOG_FULL; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; + +import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.dao.custom.ElasticSearchClient; +import com.epam.ta.reportportal.entity.launch.Launch; +import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; +import com.epam.ta.reportportal.entity.log.LogMessage; +import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Primary; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +@Primary +@Service +@ConditionalOnProperty(prefix = "rp.elasticsearch", name = "host") +public class ElasticLogService implements LogService { + + private final AmqpTemplate amqpTemplate; + private final ElasticSearchClient elasticSearchClient; + private final LogRepository logRepository; + private final LaunchRepository launchRepository; + private final TestItemRepository testItemRepository; + + public ElasticLogService(@Qualifier(value = "rabbitTemplate") AmqpTemplate amqpTemplate, + ElasticSearchClient elasticSearchClient, LogRepository logRepository, + LaunchRepository launchRepository, TestItemRepository testItemRepository) { + this.amqpTemplate = amqpTemplate; + this.elasticSearchClient = elasticSearchClient; + this.logRepository = logRepository; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + } + + public void saveLogMessage(LogFull logFull, Long launchId) { + if (Objects.isNull(logFull)) { + return; + } + amqpTemplate.convertAndSend(PROCESSING_EXCHANGE_NAME, LOG_MESSAGE_SAVING_ROUTING_KEY, + convertLogToLogMessage(logFull, launchId) + ); + } + + /** + * Used only for generation demo data, that send all per message to avoid some object/collection + * wrapping during reporting. + * + * @param logFullList list of {@link LogFull} + */ + public void saveLogMessageList(List<LogFull> logFullList, Long launchId) { + if (CollectionUtils.isEmpty(logFullList)) { + return; + } + logFullList.stream().filter(Objects::nonNull) + .forEach(logFull -> saveLogMessage(logFull, launchId)); + } + + @Override + public void deleteLogMessage(Long projectId, Long logId) { + elasticSearchClient.deleteLogsByLogIdAndProjectId(projectId, logId); + } + + @Override + public void deleteLogMessageByTestItemSet(Long projectId, Set<Long> itemIds) { + elasticSearchClient.deleteLogsByItemSetAndProjectId(projectId, itemIds); + } + + @Override + public void deleteLogMessageByLaunch(Long projectId, Long launchId) { + elasticSearchClient.deleteLogsByLaunchIdAndProjectId(projectId, launchId); + } + + @Override + public void deleteLogMessageByLaunchList(Long projectId, List<Long> launchIds) { + elasticSearchClient.deleteLogsByLaunchListAndProjectId(projectId, launchIds); + } + + @Override + public void deleteLogMessageByProject(Long projectId) { + elasticSearchClient.deleteLogsByProjectId(projectId); + } + + @Override + public Map<Long, List<IndexLog>> findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte( + Long launchId, List<Long> itemIds, int logLevel) { + Long projectId = launchRepository.findById(launchId).map(Launch::getProjectId).orElseThrow(); + Map<Long, List<IndexLog>> indexLogMap = + logRepository.findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, + itemIds, logLevel + ); + return wrapLogsWithLogMessages(projectId, indexLogMap); + } + + private Map<Long, List<IndexLog>> wrapLogsWithLogMessages(Long projectId, + Map<Long, List<IndexLog>> indexLogMap) { + Map<Long, List<IndexLog>> wrappedMap = new HashMap<>(); + if (indexLogMap != null && indexLogMap.size() > 0) { + List<Long> logIds = + indexLogMap.values().stream().flatMap(Collection::stream).map(IndexLog::getLogId) + .collect(Collectors.toList()); + Map<Long, LogMessage> logMessageMap = + elasticSearchClient.getLogMessagesByProjectIdAndIds(projectId, logIds); + + wrappedMap = indexLogMap.entrySet().stream().peek(indexLogEntry -> { + List<IndexLog> indexLogList = indexLogEntry.getValue().stream().peek(indexLog -> { + LogMessage logMessage = logMessageMap.get(indexLog.getLogId()); + if (logMessage != null) { + indexLog.setMessage(logMessage.getLogMessage()); + } + }).collect(toList()); + indexLogEntry.setValue(indexLogList); + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + return wrappedMap; + } + + @Override + public List<String> findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(Long launchId, Long itemId, + String path, Integer level) { + Long projectId = launchRepository.findById(launchId).map(Launch::getProjectId).orElseThrow(); + List<Long> logIds = + logRepository.findIdsByLaunchIdAndItemIdAndPathAndLevelGte(launchId, itemId, path, level); + + return elasticSearchClient.getLogMessagesByProjectIdAndIds(projectId, logIds).values().stream() + .map(LogMessage::getLogMessage).collect(toList()); + } + + @Override + public List<LogFull> findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + List<Long> itemIds, int logLevel) { + return wrapLogsWithLogMessages( + logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, itemIds, + logLevel + )); + } + + @Override + public List<LogFull> findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + Long itemId, int logLevel, int limit) { + return wrapLogsWithLogMessages( + logRepository.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, + itemId, logLevel, limit + )); + } + + @Override + public List<Log> findAllUnderTestItemByLaunchIdAndTestItemIdsWithLimit(Long launchId, + List<Long> itemIds, int limit) { + return logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsWithLimit(launchId, itemIds, + limit + ); + } + + @Override + public List<Log> findByTestItemId(Long itemId, int limit) { + return logRepository.findByTestItemId(itemId, limit); + } + + @Override + public List<Log> findByTestItemId(Long itemId) { + return logRepository.findByTestItemId(itemId); + } + + @Override + public List<LogFull> findByFilter(Queryable filter) { + return wrapLogsWithLogMessages(logRepository.findByFilter(filter)); + } + + @Override + // Possibly need to be refactored after filter investigation + public Page<LogFull> findByFilter(Queryable filter, Pageable pageable) { + Page<Log> byFilter = logRepository.findByFilter(filter, pageable); + return byFilter.map(this::getLogFull); + } + + @Override + public List<LogFull> findAllById(Iterable<Long> ids) { + return wrapLogsWithLogMessages(logRepository.findAllById(ids)); + } + + @Override + public Optional<LogFull> findById(Long id) { + return logRepository.findById(id).map(this::getLogFull); + } + + @Override + public Optional<LogFull> findByUuid(String uuid) { + return logRepository.findByUuid(uuid).map(this::getLogFull); + } + + @Override + public List<Long> selectTestItemIdsByStringLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern) { + return testItemRepository.selectIdsByStringLogMessage(itemIds, logLevel, pattern); + } + + @Override + public List<Long> selectTestItemIdsUnderByStringLogMessage(Long launchId, + Collection<Long> itemIds, Integer logLevel, String pattern) { + return testItemRepository.selectIdsUnderByStringLogMessage(launchId, itemIds, logLevel, + pattern); + } + + @Override + public List<Long> selectTestItemIdsByRegexLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern) { + return testItemRepository.selectIdsByRegexLogMessage(itemIds, logLevel, pattern); + } + + @Override + public List<Long> selectTestItemIdsUnderByRegexLogMessage(Long launchId, Collection<Long> itemIds, + Integer logLevel, String pattern) { + return testItemRepository.selectIdsUnderByRegexLogMessage(launchId, itemIds, logLevel, pattern); + } + + // TODO : refactoring pattern analyzer and add projectId as parameter + // Instead of this method. + private Long getProjectId(Collection<Long> itemIds) { + Long id = itemIds.stream().findFirst().get(); + return testItemRepository.findById(id).map( + testItem -> launchRepository.findById(testItem.getLaunchId()).map(Launch::getProjectId) + .orElseThrow()).orElseThrow(); + } + + private LogMessage convertLogToLogMessage(LogFull logFull, Long launchId) { + Long itemId = Objects.nonNull(logFull.getTestItem()) ? logFull.getTestItem().getItemId() : null; + return new LogMessage(logFull.getId(), logFull.getLogTime(), logFull.getLogMessage(), itemId, + launchId, logFull.getProjectId() + ); + } + + private List<LogFull> wrapLogsWithLogMessages(List<Log> logList) { + List<LogFull> logFullList = new ArrayList<>(); + + if (CollectionUtils.isNotEmpty(logList)) { + // This part of code for optimization receiving all needed message from elastic + // instead of get by single + // And for getting message from elastic we need projectId + // we get all message per projectId + logFullList = new ArrayList<>(logList.size()); + Map<Long, LogMessage> logMessageMap = new HashMap<>(); + Map<Long, List<Long>> logIdsGroupByProject = logList.stream() + .collect(groupingBy(Log::getProjectId, mapping(Log::getId, Collectors.toList()))); + + for (Map.Entry<Long, List<Long>> logIdsPerProject : logIdsGroupByProject.entrySet()) { + Long projectId = logIdsPerProject.getKey(); + List<Long> logIds = logIdsPerProject.getValue(); + logMessageMap.putAll( + elasticSearchClient.getLogMessagesByProjectIdAndIds(projectId, logIds)); + } + + for (Log log : logList) { + String logMessage = (logMessageMap.get(log.getId()) != null) ? + logMessageMap.get(log.getId()).getLogMessage() : log.getLogMessage(); + LogFull logFull = getLogFull(log, logMessage); + + logFullList.add(logFull); + } + } + + return logFullList; + } + + private LogFull getLogFull(Log log) { + LogMessage logMessage = + elasticSearchClient.getLogMessageByProjectIdAndId(log.getProjectId(), log.getId()); + String message = (logMessage != null) ? logMessage.getLogMessage() : null; + + return getLogFull(log, message); + } + + private LogFull getLogFull(Log log, String logMessage) { + LogFull logFull = LOG_TO_LOG_FULL.apply(log); + if (Strings.isNotBlank(logMessage)) { + logFull.setLogMessage(logMessage); + } + + return logFull; + } + + private List<Long> selectTestItemIdsUnderByLogMessage(Long launchId, Collection<Long> itemIds, + Integer logLevel, String string, boolean selectByPattern) { + Long projectId = getProjectId(itemIds); + List<Long> matchedItemIds = new ArrayList<>(); + for (Long itemId : itemIds) { + List<Long> logIdsPg = + testItemRepository.selectLogIdsUnderWithLogLevelCondition(launchId, itemIds, logLevel); + + List<Long> nestedItemsMatchedIds; + if (selectByPattern) { + nestedItemsMatchedIds = + elasticSearchClient.searchTestItemIdsByLogIdsAndRegexp(projectId, logIdsPg, string); + } else { + nestedItemsMatchedIds = + elasticSearchClient.searchTestItemIdsByLogIdsAndString(projectId, logIdsPg, string); + } + + if (CollectionUtils.isNotEmpty(nestedItemsMatchedIds)) { + matchedItemIds.add(itemId); + } + } + return matchedItemIds; + } + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/log/EmptyLogService.java b/src/main/java/com/epam/ta/reportportal/core/log/EmptyLogService.java new file mode 100644 index 0000000000..34e237dfd9 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/log/EmptyLogService.java @@ -0,0 +1,190 @@ +package com.epam.ta.reportportal.core.log; + +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_TO_LOG_FULL; + +import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; +import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +/** + * It's temporary class, that's used for gracefully migration logs to Elasticsearch. Will be removed + * in the future. That's why, for instance, some methods may be duplicated with ElasticLogService + * instead of moving it to some parent class. + */ +@Service +public class EmptyLogService implements LogService { + + private final LogRepository logRepository; + private final TestItemRepository testItemRepository; + + public EmptyLogService(LogRepository logRepository, TestItemRepository testItemRepository) { + this.logRepository = logRepository; + this.testItemRepository = testItemRepository; + } + + @Override + public void saveLogMessage(LogFull logFull, Long launchId) { + + } + + @Override + public void saveLogMessageList(List<LogFull> logFullList, Long launchId) { + + } + + @Override + public void deleteLogMessage(Long projectId, Long logId) { + + } + + @Override + public void deleteLogMessageByTestItemSet(Long projectId, Set<Long> itemIds) { + + } + + @Override + public void deleteLogMessageByLaunch(Long projectId, Long launchId) { + + } + + @Override + public void deleteLogMessageByLaunchList(Long projectId, List<Long> launchIds) { + + } + + @Override + public void deleteLogMessageByProject(Long projectId) { + + } + + @Override + public Map<Long, List<IndexLog>> findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte( + Long launchId, List<Long> itemIds, int logLevel) { + return logRepository.findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, + itemIds, logLevel); + } + + @Override + public List<String> findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(Long launchId, Long itemId, + String path, Integer level) { + return logRepository.findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(launchId, itemId, path, + level); + } + + @Override + public List<LogFull> findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + List<Long> itemIds, int logLevel) { + return wrapLogsWithLogMessages( + logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, itemIds, + logLevel)); + } + + @Override + public List<LogFull> findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + Long itemId, int logLevel, int limit) { + return wrapLogsWithLogMessages( + logRepository.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launchId, + itemId, logLevel, limit)); + } + + @Override + public List<Log> findAllUnderTestItemByLaunchIdAndTestItemIdsWithLimit(Long launchId, + List<Long> itemIds, int limit) { + return logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsWithLimit(launchId, itemIds, + limit); + } + + @Override + public List<Log> findByTestItemId(Long itemId, int limit) { + return logRepository.findByTestItemId(itemId, limit); + } + + @Override + public List<Log> findByTestItemId(Long itemId) { + return logRepository.findByTestItemId(itemId); + } + + @Override + public List<LogFull> findByFilter(Queryable filter) { + return wrapLogsWithLogMessages(logRepository.findByFilter(filter)); + } + + @Override + public Page<LogFull> findByFilter(Queryable filter, Pageable pageable) { + Page<Log> byFilter = logRepository.findByFilter(filter, pageable); + return byFilter.map(this::getLogFull); + } + + @Override + public List<LogFull> findAllById(Iterable<Long> ids) { + return wrapLogsWithLogMessages(logRepository.findAllById(ids)); + } + + @Override + public Optional<LogFull> findById(Long id) { + return logRepository.findById(id).map(this::getLogFull); + } + + @Override + public Optional<LogFull> findByUuid(String uuid) { + return logRepository.findByUuid(uuid).map(this::getLogFull); + } + + private List<LogFull> wrapLogsWithLogMessages(List<Log> logList) { + List<LogFull> logFullList = new ArrayList<>(); + // TODO: check for empty and add log message - tmp + if (CollectionUtils.isNotEmpty(logList)) { + logFullList = new ArrayList<>(logList.size()); + + for (Log log : logList) { + LogFull logFull = getLogFull(log); + + logFullList.add(logFull); + } + } + + return logFullList; + } + + private LogFull getLogFull(Log log) { + return LOG_TO_LOG_FULL.apply(log); + } + + @Override + public List<Long> selectTestItemIdsByStringLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern) { + return testItemRepository.selectIdsByStringLogMessage(itemIds, logLevel, pattern); + } + + @Override + public List<Long> selectTestItemIdsUnderByStringLogMessage(Long launchId, + Collection<Long> itemIds, Integer logLevel, String pattern) { + return testItemRepository.selectIdsUnderByStringLogMessage(launchId, itemIds, logLevel, + pattern); + } + + @Override + public List<Long> selectTestItemIdsByRegexLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern) { + return testItemRepository.selectIdsByRegexLogMessage(itemIds, logLevel, pattern); + } + + @Override + public List<Long> selectTestItemIdsUnderByRegexLogMessage(Long launchId, Collection<Long> itemIds, + Integer logLevel, String pattern) { + return testItemRepository.selectIdsUnderByRegexLogMessage(launchId, itemIds, logLevel, pattern); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/log/GetLogHandler.java b/src/main/java/com/epam/ta/reportportal/core/log/GetLogHandler.java index 184cab8ba5..7b8b44e682 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/GetLogHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/GetLogHandler.java @@ -24,10 +24,9 @@ import com.epam.ta.reportportal.entity.log.Log; import com.epam.ta.reportportal.ws.model.log.GetLogsUnderRq; import com.epam.ta.reportportal.ws.model.log.LogResource; -import org.springframework.data.domain.Pageable; - import java.util.List; import java.util.Map; +import org.springframework.data.domain.Pageable; /** * GET operation for {@link Log} entity @@ -36,56 +35,66 @@ */ public interface GetLogHandler { - /** - * Returns logs for specified filter - * - * @param filterable - filter definition - * @param pageable - pageable definition - * @return Iterable<LogResource> - */ - Iterable<LogResource> getLogs(String path, ReportPortalUser.ProjectDetails projectDetails, Filter filterable, Pageable pageable); + /** + * Returns logs for specified filter + * + * @param filterable - filter definition + * @param pageable - pageable definition + * @param path - logs path + * @param projectDetails - project details + * @return mapping with {@link TestItem#getItemId()} as key and its list of {@link LogResource} as value + */ + Iterable<LogResource> getLogs(String path, ReportPortalUser.ProjectDetails projectDetails, + Filter filterable, Pageable pageable); - /** - * @param logsUnderRq {@link GetLogsUnderRq} - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @return mapping with {@link TestItem#getItemId()} as key and its {@link Log} list as value - */ - Map<Long, List<LogResource>> getLogs(GetLogsUnderRq logsUnderRq, ReportPortalUser.ProjectDetails projectDetails); + /** + * @param logsUnderRq {@link GetLogsUnderRq} + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @return mapping with {@link TestItem#getItemId()} as key and its {@link Log} list as value + */ + Map<Long, List<LogResource>> getLogs(GetLogsUnderRq logsUnderRq, + ReportPortalUser.ProjectDetails projectDetails); - /** - * Returns log by UUID - * - * @param logId - target log UUID value - * @param projectDetails Project details - * @param user User - * @return LogResource - */ - LogResource getLog(String logId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Returns log by UUID + * + * @param logId - target log UUID value + * @param projectDetails Project details + * @param user User + * @return LogResource + */ + LogResource getLog(String logId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); - /** - * Calculates page number and returns entire page for specified log ID - * - * @param logId ID of log to find - * @param projectDetails Project details - * @param filterable Filter for paging - * @param pageable Paging details - * @return Page Number - */ - long getPageNumber(Long logId, ReportPortalUser.ProjectDetails projectDetails, Filter filterable, Pageable pageable); + /** + * Calculates page number and returns entire page for specified log ID + * + * @param logId ID of log to find + * @param projectDetails Project details + * @param filterable Filter for paging + * @param pageable Paging details + * @return Page Number + */ + long getPageNumber(Long logId, ReportPortalUser.ProjectDetails projectDetails, Filter filterable, + Pageable pageable); - /** - * Get logs and nested steps as one collection, filtered and sorted by passed args - * - * @param parentId {@link Log#testItem} ID or {@link com.epam.ta.reportportal.entity.item.TestItem#parent} ID - * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} - * @param params Request params - * @param queryable {@link Queryable} - * @param pageable {@link Pageable} - * @return The {@link Iterable} of {@link LogResource} and {@link com.epam.ta.reportportal.ws.model.NestedStepResource} entities - */ - Iterable<?> getNestedItems(Long parentId, ReportPortalUser.ProjectDetails projectDetails, Map<String, String> params, - Queryable queryable, Pageable pageable); + /** + * Get logs and nested steps as one collection, filtered and sorted by passed args + * + * @param parentId {@link com.epam.ta.reportportal.entity.log.Log#testItem} ID or + * {@link com.epam.ta.reportportal.entity.item.TestItem#parentId} ID + * @param projectDetails {@link com.epam.ta.reportportal.commons.ReportPortalUser.ProjectDetails} + * @param params Request params + * @param queryable {@link Queryable} + * @param pageable {@link Pageable} + * @return The {@link Iterable} of {@link LogResource} and + * {@link com.epam.ta.reportportal.ws.model.NestedStepResource} entities + */ + Iterable<?> getNestedItems(Long parentId, ReportPortalUser.ProjectDetails projectDetails, + Map<String, String> params, + Queryable queryable, Pageable pageable); - List<PagedLogResource> getLogsWithLocation(Long parentId, ReportPortalUser.ProjectDetails projectDetails, Map<String, String> params, - Queryable queryable, Pageable pageable); + List<PagedLogResource> getLogsWithLocation(Long parentId, + ReportPortalUser.ProjectDetails projectDetails, Map<String, String> params, + Queryable queryable, Pageable pageable); } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/LogService.java b/src/main/java/com/epam/ta/reportportal/core/log/LogService.java index cbb7974402..fa6e4dc4f0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/LogService.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/LogService.java @@ -1,21 +1,191 @@ package com.epam.ta.reportportal.core.log; +import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; - +import com.epam.ta.reportportal.entity.log.LogFull; +import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; public interface LogService { - /** - * launchId - temporary, need to bring log launch/testItem to normal value. - */ - void saveLogMessageToElasticSearch(Log log, Long launchId); - - /** - * Used only for generation demo data, that send all per message to avoid some object/collection wrapping - * during reporting. - * @param logList - * @param launchId - temporary, need to bring log launch/testItem to normal value. - */ - void saveLogMessageListToElasticSearch(List<Log> logList, Long launchId); + /** + * launchId - temporary, need to bring log launch/testItem to normal value. + * + * @param logFull Log info for saving + * @param launchId Log's launch id + */ + void saveLogMessage(LogFull logFull, Long launchId); + + /** + * Used only for generation demo data, that send all per message to avoid some object/collection + * wrapping during reporting. + * + * @param logFullList - The {@link List} of {@link LogFull} + * @param launchId - temporary, need to bring log launch/testItem to normal value. + */ + void saveLogMessageList(List<LogFull> logFullList, Long launchId); + + void deleteLogMessage(Long projectId, Long logId); + + void deleteLogMessageByTestItemSet(Long projectId, Set<Long> itemIds); + + void deleteLogMessageByLaunch(Long projectId, Long launchId); + + void deleteLogMessageByLaunchList(Long projectId, List<Long> launchIds); + + void deleteLogMessageByProject(Long projectId); + + /** + * Find logs as {@link IndexLog} under {@link TestItem} and group by {@link Log#getTestItem()} ID + * + * @param launchId {@link} ID of the {@link Launch} to search {@link Log} under + * @param itemIds {@link List} of the {@link Log#getTestItem()} IDs + * @param logLevel {@link Log#getLogLevel()} + * @return {@link List} of {@link Log} + */ + Map<Long, List<IndexLog>> findAllIndexUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte( + Long launchId, List<Long> itemIds, int logLevel); + + /** + * Retrieves log message of specified test item with log level greather or equals than + * {@code level} + * + * @param launchId {@link TestItem#getLaunchId()} + * @param itemId ID of {@link Log#getTestItem()} + * @param path {@link TestItem#getPath()} + * @param level log level + * @return {@link List} of {@link String} of log messages + */ + List<String> findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(Long launchId, Long itemId, + String path, Integer level); + + /** + * @param launchId {@link} ID of the {@link Launch} to search {@link Log} under + * @param itemIds {@link List} of the {@link Log#getTestItem()} IDs + * @param logLevel {@link Log#getLogLevel()} + * @return {@link List} of {@link LogFull} + */ + List<LogFull> findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + List<Long> itemIds, int logLevel); + + /** + * Find n latest logs for item + * + * @param launchId {@link} ID of the {@link Launch} to search {@link Log} under + * @param itemId {@link List} of the {@link Log#getTestItem()} IDs + * @param logLevel {@link Log#getLogLevel()} + * @param limit Number of logs to be fetch + * @return {@link List} of {@link LogFull} + */ + List<LogFull> findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(Long launchId, + Long itemId, int logLevel, int limit); + + /** + * @param launchId {@link} ID of the {@link Launch} to search {@link Log} under + * @param itemIds {@link List} of the {@link Log#getTestItem()} IDs + * @param limit Max count of {@link Log} to be loaded + * @return {@link List} of {@link Log} + */ + List<Log> findAllUnderTestItemByLaunchIdAndTestItemIdsWithLimit(Long launchId, List<Long> itemIds, + int limit); + + /** + * Load specified number of last logs for specified test item. binaryData field will be loaded if + * it specified in appropriate input parameter, all other fields will be fully loaded. + * + * @param limit Max count of logs to be loaded + * @param itemId Test Item log belongs to + * @return Found logs + */ + List<Log> findByTestItemId(Long itemId, int limit); + + /** + * Load specified number of last logs for specified test item. binaryData field will be loaded if + * it specified in appropriate input parameter, all other fields will be fully loaded. + * + * @param itemId Test Item log belongs to + * @return Found logs + */ + List<Log> findByTestItemId(Long itemId); + + /** + * Executes query built for given filter + * + * @param filter Filter to build a query + * @return List of logFulls found + */ + List<LogFull> findByFilter(Queryable filter); + + /** + * Executes query built for given filter and maps result for given page + * + * @param filter Filter to build a query + * @param pageable {@link Pageable} + * @return List of logFulls found + */ + Page<LogFull> findByFilter(Queryable filter, Pageable pageable); + + List<LogFull> findAllById(Iterable<Long> ids); + + Optional<LogFull> findById(Long id); + + Optional<LogFull> findByUuid(String uuid); + + /** + * Select item IDs which log's level is greater than or equal to provided and log's message match + * to the STRING pattern + * + * @param itemIds {@link Collection} of {@link TestItem#getItemId()} which logs should match + * @param logLevel {@link Log#getLogLevel()} + * @param pattern CASE SENSITIVE STRING pattern for log message search + * @return The {@link List} of the {@link TestItem#getItemId()} + */ + List<Long> selectTestItemIdsByStringLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern); + + /** + * Select item IDs which descendants' log's level is greater than or equal to provided and log's + * message match to the REGEX pattern + * + * @param launchId {@link TestItem#getLaunchId()} + * @param itemIds {@link Collection} of {@link TestItem#getItemId()} which logs should match + * @param logLevel {@link Log#getLogLevel()} + * @param pattern REGEX pattern for log message search + * @return The {@link List} of the {@link TestItem#getItemId()} + */ + List<Long> selectTestItemIdsUnderByStringLogMessage(Long launchId, Collection<Long> itemIds, + Integer logLevel, String pattern); + + /** + * Select item IDs which log's level is greater than or equal to provided and log's message match + * to the REGEX pattern + * + * @param itemIds {@link Collection} of {@link TestItem#getItemId()} which logs should match + * @param logLevel {@link Log#getLogLevel()} + * @param pattern REGEX pattern for log message search + * @return The {@link List} of the {@link TestItem#getItemId()} + */ + List<Long> selectTestItemIdsByRegexLogMessage(Collection<Long> itemIds, Integer logLevel, + String pattern); + + /** + * Select item IDs which descendants' log's level is greater than or equal to provided and log's + * message match to the REGEX pattern + * + * @param launchId {@link TestItem#getLaunchId()} + * @param itemIds {@link Collection} of {@link TestItem#getItemId()} which logs should match + * @param logLevel {@link Log#getLogLevel()} + * @param pattern REGEX pattern for log message search + * @return The {@link List} of the {@link TestItem#getItemId()} + */ + List<Long> selectTestItemIdsUnderByRegexLogMessage(Long launchId, Collection<Long> itemIds, + Integer logLevel, String pattern); } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/LogServiceElastic.java b/src/main/java/com/epam/ta/reportportal/core/log/LogServiceElastic.java deleted file mode 100644 index 8ac6c10edf..0000000000 --- a/src/main/java/com/epam/ta/reportportal/core/log/LogServiceElastic.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.epam.ta.reportportal.core.log; - -import com.epam.ta.reportportal.entity.log.Log; -import com.epam.ta.reportportal.entity.log.LogMessage; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.amqp.core.AmqpTemplate; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Objects; - -import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.LOG_MESSAGE_SAVING_ROUTING_KEY; -import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.PROCESSING_EXCHANGE_NAME; - -@Primary -@Service -@ConditionalOnProperty(prefix = "rp.elasticsearchLogmessage", name = "host") -public class LogServiceElastic implements LogService { - private final AmqpTemplate amqpTemplate; - - public LogServiceElastic(@Qualifier(value = "rabbitTemplate") AmqpTemplate amqpTemplate) { - this.amqpTemplate = amqpTemplate; - } - - public void saveLogMessageToElasticSearch(Log log, Long launchId) { - if (Objects.isNull(log)) return; - amqpTemplate.convertAndSend(PROCESSING_EXCHANGE_NAME, LOG_MESSAGE_SAVING_ROUTING_KEY, - convertLogToLogMessage(log, launchId)); - } - - /** - * Used only for generation demo data, that send all per message to avoid some object/collection wrapping - * during reporting. - * @param logList - */ - public void saveLogMessageListToElasticSearch(List<Log> logList, Long launchId) { - if (CollectionUtils.isEmpty(logList)) return; - logList.stream().filter(Objects::nonNull).forEach(log -> saveLogMessageToElasticSearch(log, launchId)); - } - - private LogMessage convertLogToLogMessage(Log log, Long launchId) { - Long itemId = Objects.nonNull(log.getTestItem()) ? log.getTestItem().getItemId() : null; - return new LogMessage(log.getId(), log.getLogTime(), log.getLogMessage(), itemId, launchId, log.getProjectId()); - } -} diff --git a/src/main/java/com/epam/ta/reportportal/core/log/LogServiceEmptyElastic.java b/src/main/java/com/epam/ta/reportportal/core/log/LogServiceEmptyElastic.java deleted file mode 100644 index 2b17060a30..0000000000 --- a/src/main/java/com/epam/ta/reportportal/core/log/LogServiceEmptyElastic.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.epam.ta.reportportal.core.log; - -import com.epam.ta.reportportal.entity.log.Log; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class LogServiceEmptyElastic implements LogService { - - public LogServiceEmptyElastic() { - } - - @Override - public void saveLogMessageToElasticSearch(Log log, Long launchId) { - - } - - @Override - public void saveLogMessageListToElasticSearch(List<Log> logList, Long launchId) { - - } -} diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImpl.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImpl.java index f2eaef2346..371d492f8b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImpl.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; + import com.epam.ta.reportportal.commons.BinaryDataMetaInfo; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.configs.rabbit.DeserializablePair; @@ -25,6 +27,11 @@ import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.epam.ta.reportportal.ws.rabbit.MessageHeaders; import com.epam.ta.reportportal.ws.rabbit.RequestType; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; +import javax.inject.Provider; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -32,79 +39,71 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import javax.annotation.Nonnull; -import javax.inject.Provider; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING; - /** - * Asynchronous implementation of {@link CreateLogHandler} using RabbitMQ - * to defer binding Log to ID(s) + * Asynchronous implementation of {@link CreateLogHandler} using RabbitMQ to defer binding Log to + * ID(s) * * @author Andrei Varabyeu */ @Service("asyncCreateLogHandler") public class CreateLogHandlerAsyncImpl implements CreateLogHandler { - /** - * We are using {@link Provider} there because we need - * {@link SaveLogBinaryDataTaskAsync} with scope prototype. Since current class is in - * singleton scope, we have to find a way to get new instance of job for new - * execution - */ - @Autowired - private Provider<SaveLogBinaryDataTaskAsync> saveLogBinaryDataTask; - - @Autowired - @Qualifier("saveLogsTaskExecutor") - private TaskExecutor taskExecutor; - - @Autowired - private ReportingQueueService reportingQueueService; - - @Autowired - @Qualifier(value = "rabbitTemplate") - AmqpTemplate amqpTemplate; - - @Override - @Nonnull - public EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ request, MultipartFile file, ReportPortalUser.ProjectDetails projectDetails) { - - validate(request); - - request.setUuid(UUID.randomUUID().toString()); - - if (file != null) { - CompletableFuture.supplyAsync(saveLogBinaryDataTask.get() - .withRequest(request) - .withFile(file) - .withProjectId(projectDetails.getProjectId()), taskExecutor) - .thenAccept(metaInfo -> sendMessage(request, metaInfo, projectDetails.getProjectId())); - } else { - sendMessage(request, null, projectDetails.getProjectId()); - } - - EntryCreatedAsyncRS response = new EntryCreatedAsyncRS(); - response.setId(request.getUuid()); - return response; - } - - protected void sendMessage(SaveLogRQ request, BinaryDataMetaInfo metaInfo, Long projectId) { - amqpTemplate.convertAndSend( - EXCHANGE_REPORTING, - reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), - DeserializablePair.of(request, metaInfo), - message -> { - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - headers.put(MessageHeaders.REQUEST_TYPE, RequestType.LOG); - headers.put(MessageHeaders.PROJECT_ID, projectId); - headers.put(MessageHeaders.ITEM_ID, request.getItemUuid()); - return message; - } - ); - - } + /** + * We are using {@link Provider} there because we need {@link SaveLogBinaryDataTaskAsync} with + * scope prototype. Since current class is in singleton scope, we have to find a way to get new + * instance of job for new execution + */ + @Autowired + private Provider<SaveLogBinaryDataTaskAsync> saveLogBinaryDataTask; + + @Autowired + @Qualifier("saveLogsTaskExecutor") + private TaskExecutor taskExecutor; + + @Autowired + private ReportingQueueService reportingQueueService; + + @Autowired + @Qualifier(value = "rabbitTemplate") + AmqpTemplate amqpTemplate; + + @Override + @Nonnull + public EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ request, MultipartFile file, + ReportPortalUser.ProjectDetails projectDetails) { + + validate(request); + + request.setUuid(UUID.randomUUID().toString()); + + if (file != null) { + CompletableFuture.supplyAsync(saveLogBinaryDataTask.get() + .withRequest(request) + .withFile(file) + .withProjectId(projectDetails.getProjectId()), taskExecutor) + .thenAccept(metaInfo -> sendMessage(request, metaInfo, projectDetails.getProjectId())); + } else { + sendMessage(request, null, projectDetails.getProjectId()); + } + + EntryCreatedAsyncRS response = new EntryCreatedAsyncRS(); + response.setId(request.getUuid()); + return response; + } + + protected void sendMessage(SaveLogRQ request, BinaryDataMetaInfo metaInfo, Long projectId) { + amqpTemplate.convertAndSend( + EXCHANGE_REPORTING, + reportingQueueService.getReportingQueueKey(request.getLaunchUuid()), + DeserializablePair.of(request, metaInfo), + message -> { + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + headers.put(MessageHeaders.REQUEST_TYPE, RequestType.LOG); + headers.put(MessageHeaders.PROJECT_ID, projectId); + headers.put(MessageHeaders.ITEM_ID, request.getItemUuid()); + return message; + } + ); + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerImpl.java index 60075463fb..ecaafb91dc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerImpl.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_FULL_TO_LOG; +import static java.util.Optional.ofNullable; + +import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.log.CreateLogHandler; @@ -27,11 +31,18 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.converter.builders.LogBuilder; +import com.epam.ta.reportportal.ws.converter.builders.LogFullBuilder; import com.epam.ta.reportportal.ws.model.EntryCreatedAsyncRS; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Primary; @@ -40,13 +51,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import javax.annotation.Nonnull; -import javax.inject.Provider; -import java.time.LocalDateTime; -import java.time.ZoneOffset; - -import static java.util.Optional.ofNullable; - /** * Create log handler. Save log and binary data related to it * @@ -58,78 +62,79 @@ @Transactional public class CreateLogHandlerImpl implements CreateLogHandler { - @Autowired - TestItemRepository testItemRepository; - - @Autowired - TestItemService testItemService; - - @Autowired - LaunchRepository launchRepository; - - @Autowired - LogRepository logRepository; - - /** - * We are using {@link Provider} there because we need - * {@link SaveLogBinaryDataTask} with scope prototype. Since current class is in - * singleton scope, we have to find a way to get new instance of job for new - * execution - */ - @Autowired - private Provider<SaveLogBinaryDataTask> saveLogBinaryDataTask; - - @Autowired - private LogService logService; - - @Autowired - @Qualifier("saveLogsTaskExecutor") - private TaskExecutor taskExecutor; - - @Override - @Nonnull - //TODO check saving an attachment of the item of the project A in the project's B directory - public EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ request, MultipartFile file, ReportPortalUser.ProjectDetails projectDetails) { - validate(request); - - final LogBuilder logBuilder = new LogBuilder().addSaveLogRq(request).addProjectId(projectDetails.getProjectId()); - - final Launch launch = testItemRepository.findByUuid(request.getItemUuid()).map(item -> { - logBuilder.addTestItem(item); - return testItemService.getEffectiveLaunch(item); - }).orElseGet(() -> launchRepository.findByUuid(request.getLaunchUuid()).map(l -> { - logBuilder.addLaunch(l); - return l; - }).orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, request.getLaunchUuid()))); - - final Log log = logBuilder.get(); - logRepository.save(log); - logService.saveLogMessageToElasticSearch(log, launch.getId()); - - ofNullable(file).ifPresent(f -> saveBinaryData(f, launch, log)); - - return new EntryCreatedAsyncRS(log.getUuid()); - - } - - private void saveBinaryData(MultipartFile file, Launch launch, Log log) { - - final AttachmentMetaInfo.AttachmentMetaInfoBuilder metaInfoBuilder = AttachmentMetaInfo.builder() - .withProjectId(launch.getProjectId()) - .withLaunchId(launch.getId()) - .withLaunchUuid(launch.getUuid()) - .withLogId(log.getId()) - .withFileName(file.getOriginalFilename()) - .withLogUuid(log.getUuid()) - .withCreationDate(LocalDateTime.now(ZoneOffset.UTC)); - ofNullable(log.getTestItem()).map(TestItem::getItemId).ifPresent(metaInfoBuilder::withItemId); - - SaveLogBinaryDataTask saveLogBinaryDataTask = this.saveLogBinaryDataTask.get() - .withFile(file) - .withAttachmentMetaInfo(metaInfoBuilder.build()); - - taskExecutor.execute(saveLogBinaryDataTask); - - } - + private static final Logger LOGGER = LoggerFactory.getLogger(CreateLogHandlerImpl.class); + + @Autowired + TestItemRepository testItemRepository; + + @Autowired + TestItemService testItemService; + + @Autowired + LaunchRepository launchRepository; + + @Autowired + LogRepository logRepository; + + @Autowired + AttachmentBinaryDataService attachmentBinaryDataService; + + @Autowired + private LogService logService; + + @Autowired + @Qualifier("saveLogsTaskExecutor") + private TaskExecutor taskExecutor; + + @Override + @Nonnull + //TODO check saving an attachment of the item of the project A in the project's B directory + public EntryCreatedAsyncRS createLog(@Nonnull SaveLogRQ request, MultipartFile file, + ReportPortalUser.ProjectDetails projectDetails) { + validate(request); + + final LogFullBuilder logFullBuilder = + new LogFullBuilder().addSaveLogRq(request).addProjectId(projectDetails.getProjectId()); + + final Launch launch = testItemRepository.findByUuid(request.getItemUuid()).map(item -> { + logFullBuilder.addTestItem(item); + return testItemService.getEffectiveLaunch(item); + }).orElseGet(() -> launchRepository.findByUuid(request.getLaunchUuid()).map(l -> { + logFullBuilder.addLaunch(l); + return l; + }).orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, request.getLaunchUuid()))); + + final LogFull logFull = logFullBuilder.get(); + final Log log = LOG_FULL_TO_LOG.apply(logFull); + CompletableFuture.supplyAsync(() -> logRepository.saveAndFlush(log), taskExecutor) + .thenAcceptAsync(savedLog -> { + logFull.setId(savedLog.getId()); + logService.saveLogMessage(logFull, launch.getId()); + if (file != null) { + saveBinaryData(file, launch, savedLog); + } + }, taskExecutor) + .exceptionally(e -> { + LOGGER.error("Failed to save log with attachments", e); + return null; + } + ); + + return new EntryCreatedAsyncRS(log.getUuid()); + } + + private void saveBinaryData(MultipartFile file, Launch launch, Log savedLog) { + final AttachmentMetaInfo.AttachmentMetaInfoBuilder metaInfoBuilder = + AttachmentMetaInfo.builder().withProjectId(launch.getProjectId()) + .withLaunchId(launch.getId()).withLaunchUuid(launch.getUuid()) + .withLogId(savedLog.getId()) + .withFileName(file.getOriginalFilename()) + .withLogUuid(savedLog.getUuid()) + .withCreationDate(LocalDateTime.now(ZoneOffset.UTC)); + ofNullable(savedLog.getTestItem()).map(TestItem::getItemId) + .ifPresent(metaInfoBuilder::withItemId); + + attachmentBinaryDataService.saveFileAndAttachToLog(file, metaInfoBuilder.build()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerImpl.java index ca5954a3bd..a305082dd3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerImpl.java @@ -16,11 +16,25 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.commons.Preconditions.statusIn; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.ACCESS_DENIED; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_IS_NOT_FINISHED; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.TEST_ITEM_IS_NOT_FINISHED; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.log.DeleteLogHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.ProjectRepository; @@ -33,19 +47,11 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import org.apache.commons.lang3.BooleanUtils; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.Objects; import java.util.Optional; - -import static com.epam.ta.reportportal.commons.Preconditions.statusIn; -import static com.epam.ta.reportportal.commons.Predicates.*; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.stereotype.Service; /** * Delete Logs handler. Basic implementation of @@ -57,80 +63,99 @@ @Service public class DeleteLogHandlerImpl implements DeleteLogHandler { - private final LogRepository logRepository; - - private final AttachmentRepository attachmentRepository; - - private final ProjectRepository projectRepository; - - private final TestItemService testItemService; - - private final LogIndexer logIndexer; - - public DeleteLogHandlerImpl(LogRepository logRepository, ProjectRepository projectRepository, TestItemService testItemService, - LogIndexer logIndexer, AttachmentRepository attachmentRepository) { - this.logRepository = logRepository; - this.projectRepository = projectRepository; - this.testItemService = testItemService; - this.logIndexer = logIndexer; - this.attachmentRepository = attachmentRepository; - } - - @Override - public OperationCompletionRS deleteLog(Long logId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - BusinessRule.expect(projectRepository.existsById(projectDetails.getProjectId()), BooleanUtils::isTrue) - .verify(PROJECT_NOT_FOUND, projectDetails.getProjectId()); - - Log log = validate(logId, user, projectDetails); - try { - logRepository.delete(log); - ofNullable(log.getAttachment()).ifPresent(attachment -> attachmentRepository.moveForDeletion(attachment.getId())); - } catch (Exception exc) { - throw new ReportPortalException("Error while Log instance deleting.", exc); - } - - logIndexer.cleanIndex(projectDetails.getProjectId(), Collections.singletonList(logId)); - return new OperationCompletionRS(formattedSupplier("Log with ID = '{}' successfully deleted.", logId).toString()); - } - - /** - * Validate specified log against parent objects and project - * - * @param logId - validated log ID value - * @param projectDetails Project details - * @return Log - */ - private Log validate(Long logId, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - - Log log = logRepository.findById(logId).orElseThrow(() -> new ReportPortalException(ErrorType.LOG_NOT_FOUND, logId)); - - Optional<TestItem> itemOptional = ofNullable(log.getTestItem()); - Launch launch = ofNullable(log.getTestItem()).map(testItemService::getEffectiveLaunch).orElseGet(log::getLaunch); - - //TODO check if statistics is right in item results - if (itemOptional.isPresent()) { - expect(itemOptional.get().getItemResults().getStatistics(), notNull()).verify(TEST_ITEM_IS_NOT_FINISHED, formattedSupplier( - "Unable to delete log '{}' when test item '{}' in progress state", - log.getId(), - itemOptional.get().getItemId() - )); - } else { - expect(launch.getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify(LAUNCH_IS_NOT_FINISHED, - formattedSupplier("Unable to delete log '{}' when launch '{}' in progress state", log.getId(), launch.getId()) - ); - } - - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Log '{}' not under specified '{}' project", logId, projectDetails.getProjectId()) - ); - - if (user.getUserRole() != UserRole.ADMINISTRATOR && !Objects.equals(user.getUserId(), launch.getUserId())) { - /* - * Only PROJECT_MANAGER roles could delete logs - */ - expect(projectDetails.getProjectRole(), equalTo(ProjectRole.PROJECT_MANAGER)).verify(ACCESS_DENIED); - } - - return log; - } + private final LogRepository logRepository; + + private final AttachmentRepository attachmentRepository; + + private final ProjectRepository projectRepository; + + private final TestItemService testItemService; + + private final LogIndexer logIndexer; + + private final LogService logService; + + public DeleteLogHandlerImpl(LogRepository logRepository, ProjectRepository projectRepository, + TestItemService testItemService, + LogIndexer logIndexer, AttachmentRepository attachmentRepository, LogService logService) { + this.logRepository = logRepository; + this.projectRepository = projectRepository; + this.testItemService = testItemService; + this.logIndexer = logIndexer; + this.attachmentRepository = attachmentRepository; + this.logService = logService; + } + + @Override + public OperationCompletionRS deleteLog(Long logId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + BusinessRule.expect(projectRepository.existsById(projectDetails.getProjectId()), + BooleanUtils::isTrue) + .verify(PROJECT_NOT_FOUND, projectDetails.getProjectId()); + + Log log = validate(logId, user, projectDetails); + try { + logService.deleteLogMessage(projectDetails.getProjectId(), log.getId()); + logRepository.delete(log); + ofNullable(log.getAttachment()).ifPresent( + attachment -> attachmentRepository.moveForDeletion(attachment.getId())); + } catch (Exception exc) { + throw new ReportPortalException("Error while Log instance deleting.", exc); + } + + logIndexer.cleanIndex(projectDetails.getProjectId(), Collections.singletonList(logId)); + return new OperationCompletionRS( + formattedSupplier("Log with ID = '{}' successfully deleted.", logId).toString()); + } + + /** + * Validate specified log against parent objects and project + * + * @param logId - validated log ID value + * @param projectDetails Project details + * @return Log + */ + private Log validate(Long logId, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + + Log log = logRepository.findById(logId) + .orElseThrow(() -> new ReportPortalException(ErrorType.LOG_NOT_FOUND, logId)); + + Optional<TestItem> itemOptional = ofNullable(log.getTestItem()); + Launch launch = ofNullable(log.getTestItem()).map(testItemService::getEffectiveLaunch) + .orElseGet(log::getLaunch); + + //TODO check if statistics is right in item results + if (itemOptional.isPresent()) { + expect(itemOptional.get().getItemResults().getStatistics(), notNull()).verify( + TEST_ITEM_IS_NOT_FINISHED, formattedSupplier( + "Unable to delete log '{}' when test item '{}' in progress state", + log.getId(), + itemOptional.get().getItemId() + )); + } else { + expect(launch.getStatus(), not(statusIn(StatusEnum.IN_PROGRESS))).verify( + LAUNCH_IS_NOT_FINISHED, + formattedSupplier("Unable to delete log '{}' when launch '{}' in progress state", + log.getId(), launch.getId()) + ); + } + + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + formattedSupplier("Log '{}' not under specified '{}' project", logId, + projectDetails.getProjectId()) + ); + + if (user.getUserRole() != UserRole.ADMINISTRATOR && !Objects.equals(user.getUserId(), + launch.getUserId())) { + /* + * Only PROJECT_MANAGER roles could delete logs + */ + expect(projectDetails.getProjectRole(), equalTo(ProjectRole.PROJECT_MANAGER)).verify( + ACCESS_DENIED); + } + + return log; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImpl.java index ce3a1001fc..c83b40440a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImpl.java @@ -16,10 +16,30 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.querygen.constant.LogCriteriaConstant.CRITERIA_ITEM_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_RETRY_PARENT_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.LOG_NOT_FOUND; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.CompositeFilterCondition; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.FilterTarget; +import com.epam.ta.reportportal.commons.querygen.ProjectFilter; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.log.GetLogHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.dao.constant.LogRepositoryConstants; @@ -31,6 +51,7 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.converter.PagedResourcesAssembler; import com.epam.ta.reportportal.ws.converter.converters.LogConverter; @@ -39,6 +60,13 @@ import com.epam.ta.reportportal.ws.model.log.GetLogsUnderRq; import com.epam.ta.reportportal.ws.model.log.LogResource; import com.google.common.collect.Lists; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.BooleanUtils; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; @@ -49,22 +77,6 @@ import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.querygen.constant.LogCriteriaConstant.CRITERIA_ITEM_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_RETRY_PARENT_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; -import static com.epam.ta.reportportal.ws.model.ErrorType.LOG_NOT_FOUND; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.toMap; - /** * Implementation of GET log operations * @@ -74,310 +86,354 @@ @Service public class GetLogHandlerImpl implements GetLogHandler { - public static final String EXCLUDE_PASSED_LOGS = "excludePassedLogs"; - public static final String EXCLUDE_EMPTY_STEPS = "excludeEmptySteps"; - public static final String EXCLUDE_LOG_CONTENT = "excludeLogContent"; - - private static final int NESTED_STEP_MAX_PAGE_SIZE = 300; - - private static final int LOG_UNDER_ITEM_BATCH_SIZE = 5; - - private final LogRepository logRepository; - - private final TestItemRepository testItemRepository; - - private final TestItemService testItemService; - - @Autowired - public GetLogHandlerImpl(LogRepository logRepository, TestItemRepository testItemRepository, TestItemService testItemService) { - this.logRepository = logRepository; - this.testItemRepository = testItemRepository; - this.testItemService = testItemService; - } - - @Override - public Iterable<LogResource> getLogs(@Nullable String path, ReportPortalUser.ProjectDetails projectDetails, Filter filterable, - Pageable pageable) { - ofNullable(path).ifPresent(p -> updateFilter(filterable, p)); - Page<Log> logPage = logRepository.findByFilter(ProjectFilter.of(filterable, projectDetails.getProjectId()), pageable); - return PagedResourcesAssembler.pageConverter(LogConverter.TO_RESOURCE).apply(logPage); - } - - @Override - public Map<Long, List<LogResource>> getLogs(GetLogsUnderRq logsUnderRq, ReportPortalUser.ProjectDetails projectDetails) { - - final LogLevel logLevel = LogLevel.toLevel(logsUnderRq.getLogLevel()) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, logsUnderRq.getLogLevel())); - - return testItemRepository.findAllById(logsUnderRq.getItemIds()).stream().collect(toMap(TestItem::getItemId, item -> { - final Launch launch = testItemService.getEffectiveLaunch(item); - validate(launch, projectDetails); - return logRepository.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), - item.getItemId(), - logLevel.toInt(), - LOG_UNDER_ITEM_BATCH_SIZE - ).stream().map(LogConverter.TO_RESOURCE).collect(Collectors.toList()); - })); - } - - @Override - public long getPageNumber(Long logId, ReportPortalUser.ProjectDetails projectDetails, Filter filterable, Pageable pageable) { - return logRepository.getPageNumber(logId, filterable, pageable); - } - - @Override - public LogResource getLog(String logId, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - Log log; - try { - log = findById(Long.parseLong(logId)); - } catch (NumberFormatException e) { - log = findByUuid(logId); - } - validate(log, projectDetails); - return LogConverter.TO_RESOURCE.apply(log); - } - - @Override - public Iterable<?> getNestedItems(Long parentId, ReportPortalUser.ProjectDetails projectDetails, Map<String, String> params, - Queryable queryable, Pageable pageable) { - - TestItem parentItem = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); - Launch launch = testItemService.getEffectiveLaunch(parentItem); - validate(launch, projectDetails); - - Boolean excludeEmptySteps = ofNullable(params.get(EXCLUDE_EMPTY_STEPS)).map(BooleanUtils::toBoolean).orElse(false); - Boolean excludePassedLogs = ofNullable(params.get(EXCLUDE_PASSED_LOGS)).map(BooleanUtils::toBoolean).orElse(false); - - Page<NestedItem> nestedItems = logRepository.findNestedItems(parentId, - excludeEmptySteps, - isLogsExclusionRequired(parentItem, excludePassedLogs), - queryable, - pageable - ); - - List<NestedItem> content = nestedItems.getContent(); - - Map<String, List<NestedItem>> result = content.stream().collect(groupingBy(NestedItem::getType)); - - Map<Long, Log> logMap = ofNullable(result.get(LogRepositoryConstants.LOG)).map(logs -> logRepository.findAllById(logs.stream() - .map(NestedItem::getId) - .collect(Collectors.toSet())).stream().collect(toMap(Log::getId, l -> l))).orElseGet(Collections::emptyMap); - - queryable.getFilterConditions().add(getLaunchCondition(launch.getId())); - queryable.getFilterConditions().add(getParentPathCondition(parentItem)); - Map<Long, NestedStep> nestedStepMap = ofNullable(result.get(LogRepositoryConstants.ITEM)).map(testItems -> testItemRepository.findAllNestedStepsByIds( - testItems.stream().map(NestedItem::getId).collect(Collectors.toSet()), - queryable, - excludePassedLogs - ).stream().collect(toMap(NestedStep::getId, i -> i))).orElseGet(Collections::emptyMap); - - List<Object> resources = Lists.newArrayListWithExpectedSize(content.size()); - content.forEach(nestedItem -> { - if (LogRepositoryConstants.LOG.equals(nestedItem.getType())) { - ofNullable(logMap.get(nestedItem.getId())).map(LogConverter.TO_RESOURCE).ifPresent(resources::add); - } else if (LogRepositoryConstants.ITEM.equals(nestedItem.getType())) { - ofNullable(nestedStepMap.get(nestedItem.getId())).map(TestItemConverter.TO_NESTED_STEP_RESOURCE).ifPresent(resources::add); - } - }); - - return PagedResourcesAssembler.pageConverter() - .apply(PageableExecutionUtils.getPage(resources, nestedItems.getPageable(), nestedItems::getTotalElements)); - } - - @Override - public List<PagedLogResource> getLogsWithLocation(Long parentId, ReportPortalUser.ProjectDetails projectDetails, - Map<String, String> params, Queryable queryable, Pageable pageable) { - - TestItem parentItem = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); - Launch launch = testItemService.getEffectiveLaunch(parentItem); - validate(launch, projectDetails); - - Boolean excludeEmptySteps = ofNullable(params.get(EXCLUDE_EMPTY_STEPS)).map(BooleanUtils::toBoolean).orElse(false); - Boolean excludePassedLogs = ofNullable(params.get(EXCLUDE_PASSED_LOGS)).map(BooleanUtils::toBoolean).orElse(false); - Boolean excludeLogContent = ofNullable(params.get(EXCLUDE_LOG_CONTENT)).map(BooleanUtils::toBoolean).orElse(false); - - List<PagedLogResource> loadedLogs = new LinkedList<>(); - loadInnerLogs(parentId, loadedLogs, Collections.emptyList(), excludeEmptySteps, excludePassedLogs, queryable, pageable); - - if (!excludeLogContent) { - Map<Long, Log> logMap = logRepository.findAllById(loadedLogs.stream() - .map(PagedLogResource::getId) - .collect(Collectors.toSet())).stream().collect(toMap(Log::getId, l -> l)); - loadedLogs.forEach(resource -> { - final Log model = logMap.get(resource.getId()); - LogConverter.FILL_WITH_LOG_CONTENT.apply(model, resource); - }); - } - return loadedLogs; - } - - private void loadInnerLogs(Long parentId, List<PagedLogResource> results, List<Map.Entry<Long, Integer>> pagesLocation, - boolean excludeEmptySteps, boolean excludePassedLogs, Queryable queryable, Pageable pageable) { - - TestItem parentItem = testItemRepository.findById(parentId) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); - - if (isLogsExclusionRequired(parentItem, excludePassedLogs)) { - return; - } - - final List<NestedItemPage> nestedItems = logRepository.findNestedItemsWithPage( - parentId, - excludeEmptySteps, - isLogsExclusionRequired(parentItem, excludePassedLogs), - queryable, - pageable - ); - nestedItems.stream() - .filter(nestedItem -> nestedItem.getType().equals(LogRepositoryConstants.ITEM) - || nestedItem.getLogLevel() >= LogLevel.ERROR_INT) - .forEach(nestedItem -> { - List<Map.Entry<Long, Integer>> copy = new LinkedList<>(pagesLocation); - copy.add(new AbstractMap.SimpleEntry<>(nestedItem.getId(), nestedItem.getPageNumber())); - if (nestedItem.getType().equals(LogRepositoryConstants.ITEM)) { - loadInnerLogs(nestedItem.getId(), - results, - copy, - excludeEmptySteps, - excludePassedLogs, - queryable, - PageRequest.of(1, NESTED_STEP_MAX_PAGE_SIZE, pageable.getSort()) - ); - } else { - PagedLogResource pagedLogResource = new PagedLogResource(); - pagedLogResource.setId(nestedItem.getId()); - pagedLogResource.setPagesLocation(copy); - results.add(pagedLogResource); - } - }); - } - - /** - * Validate log item on existence, availability under specified project, - * etc. - * - * @param log - log item - * @param projectDetails Project details - */ - private void validate(Log log, ReportPortalUser.ProjectDetails projectDetails) { - Long launchProjectId = ofNullable(log.getTestItem()).map(it -> testItemService.getEffectiveLaunch(it).getProjectId()) - .orElseGet(() -> log.getLaunch().getProjectId()); - - expect(launchProjectId, equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Log '{}' is not under '{}' project", log.getId(), projectDetails.getProjectName()) - ); - } - - private void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { - expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, - formattedSupplier("Launch '{}' is not under '{}' project", launch.getId(), projectDetails.getProjectName()) - ); - } - - /** - * Find log item by id - * - * @param logId - log ID - * @return - log item - */ - private Log findById(Long logId) { - return logRepository.findById(logId).orElseThrow(() -> new ReportPortalException(LOG_NOT_FOUND, logId)); - } - - /** - * Find log item by uuid - * - * @param logId - log UUID - * @return - log item - */ - private Log findByUuid(String logId) { - return logRepository.findByUuid(logId).orElseThrow(() -> new ReportPortalException(LOG_NOT_FOUND, logId)); - } - - private FilterCondition getLaunchCondition(Long launchId) { - return FilterCondition.builder().eq(CRITERIA_ITEM_LAUNCH_ID, String.valueOf(launchId)).build(); - } - - /** - * Updates 'filterable' with {@link TestItem#getLaunchId()} condition if {@link TestItem#getRetryOf()} is NULL - * otherwise updates 'filterable' with 'launchId' of the 'retry' parent - * - * @param filterable {@link Filter} with {@link FilterTarget#getClazz()} of {@link Log} - * @param path {@link TestItem#getPath()} under which {@link Log} entities should be searched - */ - private void updateFilter(Filter filterable, String path) { - TestItem testItem = testItemRepository.findByPath(path) - .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, path)); - - updatePathCondition(testItem, filterable); - - Launch launch = testItemService.getEffectiveLaunch(testItem); - - FilterCondition.ConditionBuilder itemLaunchIdConditionBuilder = FilterCondition.builder() - .eq(CRITERIA_ITEM_LAUNCH_ID, String.valueOf(launch.getId())); - - ConvertibleCondition launchIdCondition = ofNullable(testItem.getRetryOf()).map(retryOf -> (ConvertibleCondition) new CompositeFilterCondition( - Lists.newArrayList(itemLaunchIdConditionBuilder.withOperator(Operator.OR).build(), - FilterCondition.builder() - .eq(CRITERIA_RETRY_PARENT_LAUNCH_ID, String.valueOf(launch.getId())) - .withOperator(Operator.OR) - .build() - ))).orElseGet(itemLaunchIdConditionBuilder::build); - - filterable.getFilterConditions().add(launchIdCondition); - - } - - /** - * Updates 'path' condition of the {@link TestItem} whose {@link Log} entities should be searched. - * Required when there are 'Nested Steps' under the {@link TestItem} that is a 'retry' - * - * @param testItem {@link TestItem} containing logs - * @param filterable {@link Filter} with {@link FilterTarget#getClazz()} of {@link Log} - */ - private void updatePathCondition(TestItem testItem, Filter filterable) { - List<ConvertibleCondition> resultConditions = filterable.getFilterConditions() - .stream() - .flatMap(c -> c.getAllConditions().stream()) - .filter(c -> BooleanUtils.isFalse(CRITERIA_PATH.equals(c.getSearchCriteria()) && Condition.UNDER.equals(c.getCondition()))) - .collect(Collectors.toList()); - filterable.getFilterConditions().clear(); - - FilterCondition parentPathCondition = getParentPathCondition(testItem); - resultConditions.add(ofNullable(testItem.getRetryOf()).map(retryParent -> (ConvertibleCondition) new CompositeFilterCondition(Lists.newArrayList( - parentPathCondition, - FilterCondition.builder() - .withOperator(Operator.OR) - .withCondition(Condition.UNDER) - .withSearchCriteria(CRITERIA_PATH) - .withValue(String.valueOf(testItem.getPath())) - .build() - ))).orElse(parentPathCondition)); - - filterable.getFilterConditions().addAll(resultConditions); - } - - private FilterCondition getParentPathCondition(TestItem parent) { - String pathValue = ofNullable(parent.getRetryOf()).flatMap(retryParentId -> ofNullable(parent.getParentId()).flatMap( - testItemRepository::findById).map(retryParent -> retryParent.getPath() + "." + parent.getItemId())) - .orElse(parent.getPath()); - return FilterCondition.builder().withCondition(Condition.UNDER).withSearchCriteria(CRITERIA_PATH).withValue(pathValue).build(); - } - - /** - * Method to determine whether logs of the {@link TestItem} with {@link StatusEnum#PASSED} - * should be retrieved with nested steps or should be excluded from the select query - * - * @param parent {@link Log#getTestItem()} - * @param excludePassedLogs if 'true' logs of the passed items should be excluded - * @return 'true' if logs should be excluded from the select query, else 'false' - */ - private boolean isLogsExclusionRequired(TestItem parent, boolean excludePassedLogs) { - if (excludePassedLogs) { - return Stream.of(StatusEnum.values()).filter(StatusEnum::isPositive).anyMatch(s -> s == parent.getItemResults().getStatus()); - } - return false; - } + public static final String EXCLUDE_PASSED_LOGS = "excludePassedLogs"; + public static final String EXCLUDE_EMPTY_STEPS = "excludeEmptySteps"; + public static final String EXCLUDE_LOG_CONTENT = "excludeLogContent"; + + private static final int NESTED_STEP_MAX_PAGE_SIZE = 300; + + private static final int LOG_UNDER_ITEM_BATCH_SIZE = 5; + + private final LogRepository logRepository; + + private final LogService logService; + + private final TestItemRepository testItemRepository; + + private final TestItemService testItemService; + + @Autowired + public GetLogHandlerImpl(LogRepository logRepository, LogService logService, + TestItemRepository testItemRepository, TestItemService testItemService) { + this.logRepository = logRepository; + this.logService = logService; + this.testItemRepository = testItemRepository; + this.testItemService = testItemService; + } + + @Override + public Iterable<LogResource> getLogs(@Nullable String path, + ReportPortalUser.ProjectDetails projectDetails, Filter filterable, + Pageable pageable) { + ofNullable(path).ifPresent(p -> updateFilter(filterable, p)); + Page<LogFull> logFullPage = logService.findByFilter( + ProjectFilter.of(filterable, projectDetails.getProjectId()), pageable); + return PagedResourcesAssembler.pageConverter(LogConverter.TO_RESOURCE).apply(logFullPage); + } + + @Override + public Map<Long, List<LogResource>> getLogs(GetLogsUnderRq logsUnderRq, + ReportPortalUser.ProjectDetails projectDetails) { + + final LogLevel logLevel = LogLevel.toLevel(logsUnderRq.getLogLevel()) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + logsUnderRq.getLogLevel())); + + return testItemRepository.findAllById(logsUnderRq.getItemIds()).stream() + .collect(toMap(TestItem::getItemId, item -> { + final Launch launch = testItemService.getEffectiveLaunch(item); + validate(launch, projectDetails); + return logService.findLatestUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte( + launch.getId(), + item.getItemId(), + logLevel.toInt(), + LOG_UNDER_ITEM_BATCH_SIZE + ).stream().map(LogConverter.TO_RESOURCE).collect(Collectors.toList()); + })); + } + + @Override + public long getPageNumber(Long logId, ReportPortalUser.ProjectDetails projectDetails, + Filter filterable, Pageable pageable) { + return logRepository.getPageNumber(logId, filterable, pageable); + } + + @Override + public LogResource getLog(String logId, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + LogFull logFull; + try { + logFull = findById(Long.parseLong(logId)); + } catch (NumberFormatException e) { + logFull = findByUuid(logId); + } + validate(logFull, projectDetails); + return LogConverter.TO_RESOURCE.apply(logFull); + } + + @Override + public Iterable<?> getNestedItems(Long parentId, ReportPortalUser.ProjectDetails projectDetails, + Map<String, String> params, + Queryable queryable, Pageable pageable) { + + TestItem parentItem = testItemRepository.findById(parentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); + Launch launch = testItemService.getEffectiveLaunch(parentItem); + validate(launch, projectDetails); + + Boolean excludeEmptySteps = ofNullable(params.get(EXCLUDE_EMPTY_STEPS)).map( + BooleanUtils::toBoolean).orElse(false); + Boolean excludePassedLogs = ofNullable(params.get(EXCLUDE_PASSED_LOGS)).map( + BooleanUtils::toBoolean).orElse(false); + + Page<NestedItem> nestedItems = logRepository.findNestedItems(parentId, + excludeEmptySteps, + isLogsExclusionRequired(parentItem, excludePassedLogs), + queryable, + pageable + ); + + List<NestedItem> content = nestedItems.getContent(); + + Map<String, List<NestedItem>> result = content.stream() + .collect(groupingBy(NestedItem::getType)); + + Map<Long, LogFull> logMap = ofNullable(result.get(LogRepositoryConstants.LOG)).map( + logs -> logService.findAllById(logs.stream() + .map(NestedItem::getId) + .collect(Collectors.toSet())).stream().collect(toMap(LogFull::getId, l -> l))) + .orElseGet(Collections::emptyMap); + + queryable.getFilterConditions().add(getLaunchCondition(launch.getId())); + queryable.getFilterConditions().add(getParentPathCondition(parentItem)); + Map<Long, NestedStep> nestedStepMap = ofNullable(result.get(LogRepositoryConstants.ITEM)).map( + testItems -> testItemRepository.findAllNestedStepsByIds( + testItems.stream().map(NestedItem::getId).collect(Collectors.toSet()), + queryable, + excludePassedLogs + ).stream().collect(toMap(NestedStep::getId, i -> i))).orElseGet(Collections::emptyMap); + + List<Object> resources = Lists.newArrayListWithExpectedSize(content.size()); + content.forEach(nestedItem -> { + if (LogRepositoryConstants.LOG.equals(nestedItem.getType())) { + ofNullable(logMap.get(nestedItem.getId())).map(LogConverter.TO_RESOURCE) + .ifPresent(resources::add); + } else if (LogRepositoryConstants.ITEM.equals(nestedItem.getType())) { + ofNullable(nestedStepMap.get(nestedItem.getId())).map( + TestItemConverter.TO_NESTED_STEP_RESOURCE).ifPresent(resources::add); + } + }); + + return PagedResourcesAssembler.pageConverter() + .apply(PageableExecutionUtils.getPage(resources, nestedItems.getPageable(), + nestedItems::getTotalElements)); + } + + @Override + public List<PagedLogResource> getLogsWithLocation(Long parentId, + ReportPortalUser.ProjectDetails projectDetails, + Map<String, String> params, Queryable queryable, Pageable pageable) { + + TestItem parentItem = testItemRepository.findById(parentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); + Launch launch = testItemService.getEffectiveLaunch(parentItem); + validate(launch, projectDetails); + + Boolean excludeEmptySteps = ofNullable(params.get(EXCLUDE_EMPTY_STEPS)).map( + BooleanUtils::toBoolean).orElse(false); + Boolean excludePassedLogs = ofNullable(params.get(EXCLUDE_PASSED_LOGS)).map( + BooleanUtils::toBoolean).orElse(false); + Boolean excludeLogContent = ofNullable(params.get(EXCLUDE_LOG_CONTENT)).map( + BooleanUtils::toBoolean).orElse(false); + + List<PagedLogResource> loadedLogs = new LinkedList<>(); + loadInnerLogs(parentId, loadedLogs, Collections.emptyList(), excludeEmptySteps, + excludePassedLogs, queryable, pageable); + + if (!excludeLogContent) { + Map<Long, LogFull> logMap = logService.findAllById(loadedLogs.stream() + .map(PagedLogResource::getId) + .collect(Collectors.toSet())).stream().collect(toMap(LogFull::getId, l -> l)); + loadedLogs.forEach(resource -> { + final LogFull model = logMap.get(resource.getId()); + LogConverter.FILL_WITH_LOG_CONTENT.apply(model, resource); + }); + } + return loadedLogs; + } + + private void loadInnerLogs(Long parentId, List<PagedLogResource> results, + List<Map.Entry<Long, Integer>> pagesLocation, + boolean excludeEmptySteps, boolean excludePassedLogs, Queryable queryable, + Pageable pageable) { + + TestItem parentItem = testItemRepository.findById(parentId) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, parentId)); + + if (isLogsExclusionRequired(parentItem, excludePassedLogs)) { + return; + } + + final List<NestedItemPage> nestedItems = logRepository.findNestedItemsWithPage( + parentId, + excludeEmptySteps, + isLogsExclusionRequired(parentItem, excludePassedLogs), + queryable, + pageable + ); + nestedItems.stream() + .filter(nestedItem -> nestedItem.getType().equals(LogRepositoryConstants.ITEM) + || nestedItem.getLogLevel() >= LogLevel.ERROR_INT) + .forEach(nestedItem -> { + List<Map.Entry<Long, Integer>> copy = new LinkedList<>(pagesLocation); + copy.add(new AbstractMap.SimpleEntry<>(nestedItem.getId(), nestedItem.getPageNumber())); + if (nestedItem.getType().equals(LogRepositoryConstants.ITEM)) { + loadInnerLogs(nestedItem.getId(), + results, + copy, + excludeEmptySteps, + excludePassedLogs, + queryable, + PageRequest.of(1, NESTED_STEP_MAX_PAGE_SIZE, pageable.getSort()) + ); + } else { + PagedLogResource pagedLogResource = new PagedLogResource(); + pagedLogResource.setId(nestedItem.getId()); + pagedLogResource.setPagesLocation(copy); + results.add(pagedLogResource); + } + }); + } + + /** + * Validate log item on existence, availability under specified project, etc. + * + * @param log - logFull item + * @param projectDetails Project details + */ + private void validate(LogFull log, ReportPortalUser.ProjectDetails projectDetails) { + Long launchProjectId = ofNullable(log.getTestItem()).map( + it -> testItemService.getEffectiveLaunch(it).getProjectId()) + .orElseGet(() -> log.getLaunch().getProjectId()); + + expect(launchProjectId, equalTo(projectDetails.getProjectId())).verify(FORBIDDEN_OPERATION, + formattedSupplier("Log '{}' is not under '{}' project", log.getId(), + projectDetails.getProjectName()) + ); + } + + private void validate(Launch launch, ReportPortalUser.ProjectDetails projectDetails) { + expect(launch.getProjectId(), equalTo(projectDetails.getProjectId())).verify( + FORBIDDEN_OPERATION, + formattedSupplier("Launch '{}' is not under '{}' project", launch.getId(), + projectDetails.getProjectName()) + ); + } + + /** + * Find logFull item by id + * + * @param logId - log ID + * @return - log item + */ + private LogFull findById(Long logId) { + return logService.findById(logId) + .orElseThrow(() -> new ReportPortalException(LOG_NOT_FOUND, logId)); + } + + /** + * Find logFull item by uuid + * + * @param logId - log UUID + * @return - log item + */ + private LogFull findByUuid(String logId) { + return logService.findByUuid(logId) + .orElseThrow(() -> new ReportPortalException(LOG_NOT_FOUND, logId)); + } + + private FilterCondition getLaunchCondition(Long launchId) { + return FilterCondition.builder().eq(CRITERIA_ITEM_LAUNCH_ID, String.valueOf(launchId)).build(); + } + + /** + * Updates 'filterable' with {@link TestItem#getLaunchId()} condition if + * {@link TestItem#getRetryOf()} is NULL otherwise updates 'filterable' with 'launchId' of the + * 'retry' parent + * + * @param filterable {@link Filter} with {@link FilterTarget#getClazz()} of {@link Log} + * @param path {@link TestItem#getPath()} under which {@link Log} entities should be + * searched + */ + private void updateFilter(Filter filterable, String path) { + TestItem testItem = testItemRepository.findByPath(path) + .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, path)); + + updatePathCondition(testItem, filterable); + + Launch launch = testItemService.getEffectiveLaunch(testItem); + + FilterCondition.ConditionBuilder itemLaunchIdConditionBuilder = FilterCondition.builder() + .eq(CRITERIA_ITEM_LAUNCH_ID, String.valueOf(launch.getId())); + + ConvertibleCondition launchIdCondition = ofNullable(testItem.getRetryOf()).map( + retryOf -> (ConvertibleCondition) new CompositeFilterCondition( + Lists.newArrayList(itemLaunchIdConditionBuilder.withOperator(Operator.OR).build(), + FilterCondition.builder() + .eq(CRITERIA_RETRY_PARENT_LAUNCH_ID, String.valueOf(launch.getId())) + .withOperator(Operator.OR) + .build() + ))).orElseGet(itemLaunchIdConditionBuilder::build); + + filterable.getFilterConditions().add(launchIdCondition); + + } + + /** + * Updates 'path' condition of the {@link TestItem} whose {@link Log} entities should be searched. + * Required when there are 'Nested Steps' under the {@link TestItem} that is a 'retry' + * + * @param testItem {@link TestItem} containing logs + * @param filterable {@link Filter} with {@link FilterTarget#getClazz()} of {@link Log} + */ + private void updatePathCondition(TestItem testItem, Filter filterable) { + List<ConvertibleCondition> resultConditions = filterable.getFilterConditions() + .stream() + .flatMap(c -> c.getAllConditions().stream()) + .filter(c -> BooleanUtils.isFalse( + CRITERIA_PATH.equals(c.getSearchCriteria()) && Condition.UNDER.equals( + c.getCondition()))) + .collect(Collectors.toList()); + filterable.getFilterConditions().clear(); + + FilterCondition parentPathCondition = getParentPathCondition(testItem); + resultConditions.add(ofNullable(testItem.getRetryOf()).map( + retryParent -> (ConvertibleCondition) new CompositeFilterCondition(Lists.newArrayList( + parentPathCondition, + FilterCondition.builder() + .withOperator(Operator.OR) + .withCondition(Condition.UNDER) + .withSearchCriteria(CRITERIA_PATH) + .withValue(String.valueOf(testItem.getPath())) + .build() + ))).orElse(parentPathCondition)); + + filterable.getFilterConditions().addAll(resultConditions); + } + + private FilterCondition getParentPathCondition(TestItem parent) { + String pathValue = ofNullable(parent.getRetryOf()).flatMap( + retryParentId -> ofNullable(parent.getParentId()).flatMap( + testItemRepository::findById) + .map(retryParent -> retryParent.getPath() + "." + parent.getItemId())) + .orElse(parent.getPath()); + return FilterCondition.builder().withCondition(Condition.UNDER) + .withSearchCriteria(CRITERIA_PATH).withValue(pathValue).build(); + } + + /** + * Method to determine whether logs of the {@link TestItem} with {@link StatusEnum#PASSED} should + * be retrieved with nested steps or should be excluded from the select query + * + * @param parent {@link Log#getTestItem()} + * @param excludePassedLogs if 'true' logs of the passed items should be excluded + * @return 'true' if logs should be excluded from the select query, else 'false' + */ + private boolean isLogsExclusionRequired(TestItem parent, boolean excludePassedLogs) { + if (excludePassedLogs) { + return Stream.of(StatusEnum.values()).filter(StatusEnum::isPositive) + .anyMatch(s -> s == parent.getItemResults().getStatus()); + } + return false; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/PagedLogResource.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/PagedLogResource.java index 161db1e8a7..24804eb9f8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/PagedLogResource.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/PagedLogResource.java @@ -1,7 +1,6 @@ package com.epam.ta.reportportal.core.log.impl; import com.epam.ta.reportportal.ws.model.log.LogResource; - import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -11,17 +10,17 @@ */ public class PagedLogResource extends LogResource { - private List<Map.Entry<Long, Integer>> pagesLocation; + private List<Map.Entry<Long, Integer>> pagesLocation; - public PagedLogResource() { - pagesLocation = new LinkedList<>(); - } + public PagedLogResource() { + pagesLocation = new LinkedList<>(); + } - public List<Map.Entry<Long, Integer>> getPagesLocation() { - return pagesLocation; - } + public List<Map.Entry<Long, Integer>> getPagesLocation() { + return pagesLocation; + } - public void setPagesLocation(List<Map.Entry<Long, Integer>> pagesLocation) { - this.pagesLocation = pagesLocation; - } + public void setPagesLocation(List<Map.Entry<Long, Integer>> pagesLocation) { + this.pagesLocation = pagesLocation; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTask.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTask.java deleted file mode 100644 index d732e2f330..0000000000 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTask.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.log.impl; - -import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; -import com.epam.ta.reportportal.entity.attachment.AttachmentMetaInfo; -import com.google.common.base.Preconditions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.multipart.MultipartFile; - -/** - * Save binary data task. Expected to be executed asynchronously. Statefull, so - * cannot be a singleton bean. Saves binary data, then updates related log entry - * with saved data id - * <p> - * NOTE: run asynchronously in sense of run in Executor. This class is not used with RabbitMQ. - * It is original implementation for synchronous LogController - * - * @author Andrei Varabyeu - */ -public class SaveLogBinaryDataTask implements Runnable { - - @Autowired - private AttachmentBinaryDataService attachmentBinaryDataService; - - /** - * Binary data representation - */ - private MultipartFile file; - - private AttachmentMetaInfo attachmentMetaInfo; - - @Override - public void run() { - attachmentBinaryDataService.saveFileAndAttachToLog(file, attachmentMetaInfo); - } - - public SaveLogBinaryDataTask withFile(MultipartFile file) { - Preconditions.checkNotNull(file, "Binary data shouldn't be null"); - this.file = file; - return this; - } - - public SaveLogBinaryDataTask withAttachmentMetaInfo(AttachmentMetaInfo metaInfo) { - Preconditions.checkNotNull(metaInfo); - this.attachmentMetaInfo = metaInfo; - return this; - } -} diff --git a/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTaskAsync.java b/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTaskAsync.java index ab83d55340..e7ff9292b2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTaskAsync.java +++ b/src/main/java/com/epam/ta/reportportal/core/log/impl/SaveLogBinaryDataTaskAsync.java @@ -23,14 +23,13 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.google.common.base.Preconditions; +import java.util.Optional; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.multipart.MultipartFile; -import java.util.Optional; -import java.util.function.Supplier; - /** * Task to save log's binary data from MultipartFile for the use with queued RabbitMQ log saving. * Statefull, so cannot be a singleton bean. @@ -39,44 +38,46 @@ */ public class SaveLogBinaryDataTaskAsync implements Supplier<BinaryDataMetaInfo> { - private static final Logger LOGGER = LoggerFactory.getLogger(SaveLogBinaryDataTaskAsync.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SaveLogBinaryDataTaskAsync.class); - @Autowired - private AttachmentBinaryDataService attachmentBinaryDataService; + @Autowired + private AttachmentBinaryDataService attachmentBinaryDataService; - private SaveLogRQ request; + private SaveLogRQ request; - private MultipartFile file; + private MultipartFile file; - private Long projectId; + private Long projectId; - @Override - public BinaryDataMetaInfo get() { - Optional<BinaryDataMetaInfo> maybeBinaryDataMetaInfo = attachmentBinaryDataService.saveAttachment(AttachmentMetaInfo.builder() - .withProjectId(projectId) - .withLaunchUuid(request.getLaunchUuid()) - .withLogUuid(request.getUuid()) - .build(), file); - return maybeBinaryDataMetaInfo.orElseGet(() -> { - LOGGER.error("Failed to save log content data into DataStore, projectId {}, itemId {} ", projectId, request.getItemUuid()); - throw new ReportPortalException(ErrorType.BINARY_DATA_CANNOT_BE_SAVED); - }); - } + @Override + public BinaryDataMetaInfo get() { + Optional<BinaryDataMetaInfo> maybeBinaryDataMetaInfo = attachmentBinaryDataService.saveAttachment( + AttachmentMetaInfo.builder() + .withProjectId(projectId) + .withLaunchUuid(request.getLaunchUuid()) + .withLogUuid(request.getUuid()) + .build(), file); + return maybeBinaryDataMetaInfo.orElseGet(() -> { + LOGGER.error("Failed to save log content data into DataStore, projectId {}, itemId {} ", + projectId, request.getItemUuid()); + throw new ReportPortalException(ErrorType.BINARY_DATA_CANNOT_BE_SAVED); + }); + } - public SaveLogBinaryDataTaskAsync withRequest(SaveLogRQ request) { - Preconditions.checkNotNull(request, "Request shouldn't be null"); - this.request = request; - return this; - } + public SaveLogBinaryDataTaskAsync withRequest(SaveLogRQ request) { + Preconditions.checkNotNull(request, "Request shouldn't be null"); + this.request = request; + return this; + } - public SaveLogBinaryDataTaskAsync withFile(MultipartFile file) { - this.file = file; - return this; - } + public SaveLogBinaryDataTaskAsync withFile(MultipartFile file) { + this.file = file; + return this; + } - public SaveLogBinaryDataTaskAsync withProjectId(Long projectId) { - Preconditions.checkNotNull(projectId, "Project id should not be null"); - this.projectId = projectId; - return this; - } + public SaveLogBinaryDataTaskAsync withProjectId(Long projectId) { + Preconditions.checkNotNull(projectId, "Project id should not be null"); + this.projectId = projectId; + return this; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/logging/HttpLogging.java b/src/main/java/com/epam/ta/reportportal/core/logging/HttpLogging.java index 535c038283..2f6089bc2c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/logging/HttpLogging.java +++ b/src/main/java/com/epam/ta/reportportal/core/logging/HttpLogging.java @@ -28,11 +28,11 @@ @Target(ElementType.METHOD) public @interface HttpLogging { - boolean logHeaders() default true; + boolean logHeaders() default true; - boolean logRequestBody() default true; + boolean logRequestBody() default true; - boolean logResponseBody() default true; + boolean logResponseBody() default true; - boolean logExecutionTime() default true; + boolean logExecutionTime() default true; } diff --git a/src/main/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspect.java b/src/main/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspect.java index 28b0492a10..9aca8d05cc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspect.java +++ b/src/main/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspect.java @@ -19,6 +19,13 @@ import ch.qos.logback.classic.Logger; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicLong; +import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -34,14 +41,6 @@ import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.multipart.MultipartHttpServletRequest; -import javax.servlet.http.HttpServletRequest; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicLong; - /** * @author Konstantin Antipin @@ -49,179 +48,185 @@ @Aspect public class HttpLoggingAspect { - private static final String READABLE_CONTENT_TYPES = "text/plain text/html text/xml application/json application/xml application/hal+xml application/hal+json"; - - private static final String NEWLINE = "\n"; - private static final String BODY_DENOMINATOR = "-- Body --"; - private static final String BODY_BINARY_MARK = "<binary body>"; - - private static final AtomicLong COUNTER = new AtomicLong(); - - @Autowired - private ObjectMapper objectMapper; - - @Around("execution(public * *(..)) && @annotation(annotation)") - public Object log(ProceedingJoinPoint joinPoint, HttpLogging annotation) throws Throwable { - - Logger logger = (Logger) LoggerFactory.getLogger(joinPoint.getTarget().getClass()); - - - Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); - - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - Object requestBody = getBody(joinPoint, method); - - String prefix = method.getName(); - - long requestCount = COUNTER.incrementAndGet(); - - if (logger.isDebugEnabled()) { - logger.debug(formatRequestRecord(requestCount, prefix, request, requestBody, annotation)); - } - - Object response; - - long start = System.currentTimeMillis(); - try { - response = joinPoint.proceed(); - long executionTime = System.currentTimeMillis() - start; - if (logger.isDebugEnabled()) { - logger.debug(formatResponseRecord(requestCount, prefix, response, annotation, executionTime)); - } - } catch (Throwable throwable) { - logger.error(" (" + requestCount + ") - Error", throwable); - throw throwable; - } - - return response; - } - - protected Object getBody(ProceedingJoinPoint joinPoint, Method method) { - Object body = null; - Object[] args = joinPoint.getArgs(); - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < parameters.length; i++) { - Object arg = args[i]; - - if (arg != null) { - if (arg instanceof MultipartHttpServletRequest) { - body = BODY_BINARY_MARK; - break; - } else if (parameters[i].isAnnotationPresent(RequestBody.class)) { - body = arg; - break; - } else if (arg instanceof HttpEntity) { - body = ((HttpEntity) arg).getBody(); - break; - } - } - } - return body; - } - - protected String formatRequestRecord(long count, String prefix, HttpServletRequest request, - Object body, HttpLogging annotation) throws Exception { - StringBuilder record = new StringBuilder(); - - // uri - record.append(prefix) - .append(" (").append(count).append(')').append(" - Request") - .append(NEWLINE).append(' ').append(request.getMethod()) - .append(' ').append(URLDecoder.decode(request.getRequestURI(), StandardCharsets.UTF_8.displayName())); - - // headers - if (annotation.logHeaders()) { - Enumeration<String> names = request.getHeaderNames(); - while (names.hasMoreElements()) { - String name = names.nextElement(); - Enumeration<String> values = request.getHeaders(name); - record.append(NEWLINE).append(' ').append(name).append(':'); - boolean comma = false; - while (values.hasMoreElements()) { - if (comma) { - record.append(','); - } else { - comma = true; - } - record.append(' ').append(values.nextElement()); - } - } - } - - // body - if (body != null && annotation.logRequestBody()) { - try { - record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR) - .append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(body)); - } catch (JsonProcessingException e) { - // ignore - } - } - - return record.toString(); - } - - protected String formatResponseRecord(long count, String prefix, Object response, HttpLogging annotation, long executionTime) throws Exception { - boolean binaryBody = false; - StringBuilder record = new StringBuilder(); - - record.append(prefix).append(" (").append(count).append(')').append(" - Response "); - if (annotation.logExecutionTime()) { - record.append(" (").append(executionTime).append(" ms)"); - } - - if (response instanceof ResponseEntity) { - HttpStatus status = ((ResponseEntity) response).getStatusCode(); - record.append(NEWLINE).append(' ').append(status).append(" - ").append(status.getReasonPhrase()); - - if (annotation.logHeaders()) { - HttpHeaders headers = ((ResponseEntity) response).getHeaders(); - for (String name : headers.keySet()) { - record.append(NEWLINE).append(' ').append(name).append(':'); - boolean comma = false; - for (String value : headers.get(name)) { - if (HttpHeaders.CONTENT_TYPE.equals(name) && !readableContent(value)) { - binaryBody = true; - } - if (comma) { - record.append(','); - } else { - comma = true; - } - record.append(' ').append(value); - } - } - } - - if (annotation.logResponseBody()) { - record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR); - if (binaryBody) { - record.append(NEWLINE).append(' ').append('"').append(BODY_BINARY_MARK).append('"'); - } else { - try { - record.append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(((ResponseEntity<?>) response).getBody())); - } catch (JsonProcessingException ex) { - record.append(NEWLINE).append(' ').append(((ResponseEntity<String>) response).getBody()); - } - } - } - } else { - if (annotation.logResponseBody()) { - record.append(NEWLINE).append(' ').append("Status").append(" - ").append("OK (method return)"); - record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR); - try { - record.append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(response)); - } catch (JsonProcessingException ex) { - // ignore - } - } - } - - return record.toString(); - } - - protected boolean readableContent(String value) { - int idx = value.indexOf(';'); - return READABLE_CONTENT_TYPES.contains(value.substring(0, idx > 0 ? idx : value.length())); - } + private static final String READABLE_CONTENT_TYPES = "text/plain text/html text/xml application/json application/xml application/hal+xml application/hal+json"; + + private static final String NEWLINE = "\n"; + private static final String BODY_DENOMINATOR = "-- Body --"; + private static final String BODY_BINARY_MARK = "<binary body>"; + + private static final AtomicLong COUNTER = new AtomicLong(); + + @Autowired + private ObjectMapper objectMapper; + + @Around("execution(public * *(..)) && @annotation(annotation)") + public Object log(ProceedingJoinPoint joinPoint, HttpLogging annotation) throws Throwable { + + Logger logger = (Logger) LoggerFactory.getLogger(joinPoint.getTarget().getClass()); + + Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); + + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + Object requestBody = getBody(joinPoint, method); + + String prefix = method.getName(); + + long requestCount = COUNTER.incrementAndGet(); + + if (logger.isDebugEnabled()) { + logger.debug(formatRequestRecord(requestCount, prefix, request, requestBody, annotation)); + } + + Object response; + + long start = System.currentTimeMillis(); + try { + response = joinPoint.proceed(); + long executionTime = System.currentTimeMillis() - start; + if (logger.isDebugEnabled()) { + logger.debug( + formatResponseRecord(requestCount, prefix, response, annotation, executionTime)); + } + } catch (Throwable throwable) { + logger.error(" (" + requestCount + ") - Error", throwable); + throw throwable; + } + + return response; + } + + protected Object getBody(ProceedingJoinPoint joinPoint, Method method) { + Object body = null; + Object[] args = joinPoint.getArgs(); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Object arg = args[i]; + + if (arg != null) { + if (arg instanceof MultipartHttpServletRequest) { + body = BODY_BINARY_MARK; + break; + } else if (parameters[i].isAnnotationPresent(RequestBody.class)) { + body = arg; + break; + } else if (arg instanceof HttpEntity) { + body = ((HttpEntity) arg).getBody(); + break; + } + } + } + return body; + } + + protected String formatRequestRecord(long count, String prefix, HttpServletRequest request, + Object body, HttpLogging annotation) throws Exception { + StringBuilder record = new StringBuilder(); + + // uri + record.append(prefix) + .append(" (").append(count).append(')').append(" - Request") + .append(NEWLINE).append(' ').append(request.getMethod()) + .append(' ') + .append(URLDecoder.decode(request.getRequestURI(), StandardCharsets.UTF_8.displayName())); + + // headers + if (annotation.logHeaders()) { + Enumeration<String> names = request.getHeaderNames(); + while (names.hasMoreElements()) { + String name = names.nextElement(); + Enumeration<String> values = request.getHeaders(name); + record.append(NEWLINE).append(' ').append(name).append(':'); + boolean comma = false; + while (values.hasMoreElements()) { + if (comma) { + record.append(','); + } else { + comma = true; + } + record.append(' ').append(values.nextElement()); + } + } + } + + // body + if (body != null && annotation.logRequestBody()) { + try { + record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR) + .append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(body)); + } catch (JsonProcessingException e) { + // ignore + } + } + + return record.toString(); + } + + protected String formatResponseRecord(long count, String prefix, Object response, + HttpLogging annotation, long executionTime) throws Exception { + boolean binaryBody = false; + StringBuilder record = new StringBuilder(); + + record.append(prefix).append(" (").append(count).append(')').append(" - Response "); + if (annotation.logExecutionTime()) { + record.append(" (").append(executionTime).append(" ms)"); + } + + if (response instanceof ResponseEntity) { + HttpStatus status = ((ResponseEntity) response).getStatusCode(); + record.append(NEWLINE).append(' ').append(status).append(" - ") + .append(status.getReasonPhrase()); + + if (annotation.logHeaders()) { + HttpHeaders headers = ((ResponseEntity) response).getHeaders(); + for (String name : headers.keySet()) { + record.append(NEWLINE).append(' ').append(name).append(':'); + boolean comma = false; + for (String value : headers.get(name)) { + if (HttpHeaders.CONTENT_TYPE.equals(name) && !readableContent(value)) { + binaryBody = true; + } + if (comma) { + record.append(','); + } else { + comma = true; + } + record.append(' ').append(value); + } + } + } + + if (annotation.logResponseBody()) { + record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR); + if (binaryBody) { + record.append(NEWLINE).append(' ').append('"').append(BODY_BINARY_MARK).append('"'); + } else { + try { + record.append(NEWLINE).append(' ') + .append(objectMapper.writeValueAsString(((ResponseEntity<?>) response).getBody())); + } catch (JsonProcessingException ex) { + record.append(NEWLINE).append(' ') + .append(((ResponseEntity<String>) response).getBody()); + } + } + } + } else { + if (annotation.logResponseBody()) { + record.append(NEWLINE).append(' ').append("Status").append(" - ") + .append("OK (method return)"); + record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR); + try { + record.append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(response)); + } catch (JsonProcessingException ex) { + // ignore + } + } + } + + return record.toString(); + } + + protected boolean readableContent(String value) { + int idx = value.indexOf(';'); + return READABLE_CONTENT_TYPES.contains(value.substring(0, idx > 0 ? idx : value.length())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLogging.java b/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLogging.java index 32af374df4..f3359d4e45 100644 --- a/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLogging.java +++ b/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLogging.java @@ -28,7 +28,7 @@ @Target(ElementType.METHOD) public @interface RabbitMessageLogging { - boolean logHeaders() default true; + boolean logHeaders() default true; - boolean logBody() default true; + boolean logBody() default true; } diff --git a/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspect.java b/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspect.java index 121e1c51a4..1c3fb13f1c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspect.java +++ b/src/main/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspect.java @@ -18,6 +18,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.Map; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -27,14 +31,8 @@ import org.springframework.amqp.core.Message; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.util.HashMap; -import java.util.Map; /** * @author Konstantin Antipin @@ -42,80 +40,83 @@ @Aspect public class RabbitMessageLoggingAspect { - private static final String NEWLINE = "\n"; - private static final String BODY_DENOMINATOR = "-- Body --"; - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private MessageConverter messageConverter; - - @Around("execution(public * *(..)) && @annotation(annotation)") - public Object log(ProceedingJoinPoint joinPoint, RabbitMessageLogging annotation) throws Throwable { - - Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass()); - - Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); - - Map<String, Object> headers = new HashMap<>(); - Object body = getHeadersAndBody(joinPoint, method, headers); - - String prefix = method.getName(); - - if (logger.isDebugEnabled()) { - logger.debug(formatMessageRecord(prefix, headers, body, annotation)); - } - - return joinPoint.proceed(); - } - - protected Object getHeadersAndBody(ProceedingJoinPoint joinPoint, Method method, Map<String, Object> headers) { - Object body = null; - Object[] args = joinPoint.getArgs(); - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < parameters.length; i++) { - Object arg = args[i]; - - if (arg != null) { - if (arg instanceof Message) { - Message message = (Message) arg; - body = messageConverter.fromMessage(message); - headers.putAll(message.getMessageProperties().getHeaders()); - break; - } else if (parameters[i].isAnnotationPresent(Payload.class)) { - body = arg; - } else if (parameters[i].isAnnotationPresent(Header.class)) { - headers.put(parameters[i].getAnnotation(Header.class).name(), arg); - } - } - } - return body; - } - - protected String formatMessageRecord(String prefix, Map<String, Object> headers, - Object body, RabbitMessageLogging annotation) throws Exception { - StringBuilder record = new StringBuilder(); - - record.append(prefix).append(" - Rabbit message"); - - // headers - if (annotation.logHeaders()) { - for (Map.Entry<String, Object> entry : headers.entrySet()) { - record.append(NEWLINE).append(' ').append(entry.getKey()).append(": ").append(entry.getValue()); - } - } - - // body - if (annotation.logBody() && body !=null) { - try { - record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR) - .append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(body)); - } catch (JsonProcessingException e) { - // ignore - } - } - - return record.toString(); - } + private static final String NEWLINE = "\n"; + private static final String BODY_DENOMINATOR = "-- Body --"; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private MessageConverter messageConverter; + + @Around("execution(public * *(..)) && @annotation(annotation)") + public Object log(ProceedingJoinPoint joinPoint, RabbitMessageLogging annotation) + throws Throwable { + + Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass()); + + Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); + + Map<String, Object> headers = new HashMap<>(); + Object body = getHeadersAndBody(joinPoint, method, headers); + + String prefix = method.getName(); + + if (logger.isDebugEnabled()) { + logger.debug(formatMessageRecord(prefix, headers, body, annotation)); + } + + return joinPoint.proceed(); + } + + protected Object getHeadersAndBody(ProceedingJoinPoint joinPoint, Method method, + Map<String, Object> headers) { + Object body = null; + Object[] args = joinPoint.getArgs(); + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + Object arg = args[i]; + + if (arg != null) { + if (arg instanceof Message) { + Message message = (Message) arg; + body = messageConverter.fromMessage(message); + headers.putAll(message.getMessageProperties().getHeaders()); + break; + } else if (parameters[i].isAnnotationPresent(Payload.class)) { + body = arg; + } else if (parameters[i].isAnnotationPresent(Header.class)) { + headers.put(parameters[i].getAnnotation(Header.class).name(), arg); + } + } + } + return body; + } + + protected String formatMessageRecord(String prefix, Map<String, Object> headers, + Object body, RabbitMessageLogging annotation) throws Exception { + StringBuilder record = new StringBuilder(); + + record.append(prefix).append(" - Rabbit message"); + + // headers + if (annotation.logHeaders()) { + for (Map.Entry<String, Object> entry : headers.entrySet()) { + record.append(NEWLINE).append(' ').append(entry.getKey()).append(": ") + .append(entry.getValue()); + } + } + + // body + if (annotation.logBody() && body != null) { + try { + record.append(NEWLINE).append(' ').append(BODY_DENOMINATOR) + .append(NEWLINE).append(' ').append(objectMapper.writeValueAsString(body)); + } catch (JsonProcessingException e) { + // ignore + } + } + + return record.toString(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/onboarding/OnboardingService.java b/src/main/java/com/epam/ta/reportportal/core/onboarding/OnboardingService.java index 567d07bc10..11cb4d0d80 100644 --- a/src/main/java/com/epam/ta/reportportal/core/onboarding/OnboardingService.java +++ b/src/main/java/com/epam/ta/reportportal/core/onboarding/OnboardingService.java @@ -22,32 +22,34 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Map; +import org.springframework.stereotype.Service; /** * @author Antonov Maksim */ @Service public class OnboardingService { - private final OnboardingRepository onboardingRepository; - private final ObjectMapper objectMapper; - public OnboardingService(OnboardingRepository onboardingRepository, ObjectMapper objectMapper) { - this.onboardingRepository = onboardingRepository; - this.objectMapper = objectMapper; - } + private final OnboardingRepository onboardingRepository; + private final ObjectMapper objectMapper; + + public OnboardingService(OnboardingRepository onboardingRepository, ObjectMapper objectMapper) { + this.onboardingRepository = onboardingRepository; + this.objectMapper = objectMapper; + } - public Object getOnboardingDataForPageIfAvailable(String page) { - Onboarding onboarding = onboardingRepository.findAvailableOnboardingByPage(page); - // possibly use another parsing flow for some onboarding page, for now only text to list of questions - try { - return (onboarding != null) ? objectMapper.readValue(onboarding.getData(), - new TypeReference<List<Map<String, String>>>() {}) : null; - } catch (JsonProcessingException e) { - throw new ReportPortalException(ErrorType.UNCLASSIFIED_ERROR, "Unable to parse onboarding data: " + e.getMessage()); - } + public Object getOnboardingDataForPageIfAvailable(String page) { + Onboarding onboarding = onboardingRepository.findAvailableOnboardingByPage(page); + // possibly use another parsing flow for some onboarding page, for now only text to list of questions + try { + return (onboarding != null) ? objectMapper.readValue(onboarding.getData(), + new TypeReference<List<Map<String, String>>>() { + }) : null; + } catch (JsonProcessingException e) { + throw new ReportPortalException(ErrorType.UNCLASSIFIED_ERROR, + "Unable to parse onboarding data: " + e.getMessage()); } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/plugin/Pf4jPluginBox.java b/src/main/java/com/epam/ta/reportportal/core/plugin/Pf4jPluginBox.java index c3c8ed5168..8d5e21efb3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/plugin/Pf4jPluginBox.java +++ b/src/main/java/com/epam/ta/reportportal/core/plugin/Pf4jPluginBox.java @@ -18,81 +18,81 @@ import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; -import org.pf4j.PluginState; -import org.pf4j.PluginWrapper; - import java.io.InputStream; import java.util.Optional; +import org.pf4j.PluginState; +import org.pf4j.PluginWrapper; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface Pf4jPluginBox extends PluginBox { - void startUp(); + void startUp(); - void shutDown(); + void shutDown(); - /** - * Start up loaded plugin by id - * - * @param pluginId {@link PluginWrapper#getPluginId()} - * @return {@link PluginState} - */ - PluginState startUpPlugin(String pluginId); + /** + * Start up loaded plugin by id + * + * @param pluginId {@link PluginWrapper#getPluginId()} + * @return {@link PluginState} + */ + PluginState startUpPlugin(String pluginId); - /** - * Load plugin to the plugin manager by plugin file path - * - * @param pluginId {@link PluginWrapper#getPluginId()} - * @param integrationTypeDetails {@link IntegrationTypeDetails} - * @return {@link PluginWrapper#getPluginId()} - */ - boolean loadPlugin(String pluginId, IntegrationTypeDetails integrationTypeDetails); + /** + * Load plugin to the plugin manager by plugin file path + * + * @param pluginId {@link PluginWrapper#getPluginId()} + * @param integrationTypeDetails {@link IntegrationTypeDetails} + * @return {@link PluginWrapper#getPluginId()} + */ + boolean loadPlugin(String pluginId, IntegrationTypeDetails integrationTypeDetails); - /** - * Unload plugin from the plugin manager by id - * - * @param integrationType {@link IntegrationType} - * @return 'true' if a plugin was successfully unloaded, else 'false' - */ - boolean unloadPlugin(IntegrationType integrationType); + /** + * Unload plugin from the plugin manager by id + * + * @param integrationType {@link IntegrationType} + * @return 'true' if a plugin was successfully unloaded, else 'false' + */ + boolean unloadPlugin(IntegrationType integrationType); - /** - * Delete plugin by id - * - * @param pluginId {@link IntegrationType#getName()} - * @return 'true' if a plugin was successfully deleted, else 'false' - */ - boolean deletePlugin(String pluginId); + /** + * Delete plugin by id + * + * @param pluginId {@link IntegrationType#getName()} + * @return 'true' if a plugin was successfully deleted, else 'false' + */ + boolean deletePlugin(String pluginId); - /** - * Delete plugin - * - * @param pluginWrapper {@link PluginWrapper} - * @return 'true' if a plugin was successfully deleted, else 'false' - */ - boolean deletePlugin(PluginWrapper pluginWrapper); + /** + * Delete plugin + * + * @param pluginWrapper {@link PluginWrapper} + * @return 'true' if a plugin was successfully deleted, else 'false' + */ + boolean deletePlugin(PluginWrapper pluginWrapper); - /** - * Get plugin from the plugin manager by id - * - * @param id {@link PluginWrapper#getPluginId()} - * @return {@link PluginWrapper} wrapped in the {@link Optional} - */ - Optional<PluginWrapper> getPluginById(String id); + /** + * Get plugin from the plugin manager by id + * + * @param id {@link PluginWrapper#getPluginId()} + * @return {@link PluginWrapper} wrapped in the {@link Optional} + */ + Optional<PluginWrapper> getPluginById(String id); - /** - * Check if uploading plugins holder contains plugin file name - * - * @param fileName Name of the plugin file in the {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} - * which uploaded state is required - * @return 'true' if {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} contains plugin file name, - * else 'false' - * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager - */ - boolean isInUploadingState(String fileName); + /** + * Check if uploading plugins holder contains plugin file name + * + * @param fileName Name of the plugin file in the + * {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} + * which uploaded state is required + * @return 'true' if {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} + * contains plugin file name, else 'false' + * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager + */ + boolean isInUploadingState(String fileName); - IntegrationType uploadPlugin(String newPluginFileName, InputStream fileStream); + IntegrationType uploadPlugin(String newPluginFileName, InputStream fileStream); } diff --git a/src/main/java/com/epam/ta/reportportal/core/plugin/Plugin.java b/src/main/java/com/epam/ta/reportportal/core/plugin/Plugin.java index 3c44630cb5..0b53a0e1d7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/plugin/Plugin.java +++ b/src/main/java/com/epam/ta/reportportal/core/plugin/Plugin.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.core.plugin; import com.epam.reportportal.extension.common.ExtensionPoint; - import java.io.Serializable; import java.util.Objects; @@ -28,54 +27,54 @@ */ public class Plugin implements Serializable { - private String id; - private ExtensionPoint type; + private String id; + private ExtensionPoint type; - public Plugin() { + public Plugin() { - } + } - public Plugin(String id, ExtensionPoint type) { - this.id = id; - this.type = type; - } + public Plugin(String id, ExtensionPoint type) { + this.id = id; + this.type = type; + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public ExtensionPoint getType() { - return type; - } + public ExtensionPoint getType() { + return type; + } - public void setType(ExtensionPoint type) { - this.type = type; - } + public void setType(ExtensionPoint type) { + this.type = type; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Plugin plugin = (Plugin) o; - return Objects.equals(type, plugin.type); - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Plugin plugin = (Plugin) o; + return Objects.equals(type, plugin.type); + } - @Override - public int hashCode() { + @Override + public int hashCode() { - return Objects.hash(type); - } + return Objects.hash(type); + } - @Override - public String toString() { - return "Plugin{" + "type='" + type + '\'' + '}'; - } + @Override + public String toString() { + return "Plugin{" + "type='" + type + '\'' + '}'; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/plugin/PluginBox.java b/src/main/java/com/epam/ta/reportportal/core/plugin/PluginBox.java index 6cf8f6110a..90ded6bb7d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/plugin/PluginBox.java +++ b/src/main/java/com/epam/ta/reportportal/core/plugin/PluginBox.java @@ -26,31 +26,33 @@ */ public interface PluginBox { - /** - * @return All available plugins - */ - List<Plugin> getPlugins(); + /** + * @return All available plugins + */ + List<Plugin> getPlugins(); - /** - * @param type Type of plugin - * @return Optional of plugin by given type - */ - Optional<Plugin> getPlugin(String type); + /** + * @param type Type of plugin + * @return Optional of plugin by given type + */ + Optional<Plugin> getPlugin(String type); - /** - * Creates (or takes from cache) instance of given plugin - * - * @param name Plugin name / ID - * @param type Type of plugin - * @return Optional of plugin by given type - */ - <T> Optional<T> getInstance(String name, Class<T> type); + /** + * Creates (or takes from cache) instance of given plugin + * + * @param <T> The Extension Point class + * @param name Plugin name / ID + * @param type Type of plugin + * @return Optional of plugin by given type + */ + <T> Optional<T> getInstance(String name, Class<T> type); - /** - * Creates (or takes from cache) instance of given plugin - * - * @param type Type of plugin - * @return Optional of plugin by given type - */ - <T> Optional<T> getInstance(Class<T> type); + /** + * Creates (or takes from cache) instance of given plugin + * + * @param <T> The Extension Point class + * @param type Type of plugin + * @return Optional of plugin by given type + */ + <T> Optional<T> getInstance(Class<T> type); } diff --git a/src/main/java/com/epam/ta/reportportal/core/plugin/PluginInfo.java b/src/main/java/com/epam/ta/reportportal/core/plugin/PluginInfo.java index 1265b49a5d..8a46747750 100644 --- a/src/main/java/com/epam/ta/reportportal/core/plugin/PluginInfo.java +++ b/src/main/java/com/epam/ta/reportportal/core/plugin/PluginInfo.java @@ -16,82 +16,82 @@ package com.epam.ta.reportportal.core.plugin; -import javax.annotation.Nullable; import java.io.Serializable; +import javax.annotation.Nullable; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class PluginInfo implements Serializable { - private String id; + private String id; - private String version; + private String version; - private String fileId; + private String fileId; - private String fileName; + private String fileName; - private boolean isEnabled; + private boolean isEnabled; - public PluginInfo() { - } + public PluginInfo() { + } - public PluginInfo(String id, String version) { - this.id = id; - this.version = version; - } + public PluginInfo(String id, String version) { + this.id = id; + this.version = version; + } - public PluginInfo(String id, String version, String fileId, String fileName, boolean isEnabled) { - this.id = id; - this.version = version; - this.fileId = fileId; - this.fileName = fileName; - this.isEnabled = isEnabled; - } + public PluginInfo(String id, String version, String fileId, String fileName, boolean isEnabled) { + this.id = id; + this.version = version; + this.fileId = fileId; + this.fileName = fileName; + this.isEnabled = isEnabled; + } - @Nullable - public String getId() { - return id; - } + @Nullable + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - @Nullable - public String getVersion() { - return version; - } + @Nullable + public String getVersion() { + return version; + } - public void setVersion(String version) { - this.version = version; - } + public void setVersion(String version) { + this.version = version; + } - @Nullable - public String getFileId() { - return fileId; - } + @Nullable + public String getFileId() { + return fileId; + } - public void setFileId(String fileId) { - this.fileId = fileId; - } + public void setFileId(String fileId) { + this.fileId = fileId; + } - @Nullable - public String getFileName() { - return fileName; - } + @Nullable + public String getFileName() { + return fileName; + } - public void setFileName(String fileName) { - this.fileName = fileName; - } + public void setFileName(String fileName) { + this.fileName = fileName; + } - public boolean isEnabled() { - return isEnabled; - } + public boolean isEnabled() { + return isEnabled; + } - public void setEnabled(boolean enabled) { - isEnabled = enabled; - } + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/preference/GetPreferenceHandler.java b/src/main/java/com/epam/ta/reportportal/core/preference/GetPreferenceHandler.java index 7b02894a08..83d48cd36e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/preference/GetPreferenceHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/preference/GetPreferenceHandler.java @@ -26,6 +26,7 @@ */ public interface GetPreferenceHandler { - PreferenceResource getPreference(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + PreferenceResource getPreference(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/preference/UpdatePreferenceHandler.java b/src/main/java/com/epam/ta/reportportal/core/preference/UpdatePreferenceHandler.java index 9e5ba56c0a..cfb3c7fdf3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/preference/UpdatePreferenceHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/preference/UpdatePreferenceHandler.java @@ -25,23 +25,26 @@ * @author Pavel Bortnik */ public interface UpdatePreferenceHandler { - /** - * Add user preference - * - * @param projectDetails Project Details - * @param user User - * @param filterId Adding filter id - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS addPreference(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, Long filterId); - /** - * Remove user preference - * - * @param projectDetails Project Details - * @param user User - * @param filterId Removing filter id - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS removePreference(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, Long filterId); + /** + * Add user preference + * + * @param projectDetails Project Details + * @param user User + * @param filterId Adding filter id + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS addPreference(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Long filterId); + + /** + * Remove user preference + * + * @param projectDetails Project Details + * @param user User + * @param filterId Removing filter id + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS removePreference(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Long filterId); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/preference/impl/GetPreferenceHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/preference/impl/GetPreferenceHandlerImpl.java index f3d266a168..0835adf044 100644 --- a/src/main/java/com/epam/ta/reportportal/core/preference/impl/GetPreferenceHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/preference/impl/GetPreferenceHandlerImpl.java @@ -22,40 +22,40 @@ import com.epam.ta.reportportal.ws.converter.converters.UserFilterConverter; import com.epam.ta.reportportal.ws.model.filter.UserFilterResource; import com.epam.ta.reportportal.ws.model.preference.PreferenceResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** - * Default implementation of - * {@link com.epam.ta.reportportal.core.preference.GetPreferenceHandler} + * Default implementation of {@link com.epam.ta.reportportal.core.preference.GetPreferenceHandler} * * @author Dzmitry_Kavalets */ @Service public class GetPreferenceHandlerImpl implements GetPreferenceHandler { - private final UserPreferenceRepository userPreferenceRepository; + private final UserPreferenceRepository userPreferenceRepository; - @Autowired - public GetPreferenceHandlerImpl(UserPreferenceRepository userPreferenceRepository) { - this.userPreferenceRepository = userPreferenceRepository; - } + @Autowired + public GetPreferenceHandlerImpl(UserPreferenceRepository userPreferenceRepository) { + this.userPreferenceRepository = userPreferenceRepository; + } - @Override - public PreferenceResource getPreference(ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - List<UserPreference> userPreferences = userPreferenceRepository.findByProjectIdAndUserId(projectDetails.getProjectId(), - user.getUserId() - ); - PreferenceResource preferenceResource = new PreferenceResource(); - preferenceResource.setUserId(user.getUserId()); - preferenceResource.setProjectId(projectDetails.getProjectId()); - List<UserFilterResource> filters = userPreferences.stream() - .map(it -> UserFilterConverter.TO_FILTER_RESOURCE.apply(it.getFilter())) - .collect(Collectors.toList()); - preferenceResource.setFilters(filters); - return preferenceResource; - } + @Override + public PreferenceResource getPreference(ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + List<UserPreference> userPreferences = userPreferenceRepository.findByProjectIdAndUserId( + projectDetails.getProjectId(), + user.getUserId() + ); + PreferenceResource preferenceResource = new PreferenceResource(); + preferenceResource.setUserId(user.getUserId()); + preferenceResource.setProjectId(projectDetails.getProjectId()); + List<UserFilterResource> filters = userPreferences.stream() + .map(it -> UserFilterConverter.TO_FILTER_RESOURCE.apply(it.getFilter())) + .collect(Collectors.toList()); + preferenceResource.setFilters(filters); + return preferenceResource; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/project/CreateProjectHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/CreateProjectHandler.java index 5b37a34a05..a7fb7e1bd7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/CreateProjectHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/CreateProjectHandler.java @@ -29,14 +29,14 @@ */ public interface CreateProjectHandler { - /** - * Create new project - * - * @param createProjectRQ Request Data - * @param user ReportPortal User - * @return Response data - */ - EntryCreatedRS createProject(CreateProjectRQ createProjectRQ, ReportPortalUser user); + /** + * Create new project + * + * @param createProjectRQ Request Data + * @param user ReportPortal User + * @return Response data + */ + EntryCreatedRS createProject(CreateProjectRQ createProjectRQ, ReportPortalUser user); - Project createPersonal(User user); + Project createPersonal(User user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/project/DeleteProjectHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/DeleteProjectHandler.java index 4a00ae336d..2aa783949c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/DeleteProjectHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/DeleteProjectHandler.java @@ -33,6 +33,7 @@ public interface DeleteProjectHandler { * Delete specified project. * * @param projectId Project id + * @param user {@link ReportPortalUser} * @return Result of operation * @throws ReportPortalException if project not found */ @@ -42,6 +43,7 @@ public interface DeleteProjectHandler { * Delete specified project. * * @param ids projects ids + * @param user {@link ReportPortalUser} * @return Bulk result of operation * @throws ReportPortalException if project not found */ @@ -52,6 +54,7 @@ public interface DeleteProjectHandler { * * @param projectName Project name * @param username User name + * @return {@link OperationCompletionRS} info about operation completion */ OperationCompletionRS deleteProjectIndex(String projectName, String username); diff --git a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java index e612bdc2d4..81ee3dc926 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java @@ -24,93 +24,95 @@ import com.epam.ta.reportportal.ws.model.project.ProjectResource; import com.epam.ta.reportportal.ws.model.user.SearchUserResource; import com.epam.ta.reportportal.ws.model.user.UserResource; -import org.springframework.data.domain.Pageable; - -import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.springframework.data.domain.Pageable; /** * @author Andrei_Ramanchuk */ public interface GetProjectHandler { - /** - * Get project users info - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param filter {@link Filter} - * @param pageable {@link Pageable} - * @return list of {@link UserResource} - */ - Iterable<UserResource> getProjectUsers(String projectName, Filter filter, Pageable pageable); - - boolean exists(Long id); - - Project get(ReportPortalUser.ProjectDetails projectDetails); - - Project get(Long id); - - Project get(String name); - - /** - * Find project entity without fetching related entities - * - * @param name Project name to search - * @return {@link Project} - */ - Project getRaw(String name); - - /** - * Get project resource information - * - * @param projectName Project name - * @param user User - * @return {@link ProjectResource} - */ - ProjectResource getResource(String projectName, ReportPortalUser user); - - /** - * Get list of specified usernames - * - * @param projectDetails Project name - * @param value Login - * @return List of found user logins - */ - List<String> getUserNames(ReportPortalUser.ProjectDetails projectDetails, String value); - - /** - * Performs global search for user - * - * @param value login OR full name of user - * @param projectDetails - * @return List of found user resources - */ - Iterable<SearchUserResource> getUserNames(String value, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable); - - /** - * Get all project names - * - * @return All project names - */ - List<String> getAllProjectNames(); - - /** - * Get all project names, which contain provided term - * - * @return {@link List} of the {@link com.epam.ta.reportportal.entity.project.Project#name} - */ - List<String> getAllProjectNamesByTerm(String term); - - /** - * Export Projects info according to the {@link ReportFormat} type - * - * @param reportFormat {@link ReportFormat} - * @param filter {@link Queryable} - * @param outputStream {@link HttpServletResponse#getOutputStream()} - */ - void exportProjects(ReportFormat reportFormat, Queryable filter, OutputStream outputStream); - - Map<String, Boolean> getAnalyzerIndexingStatus(); + /** + * Get project users info + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param filter {@link Filter} + * @param pageable {@link Pageable} + * @return list of {@link UserResource} + */ + Iterable<UserResource> getProjectUsers(String projectName, Filter filter, Pageable pageable); + + boolean exists(Long id); + + Project get(ReportPortalUser.ProjectDetails projectDetails); + + Project get(Long id); + + Project get(String name); + + /** + * Find project entity without fetching related entities + * + * @param name Project name to search + * @return {@link Project} + */ + Project getRaw(String name); + + /** + * Get project resource information + * + * @param projectName Project name + * @param user User + * @return {@link ProjectResource} + */ + ProjectResource getResource(String projectName, ReportPortalUser user); + + /** + * Get list of specified usernames + * + * @param projectDetails Project name + * @param value Login + * @return List of found user logins + */ + List<String> getUserNames(ReportPortalUser.ProjectDetails projectDetails, String value); + + /** + * Performs global search for user + * + * @param value login OR full name of user + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @param pageable {@link Pageable} Page Details + * @return List of found user resources + */ + Iterable<SearchUserResource> getUserNames(String value, + ReportPortalUser.ProjectDetails projectDetails, Pageable pageable); + + /** + * Get all project names + * + * @return All project names + */ + List<String> getAllProjectNames(); + + /** + * Get all project names, which contain provided term + * + * @param term project term + * @return {@link List} of the {@link com.epam.ta.reportportal.entity.project.Project#name} + */ + List<String> getAllProjectNamesByTerm(String term); + + /** + * Export Projects info according to the {@link ReportFormat} type + * + * @param reportFormat {@link ReportFormat} + * @param filter {@link Queryable} + * @param outputStream {@link HttpServletResponse#getOutputStream()} + */ + void exportProjects(ReportFormat reportFormat, Queryable filter, OutputStream outputStream); + + Map<String, Boolean> getAnalyzerIndexingStatus(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectInfoHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectInfoHandler.java index d37050ec99..8cc231aed3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectInfoHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectInfoHandler.java @@ -19,42 +19,43 @@ import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.entity.enums.InfoInterval; import com.epam.ta.reportportal.ws.model.project.ProjectInfoResource; -import org.springframework.data.domain.Pageable; - import java.util.Map; +import org.springframework.data.domain.Pageable; /** - * Get {@link com.epam.ta.reportportal.ws.model.project.ProjectInfoResource} - * request handler + * Get {@link com.epam.ta.reportportal.ws.model.project.ProjectInfoResource} request handler * * @author Dzmitry_Kavalets */ public interface GetProjectInfoHandler { - /** - * Get all projects info - * - * @return - */ - Iterable<ProjectInfoResource> getAllProjectsInfo(Queryable filter, Pageable pageable); + /** + * Get all projects info + * + * @param filter Queryable filter to apply on the projects + * @param pageable Pagination information for the results + * @return An {@link Iterable} of {@link ProjectInfoResource} containing information about all projects + */ + Iterable<ProjectInfoResource> getAllProjectsInfo(Queryable filter, Pageable pageable); - /** - * Get project info - * - * @param projectName Project name - * @param interval Interval - * @return Project info resource - */ - ProjectInfoResource getProjectInfo(String projectName, String interval); + /** + * Get project info + * + * @param projectName Project name + * @param interval Interval + * @return Project info resource + */ + ProjectInfoResource getProjectInfo(String projectName, String interval); - /** - * Get widget data content for specified project by specified - * {@link InfoInterval} and {@link com.epam.ta.reportportal.entity.project.email.ProjectInfoWidget} - * - * @param projectName Project name - * @param interval Interval - * @param widgetCode Project Info Widget code - * @return - */ - Map<String, ?> getProjectInfoWidgetContent(String projectName, String interval, String widgetCode); + /** + * Get widget data content for specified project by specified {@link InfoInterval} and + * {@link com.epam.ta.reportportal.entity.project.email.ProjectInfoWidget} + * + * @param projectName Project name + * @param interval Interval + * @param widgetCode Project Info Widget code + * @return Map of widget data content + */ + Map<String, ?> getProjectInfoWidgetContent(String projectName, String interval, + String widgetCode); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/ProjectUserHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/ProjectUserHandler.java index 62a822c075..ef90e454de 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/ProjectUserHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/ProjectUserHandler.java @@ -7,5 +7,5 @@ public interface ProjectUserHandler { - ProjectUser assign(User user, Project project, ProjectRole projectRole, User creator); + ProjectUser assign(User user, Project project, ProjectRole projectRole, User creator, boolean isSystemEvent); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/UpdateProjectHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/UpdateProjectHandler.java index d023355467..784fc1f690 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/UpdateProjectHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/UpdateProjectHandler.java @@ -17,6 +17,7 @@ package com.epam.ta.reportportal.core.project; import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.project.AssignUsersRQ; @@ -31,55 +32,58 @@ */ public interface UpdateProjectHandler { - /** - * Update specified project(projectName, customer and addInfo) - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param updateProjectRQ Project data - * @param user ReportPortal user - * @return Operation result - * @throws ReportPortalException - */ - OperationCompletionRS updateProject(String projectName, UpdateProjectRQ updateProjectRQ, ReportPortalUser user); + /** + * Update specified project email configuration + * + * @param projectName Project Name + * @param updateProjectNotificationConfigRQ Request Data + * @param user User performing that update + * @return Operation Result + */ + OperationCompletionRS updateProjectNotificationConfig(String projectName, ReportPortalUser user, + ProjectNotificationConfigDTO updateProjectNotificationConfigRQ); - /** - * Update specified project email configuration - * - * @param projectName Project Name - * @param updateProjectNotificationConfigRQ Request Data - * @param user User performing that update - * @return Operation Result - */ - OperationCompletionRS updateProjectNotificationConfig(String projectName, ReportPortalUser user, - ProjectNotificationConfigDTO updateProjectNotificationConfigRQ); + /** + * Update specified project(projectName, customer and addInfo) + * + * @param projectName {@link Project#getName()} + * @param updateProjectRQ Project data + * @param user ReportPortal user + * @return Operation result + * @throws ReportPortalException in case of error due updating project + */ + OperationCompletionRS updateProject(String projectName, UpdateProjectRQ updateProjectRQ, + ReportPortalUser user); - /** - * Un-assign specified user from project - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param modifier Modifier User - * @param unassignUsersRQ Request Data - * @return Operation Result - * @throws ReportPortalException - */ - OperationCompletionRS unassignUsers(String projectName, UnassignUsersRQ unassignUsersRQ, ReportPortalUser modifier); + /** + * Un-assign specified user from project + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param modifier Modifier User + * @param unassignUsersRQ Request Data + * @return Operation Result + * @throws ReportPortalException in case of error due unassign users + */ + OperationCompletionRS unassignUsers(String projectName, UnassignUsersRQ unassignUsersRQ, + ReportPortalUser modifier); - /** - * Assign specified user from project - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param modifier Modifier User - * @param assignUsersRQ Request Data - * @return Operation Result - */ - OperationCompletionRS assignUsers(String projectName, AssignUsersRQ assignUsersRQ, ReportPortalUser modifier); + /** + * Assign specified user from project + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param modifier Modifier User + * @param assignUsersRQ Request Data + * @return Operation Result + */ + OperationCompletionRS assignUsers(String projectName, AssignUsersRQ assignUsersRQ, + ReportPortalUser modifier); - /** - * Index logs for specified project - * - * @param projectName Project name - * @param user User - * @return Operation Result - */ - OperationCompletionRS indexProjectData(String projectName, ReportPortalUser user); + /** + * Index logs for specified project + * + * @param projectName Project name + * @param user User + * @return Operation Result + */ + OperationCompletionRS indexProjectData(String projectName, ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProvider.java b/src/main/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProvider.java index 6858097dc5..adcc3566e4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProvider.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProvider.java @@ -19,28 +19,27 @@ import com.epam.ta.reportportal.core.project.GetProjectHandler; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectUtils; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProjectConfigProvider { - private final GetProjectHandler getProjectHandler; + private final GetProjectHandler getProjectHandler; - @Autowired - public ProjectConfigProvider(GetProjectHandler getProjectHandler) { - this.getProjectHandler = getProjectHandler; - } + @Autowired + public ProjectConfigProvider(GetProjectHandler getProjectHandler) { + this.getProjectHandler = getProjectHandler; + } - @Transactional(readOnly = true) - public Map<String, String> provide(Long projectId) { - final Project project = getProjectHandler.get(projectId); - return ProjectUtils.getConfigParameters(project.getProjectAttributes()); - } + @Transactional(readOnly = true) + public Map<String, String> provide(Long projectId) { + final Project project = getProjectHandler.get(projectId); + return ProjectUtils.getConfigParameters(project.getProjectAttributes()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImpl.java index e40ce5ecfa..fe7570343d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImpl.java @@ -20,6 +20,7 @@ import static com.epam.ta.reportportal.commons.Predicates.isPresent; import static com.epam.ta.reportportal.commons.Predicates.not; import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; import com.epam.reportportal.extension.event.ProjectEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; @@ -155,7 +156,7 @@ public Project createPersonal(User user) { final Project personalProject = personalProjectService.generatePersonalProject(user); personalProject.getUsers().clear(); projectRepository.save(personalProject); - publishProjectCreatedEvent(null, "ReportPortal", personalProject); + publishProjectCreatedEvent(null, RP_SUBJECT_NAME, personalProject); return personalProject; } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImpl.java index 4c3b517afc..db3b6140cc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImpl.java @@ -18,8 +18,10 @@ import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.AUTO_ANALYZER_KEY; +import static com.epam.ta.reportportal.core.events.activity.util.ActivityDetailsUtil.RP_SUBJECT_NAME; import static com.epam.ta.reportportal.ws.converter.converters.ExceptionConverter.TO_ERROR_RS; +import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; @@ -31,7 +33,6 @@ import com.epam.ta.reportportal.core.events.activity.ProjectIndexEvent; import com.epam.ta.reportportal.core.project.DeleteProjectHandler; import com.epam.ta.reportportal.core.remover.ContentRemover; -import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.IssueTypeRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.ProjectRepository; @@ -41,6 +42,7 @@ import com.epam.ta.reportportal.entity.project.ProjectIssueType; import com.epam.ta.reportportal.entity.user.User; import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.util.FeatureFlagHandler; import com.epam.ta.reportportal.ws.model.DeleteBulkRS; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; @@ -78,31 +80,34 @@ public class DeleteProjectHandlerImpl implements DeleteProjectHandler { private final MessageBus messageBus; - private final AttachmentRepository attachmentRepository; - private final IssueTypeRepository issueTypeRepository; private final ContentRemover<Project> projectContentRemover; private final LogRepository logRepository; + private final AttachmentBinaryDataService attachmentBinaryDataService; + + private final FeatureFlagHandler featureFlagHandler; + @Autowired public DeleteProjectHandlerImpl(ProjectRepository projectRepository, UserRepository userRepository, LogIndexer logIndexer, AnalyzerServiceClient analyzerServiceClient, AnalyzerStatusCache analyzerStatusCache, - MessageBus messageBus, - AttachmentRepository attachmentRepository, IssueTypeRepository issueTypeRepository, - ContentRemover<Project> projectContentRemover, LogRepository logRepository) { + MessageBus messageBus, AttachmentBinaryDataService attachmentBinaryDataService, + IssueTypeRepository issueTypeRepository, ContentRemover<Project> projectContentRemover, + LogRepository logRepository, FeatureFlagHandler featureFlagHandler) { this.projectRepository = projectRepository; this.userRepository = userRepository; this.logIndexer = logIndexer; this.analyzerServiceClient = analyzerServiceClient; this.analyzerStatusCache = analyzerStatusCache; this.messageBus = messageBus; - this.attachmentRepository = attachmentRepository; this.issueTypeRepository = issueTypeRepository; this.projectContentRemover = projectContentRemover; this.logRepository = logRepository; + this.featureFlagHandler = featureFlagHandler; + this.attachmentBinaryDataService = attachmentBinaryDataService; } @Override @@ -120,7 +125,7 @@ private void publishSpecialProjectDeletedEvent(ReportPortalUser user, Project pr String username = user.getUsername(); publishProjectDeletedEvent(userId, username, project.getId(), project.getName()); } else { - publishProjectDeletedEvent(null, "ReportPortal", project.getId(), "personal_project"); + publishProjectDeletedEvent(null, RP_SUBJECT_NAME, project.getId(), "personal_project"); } } @@ -151,21 +156,20 @@ public DeleteBulkRS bulkDeleteProjects(List<Long> ids, ReportPortalUser user) { publishProjectBulkDeletedEvent(user, deletedProjectsMap.values()); return new DeleteBulkRS(List.copyOf(deletedProjectsMap.keySet()), Collections.emptyList(), - exceptions.stream().map(TO_ERROR_RS).collect(Collectors.toList())); + exceptions.stream().map(TO_ERROR_RS).collect(Collectors.toList()) + ); } private void publishProjectBulkDeletedEvent(ReportPortalUser user, Collection<String> names) { - ProjectBulkDeletedEvent bulkDeletedEvent = new ProjectBulkDeletedEvent(user.getUserId(), - user.getUsername(), names); + ProjectBulkDeletedEvent bulkDeletedEvent = + new ProjectBulkDeletedEvent(user.getUserId(), user.getUsername(), names); messageBus.publishActivity(bulkDeletedEvent); } @Override public OperationCompletionRS deleteProjectIndex(String projectName, String username) { expect(analyzerServiceClient.hasClients(), Predicate.isEqual(true)).verify( - ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "There are no analyzer deployed." - ); + ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, "There are no analyzer deployed."); Project project = projectRepository.findByName(projectName) .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); @@ -174,7 +178,8 @@ public OperationCompletionRS deleteProjectIndex(String projectName, String usern .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, username)); expect(AnalyzerUtils.getAnalyzerConfig(project).isIndexingRunning(), - Predicate.isEqual(false)).verify(ErrorType.FORBIDDEN_OPERATION, + Predicate.isEqual(false) + ).verify(ErrorType.FORBIDDEN_OPERATION, "Index can not be removed until index generation proceeds." ); @@ -182,35 +187,33 @@ public OperationCompletionRS deleteProjectIndex(String projectName, String usern .orElseThrow( () -> new ReportPortalException(ErrorType.ANALYZER_NOT_FOUND, AUTO_ANALYZER_KEY)); expect(analyzeStatus.asMap().containsValue(project.getId()), Predicate.isEqual(false)).verify( - ErrorType.FORBIDDEN_OPERATION, - "Index can not be removed until index generation proceeds." - ); + ErrorType.FORBIDDEN_OPERATION, "Index can not be removed until index generation proceeds."); logIndexer.deleteIndex(project.getId()); messageBus.publishActivity( new ProjectIndexEvent(user.getId(), user.getLogin(), project.getId(), project.getName(), - false)); + false + )); return new OperationCompletionRS( "Project index with name = '" + projectName + "' is successfully deleted."); } private OperationCompletionRS deleteProject(Project project) { - Set<Long> defaultIssueTypeIds = issueTypeRepository.getDefaultIssueTypes() - .stream() - .map(IssueType::getId) - .collect(Collectors.toSet()); - Set<IssueType> issueTypesToRemove = project.getProjectIssueTypes() - .stream() - .map(ProjectIssueType::getIssueType) - .filter(issueType -> !defaultIssueTypeIds.contains(issueType.getId())) - .collect(Collectors.toSet()); + Set<Long> defaultIssueTypeIds = + issueTypeRepository.getDefaultIssueTypes().stream().map(IssueType::getId) + .collect(Collectors.toSet()); + Set<IssueType> issueTypesToRemove = + project.getProjectIssueTypes().stream().map(ProjectIssueType::getIssueType) + .filter(issueType -> !defaultIssueTypeIds.contains(issueType.getId())) + .collect(Collectors.toSet()); projectContentRemover.remove(project); projectRepository.delete(project); issueTypeRepository.deleteAll(issueTypesToRemove); logIndexer.deleteIndex(project.getId()); analyzerServiceClient.removeSuggest(project.getId()); logRepository.deleteByProjectId(project.getId()); - attachmentRepository.moveForDeletionByProjectId(project.getId()); + attachmentBinaryDataService.deleteAllByProjectId(project.getId()); + return new OperationCompletionRS( "Project with id = '" + project.getId() + "' has been successfully deleted."); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverter.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverter.java index d22228187a..fd5ca58e5f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverter.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverter.java @@ -16,32 +16,42 @@ package com.epam.ta.reportportal.core.project.impl; +import static com.epam.ta.reportportal.core.project.impl.ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY; +import static com.epam.ta.reportportal.core.project.impl.ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_NAME; +import static com.epam.ta.reportportal.core.statistics.StatisticsHelper.extractStatisticsCount; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.WEEKS; + import com.epam.ta.reportportal.entity.enums.InfoInterval; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.ws.model.widget.ChartObject; import com.google.common.collect.Lists; -import org.joda.time.DateTime; -import org.joda.time.DateTimeConstants; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - import java.text.DecimalFormat; import java.time.LocalDate; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.IsoFields; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.DoubleSummaryStatistics; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; - -import static com.epam.ta.reportportal.core.project.impl.ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY; -import static com.epam.ta.reportportal.core.project.impl.ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_NAME; -import static com.epam.ta.reportportal.core.statistics.StatisticsHelper.extractStatisticsCount; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.WEEKS; +import org.joda.time.DateTime; +import org.joda.time.DateTimeConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; /** * Data converter for Report Portal common UI graphics @@ -51,251 +61,264 @@ @Service("projectInfoDataConverter") public class ProjectInfoWidgetDataConverter { - private Map<InfoInterval, ProjectInfoGroup> grouping; + private Map<InfoInterval, ProjectInfoGroup> grouping; - @Autowired - public ProjectInfoWidgetDataConverter(@Qualifier("groupingStrategy") Map<InfoInterval, ProjectInfoGroup> grouping) { - this.grouping = grouping; - } + @Autowired + public ProjectInfoWidgetDataConverter( + @Qualifier("groupingStrategy") Map<InfoInterval, ProjectInfoGroup> grouping) { + this.grouping = grouping; + } - public enum ProjectInfoGroup { - BY_DAY, - BY_WEEK, - BY_NAME - } + public enum ProjectInfoGroup { + BY_DAY, + BY_WEEK, + BY_NAME + } - private static DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendValue(IsoFields.WEEK_BASED_YEAR, 4) - .appendLiteral("-W") - .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) - .toFormatter(); + private static DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendValue( + IsoFields.WEEK_BASED_YEAR, 4) + .appendLiteral("-W") + .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) + .toFormatter(); - /** - * <b>Percentage Of Investigation</b> project info widget content - * - * @param initial - * @param interval - * @return - */ - public Map<String, List<ChartObject>> getInvestigatedProjectInfo(List<Launch> initial, InfoInterval interval) { - if (initial.isEmpty()) { - return new HashMap<>(); - } - final DecimalFormat formatter = new DecimalFormat("###.##"); - final String INV = "investigated"; - final String TI = "toInvestigate"; - Map<String, List<ChartObject>> result = new HashMap<>(); - Map<String, List<Launch>> grouped = groupBy(initial, grouping.get(interval)); - Iterator<Entry<String, List<Launch>>> iterator = grouped.entrySet().iterator(); - while (iterator.hasNext()) { - Entry<String, List<Launch>> pair = iterator.next(); - double investigated = 0; - double toInvestigate = 0; - List<Launch> group = pair.getValue(); - ChartObject currentGroup = new ChartObject(); - currentGroup.setName(pair.getKey()); - Map<String, String> values = new HashMap<>(); - for (Launch one : group) { - investigated = - investigated + extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, one.getStatistics()) + extractStatisticsCount( - DEFECTS_SYSTEM_ISSUE_TOTAL, - one.getStatistics() - ) + extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, one.getStatistics()); - toInvestigate = toInvestigate + extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, one.getStatistics()); - } - if ((investigated + toInvestigate) > 0) { - double investigatedPercent = (investigated / (investigated + toInvestigate)) * 100; - double toInvestigatePercent = 100 - investigatedPercent; - values.put(INV, formatter.format(investigatedPercent)); - values.put(TI, formatter.format(toInvestigatePercent)); - } else { - values.put(INV, "0"); - values.put(TI, "0"); - } - currentGroup.setValues(values); - result.put(pair.getKey(), Collections.singletonList(currentGroup)); - iterator.remove(); - } - return result; - } + /** + * <b>Percentage Of Investigation</b> project info widget content + * + * @param initial A list of {@link Launch} objects to calculate investigation percentages + * @param interval An {@link InfoInterval} representing the grouping interval (e.g., daily, weekly) + * @return A {@link Map} with keys representing interval group names and values containing + * {@link List} of {@link ChartObject} instances with investigated and to-investigate percentage information + */ + public Map<String, List<ChartObject>> getInvestigatedProjectInfo(List<Launch> initial, + InfoInterval interval) { + if (initial.isEmpty()) { + return new HashMap<>(); + } + final DecimalFormat formatter = new DecimalFormat("###.##"); + final String INV = "investigated"; + final String TI = "toInvestigate"; + Map<String, List<ChartObject>> result = new HashMap<>(); + Map<String, List<Launch>> grouped = groupBy(initial, grouping.get(interval)); + Iterator<Entry<String, List<Launch>>> iterator = grouped.entrySet().iterator(); + while (iterator.hasNext()) { + Entry<String, List<Launch>> pair = iterator.next(); + double investigated = 0; + double toInvestigate = 0; + List<Launch> group = pair.getValue(); + ChartObject currentGroup = new ChartObject(); + currentGroup.setName(pair.getKey()); + Map<String, String> values = new HashMap<>(); + for (Launch one : group) { + investigated = + investigated + extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, one.getStatistics()) + + extractStatisticsCount( + DEFECTS_SYSTEM_ISSUE_TOTAL, + one.getStatistics() + ) + extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, one.getStatistics()); + toInvestigate = toInvestigate + extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, + one.getStatistics()); + } + if ((investigated + toInvestigate) > 0) { + double investigatedPercent = (investigated / (investigated + toInvestigate)) * 100; + double toInvestigatePercent = 100 - investigatedPercent; + values.put(INV, formatter.format(investigatedPercent)); + values.put(TI, formatter.format(toInvestigatePercent)); + } else { + values.put(INV, "0"); + values.put(TI, "0"); + } + currentGroup.setValues(values); + result.put(pair.getKey(), Collections.singletonList(currentGroup)); + iterator.remove(); + } + return result; + } - /** - * <b>Test-cases statistics in unique launches</b> project info widget - * content data-source - * - * @param initial - * @return - */ - public Map<String, List<ChartObject>> getTestCasesStatisticsProjectInfo(List<Launch> initial) { - DecimalFormat formatter = new DecimalFormat("#####.##"); - final String MIN = "min"; - final String MAX = "max"; - final String AVG = "avg"; - String globalAverageSeria = "Median value in all unique launches"; + /** + * <b>Test-cases statistics in unique launches</b> project info widget + * content data-source + * + * @param initial A list of {@link Launch} objects to calculate test-case statistics + * @return A {@link Map} with keys representing launch names and values containing + * {@link List} of {@link ChartObject} instances with min, max, and average statistics + */ + public Map<String, List<ChartObject>> getTestCasesStatisticsProjectInfo(List<Launch> initial) { + DecimalFormat formatter = new DecimalFormat("#####.##"); + final String MIN = "min"; + final String MAX = "max"; + final String AVG = "avg"; + String globalAverageSeria = "Median value in all unique launches"; - if (initial.isEmpty()) { - return new HashMap<>(); - } + if (initial.isEmpty()) { + return new HashMap<>(); + } - Map<String, List<ChartObject>> result = new HashMap<>(); - Map<String, List<Launch>> grouped = groupBy(initial, BY_NAME); - for (Entry<String, List<Launch>> pair : grouped.entrySet()) { - ChartObject singleStat = new ChartObject(); - singleStat.setName(pair.getKey()); - Map<String, String> values = new HashMap<>(); - List<Launch> group = pair.getValue(); + Map<String, List<ChartObject>> result = new HashMap<>(); + Map<String, List<Launch>> grouped = groupBy(initial, BY_NAME); + for (Entry<String, List<Launch>> pair : grouped.entrySet()) { + ChartObject singleStat = new ChartObject(); + singleStat.setName(pair.getKey()); + Map<String, String> values = new HashMap<>(); + List<Launch> group = pair.getValue(); - DoubleSummaryStatistics statistics = group.stream() - .mapToDouble(launch -> launch.getStatistics() - .stream() - .filter(it -> it.getStatisticsField().getName().equalsIgnoreCase(EXECUTIONS_TOTAL)) - .findFirst() - .orElse(new Statistics()) - .getCounter()) - .summaryStatistics(); + DoubleSummaryStatistics statistics = group.stream() + .mapToDouble(launch -> launch.getStatistics() + .stream() + .filter(it -> it.getStatisticsField().getName().equalsIgnoreCase(EXECUTIONS_TOTAL)) + .findFirst() + .orElse(new Statistics()) + .getCounter()) + .summaryStatistics(); - values.put(MIN, String.valueOf(statistics.getMin())); - values.put(MAX, String.valueOf(statistics.getMax())); - values.put(AVG, formatter.format(statistics.getAverage())); - singleStat.setValues(values); + values.put(MIN, String.valueOf(statistics.getMin())); + values.put(MAX, String.valueOf(statistics.getMax())); + values.put(AVG, formatter.format(statistics.getAverage())); + singleStat.setValues(values); - result.put(pair.getKey(), Collections.singletonList(singleStat)); - } + result.put(pair.getKey(), Collections.singletonList(singleStat)); + } - /* - * Separate label for 'Median value in all unique launches' on the table - */ - // TODO Implement new MEDIAN calculation! - result.put(globalAverageSeria, Collections.singletonList(new ChartObject())); - return result; - } + /* + * Separate label for 'Median value in all unique launches' on the table + */ + // TODO Implement new MEDIAN calculation! + result.put(globalAverageSeria, Collections.singletonList(new ChartObject())); + return result; + } - /** - * <b>Quantity of Launches</b> project info widget content - * - * @param initial - * @param interval - * @return - */ - public Map<String, List<ChartObject>> getLaunchesQuantity(List<Launch> initial, InfoInterval interval) { - final String START_PERIOD = "start"; - final String END_PERIOD = "end"; - final String COUNT = "count"; - final String INTERVAL = "interval"; - HashMap<String, List<ChartObject>> result = new HashMap<>(); - if (initial.isEmpty()) { - return result; - } - ProjectInfoGroup criteria = grouping.get(interval); - Map<String, List<Launch>> grouped = groupBy(initial, criteria); - for (Entry<String, List<Launch>> entry : grouped.entrySet()) { - List<Launch> launches = entry.getValue(); - Integer count = null != launches ? launches.size() : 0; - ChartObject group = new ChartObject(); - Map<String, String> values = new HashMap<>(); - values.put(COUNT, String.valueOf(count)); - values.put(INTERVAL, interval.getInterval()); - if (criteria != BY_DAY) { - DateTime parse = DateTime.parse(entry.getKey()); - // TODO remove Yoda time. replace with JDK8 - values.put(START_PERIOD, parse.withDayOfWeek(DateTimeConstants.MONDAY).toString("yyy-MM-dd")); - values.put(END_PERIOD, parse.withDayOfWeek(DateTimeConstants.SUNDAY).toString("yyy-MM-dd")); - } else { - values.put(START_PERIOD, entry.getKey()); - } - group.setName("Number of launches"); - group.setValues(values); - result.put(entry.getKey(), Collections.singletonList(group)); - } - return result; - } + /** + * <b>Quantity of Launches</b> project info widget content + * + * @param initial A list of {@link Launch} objects to calculate the quantity of launches + * @param interval An {@link InfoInterval} representing the grouping interval (e.g., daily, weekly) + * @return A {@link Map} with keys representing interval group names and values containing + * {@link List} of {@link ChartObject} instances with launch quantity information + */ + public Map<String, List<ChartObject>> getLaunchesQuantity(List<Launch> initial, + InfoInterval interval) { + final String START_PERIOD = "start"; + final String END_PERIOD = "end"; + final String COUNT = "count"; + final String INTERVAL = "interval"; + HashMap<String, List<ChartObject>> result = new HashMap<>(); + if (initial.isEmpty()) { + return result; + } + ProjectInfoGroup criteria = grouping.get(interval); + Map<String, List<Launch>> grouped = groupBy(initial, criteria); + for (Entry<String, List<Launch>> entry : grouped.entrySet()) { + List<Launch> launches = entry.getValue(); + Integer count = null != launches ? launches.size() : 0; + ChartObject group = new ChartObject(); + Map<String, String> values = new HashMap<>(); + values.put(COUNT, String.valueOf(count)); + values.put(INTERVAL, interval.getInterval()); + if (criteria != BY_DAY) { + DateTime parse = DateTime.parse(entry.getKey()); + // TODO remove Yoda time. replace with JDK8 + values.put(START_PERIOD, + parse.withDayOfWeek(DateTimeConstants.MONDAY).toString("yyy-MM-dd")); + values.put(END_PERIOD, parse.withDayOfWeek(DateTimeConstants.SUNDAY).toString("yyy-MM-dd")); + } else { + values.put(START_PERIOD, entry.getKey()); + } + group.setName("Number of launches"); + group.setValues(values); + result.put(entry.getKey(), Collections.singletonList(group)); + } + return result; + } - /** - * <b>Launch statistics line chart</b> project info widget content - * - * @param initial - * @param interval - * @return - */ - public Map<String, List<ChartObject>> getLaunchesIssues(List<Launch> initial, InfoInterval interval) { - HashMap<String, List<ChartObject>> result = new HashMap<>(); - if (initial.isEmpty()) { - return result; - } - final String PB = "productBug"; - final String SI = "systemIssue"; - final String AB = "automationBug"; - final String TI = "toInvestigate"; + /** + * <b>Launch statistics line chart</b> project info widget content + * + * @param initial A list of {@link Launch} objects to calculate the issues + * @param interval An {@link InfoInterval} representing the grouping interval (e.g., daily, weekly) + * @return A {@link Map} with keys representing interval group names and values containing + * {@link List} of {@link ChartObject} instances with issue count information + */ + public Map<String, List<ChartObject>> getLaunchesIssues(List<Launch> initial, + InfoInterval interval) { + HashMap<String, List<ChartObject>> result = new HashMap<>(); + if (initial.isEmpty()) { + return result; + } + final String PB = "productBug"; + final String SI = "systemIssue"; + final String AB = "automationBug"; + final String TI = "toInvestigate"; - ProjectInfoGroup criteria = grouping.get(interval); - Map<String, List<Launch>> grouped = groupBy(initial, criteria); - for (Entry<String, List<Launch>> entry : grouped.entrySet()) { - List<Launch> launches = entry.getValue(); - Integer pbCount = 0; - Integer abCount = 0; - Integer siCount = 0; - Integer tiCount = 0; - for (Launch launch : launches) { - pbCount += extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, launch.getStatistics()); - abCount += extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, launch.getStatistics()); - siCount += extractStatisticsCount(DEFECTS_SYSTEM_ISSUE_TOTAL, launch.getStatistics()); - tiCount += extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()); - } - ChartObject object = new ChartObject(); - Map<String, String> values = new HashMap<>(); - values.put(PB, String.valueOf(pbCount)); - values.put(SI, String.valueOf(siCount)); - values.put(AB, String.valueOf(abCount)); - values.put(TI, String.valueOf(tiCount)); - object.setValues(values); - result.put(entry.getKey(), Collections.singletonList(object)); - } - return result; - } + ProjectInfoGroup criteria = grouping.get(interval); + Map<String, List<Launch>> grouped = groupBy(initial, criteria); + for (Entry<String, List<Launch>> entry : grouped.entrySet()) { + List<Launch> launches = entry.getValue(); + Integer pbCount = 0; + Integer abCount = 0; + Integer siCount = 0; + Integer tiCount = 0; + for (Launch launch : launches) { + pbCount += extractStatisticsCount(DEFECTS_PRODUCT_BUG_TOTAL, launch.getStatistics()); + abCount += extractStatisticsCount(DEFECTS_AUTOMATION_BUG_TOTAL, launch.getStatistics()); + siCount += extractStatisticsCount(DEFECTS_SYSTEM_ISSUE_TOTAL, launch.getStatistics()); + tiCount += extractStatisticsCount(DEFECTS_TO_INVESTIGATE_TOTAL, launch.getStatistics()); + } + ChartObject object = new ChartObject(); + Map<String, String> values = new HashMap<>(); + values.put(PB, String.valueOf(pbCount)); + values.put(SI, String.valueOf(siCount)); + values.put(AB, String.valueOf(abCount)); + values.put(TI, String.valueOf(tiCount)); + object.setValues(values); + result.put(entry.getKey(), Collections.singletonList(object)); + } + return result; + } - /** - * Utility method for grouping input list of {@link Launch} by - * {@link ProjectInfoGroup} criteria - * - * @param initial - * @param criteria - * @return - */ - private static Map<String, List<Launch>> groupBy(List<Launch> initial, ProjectInfoGroup criteria) { - Map<String, List<Launch>> result = new LinkedHashMap<>(); - LocalDate prevDate = null; - for (Launch launch : initial) { - final LocalDate localDate = launch.getStartTime().atZone(ZoneOffset.UTC).toLocalDate(); + /** + * Utility method for grouping input list of {@link Launch} by {@link ProjectInfoGroup} criteria + * + * @param initial A list of {@link Launch} objects to be grouped + * @param criteria The {@link ProjectInfoGroup} criteria that determines the grouping key + * @return A map where the keys represent the grouping parameters (e.g., launch names or formatted dates) + * and the values are lists of {@link Launch} objects grouped under that key + */ + private static Map<String, List<Launch>> groupBy(List<Launch> initial, + ProjectInfoGroup criteria) { + Map<String, List<Launch>> result = new LinkedHashMap<>(); + LocalDate prevDate = null; + for (Launch launch : initial) { + final LocalDate localDate = launch.getStartTime().atZone(ZoneOffset.UTC).toLocalDate(); - String key; - switch (criteria) { - case BY_NAME: - key = launch.getName(); - break; - default: - key = formattedDate(criteria, localDate); - if (prevDate != null) { - while (prevDate.isBefore(localDate)) { - if (!result.containsKey(formattedDate(criteria, prevDate))) { - result.put(formattedDate(criteria, prevDate), new ArrayList<>()); - } - prevDate = prevDate.plus(1, criteria == BY_DAY ? DAYS : WEEKS); - } - } - } - if (!result.containsKey(key)) { - result.put(key, Lists.newArrayList(launch)); - } else { - List<Launch> prev = result.get(key); - prev.add(launch); - result.put(key, prev); - } - prevDate = localDate; - } - return result; - } + String key; + switch (criteria) { + case BY_NAME: + key = launch.getName(); + break; + default: + key = formattedDate(criteria, localDate); + if (prevDate != null) { + while (prevDate.isBefore(localDate)) { + if (!result.containsKey(formattedDate(criteria, prevDate))) { + result.put(formattedDate(criteria, prevDate), new ArrayList<>()); + } + prevDate = prevDate.plus(1, criteria == BY_DAY ? DAYS : WEEKS); + } + } + } + if (!result.containsKey(key)) { + result.put(key, Lists.newArrayList(launch)); + } else { + List<Launch> prev = result.get(key); + prev.add(launch); + result.put(key, prev); + } + prevDate = localDate; + } + return result; + } - private static String formattedDate(ProjectInfoGroup criteria, LocalDate localDate) { - return criteria == BY_DAY ? localDate.toString() : formatter.format(localDate); - } + private static String formattedDate(ProjectInfoGroup criteria, LocalDate localDate) { + return criteria == BY_DAY ? localDate.toString() : formatter.format(localDate); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectUserHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectUserHandlerImpl.java index 2859370b15..671868258d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectUserHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/ProjectUserHandlerImpl.java @@ -26,14 +26,15 @@ public ProjectUserHandlerImpl(ApplicationEventPublisher eventPublisher, } @Override - public ProjectUser assign(User user, Project project, ProjectRole projectRole, User creator) { + public ProjectUser assign(User user, Project project, ProjectRole projectRole, User creator, + boolean isSystemEvent) { final ProjectUser projectUser = new ProjectUser().withProjectRole(projectRole) .withUser(user) .withProject(project); projectUserRepository.save(projectUser); AssignUserEvent assignUserEvent = new AssignUserEvent(getUserActivityResource(user, project), - creator.getId(), creator.getLogin()); + creator.getId(), creator.getLogin(), isSystemEvent); eventPublisher.publishEvent(assignUserEvent); return projectUser; diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/UpdateProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/UpdateProjectHandlerImpl.java index e14bb10ac9..685702ac58 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/UpdateProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/UpdateProjectHandlerImpl.java @@ -421,7 +421,8 @@ private void assignUser(String name, ProjectRole projectRole, List<String> assig AssignUserEvent assignUserEvent = new AssignUserEvent( convertUserToResource(modifyingUser, projectUser), authorizedUser.getUserId(), - authorizedUser.getUsername()); + authorizedUser.getUsername(), + false); applicationEventPublisher.publishEvent(assignUserEvent); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/CreateProjectSettingsHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/CreateProjectSettingsHandler.java index 07ebde0a09..e0e3297479 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/CreateProjectSettingsHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/CreateProjectSettingsHandler.java @@ -27,23 +27,25 @@ */ public interface CreateProjectSettingsHandler { - /** - * Create issue sub-type for specified project - * - * @param projectName Project name - * @param user User - * @param rq Create issue sub type rq - * @return EntryCreatedRS - */ - IssueSubTypeCreatedRS createProjectIssueSubType(String projectName, ReportPortalUser user, CreateIssueSubTypeRQ rq); + /** + * Create issue sub-type for specified project + * + * @param projectName Project name + * @param user User + * @param rq Create issue sub type rq + * @return EntryCreatedRS + */ + IssueSubTypeCreatedRS createProjectIssueSubType(String projectName, ReportPortalUser user, + CreateIssueSubTypeRQ rq); - /** - * Create {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} entity - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param createPatternTemplateRQ {@link CreatePatternTemplateRQ} - * @param user {@link ReportPortalUser} - * @return {@link EntryCreatedRS} - */ - EntryCreatedRS createPatternTemplate(String projectName, CreatePatternTemplateRQ createPatternTemplateRQ, ReportPortalUser user); + /** + * Create {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} entity + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param createPatternTemplateRQ {@link CreatePatternTemplateRQ} + * @param user {@link ReportPortalUser} + * @return {@link EntryCreatedRS} + */ + EntryCreatedRS createPatternTemplate(String projectName, + CreatePatternTemplateRQ createPatternTemplateRQ, ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/DeleteProjectSettingsHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/DeleteProjectSettingsHandler.java index 983b2844f3..92cc4db052 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/DeleteProjectSettingsHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/DeleteProjectSettingsHandler.java @@ -24,24 +24,25 @@ */ public interface DeleteProjectSettingsHandler { - /** - * Remove specified issue sub-type for specified project - * - * @param projectName Project name - * @param user User - * @param id Issue id - * @return OperationCompletionRS - */ - OperationCompletionRS deleteProjectIssueSubType(String projectName, ReportPortalUser user, Long id); + /** + * Remove specified issue sub-type for specified project + * + * @param projectName Project name + * @param user User + * @param id Issue id + * @return OperationCompletionRS + */ + OperationCompletionRS deleteProjectIssueSubType(String projectName, ReportPortalUser user, + Long id); - /** - * Delete {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} by ID and project ID - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param user {@link ReportPortalUser} - * @param id {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate#id} - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS deletePatternTemplate(String projectName, ReportPortalUser user, Long id); + /** + * Delete {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} by ID and project ID + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param user {@link ReportPortalUser} + * @param id {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate#id} + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS deletePatternTemplate(String projectName, ReportPortalUser user, Long id); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/GetProjectSettingsHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/GetProjectSettingsHandler.java index 11c96bfede..f3b4e0f644 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/GetProjectSettingsHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/GetProjectSettingsHandler.java @@ -23,11 +23,11 @@ */ public interface GetProjectSettingsHandler { - /** - * Provide additional settings for specified project - * - * @param projectName Project name - * @return ProjectSettingsResource - */ - ProjectSettingsResource getProjectSettings(String projectName); + /** + * Provide additional settings for specified project + * + * @param projectName Project name + * @return ProjectSettingsResource + */ + ProjectSettingsResource getProjectSettings(String projectName); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/UpdateProjectSettingsHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/UpdateProjectSettingsHandler.java index 6bc5dbd709..91461da027 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/UpdateProjectSettingsHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/UpdateProjectSettingsHandler.java @@ -26,23 +26,27 @@ */ public interface UpdateProjectSettingsHandler { - /** - * Update issue sub-type for specified project - * - * @param projectName Project name - * @param rq Update rq - * @return OperationCompletionRS - */ - OperationCompletionRS updateProjectIssueSubType(String projectName, ReportPortalUser user, UpdateIssueSubTypeRQ rq); + /** + * Update issue sub-type for specified project + * + * @param projectName Project name + * @param user {@link ReportPortalUser} + * @param rq Update rq + * @return OperationCompletionRS + */ + OperationCompletionRS updateProjectIssueSubType(String projectName, ReportPortalUser user, + UpdateIssueSubTypeRQ rq); - /** - * Update {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} by ID and project ID - * - * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} - * @param updatePatternTemplateRQ {@link UpdatePatternTemplateRQ} - * @param user {@link ReportPortalUser} - * @return {@link OperationCompletionRS} - */ - OperationCompletionRS updatePatternTemplate(Long id, String projectName, UpdatePatternTemplateRQ updatePatternTemplateRQ, - ReportPortalUser user); + /** + * Update {@link com.epam.ta.reportportal.entity.pattern.PatternTemplate} by ID and project ID + * + * @param projectName {@link com.epam.ta.reportportal.entity.project.Project#name} + * @param updatePatternTemplateRQ {@link UpdatePatternTemplateRQ} + * @param user {@link ReportPortalUser} + * @param id id of pattern template + * @return {@link OperationCompletionRS} + */ + OperationCompletionRS updatePatternTemplate(Long id, String projectName, + UpdatePatternTemplateRQ updatePatternTemplateRQ, + ReportPortalUser user); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImpl.java index 979501b713..7389c85fb6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImpl.java @@ -1,201 +1,212 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.project.settings.impl; - -import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.validation.Suppliers; -import com.epam.ta.reportportal.core.analyzer.pattern.CreatePatternTemplateHandler; -import com.epam.ta.reportportal.core.events.MessageBus; -import com.epam.ta.reportportal.core.events.activity.DefectTypeCreatedEvent; -import com.epam.ta.reportportal.core.events.activity.PatternCreatedEvent; -import com.epam.ta.reportportal.core.project.settings.CreateProjectSettingsHandler; -import com.epam.ta.reportportal.dao.IssueGroupRepository; -import com.epam.ta.reportportal.dao.IssueTypeRepository; -import com.epam.ta.reportportal.dao.ProjectRepository; -import com.epam.ta.reportportal.dao.WidgetRepository; -import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; -import com.epam.ta.reportportal.entity.item.issue.IssueGroup; -import com.epam.ta.reportportal.entity.item.issue.IssueType; -import com.epam.ta.reportportal.entity.pattern.PatternTemplate; -import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; -import com.epam.ta.reportportal.entity.project.Project; -import com.epam.ta.reportportal.entity.project.ProjectIssueType; -import com.epam.ta.reportportal.entity.widget.Widget; -import com.epam.ta.reportportal.entity.widget.WidgetType; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.converter.builders.IssueTypeBuilder; -import com.epam.ta.reportportal.ws.converter.converters.PatternTemplateConverter; -import com.epam.ta.reportportal.ws.model.EntryCreatedRS; -import com.epam.ta.reportportal.ws.model.ErrorType; -import com.epam.ta.reportportal.ws.model.ValidationConstraints; -import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; -import com.epam.ta.reportportal.ws.model.project.config.IssueSubTypeCreatedRS; -import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; -import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableMap; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.*; -import static com.epam.ta.reportportal.ws.converter.converters.IssueTypeConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; - -/** - * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> - */ -@Service -@Transactional -public class CreateProjectSettingsHandlerImpl implements CreateProjectSettingsHandler { - - private static final Map<String, String> PREFIX = ImmutableMap.<String, String>builder().put(AUTOMATION_BUG.getValue(), "ab_") - .put(PRODUCT_BUG.getValue(), "pb_") - .put(SYSTEM_ISSUE.getValue(), "si_") - .put(NO_DEFECT.getValue(), "nd_") - .put(TO_INVESTIGATE.getValue(), "ti_") - .build(); - - private final ProjectRepository projectRepository; - - private final WidgetRepository widgetRepository; - - private final IssueGroupRepository issueGroupRepository; - - private final IssueTypeRepository issueTypeRepository; - - private final Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateMapping; - - private final MessageBus messageBus; - - @Autowired - public CreateProjectSettingsHandlerImpl(ProjectRepository projectRepository, WidgetRepository widgetRepository, - IssueGroupRepository issueGroupRepository, IssueTypeRepository issueTypeRepository, - @Qualifier("createPatternTemplateMapping") Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateMapping, - MessageBus messageBus) { - this.projectRepository = projectRepository; - this.widgetRepository = widgetRepository; - this.issueGroupRepository = issueGroupRepository; - this.issueTypeRepository = issueTypeRepository; - this.createPatternTemplateMapping = createPatternTemplateMapping; - this.messageBus = messageBus; - } - - @Override - public IssueSubTypeCreatedRS createProjectIssueSubType(String projectName, ReportPortalUser user, CreateIssueSubTypeRQ rq) { - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectName)); - - expect(NOT_ISSUE_FLAG.getValue().equalsIgnoreCase(rq.getTypeRef()), equalTo(false)).verify(INCORRECT_REQUEST, - "Impossible to create sub-type for 'Not Issue' type." - ); - - /* Check if global issue type reference is valid */ - TestItemIssueGroup expectedGroup = TestItemIssueGroup.fromValue(rq.getTypeRef()) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, rq.getTypeRef())); - - List<ProjectIssueType> existingSubTypes = project.getProjectIssueTypes() - .stream() - .filter(projectIssueType -> projectIssueType.getIssueType().getIssueGroup().getTestItemIssueGroup().equals(expectedGroup)) - .collect(Collectors.toList()); - - expect(existingSubTypes.size() < ValidationConstraints.MAX_ISSUE_SUBTYPES, equalTo(true)).verify(INCORRECT_REQUEST, - "Sub Issues count is bound of size limit" - ); - - String locator = PREFIX.get(expectedGroup.getValue()) + shortUUID(); - IssueType subType = new IssueTypeBuilder().addLocator(locator) - .addIssueGroup(issueGroupRepository.findByTestItemIssueGroup(expectedGroup)) - .addLongName(rq.getLongName()) - .addShortName(rq.getShortName()) - .addHexColor(rq.getColor()) - .get(); - - ProjectIssueType projectIssueType = new ProjectIssueType(); - projectIssueType.setIssueType(subType); - projectIssueType.setProject(project); - - project.getProjectIssueTypes().add(projectIssueType); - - issueTypeRepository.save(subType); - projectRepository.save(project); - - updateWidgets(project, subType); - - messageBus.publishActivity(new DefectTypeCreatedEvent(TO_ACTIVITY_RESOURCE.apply(subType), - user.getUserId(), - user.getUsername(), - project.getId() - )); - return new IssueSubTypeCreatedRS(subType.getId(), subType.getLocator()); - } - - /** - * Update {@link Widget#getContentFields()} of the widgets that support issue type updates ({@link WidgetType#isSupportMultilevelStructure()}) - * and have content fields for the same {@link IssueGroup#getTestItemIssueGroup()} as provided issueType - * - * @param project {@link Project} - * @param issueType {@link IssueType} - */ - private void updateWidgets(Project project, IssueType issueType) { - String issueGroupContentField = - "statistics$defects$" + issueType.getIssueGroup().getTestItemIssueGroup().getValue().toLowerCase() + "$"; - widgetRepository.findAllByProjectIdAndWidgetTypeInAndContentFieldContaining(project.getId(), - Arrays.stream(WidgetType.values()) - .filter(WidgetType::isIssueTypeUpdateSupported) - .map(WidgetType::getType) - .collect(Collectors.toList()), - issueGroupContentField - ).forEach(widget -> { - widget.getContentFields().add(issueGroupContentField + issueType.getLocator()); - widgetRepository.save(widget); - }); - } - - @Override - public EntryCreatedRS createPatternTemplate(String projectName, CreatePatternTemplateRQ createPatternTemplateRQ, - ReportPortalUser user) { - - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - - PatternTemplate patternTemplate = createPatternTemplateMapping.get(PatternTemplateType.fromString(createPatternTemplateRQ.getType()) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Unknown pattern template type - '{}'", createPatternTemplateRQ.getType()).get() - ))).createPatternTemplate(project.getId(), createPatternTemplateRQ); - - messageBus.publishActivity(new PatternCreatedEvent(user.getUserId(), - user.getUsername(), - PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply(patternTemplate) - )); - return new EntryCreatedRS(patternTemplate.getId()); - } - - private static String shortUUID() { - long l = ByteBuffer.wrap(UUID.randomUUID().toString().getBytes(Charsets.UTF_8)).getLong(); - return Long.toString(l, Character.MAX_RADIX); - } -} +/* + * Copyright 2019 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.impl; + +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.AUTOMATION_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NO_DEFECT; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.PRODUCT_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.SYSTEM_ISSUE; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static com.epam.ta.reportportal.ws.converter.converters.IssueTypeConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.validation.Suppliers; +import com.epam.ta.reportportal.core.analyzer.pattern.service.CreatePatternTemplateHandler; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.DefectTypeCreatedEvent; +import com.epam.ta.reportportal.core.events.activity.PatternCreatedEvent; +import com.epam.ta.reportportal.core.project.settings.CreateProjectSettingsHandler; +import com.epam.ta.reportportal.dao.IssueGroupRepository; +import com.epam.ta.reportportal.dao.IssueTypeRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.WidgetRepository; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.item.issue.IssueGroup; +import com.epam.ta.reportportal.entity.item.issue.IssueType; +import com.epam.ta.reportportal.entity.pattern.PatternTemplate; +import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.ProjectIssueType; +import com.epam.ta.reportportal.entity.widget.Widget; +import com.epam.ta.reportportal.entity.widget.WidgetType; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.converter.builders.IssueTypeBuilder; +import com.epam.ta.reportportal.ws.converter.converters.PatternTemplateConverter; +import com.epam.ta.reportportal.ws.model.EntryCreatedRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.ValidationConstraints; +import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; +import com.epam.ta.reportportal.ws.model.project.config.IssueSubTypeCreatedRS; +import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> + */ +@Service +@Transactional +public class CreateProjectSettingsHandlerImpl implements CreateProjectSettingsHandler { + + private static final Map<String, String> PREFIX = ImmutableMap.<String, String>builder() + .put(AUTOMATION_BUG.getValue(), "ab_") + .put(PRODUCT_BUG.getValue(), "pb_") + .put(SYSTEM_ISSUE.getValue(), "si_") + .put(NO_DEFECT.getValue(), "nd_") + .put(TO_INVESTIGATE.getValue(), "ti_") + .build(); + + private final ProjectRepository projectRepository; + + private final WidgetRepository widgetRepository; + + private final IssueGroupRepository issueGroupRepository; + + private final IssueTypeRepository issueTypeRepository; + + private final Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateMapping; + + private final MessageBus messageBus; + + @Autowired + public CreateProjectSettingsHandlerImpl(ProjectRepository projectRepository, + WidgetRepository widgetRepository, + IssueGroupRepository issueGroupRepository, IssueTypeRepository issueTypeRepository, + @Qualifier("createPatternTemplateMapping") Map<PatternTemplateType, CreatePatternTemplateHandler> createPatternTemplateMapping, + MessageBus messageBus) { + this.projectRepository = projectRepository; + this.widgetRepository = widgetRepository; + this.issueGroupRepository = issueGroupRepository; + this.issueTypeRepository = issueTypeRepository; + this.createPatternTemplateMapping = createPatternTemplateMapping; + this.messageBus = messageBus; + } + + @Override + public IssueSubTypeCreatedRS createProjectIssueSubType(String projectName, ReportPortalUser user, + CreateIssueSubTypeRQ rq) { + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectName)); + + expect(NOT_ISSUE_FLAG.getValue().equalsIgnoreCase(rq.getTypeRef()), equalTo(false)).verify( + INCORRECT_REQUEST, + "Impossible to create sub-type for 'Not Issue' type." + ); + + /* Check if global issue type reference is valid */ + TestItemIssueGroup expectedGroup = TestItemIssueGroup.fromValue(rq.getTypeRef()) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, rq.getTypeRef())); + + expect( + project.getProjectIssueTypes().size() < ValidationConstraints.MAX_ISSUE_TYPES_AND_SUBTYPES, + equalTo(true)).verify(INCORRECT_REQUEST, + "Sub Issues count is bound of size limit" + ); + + String locator = PREFIX.get(expectedGroup.getValue()) + shortUUID(); + IssueType subType = new IssueTypeBuilder().addLocator(locator) + .addIssueGroup(issueGroupRepository.findByTestItemIssueGroup(expectedGroup)) + .addLongName(rq.getLongName()) + .addShortName(rq.getShortName()) + .addHexColor(rq.getColor()) + .get(); + + ProjectIssueType projectIssueType = new ProjectIssueType(); + projectIssueType.setIssueType(subType); + projectIssueType.setProject(project); + + project.getProjectIssueTypes().add(projectIssueType); + + issueTypeRepository.save(subType); + projectRepository.save(project); + + updateWidgets(project, subType); + + messageBus.publishActivity(new DefectTypeCreatedEvent(TO_ACTIVITY_RESOURCE.apply(subType), + user.getUserId(), + user.getUsername(), + project.getId() + )); + return new IssueSubTypeCreatedRS(subType.getId(), subType.getLocator()); + } + + /** + * Update {@link Widget#getContentFields()} of the widgets that support issue type updates + * ({@link WidgetType#isSupportMultilevelStructure()}) and have content fields for the same + * {@link IssueGroup#getTestItemIssueGroup()} as provided issueType + * + * @param project {@link Project} + * @param issueType {@link IssueType} + */ + private void updateWidgets(Project project, IssueType issueType) { + String issueGroupContentField = + "statistics$defects$" + issueType.getIssueGroup().getTestItemIssueGroup().getValue() + .toLowerCase() + "$"; + widgetRepository.findAllByProjectIdAndWidgetTypeInAndContentFieldContaining(project.getId(), + Arrays.stream(WidgetType.values()) + .filter(WidgetType::isIssueTypeUpdateSupported) + .map(WidgetType::getType) + .collect(Collectors.toList()), + issueGroupContentField + ).forEach(widget -> { + widget.getContentFields().add(issueGroupContentField + issueType.getLocator()); + widgetRepository.save(widget); + }); + } + + @Override + public EntryCreatedRS createPatternTemplate(String projectName, + CreatePatternTemplateRQ createPatternTemplateRQ, + ReportPortalUser user) { + + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + + PatternTemplate patternTemplate = createPatternTemplateMapping.get( + PatternTemplateType.fromString(createPatternTemplateRQ.getType()) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Unknown pattern template type - '{}'", + createPatternTemplateRQ.getType()).get() + ))).createPatternTemplate(project.getId(), createPatternTemplateRQ); + + messageBus.publishActivity(new PatternCreatedEvent(user.getUserId(), + user.getUsername(), + PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply(patternTemplate) + )); + return new EntryCreatedRS(patternTemplate.getId()); + } + + private static String shortUUID() { + long l = ByteBuffer.wrap(UUID.randomUUID().toString().getBytes(Charsets.UTF_8)).getLong(); + return Long.toString(l, Character.MAX_RADIX); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImpl.java index 71bd7874c1..f7f14e91ec 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImpl.java @@ -34,17 +34,17 @@ @Transactional(readOnly = true) public class GetProjectSettingsHandlerImpl implements GetProjectSettingsHandler { - private final ProjectRepository repository; + private final ProjectRepository repository; - @Autowired - public GetProjectSettingsHandlerImpl(ProjectRepository repository) { - this.repository = repository; - } + @Autowired + public GetProjectSettingsHandlerImpl(ProjectRepository repository) { + this.repository = repository; + } - @Override - public ProjectSettingsResource getProjectSettings(String projectName) { - Project project = repository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - return ProjectSettingsConverter.TO_PROJECT_SETTINGS_RESOURCE.apply(project); - } + @Override + public ProjectSettingsResource getProjectSettings(String projectName) { + Project project = repository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + return ProjectSettingsConverter.TO_PROJECT_SETTINGS_RESOURCE.apply(project); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImpl.java index a098f0435a..7c99aab66f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImpl.java @@ -16,6 +16,21 @@ package com.epam.ta.reportportal.core.project.settings.impl; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.in; +import static com.epam.ta.reportportal.commons.Predicates.not; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.AUTOMATION_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NO_DEFECT; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.PRODUCT_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.SYSTEM_ISSUE; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static com.epam.ta.reportportal.ws.converter.converters.IssueTypeConverter.TO_ACTIVITY_RESOURCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.FORBIDDEN_OPERATION; +import static com.epam.ta.reportportal.ws.model.ErrorType.ISSUE_TYPE_NOT_FOUND; +import static com.epam.ta.reportportal.ws.model.ErrorType.PROJECT_NOT_FOUND; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -40,21 +55,13 @@ import com.epam.ta.reportportal.ws.model.project.config.UpdateOneIssueSubTypeRQ; import com.epam.ta.reportportal.ws.model.project.config.pattern.UpdatePatternTemplateRQ; import com.google.common.collect.Sets; +import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.*; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.*; -import static com.epam.ta.reportportal.ws.converter.converters.IssueTypeConverter.TO_ACTIVITY_RESOURCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.*; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @@ -62,104 +69,119 @@ @Transactional public class UpdateProjectSettingsHandlerImpl implements UpdateProjectSettingsHandler { - private final ProjectRepository projectRepository; - - private final PatternTemplateRepository patternTemplateRepository; - - private final MessageBus messageBus; - - @Autowired - public UpdateProjectSettingsHandlerImpl(ProjectRepository projectRepository, PatternTemplateRepository patternTemplateRepository, - MessageBus messageBus) { - this.projectRepository = projectRepository; - this.patternTemplateRepository = patternTemplateRepository; - this.messageBus = messageBus; - } - - @Override - public OperationCompletionRS updateProjectIssueSubType(String projectName, ReportPortalUser user, - UpdateIssueSubTypeRQ updateIssueSubTypeRQ) { - expect(updateIssueSubTypeRQ.getIds().size() > 0, equalTo(true)).verify(FORBIDDEN_OPERATION, - "Please specify at least one item data for update." - ); - - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectName)); - - List<IssueTypeActivityResource> issueTypeActivityResources = updateIssueSubTypeRQ.getIds() - .stream() - .map(subTypeRQ -> TO_ACTIVITY_RESOURCE.apply(validateAndUpdate(subTypeRQ, - project.getProjectIssueTypes().stream().map(ProjectIssueType::getIssueType).collect(Collectors.toList()) - ))) - .collect(Collectors.toList()); - - projectRepository.save(project); - issueTypeActivityResources.forEach(it -> messageBus.publishActivity(new DefectTypeUpdatedEvent(it, - user.getUserId(), - user.getUsername(), - project.getId() - ))); - return new OperationCompletionRS("Issue sub-type(s) was updated successfully."); - } - - @Override - public OperationCompletionRS updatePatternTemplate(Long id, String projectName, UpdatePatternTemplateRQ updatePatternTemplateRQ, - ReportPortalUser user) { - - Project project = projectRepository.findByName(projectName) - .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); - - PatternTemplate patternTemplate = patternTemplateRepository.findById(id) - .orElseThrow(() -> new ReportPortalException(ErrorType.PATTERN_TEMPLATE_NOT_FOUND_IN_PROJECT, id, project.getId())); - - final String name = StringUtils.trim(updatePatternTemplateRQ.getName()); - - if (!patternTemplate.getName().equalsIgnoreCase(name)) { - BusinessRule.expect(patternTemplateRepository.existsByProjectIdAndNameIgnoreCase( - project.getId(), name - ), equalTo(false)).verify(ErrorType.RESOURCE_ALREADY_EXISTS, name); - } - - PatternTemplateActivityResource before = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply(patternTemplate); - - patternTemplate.setName(name); - patternTemplate.setEnabled(updatePatternTemplateRQ.getEnabled()); - - PatternTemplateActivityResource after = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply(patternTemplate); - - messageBus.publishActivity(new PatternUpdatedEvent(user.getUserId(), user.getUsername(), before, after)); - - return new OperationCompletionRS(Suppliers.formattedSupplier("Pattern template with ID = '{}' has been successfully updated", id) - .get()); - - } - - private IssueType validateAndUpdate(UpdateOneIssueSubTypeRQ issueSubTypeRQ, List<IssueType> issueTypes) { - /* Check if global issue type reference is valid */ - TestItemIssueGroup expectedGroup = TestItemIssueGroup.fromValue(issueSubTypeRQ.getTypeRef()) - .orElseThrow(() -> new ReportPortalException(ISSUE_TYPE_NOT_FOUND, issueSubTypeRQ.getTypeRef())); - - IssueType exist = issueTypes.stream() - .filter(issueType -> issueType.getLocator().equalsIgnoreCase(issueSubTypeRQ.getLocator())) - .findFirst() - .orElseThrow(() -> new ReportPortalException(ISSUE_TYPE_NOT_FOUND, issueSubTypeRQ.getLocator())); - - expect(exist.getIssueGroup().getTestItemIssueGroup().equals(expectedGroup), equalTo(true)).verify(FORBIDDEN_OPERATION, - "You cannot change sub-type references to global type." - ); - - expect(exist.getLocator(), - not(in(Sets.newHashSet(AUTOMATION_BUG.getLocator(), - PRODUCT_BUG.getLocator(), - SYSTEM_ISSUE.getLocator(), - NO_DEFECT.getLocator(), - TO_INVESTIGATE.getLocator() - ))) - ).verify(FORBIDDEN_OPERATION, "You cannot remove predefined global issue types."); - - ofNullable(issueSubTypeRQ.getLongName()).ifPresent(exist::setLongName); - ofNullable(issueSubTypeRQ.getShortName()).ifPresent(exist::setShortName); - ofNullable(issueSubTypeRQ.getColor()).ifPresent(exist::setHexColor); - return exist; - } + private final ProjectRepository projectRepository; + + private final PatternTemplateRepository patternTemplateRepository; + + private final MessageBus messageBus; + + @Autowired + public UpdateProjectSettingsHandlerImpl(ProjectRepository projectRepository, + PatternTemplateRepository patternTemplateRepository, + MessageBus messageBus) { + this.projectRepository = projectRepository; + this.patternTemplateRepository = patternTemplateRepository; + this.messageBus = messageBus; + } + + @Override + public OperationCompletionRS updateProjectIssueSubType(String projectName, ReportPortalUser user, + UpdateIssueSubTypeRQ updateIssueSubTypeRQ) { + expect(updateIssueSubTypeRQ.getIds().size() > 0, equalTo(true)).verify(FORBIDDEN_OPERATION, + "Please specify at least one item data for update." + ); + + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(PROJECT_NOT_FOUND, projectName)); + + List<IssueTypeActivityResource> issueTypeActivityResources = updateIssueSubTypeRQ.getIds() + .stream() + .map(subTypeRQ -> TO_ACTIVITY_RESOURCE.apply(validateAndUpdate(subTypeRQ, + project.getProjectIssueTypes().stream().map(ProjectIssueType::getIssueType) + .collect(Collectors.toList()) + ))) + .collect(Collectors.toList()); + + projectRepository.save(project); + issueTypeActivityResources.forEach( + it -> messageBus.publishActivity(new DefectTypeUpdatedEvent(it, + user.getUserId(), + user.getUsername(), + project.getId() + ))); + return new OperationCompletionRS("Issue sub-type(s) was updated successfully."); + } + + @Override + public OperationCompletionRS updatePatternTemplate(Long id, String projectName, + UpdatePatternTemplateRQ updatePatternTemplateRQ, + ReportPortalUser user) { + + Project project = projectRepository.findByName(projectName) + .orElseThrow(() -> new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, projectName)); + + PatternTemplate patternTemplate = patternTemplateRepository.findById(id) + .orElseThrow( + () -> new ReportPortalException(ErrorType.PATTERN_TEMPLATE_NOT_FOUND_IN_PROJECT, id, + project.getId())); + + final String name = StringUtils.trim(updatePatternTemplateRQ.getName()); + + if (!patternTemplate.getName().equalsIgnoreCase(name)) { + BusinessRule.expect(patternTemplateRepository.existsByProjectIdAndNameIgnoreCase( + project.getId(), name + ), equalTo(false)).verify(ErrorType.RESOURCE_ALREADY_EXISTS, name); + } + + PatternTemplateActivityResource before = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply( + patternTemplate); + + patternTemplate.setName(name); + patternTemplate.setEnabled(updatePatternTemplateRQ.getEnabled()); + + PatternTemplateActivityResource after = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply( + patternTemplate); + + messageBus.publishActivity( + new PatternUpdatedEvent(user.getUserId(), user.getUsername(), before, after)); + + return new OperationCompletionRS( + Suppliers.formattedSupplier("Pattern template with ID = '{}' has been successfully updated", + id) + .get()); + + } + + private IssueType validateAndUpdate(UpdateOneIssueSubTypeRQ issueSubTypeRQ, + List<IssueType> issueTypes) { + /* Check if global issue type reference is valid */ + TestItemIssueGroup expectedGroup = TestItemIssueGroup.fromValue(issueSubTypeRQ.getTypeRef()) + .orElseThrow( + () -> new ReportPortalException(ISSUE_TYPE_NOT_FOUND, issueSubTypeRQ.getTypeRef())); + + IssueType exist = issueTypes.stream() + .filter(issueType -> issueType.getLocator().equalsIgnoreCase(issueSubTypeRQ.getLocator())) + .findFirst() + .orElseThrow( + () -> new ReportPortalException(ISSUE_TYPE_NOT_FOUND, issueSubTypeRQ.getLocator())); + + expect(exist.getIssueGroup().getTestItemIssueGroup().equals(expectedGroup), + equalTo(true)).verify(FORBIDDEN_OPERATION, + "You cannot change sub-type references to global type." + ); + + expect(exist.getLocator(), + not(in(Sets.newHashSet(AUTOMATION_BUG.getLocator(), + PRODUCT_BUG.getLocator(), + SYSTEM_ISSUE.getLocator(), + NO_DEFECT.getLocator(), + TO_INVESTIGATE.getLocator() + ))) + ).verify(FORBIDDEN_OPERATION, "You cannot remove predefined global issue types."); + + ofNullable(issueSubTypeRQ.getLongName()).ifPresent(exist::setLongName); + ofNullable(issueSubTypeRQ.getShortName()).ifPresent(exist::setShortName); + ofNullable(issueSubTypeRQ.getColor()).ifPresent(exist::setHexColor); + return exist; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandler.java new file mode 100644 index 0000000000..55cd982c36 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.ws.model.EntryCreatedRS; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +public interface CreateProjectNotificationHandler { + + EntryCreatedRS createNotification(Project project, SenderCaseDTO createNotificationRQ, + ReportPortalUser user); + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImpl.java new file mode 100644 index 0000000000..29879a1487 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImpl.java @@ -0,0 +1,88 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.NotificationsConfigUpdatedEvent; +import com.epam.ta.reportportal.core.project.validator.notification.ProjectNotificationValidator; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.ws.converter.converters.NotificationConfigConverter; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import com.epam.ta.reportportal.ws.model.EntryCreatedRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.project.ProjectResource; +import com.epam.ta.reportportal.ws.model.project.email.ProjectNotificationConfigDTO; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.Optional; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class CreateProjectNotificationHandlerImpl implements CreateProjectNotificationHandler { + + private final SenderCaseRepository senderCaseRepository; + private final MessageBus messageBus; + private final ProjectConverter projectConverter; + private final ProjectNotificationValidator projectNotificationValidator; + + public CreateProjectNotificationHandlerImpl(SenderCaseRepository senderCaseRepository, + MessageBus messageBus, + ProjectConverter projectConverter, + ProjectNotificationValidator projectNotificationValidator) { + this.senderCaseRepository = senderCaseRepository; + this.messageBus = messageBus; + this.projectConverter = projectConverter; + this.projectNotificationValidator = projectNotificationValidator; + } + + @Override + public EntryCreatedRS createNotification(Project project, SenderCaseDTO createNotificationRQ, + ReportPortalUser user) { + expect(senderCaseRepository.findByProjectIdAndRuleNameIgnoreCase(project.getId(), + createNotificationRQ.getRuleName()), + Optional::isEmpty) + .verify(ErrorType.RESOURCE_ALREADY_EXISTS, createNotificationRQ.getRuleName()); + + projectNotificationValidator.validateCreateRQ(project, createNotificationRQ); + + SenderCase senderCase = NotificationConfigConverter.TO_CASE_MODEL.apply(createNotificationRQ); + senderCase.setId(null); + senderCase.setProject(project); + senderCaseRepository.save(senderCase); + + ProjectResource projectResource = projectConverter.TO_PROJECT_RESOURCE.apply(project); + ProjectNotificationConfigDTO projectNotificationConfigDTO = projectResource.getConfiguration() + .getProjectConfig(); + projectNotificationConfigDTO.getSenderCases().add(createNotificationRQ); + + messageBus.publishActivity(new NotificationsConfigUpdatedEvent(projectResource, + projectResource.getConfiguration().getProjectConfig(), + user.getUserId(), + user.getUsername() + )); + + return new EntryCreatedRS(senderCase.getId()); + } + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandler.java new file mode 100644 index 0000000000..28e6165771 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandler.java @@ -0,0 +1,32 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +public interface DeleteProjectNotificationHandler { + + OperationCompletionRS deleteNotification(Project project, Long notificationId, + ReportPortalUser user); +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImpl.java new file mode 100644 index 0000000000..9c914c8203 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImpl.java @@ -0,0 +1,91 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static java.util.Optional.ofNullable; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.validation.Suppliers; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.NotificationsConfigUpdatedEvent; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.project.ProjectResource; +import com.epam.ta.reportportal.ws.model.project.email.ProjectNotificationConfigDTO; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class DeleteProjectNotificationHandlerImpl implements DeleteProjectNotificationHandler { + + private final SenderCaseRepository senderCaseRepository; + private final MessageBus messageBus; + private final ProjectConverter projectConverter; + + public DeleteProjectNotificationHandlerImpl(SenderCaseRepository senderCaseRepository, + MessageBus messageBus, + ProjectConverter projectConverter) { + this.senderCaseRepository = senderCaseRepository; + this.messageBus = messageBus; + this.projectConverter = projectConverter; + } + + @Override + public OperationCompletionRS deleteNotification(Project project, Long notificationId, + ReportPortalUser user) { + Optional<SenderCase> senderCase = senderCaseRepository.findById(notificationId); + expect(senderCase, + (notification) -> notification.map( + ntf -> Objects.equals(ntf.getProject().getId(), project.getId())).orElse(false)) + .verify( + ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier( + "Notification '{}' not found. Did you use correct Notification ID?", + notificationId).get() + ); + senderCaseRepository.deleteSenderCaseById(notificationId); + + ProjectResource projectResource = projectConverter.TO_PROJECT_RESOURCE.apply(project); + ProjectNotificationConfigDTO projectNotificationConfigDTO = projectResource.getConfiguration() + .getProjectConfig(); + ofNullable(projectNotificationConfigDTO.getSenderCases()).ifPresent( + scs -> projectNotificationConfigDTO.setSenderCases( + scs.stream().filter(sc -> !Objects.equals(sc.getId(), notificationId)) + .collect(Collectors.toList()) + )); + + messageBus.publishActivity(new NotificationsConfigUpdatedEvent(projectResource, + projectResource.getConfiguration().getProjectConfig(), + user.getUserId(), + user.getUsername() + )); + + return new OperationCompletionRS("Notification rule was deleted successfully."); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandler.java new file mode 100644 index 0000000000..052be9282d --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandler.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.List; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +public interface GetProjectNotificationsHandler { + + List<SenderCaseDTO> getProjectNotifications(Long projectId); + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImpl.java new file mode 100644 index 0000000000..ebb99190b6 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.ws.converter.converters.NotificationConfigConverter; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class GetProjectNotificationsHandlerImpl implements GetProjectNotificationsHandler { + + private final SenderCaseRepository senderCaseRepository; + + @Autowired + public GetProjectNotificationsHandlerImpl(SenderCaseRepository senderCaseRepository) { + this.senderCaseRepository = senderCaseRepository; + } + + @Override + public List<SenderCaseDTO> getProjectNotifications(Long projectId) { + return senderCaseRepository.findAllByProjectId(projectId).stream() + .map(NotificationConfigConverter.TO_CASE_RESOURCE) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/ProjectRecipientHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/ProjectRecipientHandler.java index ef2adbf88b..dfb66cf7cc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/ProjectRecipientHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/ProjectRecipientHandler.java @@ -11,5 +11,5 @@ */ public interface ProjectRecipientHandler { - void handle(Iterable<User> users, Project project); + void handle(Iterable<User> users, Project project); } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/RecipientRemover.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/RecipientRemover.java index 08a4a93fe7..0534c9725e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/RecipientRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/RecipientRemover.java @@ -1,17 +1,16 @@ package com.epam.ta.reportportal.core.project.settings.notification; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toSet; +import static java.util.stream.StreamSupport.stream; + import com.epam.ta.reportportal.dao.SenderCaseRepository; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.user.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Set; - -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toSet; -import static java.util.stream.StreamSupport.stream; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author Ivan Budaev @@ -19,26 +18,27 @@ @Service public class RecipientRemover implements ProjectRecipientHandler { - private final SenderCaseRepository senderCaseRepository; + private final SenderCaseRepository senderCaseRepository; - @Autowired - public RecipientRemover(SenderCaseRepository senderCaseRepository) { - this.senderCaseRepository = senderCaseRepository; - } + @Autowired + public RecipientRemover(SenderCaseRepository senderCaseRepository) { + this.senderCaseRepository = senderCaseRepository; + } - /** - * @param users {@link User} collection to remove from project recipient list - * @param project {@link Project} - */ - @Override - public void handle(Iterable<User> users, Project project) { - final Set<String> toExclude = stream(users.spliterator(), false).map(user -> asList(user.getEmail().toLowerCase(), - user.getLogin().toLowerCase() - )).flatMap(List::stream).collect(toSet()); - /* Current recipients of specified project */ - senderCaseRepository.findAllByProjectId(project.getId()).forEach(senderCase -> { - // saved - list of saved user emails before changes - senderCaseRepository.deleteRecipients(senderCase.getId(), toExclude); - }); - } + /** + * @param users {@link User} collection to remove from project recipient list + * @param project {@link Project} + */ + @Override + public void handle(Iterable<User> users, Project project) { + final Set<String> toExclude = stream(users.spliterator(), false).map( + user -> asList(user.getEmail().toLowerCase(), + user.getLogin().toLowerCase() + )).flatMap(List::stream).collect(toSet()); + /* Current recipients of specified project */ + senderCaseRepository.findAllByProjectId(project.getId()).forEach(senderCase -> { + // saved - list of saved user emails before changes + senderCaseRepository.deleteRecipients(senderCase.getId(), toExclude); + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandler.java new file mode 100644 index 0000000000..11e785b0b5 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandler.java @@ -0,0 +1,34 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +public interface UpdateProjectNotificationHandler { + + OperationCompletionRS updateNotification(Project project, SenderCaseDTO updateNotificationRQ, + ReportPortalUser user); + +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImpl.java new file mode 100644 index 0000000000..4a51f5be29 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImpl.java @@ -0,0 +1,93 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.validation.Suppliers; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.events.activity.NotificationsConfigUpdatedEvent; +import com.epam.ta.reportportal.core.project.validator.notification.ProjectNotificationValidator; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.ws.converter.converters.NotificationConfigConverter; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.project.ProjectResource; +import com.epam.ta.reportportal.ws.model.project.email.ProjectNotificationConfigDTO; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.Objects; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class UpdateProjectNotificationHandlerImpl implements UpdateProjectNotificationHandler { + + private final SenderCaseRepository senderCaseRepository; + private final MessageBus messageBus; + private final ProjectConverter projectConverter; + private final ProjectNotificationValidator projectNotificationValidator; + + public UpdateProjectNotificationHandlerImpl(SenderCaseRepository senderCaseRepository, + MessageBus messageBus, + ProjectConverter projectConverter, + ProjectNotificationValidator projectNotificationValidator) { + this.senderCaseRepository = senderCaseRepository; + this.messageBus = messageBus; + this.projectConverter = projectConverter; + this.projectNotificationValidator = projectNotificationValidator; + } + + @Override + public OperationCompletionRS updateNotification(Project project, + SenderCaseDTO updateNotificationRQ, ReportPortalUser user) { + expect(updateNotificationRQ.getId(), Objects::nonNull).verify(ErrorType.BAD_REQUEST_ERROR, + "Please specify notification Id"); + expect(senderCaseRepository.findById(updateNotificationRQ.getId()), + (notification) -> notification.map( + ntf -> Objects.equals(ntf.getProject().getId(), project.getId())).orElse(false)) + .verify(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier( + "Notification '{}' not found. Did you use correct Notification ID?", + updateNotificationRQ.getId()).get() + ); + projectNotificationValidator.validateUpdateRQ(project, updateNotificationRQ); + SenderCase notification = NotificationConfigConverter.TO_CASE_MODEL.apply(updateNotificationRQ); + notification.setProject(project); + senderCaseRepository.save(notification); + + ProjectResource projectResource = projectConverter.TO_PROJECT_RESOURCE.apply(project); + ProjectNotificationConfigDTO projectNotificationConfigDTO = projectResource.getConfiguration() + .getProjectConfig(); + projectNotificationConfigDTO.getSenderCases().add(updateNotificationRQ); + + messageBus.publishActivity(new NotificationsConfigUpdatedEvent(projectResource, + projectResource.getConfiguration().getProjectConfig(), + user.getUserId(), + user.getUsername() + )); + + return new OperationCompletionRS("Notification rule was updated successfully."); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundLessRule.java b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundLessRule.java index f19b04308b..e2707312f1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundLessRule.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundLessRule.java @@ -4,19 +4,19 @@ public class DelayBoundLessRule { - private final ProjectAttributeEnum lower; - private final ProjectAttributeEnum higher; + private final ProjectAttributeEnum lower; + private final ProjectAttributeEnum higher; - public DelayBoundLessRule(ProjectAttributeEnum lower, ProjectAttributeEnum higher) { - this.lower = lower; - this.higher = higher; - } + public DelayBoundLessRule(ProjectAttributeEnum lower, ProjectAttributeEnum higher) { + this.lower = lower; + this.higher = higher; + } - public ProjectAttributeEnum getLower() { - return lower; - } + public ProjectAttributeEnum getLower() { + return lower; + } - public ProjectAttributeEnum getHigher() { - return higher; - } + public ProjectAttributeEnum getHigher() { + return higher; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundValidator.java b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundValidator.java index 3795df3da6..ae44312b20 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/DelayBoundValidator.java @@ -1,58 +1,61 @@ package com.epam.ta.reportportal.core.project.validator.attribute; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.FOREVER_ALIAS; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.epam.ta.reportportal.exception.ReportPortalException; - import java.util.List; import java.util.Map; -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.FOREVER_ALIAS; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; -import static java.util.Optional.ofNullable; - public class DelayBoundValidator { - private final List<DelayBoundLessRule> rules; - - public DelayBoundValidator(List<DelayBoundLessRule> rules) { - this.rules = rules; - } - - public void validate(Map<String, String> currentAttributes, Map<ProjectAttributeEnum, Long> newAttributes) { - rules.forEach(rule -> { - Long lowerDelay = ofNullable(newAttributes.get(rule.getLower())).orElseGet(() -> getCurrentDelay(currentAttributes, - rule.getLower() - )); - Long higherDelay = ofNullable(newAttributes.get(rule.getHigher())).orElseGet(() -> getCurrentDelay(currentAttributes, - rule.getHigher() - )); - - BusinessRule.expect(lowerDelay <= higherDelay, equalTo(Boolean.TRUE)) - .verify(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Delay of '{}' should not be higher than '{}'", - rule.getLower().getAttribute(), - rule.getHigher().getAttribute() - ).toString() - ); - }); - } - - private Long getCurrentDelay(Map<String, String> currentAttributes, ProjectAttributeEnum attribute) { - return ofNullable(currentAttributes.get(attribute.getAttribute())).map(this::resolveDelay) - .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Attribute - {} was not found"), - attribute.getAttribute() - )); - } - - private Long resolveDelay(String value) { - try { - return FOREVER_ALIAS.equals(value) ? Long.MAX_VALUE : Long.parseLong(value); - } catch (NumberFormatException exc) { - throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); - } - } + private final List<DelayBoundLessRule> rules; + + public DelayBoundValidator(List<DelayBoundLessRule> rules) { + this.rules = rules; + } + + public void validate(Map<String, String> currentAttributes, + Map<ProjectAttributeEnum, Long> newAttributes) { + rules.forEach(rule -> { + Long lowerDelay = ofNullable(newAttributes.get(rule.getLower())).orElseGet( + () -> getCurrentDelay(currentAttributes, + rule.getLower() + )); + Long higherDelay = ofNullable(newAttributes.get(rule.getHigher())).orElseGet( + () -> getCurrentDelay(currentAttributes, + rule.getHigher() + )); + + BusinessRule.expect(lowerDelay <= higherDelay, equalTo(Boolean.TRUE)) + .verify(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Delay of '{}' should not be higher than '{}'", + rule.getLower().getAttribute(), + rule.getHigher().getAttribute() + ).toString() + ); + }); + } + + private Long getCurrentDelay(Map<String, String> currentAttributes, + ProjectAttributeEnum attribute) { + return ofNullable(currentAttributes.get(attribute.getAttribute())).map(this::resolveDelay) + .orElseThrow(() -> new ReportPortalException(BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Attribute - {} was not found"), + attribute.getAttribute() + )); + } + + private Long resolveDelay(String value) { + try { + return FOREVER_ALIAS.equals(value) ? Long.MAX_VALUE : Long.parseLong(value); + } catch (NumberFormatException exc) { + throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/ProjectAttributeValidator.java b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/ProjectAttributeValidator.java index 8ded892e13..cb7f9649b9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/ProjectAttributeValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/validator/attribute/ProjectAttributeValidator.java @@ -1,89 +1,94 @@ package com.epam.ta.reportportal.core.project.validator.attribute; +import static com.epam.ta.reportportal.commons.Predicates.isPresent; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.FOREVER_ALIAS; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.AnalyzeMode; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.apache.commons.lang3.BooleanUtils; - import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.isPresent; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum.FOREVER_ALIAS; -import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toSet; +import org.apache.commons.lang3.BooleanUtils; //TODO need refactoring - split attributes validation logic public class ProjectAttributeValidator { - private final DelayBoundValidator delayBoundValidator; - - public ProjectAttributeValidator(DelayBoundValidator delayBoundValidator) { - this.delayBoundValidator = delayBoundValidator; - } - - public void verifyProjectAttributes(Map<String, String> currentAttributes, Map<String, String> newAttributes) { - Set<String> incompatibleAttributes = newAttributes.keySet() - .stream() - .filter(it -> !ProjectAttributeEnum.isPresent(it)) - .collect(toSet()); - expect(incompatibleAttributes, Set::isEmpty).verify(BAD_REQUEST_ERROR, incompatibleAttributes); - - ofNullable(newAttributes.get(ProjectAttributeEnum.AUTO_ANALYZER_MODE.getAttribute())).ifPresent(analyzerMode -> expect(AnalyzeMode.fromString( - analyzerMode), isPresent()).verify(ErrorType.BAD_REQUEST_ERROR, analyzerMode)); - - ofNullable(newAttributes.get(ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH.getAttribute())).ifPresent(attr -> BusinessRule.expect( - validatePercentage(attr), - BooleanUtils::isTrue - ).verify(BAD_REQUEST_ERROR, ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH)); - - final Map<ProjectAttributeEnum, Long> delays = validateDelays(newAttributes, - List.of(ProjectAttributeEnum.KEEP_SCREENSHOTS, - ProjectAttributeEnum.KEEP_LOGS, - ProjectAttributeEnum.KEEP_LAUNCHES, - ProjectAttributeEnum.INTERRUPT_JOB_TIME - ) - ); - - delayBoundValidator.validate(currentAttributes, delays); - } - - private Map<ProjectAttributeEnum, Long> validateDelays(Map<String, String> attributes, List<ProjectAttributeEnum> projectAttributes) { - return projectAttributes.stream() - .filter(it -> attributes.containsKey(it.getAttribute())) - .collect(Collectors.toMap(a -> a, a -> getDelay(attributes.get(a.getAttribute())))); - } - - private Long getDelay(String value) { - final Long delay = FOREVER_ALIAS.equals(value) ? Long.MAX_VALUE : getLong(value); - BusinessRule.expect(delay, d -> d >= 0).verify(BAD_REQUEST_ERROR, "Delay attribute value should be greater than 0"); - return delay; - } - - private boolean validatePercentage(String value) { - final int percent = getInt(value); - return percent >= 0 && percent <= 100; - } - - private Long getLong(String value) { - try { - return Long.parseLong(value); - } catch (NumberFormatException exc) { - throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); - } - } - - private Integer getInt(String value) { - try { - return Integer.parseInt(value); - } catch (NumberFormatException exc) { - throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); - } - } + private final DelayBoundValidator delayBoundValidator; + + public ProjectAttributeValidator(DelayBoundValidator delayBoundValidator) { + this.delayBoundValidator = delayBoundValidator; + } + + public void verifyProjectAttributes(Map<String, String> currentAttributes, + Map<String, String> newAttributes) { + Set<String> incompatibleAttributes = newAttributes.keySet() + .stream() + .filter(it -> !ProjectAttributeEnum.isPresent(it)) + .collect(toSet()); + expect(incompatibleAttributes, Set::isEmpty).verify(BAD_REQUEST_ERROR, incompatibleAttributes); + + ofNullable(newAttributes.get(ProjectAttributeEnum.AUTO_ANALYZER_MODE.getAttribute())).ifPresent( + analyzerMode -> expect(AnalyzeMode.fromString( + analyzerMode), isPresent()).verify(ErrorType.BAD_REQUEST_ERROR, analyzerMode)); + + ofNullable(newAttributes.get( + ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH.getAttribute())).ifPresent( + attr -> BusinessRule.expect( + validatePercentage(attr), + BooleanUtils::isTrue + ).verify(BAD_REQUEST_ERROR, ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH)); + + final Map<ProjectAttributeEnum, Long> delays = validateDelays(newAttributes, + List.of(ProjectAttributeEnum.KEEP_SCREENSHOTS, + ProjectAttributeEnum.KEEP_LOGS, + ProjectAttributeEnum.KEEP_LAUNCHES, + ProjectAttributeEnum.INTERRUPT_JOB_TIME + ) + ); + + delayBoundValidator.validate(currentAttributes, delays); + } + + private Map<ProjectAttributeEnum, Long> validateDelays(Map<String, String> attributes, + List<ProjectAttributeEnum> projectAttributes) { + return projectAttributes.stream() + .filter(it -> attributes.containsKey(it.getAttribute())) + .collect(Collectors.toMap(a -> a, a -> getDelay(attributes.get(a.getAttribute())))); + } + + private Long getDelay(String value) { + final Long delay = FOREVER_ALIAS.equals(value) ? Long.MAX_VALUE : getLong(value); + BusinessRule.expect(delay, d -> d >= 0) + .verify(BAD_REQUEST_ERROR, "Delay attribute value should be greater than 0"); + return delay; + } + + private boolean validatePercentage(String value) { + final int percent = getInt(value); + return percent >= 0 && percent <= 100; + } + + private Long getLong(String value) { + try { + return Long.parseLong(value); + } catch (NumberFormatException exc) { + throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); + } + } + + private Integer getInt(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException exc) { + throw new ReportPortalException(BAD_REQUEST_ERROR, exc.getMessage()); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/project/validator/notification/ProjectNotificationValidator.java b/src/main/java/com/epam/ta/reportportal/core/project/validator/notification/ProjectNotificationValidator.java new file mode 100644 index 0000000000..d71e8aef83 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/project/validator/notification/ProjectNotificationValidator.java @@ -0,0 +1,126 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.validator.notification; + +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.Predicates.notNull; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.entity.enums.SendCase.findByName; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.util.email.EmailRulesValidator; +import com.epam.ta.reportportal.ws.converter.converters.NotificationConfigConverter; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class ProjectNotificationValidator { + + private final SenderCaseRepository senderCaseRepository; + + @Autowired + public ProjectNotificationValidator(SenderCaseRepository senderCaseRepository) { + this.senderCaseRepository = senderCaseRepository; + } + + public void validateCreateRQ(Project project, SenderCaseDTO senderCaseDTO) { + validateRecipients(senderCaseDTO); + + normalizeCreateNotificationRQ(project, senderCaseDTO); + + Optional<SenderCaseDTO> duplicate = senderCaseRepository.findAllByProjectId(project.getId()) + .stream() + .map(NotificationConfigConverter.TO_CASE_RESOURCE) + .filter(existing -> equalsWithoutRuleName(existing, senderCaseDTO)) + .findFirst(); + expect(duplicate, Optional::isEmpty).verify(BAD_REQUEST_ERROR, + "Project email settings contain duplicate cases"); + } + + public void validateUpdateRQ(Project project, SenderCaseDTO senderCaseDTO) { + validateRecipients(senderCaseDTO); + + normalizeCreateNotificationRQ(project, senderCaseDTO); + + Optional<SenderCaseDTO> duplicate = senderCaseRepository.findAllByProjectId(project.getId()) + .stream() + .filter(senderCase -> !Objects.equals(senderCase.getId(), senderCaseDTO.getId())) + .map(NotificationConfigConverter.TO_CASE_RESOURCE) + .filter(o1 -> equalsWithoutRuleName(o1, senderCaseDTO)) + .findFirst(); + expect(duplicate, Optional::isEmpty).verify(BAD_REQUEST_ERROR, + "Project email settings contain duplicate cases"); + } + + private void validateRecipients(SenderCaseDTO senderCaseDTO) { + List<String> recipients = senderCaseDTO.getRecipients(); + expect(findByName(senderCaseDTO.getSendCase()), Optional::isPresent) + .verify(BAD_REQUEST_ERROR, senderCaseDTO.getSendCase()); + expect(recipients, notNull()).verify(BAD_REQUEST_ERROR, "Recipients list should not be null"); + expect(recipients.isEmpty(), equalTo(false)) + .verify(BAD_REQUEST_ERROR, + formattedSupplier("Empty recipients list for email case '{}' ", senderCaseDTO)); + } + + private void normalizeCreateNotificationRQ(Project project, SenderCaseDTO createNotificationRQ) { + createNotificationRQ.setRecipients( + createNotificationRQ.getRecipients().stream().map(recipient -> { + EmailRulesValidator.validateRecipient(project, recipient); + return recipient.trim(); + }).distinct().collect(toList()) + ); + ofNullable(createNotificationRQ.getLaunchNames()).ifPresent( + launchNames -> createNotificationRQ.setLaunchNames( + launchNames.stream().map(name -> { + EmailRulesValidator.validateLaunchName(name); + return name.trim(); + }).distinct().collect(toList())) + ); + ofNullable(createNotificationRQ.getAttributes()).ifPresent( + attributes -> createNotificationRQ.setAttributes( + attributes.stream().peek(attribute -> { + EmailRulesValidator.validateLaunchAttribute(attribute); + attribute.setValue(attribute.getValue().trim()); + }).collect(Collectors.toSet())) + ); + } + + private boolean equalsWithoutRuleName(SenderCaseDTO senderCase, SenderCaseDTO toCompare) { + return CollectionUtils.isEqualCollection(senderCase.getRecipients(), toCompare.getRecipients()) + && Objects.equals(senderCase.getSendCase(), toCompare.getSendCase()) + && CollectionUtils.isEqualCollection(senderCase.getLaunchNames(), + toCompare.getLaunchNames()) + && CollectionUtils.isEqualCollection(senderCase.getAttributes(), toCompare.getAttributes()) + && Objects.equals(senderCase.getAttributesOperator(), toCompare.getAttributesOperator()); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/ContentRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/ContentRemover.java index 20c26c9441..265b4e4edb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/ContentRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/ContentRemover.java @@ -5,5 +5,5 @@ */ public interface ContentRemover<T> { - void remove(T entity); + void remove(T entity); } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/item/ItemClusterRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/item/ItemClusterRemover.java index 721d04d250..e916caaa77 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/item/ItemClusterRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/item/ItemClusterRemover.java @@ -27,15 +27,15 @@ @Service public class ItemClusterRemover implements ContentRemover<Long> { - private final ClusterRepository clusterRepository; + private final ClusterRepository clusterRepository; - @Autowired - public ItemClusterRemover(ClusterRepository clusterRepository) { - this.clusterRepository = clusterRepository; - } + @Autowired + public ItemClusterRemover(ClusterRepository clusterRepository) { + this.clusterRepository = clusterRepository; + } - @Override - public void remove(Long itemId) { - clusterRepository.deleteClusterTestItemsByItemId(itemId); - } + @Override + public void remove(Long itemId) { + clusterRepository.deleteClusterTestItemsByItemId(itemId); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/launch/LaunchClusterRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/launch/LaunchClusterRemover.java index da0afca66b..0daff4456d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/launch/LaunchClusterRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/launch/LaunchClusterRemover.java @@ -28,16 +28,16 @@ @Service public class LaunchClusterRemover implements ContentRemover<Launch> { - private final ClusterRepository clusterRepository; + private final ClusterRepository clusterRepository; - @Autowired - public LaunchClusterRemover(ClusterRepository clusterRepository) { - this.clusterRepository = clusterRepository; - } + @Autowired + public LaunchClusterRemover(ClusterRepository clusterRepository) { + this.clusterRepository = clusterRepository; + } - @Override - public void remove(Launch launch) { - clusterRepository.deleteClusterTestItemsByLaunchId(launch.getId()); - clusterRepository.deleteAllByLaunchId(launch.getId()); - } + @Override + public void remove(Launch launch) { + clusterRepository.deleteClusterTestItemsByLaunchId(launch.getId()); + clusterRepository.deleteAllByLaunchId(launch.getId()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectClusterRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectClusterRemover.java index f633521c80..c7baa0e58e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectClusterRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectClusterRemover.java @@ -28,16 +28,16 @@ @Service public class ProjectClusterRemover implements ContentRemover<Project> { - private final ClusterRepository clusterRepository; + private final ClusterRepository clusterRepository; - @Autowired - public ProjectClusterRemover(ClusterRepository clusterRepository) { - this.clusterRepository = clusterRepository; - } + @Autowired + public ProjectClusterRemover(ClusterRepository clusterRepository) { + this.clusterRepository = clusterRepository; + } - @Override - public void remove(Project project) { - clusterRepository.deleteClusterTestItemsByProjectId(project.getId()); - clusterRepository.deleteAllByProjectId(project.getId()); - } + @Override + public void remove(Project project) { + clusterRepository.deleteClusterTestItemsByProjectId(project.getId()); + clusterRepository.deleteAllByProjectId(project.getId()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectContentRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectContentRemover.java index 0de8986f42..7eb913216c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectContentRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectContentRemover.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.core.remover.ContentRemover; import com.epam.ta.reportportal.entity.project.Project; - import java.util.List; /** @@ -26,14 +25,14 @@ */ public class ProjectContentRemover implements ContentRemover<Project> { - private final List<ContentRemover<Project>> removers; + private final List<ContentRemover<Project>> removers; - public ProjectContentRemover(List<ContentRemover<Project>> removers) { - this.removers = removers; - } + public ProjectContentRemover(List<ContentRemover<Project>> removers) { + this.removers = removers; + } - @Override - public void remove(Project project) { - removers.forEach(r -> r.remove(project)); - } + @Override + public void remove(Project project) { + removers.forEach(r -> r.remove(project)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectWidgetRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectWidgetRemover.java index d1c7d45174..9c50d69602 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectWidgetRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/project/ProjectWidgetRemover.java @@ -6,34 +6,33 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetType; +import java.util.Collections; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProjectWidgetRemover implements ContentRemover<Project> { - private final WidgetRepository widgetRepository; - private final WidgetContentRemover widgetContentRemover; + private final WidgetRepository widgetRepository; + private final WidgetContentRemover widgetContentRemover; - @Autowired - public ProjectWidgetRemover(WidgetRepository widgetRepository, - @Qualifier("delegatingStateContentRemover") WidgetContentRemover widgetContentRemover) { - this.widgetRepository = widgetRepository; - this.widgetContentRemover = widgetContentRemover; - } + @Autowired + public ProjectWidgetRemover(WidgetRepository widgetRepository, + @Qualifier("delegatingStateContentRemover") WidgetContentRemover widgetContentRemover) { + this.widgetRepository = widgetRepository; + this.widgetContentRemover = widgetContentRemover; + } - @Override - public void remove(Project project) { - List<Widget> widgets = widgetRepository.findAllByProjectIdAndWidgetTypeIn(project.getId(), - Collections.singletonList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType()) - ); - widgets.forEach(widgetContentRemover::removeContent); - } + @Override + public void remove(Project project) { + List<Widget> widgets = widgetRepository.findAllByProjectIdAndWidgetTypeIn(project.getId(), + Collections.singletonList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType()) + ); + widgets.forEach(widgetContentRemover::removeContent); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/user/UserContentRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserContentRemover.java new file mode 100644 index 0000000000..c966c748af --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserContentRemover.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.remover.user; + +import com.epam.ta.reportportal.core.remover.ContentRemover; +import com.epam.ta.reportportal.entity.user.User; +import java.util.List; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +public class UserContentRemover implements ContentRemover<User> { + + private final List<ContentRemover<User>> removers; + + public UserContentRemover(List<ContentRemover<User>> removers) { + this.removers = removers; + } + + @Override + public void remove(User user) { + removers.forEach(r -> r.remove(user)); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemover.java new file mode 100644 index 0000000000..977867cd60 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemover.java @@ -0,0 +1,66 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.remover.user; + +import static java.util.Optional.ofNullable; + +import com.epam.ta.reportportal.core.remover.ContentRemover; +import com.epam.ta.reportportal.dao.AttachmentRepository; +import com.epam.ta.reportportal.entity.attachment.Attachment; +import com.epam.ta.reportportal.entity.user.User; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +@Service +public class UserPhotoRemover implements ContentRemover<User> { + + private static final String ATTACHMENT_CONTENT_TYPE = "attachmentContentType"; + + private final AttachmentRepository attachmentRepository; + + @Autowired + public UserPhotoRemover(AttachmentRepository attachmentRepository) { + this.attachmentRepository = attachmentRepository; + } + + @Override + public void remove(User user) { + ofNullable(user.getAttachment()).ifPresent(fileId -> { + List<Long> attachmentsIds = new ArrayList<>(2); + attachmentsIds.add(prepareAttachmentAndGetId(fileId)); + Optional.ofNullable(user.getAttachmentThumbnail()) + .ifPresent(thumbnailId -> attachmentsIds.add(prepareAttachmentAndGetId(thumbnailId))); + ofNullable(user.getMetadata()).ifPresent( + metadata -> metadata.getMetadata().remove(ATTACHMENT_CONTENT_TYPE)); + attachmentRepository.moveForDeletion(attachmentsIds); + }); + } + + private Long prepareAttachmentAndGetId(String fileId) { + Attachment attachment = new Attachment(); + attachment.setFileId(fileId); + attachment.setCreationDate(LocalDateTime.now()); + return attachmentRepository.save(attachment).getId(); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/core/remover/user/UserWidgetRemover.java b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserWidgetRemover.java index ad5013043b..9d743e28e0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/remover/user/UserWidgetRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/remover/user/UserWidgetRemover.java @@ -22,11 +22,10 @@ import com.epam.ta.reportportal.entity.user.User; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetType; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.List; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -34,20 +33,20 @@ @Service public class UserWidgetRemover implements ContentRemover<User> { - private final WidgetRepository widgetRepository; - private final WidgetContentRemover widgetContentRemover; + private final WidgetRepository widgetRepository; + private final WidgetContentRemover widgetContentRemover; - public UserWidgetRemover(WidgetRepository widgetRepository, - @Qualifier("delegatingStateContentRemover") WidgetContentRemover widgetContentRemover) { - this.widgetRepository = widgetRepository; - this.widgetContentRemover = widgetContentRemover; - } + public UserWidgetRemover(WidgetRepository widgetRepository, + @Qualifier("delegatingStateContentRemover") WidgetContentRemover widgetContentRemover) { + this.widgetRepository = widgetRepository; + this.widgetContentRemover = widgetContentRemover; + } - @Override - public void remove(User user) { - List<Widget> widgets = widgetRepository.findAllByOwnerAndWidgetTypeIn(user.getLogin(), - Collections.singletonList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType()) - ); - widgets.forEach(widgetContentRemover::removeContent); - } + @Override + public void remove(User user) { + List<Widget> widgets = widgetRepository.findAllByOwnerAndWidgetTypeIn(user.getLogin(), + Collections.singletonList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType()) + ); + widgets.forEach(widgetContentRemover::removeContent); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/statistics/StatisticsHelper.java b/src/main/java/com/epam/ta/reportportal/core/statistics/StatisticsHelper.java index 9c4c794e5c..5d84cf435b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/statistics/StatisticsHelper.java +++ b/src/main/java/com/epam/ta/reportportal/core/statistics/StatisticsHelper.java @@ -16,62 +16,66 @@ package com.epam.ta.reportportal.core.statistics; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.entity.statistics.StatisticsField; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.Arrays; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.NOT_ISSUE_FLAG; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public final class StatisticsHelper { - private static final String TOTAL = "statistics$executions$total"; - private static final String PASSED = "statistics$executions$passed"; - private static final String SKIPPED = "statistics$executions$skipped"; - private static final String FAILED = "statistics$executions$failed"; + private static final String TOTAL = "statistics$executions$total"; + private static final String PASSED = "statistics$executions$passed"; + private static final String SKIPPED = "statistics$executions$skipped"; + private static final String FAILED = "statistics$executions$failed"; - private StatisticsHelper() { - //static only - } + private StatisticsHelper() { + //static only + } - public static StatusEnum getStatusFromStatistics(Set<Statistics> statistics) { - return statistics.stream().anyMatch(FAILED_PREDICATE) ? StatusEnum.FAILED : StatusEnum.PASSED; - } + public static StatusEnum getStatusFromStatistics(Set<Statistics> statistics) { + return statistics.stream().anyMatch(FAILED_PREDICATE) ? StatusEnum.FAILED : StatusEnum.PASSED; + } - private final static Predicate<Statistics> FAILED_PREDICATE = statistics -> { - StatisticsField statisticsField = ofNullable(statistics.getStatisticsField()).orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - "Statistics should contain a name field." - )); - String field = statisticsField.getName(); - Integer counter = statistics.getCounter(); - return (field.contains("failed") || field.contains("skipped") || field.contains("to_investigate")) && counter > 0; - }; + private final static Predicate<Statistics> FAILED_PREDICATE = statistics -> { + StatisticsField statisticsField = ofNullable(statistics.getStatisticsField()).orElseThrow( + () -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Statistics should contain a name field." + )); + String field = statisticsField.getName(); + Integer counter = statistics.getCounter(); + return + (field.contains("failed") || field.contains("skipped") || field.contains("to_investigate")) + && counter > 0; + }; - public static Integer extractStatisticsCount(String statisticsField, Set<Statistics> statistics) { - return statistics.stream() - .filter(it -> it.getStatisticsField().getName().equalsIgnoreCase(statisticsField)) - .findFirst() - .orElse(new Statistics()) - .getCounter(); - } + public static Integer extractStatisticsCount(String statisticsField, Set<Statistics> statistics) { + return statistics.stream() + .filter(it -> it.getStatisticsField().getName().equalsIgnoreCase(statisticsField)) + .findFirst() + .orElse(new Statistics()) + .getCounter(); + } - public static Stream<String> defaultStatisticsFields() { - return Stream.concat( - Arrays.stream(TestItemIssueGroup.values()) - .filter(value -> !value.getIssueCounterField().equalsIgnoreCase(NOT_ISSUE_FLAG.getIssueCounterField())) - .map(value -> "statistics$defects$" + value.getValue().toLowerCase() + "$" + value.getLocator()), - Stream.of(TOTAL, PASSED, SKIPPED, FAILED) - ); - } + public static Stream<String> defaultStatisticsFields() { + return Stream.concat( + Arrays.stream(TestItemIssueGroup.values()) + .filter(value -> !value.getIssueCounterField() + .equalsIgnoreCase(NOT_ISSUE_FLAG.getIssueCounterField())) + .map(value -> "statistics$defects$" + value.getValue().toLowerCase() + "$" + + value.getLocator()), + Stream.of(TOTAL, PASSED, SKIPPED, FAILED) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/user/CreateUserHandler.java b/src/main/java/com/epam/ta/reportportal/core/user/CreateUserHandler.java index 9741a99305..b10b1c7ea7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/CreateUserHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/CreateUserHandler.java @@ -19,7 +19,13 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.YesNoRS; -import com.epam.ta.reportportal.ws.model.user.*; +import com.epam.ta.reportportal.ws.model.user.CreateUserBidRS; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQ; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQConfirm; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQFull; +import com.epam.ta.reportportal.ws.model.user.CreateUserRS; +import com.epam.ta.reportportal.ws.model.user.ResetPasswordRQ; +import com.epam.ta.reportportal.ws.model.user.RestorePasswordRQ; /** * Post request handler @@ -28,56 +34,57 @@ */ public interface CreateUserHandler { - /** - * Create completed user object by administrator - * - * @param request Create request - * @param user User that creates request - * @param basicUrl App URL for user URL to be created - * @return Operation result - */ - CreateUserRS createUserByAdmin(CreateUserRQFull request, ReportPortalUser user, String basicUrl); + /** + * Create completed user object by administrator + * + * @param request Create request + * @param user User that creates request + * @param basicUrl App URL for user URL to be created + * @return Operation result + */ + CreateUserRS createUserByAdmin(CreateUserRQFull request, ReportPortalUser user, String basicUrl); - /** - * Create new User (confirm invitation) - * - * @param request Create request - * @param uuid Create UUID - * @return Operation result - */ - CreateUserRS createUser(CreateUserRQConfirm request, String uuid); + /** + * Create new User (confirm invitation) + * + * @param request Create request + * @param uuid Create UUID + * @return Operation result + */ + CreateUserRS createUser(CreateUserRQConfirm request, String uuid); - /** - * Create user bid (send invitation) - * - * @param request Create Request - * @param username Username/User that creates the request - * @return Operation result - */ - CreateUserBidRS createUserBid(CreateUserRQ request, ReportPortalUser username, String userRegURL); + /** + * Create user bid (send invitation) + * + * @param request Create Request + * @param username Username/User that creates the request + * @param userRegURL User registration url + * @return Operation result + */ + CreateUserBidRS createUserBid(CreateUserRQ request, ReportPortalUser username, String userRegURL); - /** - * Create restore password bid - * - * @param rq Restore RQ - * @param baseUrl App Base URL for reset URL to be built - * @return Operation result - */ - OperationCompletionRS createRestorePasswordBid(RestorePasswordRQ rq, String baseUrl); + /** + * Create restore password bid + * + * @param rq Restore RQ + * @param baseUrl App Base URL for reset URL to be built + * @return Operation result + */ + OperationCompletionRS createRestorePasswordBid(RestorePasswordRQ rq, String baseUrl); - /** - * Reset password - * - * @param rq - * @return Operation result - */ - OperationCompletionRS resetPassword(ResetPasswordRQ rq); + /** + * Reset password + * + * @param rq request for reset password + * @return Operation result + */ + OperationCompletionRS resetPassword(ResetPasswordRQ rq); - /** - * Verify reset password bid exist - * - * @param uuid Reset Password UUID - * @return {@link YesNoRS} - */ - YesNoRS isResetPasswordBidExist(String uuid); + /** + * Verify reset password bid exist + * + * @param uuid Reset Password UUID + * @return {@link YesNoRS} + */ + YesNoRS isResetPasswordBidExist(String uuid); } diff --git a/src/main/java/com/epam/ta/reportportal/core/user/DeleteUserHandler.java b/src/main/java/com/epam/ta/reportportal/core/user/DeleteUserHandler.java index 531b5f4048..b14a0c9b4f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/DeleteUserHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/DeleteUserHandler.java @@ -27,14 +27,16 @@ * @author Aliaksandr_Kazantsau */ public interface DeleteUserHandler { - /** - * Delete User - * - * @param userId User to be deleted - * @param currentUser User performing the edit operation - * @return Operation result - */ - OperationCompletionRS deleteUser(Long userId, ReportPortalUser currentUser); + + /** + * Delete User, User Personal Project, User Photo. User Dashboard, Widgets, Filters still + * available. + * + * @param userId User to be deleted + * @param currentUser User performing the edit operation + * @return Operation result + */ + OperationCompletionRS deleteUser(Long userId, ReportPortalUser currentUser); DeleteBulkRS deleteUsers(List<Long> ids, ReportPortalUser currentUser); diff --git a/src/main/java/com/epam/ta/reportportal/core/user/EditUserHandler.java b/src/main/java/com/epam/ta/reportportal/core/user/EditUserHandler.java index 77077703a7..bd79cc62f0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/EditUserHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/EditUserHandler.java @@ -29,39 +29,40 @@ */ public interface EditUserHandler { - /** - * Edit User - * - * @param username Name of user - * @param editUserRQ Edit request - * @param editor User performing the edit operation - * @return Completion result - */ - OperationCompletionRS editUser(String username, EditUserRQ editUserRQ, ReportPortalUser editor); + /** + * Edit User + * + * @param username Name of user + * @param editUserRQ Edit request + * @param editor User performing the edit operation + * @return Completion result + */ + OperationCompletionRS editUser(String username, EditUserRQ editUserRQ, ReportPortalUser editor); - /** - * Upload photo - * - * @param username Name of user - * @param file New photo - * @return Completion result - */ - OperationCompletionRS uploadPhoto(String username, MultipartFile file); + /** + * Upload photo + * + * @param username Name of user + * @param file New photo + * @return Completion result + */ + OperationCompletionRS uploadPhoto(String username, MultipartFile file); - /** - * Delete user's photo - * - * @param username Name of user - * @return Completion result - */ - OperationCompletionRS deletePhoto(String username); + /** + * Delete user's photo + * + * @param username Name of user + * @return Completion result + */ + OperationCompletionRS deletePhoto(String username); - /** - * Change password - * - * @param currentUser User performing the edit operation - * @param changePasswordRQ Request body - * @return Completion result - */ - OperationCompletionRS changePassword(ReportPortalUser currentUser, ChangePasswordRQ changePasswordRQ); + /** + * Change password + * + * @param currentUser User performing the edit operation + * @param changePasswordRQ Request body + * @return Completion result + */ + OperationCompletionRS changePassword(ReportPortalUser currentUser, + ChangePasswordRQ changePasswordRQ); } diff --git a/src/main/java/com/epam/ta/reportportal/core/user/GetUserHandler.java b/src/main/java/com/epam/ta/reportportal/core/user/GetUserHandler.java index 2ec3853f4b..11ad6bd045 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/GetUserHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/GetUserHandler.java @@ -23,80 +23,80 @@ import com.epam.ta.reportportal.ws.model.YesNoRS; import com.epam.ta.reportportal.ws.model.user.UserBidRS; import com.epam.ta.reportportal.ws.model.user.UserResource; -import org.springframework.data.domain.Pageable; - -import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.springframework.data.domain.Pageable; /** * @author Andrei_Ramanchuk */ public interface GetUserHandler { - /** - * Get specified user info - * - * @param username Username - * @param currentUser Logged-in username - * @return {@link UserResource} - */ - UserResource getUser(String username, ReportPortalUser currentUser); + /** + * Get specified user info + * + * @param username Username + * @param currentUser Logged-in username + * @return {@link UserResource} + */ + UserResource getUser(String username, ReportPortalUser currentUser); - /** - * Get logged-in user info - * - * @param currentUser Logged-in username - * @return {@link UserResource} - */ - UserResource getUser(ReportPortalUser currentUser); + /** + * Get logged-in user info + * + * @param currentUser Logged-in username + * @return {@link UserResource} + */ + UserResource getUser(ReportPortalUser currentUser); - /** - * Get information about user registration bid - * - * @param uuid UUID - * @return {@link UserBidRS} - */ - UserBidRS getBidInformation(String uuid); + /** + * Get information about user registration bid + * + * @param uuid UUID + * @return {@link UserBidRS} + */ + UserBidRS getBidInformation(String uuid); - /** - * Validate existence of username or email - * - * @param username User name - * @param email email - * @return {@link YesNoRS} - */ - YesNoRS validateInfo(String username, String email); + /** + * Validate existence of username or email + * + * @param username User name + * @param email email + * @return {@link YesNoRS} + */ + YesNoRS validateInfo(String username, String email); - /** - * Get all users by filter with paging - * - * @param filter Filter - * @param pageable Paging - * @param projectDetails Project details - * @return Page of users - */ - Iterable<UserResource> getUsers(Filter filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails); + /** + * Get all users by filter with paging + * + * @param filter Filter + * @param pageable Paging + * @param projectDetails Project details + * @return Page of users + */ + Iterable<UserResource> getUsers(Filter filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails); - Map<String, UserResource.AssignedProject> getUserProjects(String userName); + Map<String, UserResource.AssignedProject> getUserProjects(String userName); - /** - * Get page of users with filter - * - * @param filter Filter - * @param pageable Paging - * @return Page of {@link UserResource} - */ - Iterable<UserResource> getAllUsers(Queryable filter, Pageable pageable); + /** + * Get page of users with filter + * + * @param filter Filter + * @param pageable Paging + * @return Page of {@link UserResource} + */ + Iterable<UserResource> getAllUsers(Queryable filter, Pageable pageable); - /** - * Export Users info according to the {@link ReportFormat} type - * - * @param reportFormat {@link ReportFormat} - * @param filter {@link Filter} - * @param outputStream {@link HttpServletResponse#getOutputStream()} - */ - void exportUsers(ReportFormat reportFormat, OutputStream outputStream, Queryable filter); + /** + * Export Users info according to the {@link ReportFormat} type + * + * @param reportFormat {@link ReportFormat} + * @param filter {@link Filter} + * @param outputStream {@link HttpServletResponse#getOutputStream()} + */ + void exportUsers(ReportFormat reportFormat, OutputStream outputStream, Queryable filter); - Iterable<UserResource> searchUsers(String term, Pageable pageable); + Iterable<UserResource> searchUsers(String term, Pageable pageable); } diff --git a/src/main/java/com/epam/ta/reportportal/core/user/impl/ApiKeyHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/user/impl/ApiKeyHandlerImpl.java index a018144c73..bc81adebd3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/impl/ApiKeyHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/impl/ApiKeyHandlerImpl.java @@ -18,6 +18,7 @@ import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.NOT_FOUND; import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.validation.Suppliers; @@ -29,6 +30,7 @@ import com.epam.ta.reportportal.ws.converter.converters.ApiKeyConverter; import com.epam.ta.reportportal.ws.model.ApiKeyRS; import com.epam.ta.reportportal.ws.model.ApiKeysRS; +import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.google.common.annotations.VisibleForTesting; import java.nio.ByteBuffer; @@ -37,6 +39,7 @@ import java.util.Base64; import java.util.List; import java.util.UUID; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.xml.bind.DatatypeConverter; import org.apache.commons.codec.digest.DigestUtils; @@ -92,6 +95,8 @@ public ApiKeyRS createApiKey(String name, Long userId) { @Override public OperationCompletionRS deleteApiKey(Long id) { + expect(apiKeyRepository.existsById(id), Predicates.equalTo(true)) + .verify(NOT_FOUND, "Api key"); apiKeyRepository.deleteById(id); return new OperationCompletionRS("Api key with ID = '" + id + "' was successfully deleted."); } diff --git a/src/main/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImpl.java index a43751c234..5baa5625e9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImpl.java @@ -38,6 +38,7 @@ import com.epam.ta.reportportal.auth.authenticator.UserAuthenticator; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; +import com.epam.ta.reportportal.core.events.activity.CreateInvitationLinkEvent; import com.epam.ta.reportportal.core.events.activity.UserCreatedEvent; import com.epam.ta.reportportal.core.integration.GetIntegrationHandler; import com.epam.ta.reportportal.core.project.CreateProjectHandler; @@ -47,6 +48,7 @@ import com.epam.ta.reportportal.dao.RestorePasswordBidRepository; import com.epam.ta.reportportal.dao.UserCreationBidRepository; import com.epam.ta.reportportal.dao.UserRepository; +import com.epam.ta.reportportal.entity.Metadata; import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.project.Project; @@ -75,6 +77,8 @@ import com.epam.ta.reportportal.ws.model.user.CreateUserRS; import com.epam.ta.reportportal.ws.model.user.ResetPasswordRQ; import com.epam.ta.reportportal.ws.model.user.RestorePasswordRQ; +import com.google.common.collect.Maps; +import java.util.Map; import java.util.Optional; import java.util.function.Predicate; import javax.persistence.PersistenceException; @@ -96,6 +100,9 @@ @Service public class CreateUserHandlerImpl implements CreateUserHandler { + public static final String BID_TYPE = "type"; + public static final String INTERNAL_BID_TYPE = "internal"; + private final UserRepository userRepository; private final UserAuthenticator userAuthenticator; @@ -156,7 +163,7 @@ public CreateUserRS createUserByAdmin(CreateUserRQFull request, ReportPortalUser normalize(request); - Pair<UserActivityResource, CreateUserRS> pair = saveUser(request, administrator); + Pair<UserActivityResource, CreateUserRS> pair = saveUser(request, administrator, false); emailExecutorService.execute(() -> emailServiceFactory.getDefaultEmailService(true) .sendCreateUserConfirmationEmail(request, basicUrl)); @@ -205,7 +212,7 @@ private String getNormalized(String original) { } private Pair<UserActivityResource, CreateUserRS> saveUser(CreateUserRQFull request, - User creator) { + User creator, boolean isSystemEvent) { final Project projectToAssign = getProjectHandler.getRaw(normalizeId(request.getDefaultProject())); @@ -220,7 +227,7 @@ private Pair<UserActivityResource, CreateUserRS> saveUser(CreateUserRQFull reque userRepository.save(user); UserActivityResource userActivityResource = getUserActivityResource(user); UserCreatedEvent userCreatedEvent = new UserCreatedEvent(userActivityResource, - creator.getId(), creator.getLogin()); + creator.getId(), creator.getLogin(), isSystemEvent); eventPublisher.publishEvent(userCreatedEvent); } catch (PersistenceException pe) { if (pe.getCause() instanceof ConstraintViolationException) { @@ -234,9 +241,9 @@ private Pair<UserActivityResource, CreateUserRS> saveUser(CreateUserRQFull reque userAuthenticator.authenticate(user); - projectUserHandler.assign(user, projectToAssign, projectRole, creator); + projectUserHandler.assign(user, projectToAssign, projectRole, creator, false); final Project personalProject = createProjectHandler.createPersonal(user); - projectUserHandler.assign(user, personalProject, ProjectRole.PROJECT_MANAGER, creator); + projectUserHandler.assign(user, personalProject, ProjectRole.PROJECT_MANAGER, creator, isSystemEvent); final CreateUserRS response = new CreateUserRS(); response.setId(user.getId()); @@ -265,7 +272,7 @@ private User convert(CreateUserRQFull request) { @Override @Transactional public CreateUserRS createUser(CreateUserRQConfirm request, String uuid) { - final UserCreationBid bid = userCreationBidRepository.findById(uuid) + final UserCreationBid bid = userCreationBidRepository.findByUuidAndType(uuid, INTERNAL_BID_TYPE) .orElseThrow(() -> new ReportPortalException(INCORRECT_REQUEST, "Impossible to register user. UUID expired or already registered." )); @@ -277,7 +284,7 @@ public CreateUserRS createUser(CreateUserRQConfirm request, String uuid) { "Email from bid not match."); User invitingUser = bid.getInvitingUser(); - final Pair<UserActivityResource, CreateUserRS> pair = saveUser(createUserRQFull, invitingUser); + final Pair<UserActivityResource, CreateUserRS> pair = saveUser(createUserRQFull, invitingUser, true); userCreationBidRepository.deleteAllByEmail(createUserRQFull.getEmail()); @@ -291,7 +298,7 @@ private CreateUserRQFull convertToCreateRequest(CreateUserRQConfirm request, createUserRQFull.setEmail(request.getEmail()); createUserRQFull.setFullName(request.getFullName()); createUserRQFull.setPassword(request.getPassword()); - createUserRQFull.setDefaultProject(bid.getDefaultProject().getName()); + createUserRQFull.setDefaultProject(bid.getProjectName()); createUserRQFull.setAccountRole(UserRole.USER.name()); createUserRQFull.setProjectRole(bid.getRole()); return createUserRQFull; @@ -333,6 +340,7 @@ public CreateUserBidRS createUserBid(CreateUserRQ request, ReportPortalUser logg () -> new ReportPortalException(ROLE_NOT_FOUND, request.getRole())).name()); UserCreationBid bid = UserCreationBidConverter.TO_USER.apply(request, defaultProject); + bid.setMetadata(getUserCreationBidMetadata()); bid.setInvitingUser(userRepository.getById(loggedInUser.getUserId())); try { userCreationBidRepository.save(bid); @@ -346,6 +354,10 @@ public CreateUserBidRS createUserBid(CreateUserRQ request, ReportPortalUser logg .sendCreateUserConfirmationEmail("User registration confirmation", new String[] {bid.getEmail()}, emailLink.toString())); + eventPublisher.publishEvent( + new CreateInvitationLinkEvent(loggedInUser.getUserId(), loggedInUser.getUsername(), + defaultProject.getId())); + CreateUserBidRS response = new CreateUserBidRS(); String msg = "Bid for user creation with email '" + request.getEmail() + "' is successfully registered. Confirmation info will be send on provided email. " @@ -357,6 +369,12 @@ public CreateUserBidRS createUserBid(CreateUserRQ request, ReportPortalUser logg return response; } + private Metadata getUserCreationBidMetadata() { + final Map<String, Object> meta = Maps.newHashMapWithExpectedSize(1); + meta.put(BID_TYPE, INTERNAL_BID_TYPE); + return new Metadata(meta); + } + @Override public OperationCompletionRS createRestorePasswordBid(RestorePasswordRQ rq, String baseUrl) { String email = normalizeId(rq.getEmail()); diff --git a/src/main/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImpl.java index a30ee5ac32..6459fbf948 100644 --- a/src/main/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImpl.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.user.impl; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.UserCriteriaConstant.CRITERIA_EMAIL; +import static com.epam.ta.reportportal.commons.querygen.constant.UserCriteriaConstant.CRITERIA_EXPIRED; +import static com.epam.ta.reportportal.commons.querygen.constant.UserCriteriaConstant.CRITERIA_USER; +import static com.epam.ta.reportportal.core.user.impl.CreateUserHandlerImpl.INTERNAL_BID_TYPE; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toMap; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Condition; @@ -42,6 +50,11 @@ import com.epam.ta.reportportal.ws.model.user.UserBidRS; import com.epam.ta.reportportal.ws.model.user.UserResource; import com.google.common.base.Preconditions; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import net.sf.jasperreports.engine.JRDataSource; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; @@ -52,17 +65,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.io.OutputStream; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.UserCriteriaConstant.*; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toMap; - /** * Implementation for GET user operations * @@ -71,129 +73,139 @@ @Service public class GetUserHandlerImpl implements GetUserHandler { - private final UserRepository userRepository; - - private final UserCreationBidRepository userCreationBidRepository; - - private final ProjectRepository projectRepository; - - private final PersonalProjectService personalProjectService; - - private final GetJasperReportHandler<User> jasperReportHandler; - - @Autowired - public GetUserHandlerImpl(UserRepository userRepo, UserCreationBidRepository userCreationBidRepository, - ProjectRepository projectRepository, PersonalProjectService personalProjectService, - @Qualifier("userJasperReportHandler") GetJasperReportHandler<User> jasperReportHandler) { - this.userRepository = Preconditions.checkNotNull(userRepo); - this.userCreationBidRepository = Preconditions.checkNotNull(userCreationBidRepository); - this.projectRepository = projectRepository; - this.personalProjectService = personalProjectService; - this.jasperReportHandler = jasperReportHandler; - } - - @Override - public UserResource getUser(String username, ReportPortalUser loggedInUser) { - - User user = userRepository.findByLogin(username.toLowerCase()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, username)); - return UserConverter.TO_RESOURCE.apply(user); - } - - @Override - public UserResource getUser(ReportPortalUser loggedInUser) { - User user = userRepository.findByLogin(loggedInUser.getUsername()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, loggedInUser.getUsername())); - return UserConverter.TO_RESOURCE.apply(user); - } - - @Override - public Iterable<UserResource> getUsers(Filter filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails) { - // Active users only - filter.withCondition(new FilterCondition(Condition.EQUALS, false, "false", CRITERIA_EXPIRED)); - filter.withCondition(new FilterCondition(Condition.EQUALS, - false, - String.valueOf(projectDetails.getProjectId()), - CRITERIA_PROJECT_ID - )); - - return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE) - .apply(userRepository.findByFilterExcluding(filter, pageable, "email")); - } - - @Override - public UserBidRS getBidInformation(String uuid) { - Optional<UserCreationBid> bid = userCreationBidRepository.findById(uuid); - return bid.map(b -> { - UserBidRS rs = new UserBidRS(); - rs.setIsActive(true); - rs.setEmail(b.getEmail()); - rs.setUuid(b.getUuid()); - return rs; - }).orElseGet(() -> { - UserBidRS rs = new UserBidRS(); - rs.setIsActive(false); - return rs; - }); - } - - @Override - public YesNoRS validateInfo(String username, String email) { - if (null != username) { - Optional<User> user = userRepository.findByLogin(EntityUtils.normalizeId(username)); - return user.isPresent() ? new YesNoRS(true) : new YesNoRS(false); - } else if (null != email) { - Optional<User> user = userRepository.findByEmail(EntityUtils.normalizeId(email)); - return user.isPresent() ? new YesNoRS(true) : new YesNoRS(false); - } - return new YesNoRS(false); - } - - @Override - public Map<String, UserResource.AssignedProject> getUserProjects(String userName) { - return projectRepository.findUserProjects(userName).stream().collect(toMap(Project::getName, it -> { - UserResource.AssignedProject assignedProject = new UserResource.AssignedProject(); - assignedProject.setEntryType(it.getProjectType().name()); - ProjectUser projectUser = ProjectUtils.findUserConfigByLogin(it, userName); - - ofNullable(ofNullable(projectUser).orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, userName)) - .getProjectRole()).ifPresent(role -> assignedProject.setProjectRole(role.name())); - - return assignedProject; - })); - } - - @Override - public Iterable<UserResource> getAllUsers(Queryable filter, Pageable pageable) { - final Page<User> users = userRepository.findByFilter(filter, pageable); - return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE).apply(users); - } - - @Override - public void exportUsers(ReportFormat reportFormat, OutputStream outputStream, Queryable filter) { - - final List<User> users = userRepository.findByFilter(filter); - - List<? extends Map<String, ?>> data = users.stream().map(jasperReportHandler::convertParams).collect(Collectors.toList()); - - JRDataSource jrDataSource = new JRBeanCollectionDataSource(data); - - //don't provide any params to not overwrite params from the Jasper template - JasperPrint jasperPrint = jasperReportHandler.getJasperPrint(null, jrDataSource); - - jasperReportHandler.writeReport(reportFormat, outputStream, jasperPrint); - } - - @Override - public Iterable<UserResource> searchUsers(String term, Pageable pageable) { - - Filter filter = Filter.builder() - .withTarget(User.class) - .withCondition(new FilterCondition(Operator.OR, Condition.CONTAINS, false, term, CRITERIA_USER)) - .withCondition(new FilterCondition(Operator.OR, Condition.CONTAINS, false, term, CRITERIA_EMAIL)) - .build(); - return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE).apply(userRepository.findByFilter(filter, pageable)); - - } + private final UserRepository userRepository; + + private final UserCreationBidRepository userCreationBidRepository; + + private final ProjectRepository projectRepository; + + private final PersonalProjectService personalProjectService; + + private final GetJasperReportHandler<User> jasperReportHandler; + + @Autowired + public GetUserHandlerImpl(UserRepository userRepo, + UserCreationBidRepository userCreationBidRepository, + ProjectRepository projectRepository, PersonalProjectService personalProjectService, + @Qualifier("userJasperReportHandler") GetJasperReportHandler<User> jasperReportHandler) { + this.userRepository = Preconditions.checkNotNull(userRepo); + this.userCreationBidRepository = Preconditions.checkNotNull(userCreationBidRepository); + this.projectRepository = projectRepository; + this.personalProjectService = personalProjectService; + this.jasperReportHandler = jasperReportHandler; + } + + @Override + public UserResource getUser(String username, ReportPortalUser loggedInUser) { + + User user = userRepository.findByLogin(username.toLowerCase()) + .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, username)); + return UserConverter.TO_RESOURCE.apply(user); + } + + @Override + public UserResource getUser(ReportPortalUser loggedInUser) { + User user = userRepository.findByLogin(loggedInUser.getUsername()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.USER_NOT_FOUND, loggedInUser.getUsername())); + return UserConverter.TO_RESOURCE.apply(user); + } + + @Override + public Iterable<UserResource> getUsers(Filter filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails) { + // Active users only + filter.withCondition(new FilterCondition(Condition.EQUALS, false, "false", CRITERIA_EXPIRED)); + filter.withCondition(new FilterCondition(Condition.EQUALS, + false, + String.valueOf(projectDetails.getProjectId()), + CRITERIA_PROJECT_ID + )); + + return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE) + .apply(userRepository.findByFilterExcluding(filter, pageable, "email")); + } + + @Override + public UserBidRS getBidInformation(String uuid) { + Optional<UserCreationBid> bid = userCreationBidRepository.findByUuidAndType(uuid, + INTERNAL_BID_TYPE); + return bid.map(b -> { + UserBidRS rs = new UserBidRS(); + rs.setIsActive(true); + rs.setEmail(b.getEmail()); + rs.setUuid(b.getUuid()); + return rs; + }).orElseGet(() -> { + UserBidRS rs = new UserBidRS(); + rs.setIsActive(false); + return rs; + }); + } + + @Override + public YesNoRS validateInfo(String username, String email) { + if (null != username) { + Optional<User> user = userRepository.findByLogin(EntityUtils.normalizeId(username)); + return user.isPresent() ? new YesNoRS(true) : new YesNoRS(false); + } else if (null != email) { + Optional<User> user = userRepository.findByEmail(EntityUtils.normalizeId(email)); + return user.isPresent() ? new YesNoRS(true) : new YesNoRS(false); + } + return new YesNoRS(false); + } + + @Override + public Map<String, UserResource.AssignedProject> getUserProjects(String userName) { + return projectRepository.findUserProjects(userName).stream() + .collect(toMap(Project::getName, it -> { + UserResource.AssignedProject assignedProject = new UserResource.AssignedProject(); + assignedProject.setEntryType(it.getProjectType().name()); + ProjectUser projectUser = ProjectUtils.findUserConfigByLogin(it, userName); + + ofNullable(ofNullable(projectUser).orElseThrow( + () -> new ReportPortalException(ErrorType.USER_NOT_FOUND, userName)) + .getProjectRole()).ifPresent(role -> assignedProject.setProjectRole(role.name())); + + return assignedProject; + })); + } + + @Override + public Iterable<UserResource> getAllUsers(Queryable filter, Pageable pageable) { + final Page<User> users = userRepository.findByFilter(filter, pageable); + return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE).apply(users); + } + + @Override + public void exportUsers(ReportFormat reportFormat, OutputStream outputStream, Queryable filter) { + + final List<User> users = userRepository.findByFilter(filter); + + List<? extends Map<String, ?>> data = users.stream().map(jasperReportHandler::convertParams) + .collect(Collectors.toList()); + + JRDataSource jrDataSource = new JRBeanCollectionDataSource(data); + + //don't provide any params to not overwrite params from the Jasper template + JasperPrint jasperPrint = jasperReportHandler.getJasperPrint(null, jrDataSource); + + jasperReportHandler.writeReport(reportFormat, outputStream, jasperPrint); + } + + @Override + public Iterable<UserResource> searchUsers(String term, Pageable pageable) { + + Filter filter = Filter.builder() + .withTarget(User.class) + .withCondition( + new FilterCondition(Operator.OR, Condition.CONTAINS, false, term, CRITERIA_USER)) + .withCondition( + new FilterCondition(Operator.OR, Condition.CONTAINS, false, term, CRITERIA_EMAIL)) + .build(); + return PagedResourcesAssembler.pageConverter(UserConverter.TO_RESOURCE) + .apply(userRepository.findByFilter(filter, pageable)); + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/CreateWidgetHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/CreateWidgetHandler.java index 37db1da3ea..1d5c8cf0ab 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/CreateWidgetHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/CreateWidgetHandler.java @@ -25,14 +25,15 @@ */ public interface CreateWidgetHandler { - /** - * Creates a new widget - * - * @param createWidgetRQ Widget details - * @param projectDetails Project details - * @param user User - * @return EntryCreatedRS - */ - EntryCreatedRS createWidget(WidgetRQ createWidgetRQ, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); + /** + * Creates a new widget + * + * @param createWidgetRQ Widget details + * @param projectDetails Project details + * @param user User + * @return EntryCreatedRS + */ + EntryCreatedRS createWidget(WidgetRQ createWidgetRQ, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/UpdateWidgetHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/UpdateWidgetHandler.java index 78700815bc..df8f2bea0d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/UpdateWidgetHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/UpdateWidgetHandler.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.widget.WidgetRQ; - import java.util.Collection; /** @@ -28,10 +27,17 @@ */ public interface UpdateWidgetHandler { - /** - * Update widget with specified id - */ - OperationCompletionRS updateWidget(Long widgetId, WidgetRQ updateRQ, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user); + /** + * Update a widget with a specified id. + * + * @param widgetId The ID of the widget to be updated + * @param updateRQ The {@link WidgetRQ} containing the updated information for the widget + * @param projectDetails The {@link ReportPortalUser.ProjectDetails} for the project associated with the widget + * @param user The {@link ReportPortalUser} who is updating the widget + * @return An {@link OperationCompletionRS} instance indicating the result of the update operation + */ + OperationCompletionRS updateWidget(Long widgetId, WidgetRQ updateRQ, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/BuildFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/BuildFilterStrategy.java index 427a1f7e64..203df47db0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/BuildFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/BuildFilterStrategy.java @@ -18,9 +18,8 @@ import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.data.domain.Sort; - import java.util.Map; +import org.springframework.data.domain.Sort; /** * Strategy definition interface for building widget specific filters @@ -29,12 +28,13 @@ */ public interface BuildFilterStrategy { - /** - * Get widget content with predefined filter in accordance with used - * strategy - * - * @return - */ - Map<Filter, Sort> buildFilter(Widget widget); + /** + * Get widget content with predefined filter in accordance with used strategy + * + * @param widget the widget to apply the filters and sorting on + * @return Map of filters and sorts where the key is the {@link Filter} + * and the value is the corresponding {@link Sort} for the given widget + */ + Map<Filter, Sort> buildFilter(Widget widget); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/LoadContentStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/LoadContentStrategy.java index a6805fd429..e0db040728 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/LoadContentStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/LoadContentStrategy.java @@ -18,10 +18,9 @@ import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; -import org.springframework.data.domain.Sort; - import java.util.List; import java.util.Map; +import org.springframework.data.domain.Sort; /** * Strategy definition interface for loading widget content. @@ -30,6 +29,7 @@ */ public interface LoadContentStrategy { - Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, int limit); + Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, int limit); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategy.java index 0a0fab75c3..1397d471b2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategy.java @@ -1,14 +1,13 @@ package com.epam.ta.reportportal.core.widget.content; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.util.MultiValueMap; - import java.util.Map; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface MaterializedLoadContentStrategy { - Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params); + Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategyImpl.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategyImpl.java index 0398456e4b..5d2593a3fb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategyImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/MaterializedLoadContentStrategyImpl.java @@ -1,11 +1,15 @@ package com.epam.ta.reportportal.core.widget.content; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetState; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -13,33 +17,30 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.MultiValueMap; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class MaterializedLoadContentStrategyImpl implements MaterializedLoadContentStrategy { - private final Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping; + private final Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping; - @Autowired - public MaterializedLoadContentStrategyImpl(@Qualifier("widgetStateHandlerMapping") Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping) { - this.widgetStateHandlerMapping = widgetStateHandlerMapping; - } + @Autowired + public MaterializedLoadContentStrategyImpl( + @Qualifier("widgetStateHandlerMapping") Map<WidgetState, MaterializedWidgetStateHandler> widgetStateHandlerMapping) { + this.widgetStateHandlerMapping = widgetStateHandlerMapping; + } - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { - WidgetState widgetState = ofNullable(WidgetOptionUtil.getValueByKey(STATE, - widget.getWidgetOptions() - )).flatMap(WidgetState::findByName) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Widget state not provided")); + WidgetState widgetState = ofNullable(WidgetOptionUtil.getValueByKey(STATE, + widget.getWidgetOptions() + )).flatMap(WidgetState::findByName) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Widget state not provided")); - return widgetStateHandlerMapping.get(widgetState).handleWidgetState(widget, params); - } + return widgetStateHandlerMapping.get(widgetState).handleWidgetState(widget, params); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/MultilevelLoadContentStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/MultilevelLoadContentStrategy.java index fe8997ffd7..945f56dd37 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/MultilevelLoadContentStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/MultilevelLoadContentStrategy.java @@ -18,17 +18,17 @@ import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; -import org.springframework.data.domain.Sort; -import org.springframework.util.MultiValueMap; - import java.util.List; import java.util.Map; +import org.springframework.data.domain.Sort; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public interface MultilevelLoadContentStrategy { - Map<String, Object> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, - String[] attributes, MultiValueMap<String, String> params, int limit); + Map<String, Object> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, + String[] attributes, MultiValueMap<String, String> params, int limit); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/constant/ContentLoaderConstants.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/constant/ContentLoaderConstants.java index cb6a330586..571dccd381 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/constant/ContentLoaderConstants.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/constant/ContentLoaderConstants.java @@ -21,26 +21,26 @@ */ public final class ContentLoaderConstants { - public static final String CONTENT_FIELDS_DELIMITER = ","; + public static final String CONTENT_FIELDS_DELIMITER = ","; - public static final String RESULT = "result"; - public static final String LATEST_OPTION = "latest"; - public static final String LATEST_LAUNCH = "latestLaunch"; - public static final String LAUNCH_NAME_FIELD = "launchNameFilter"; - public static final String USER = "user"; - public static final String ACTION_TYPE = "actionType"; - public static final String ATTRIBUTES = "attributes"; - public static final String ATTRIBUTE_KEY = "attributeKey"; - public static final String PATTERN_TEMPLATE_NAME = "patternTemplateName"; - public static final String ITEM_TYPE = "type"; - public static final String INCLUDE_METHODS = "includeMethods"; - public static final String FLAKY = "flaky"; - public static final String CUSTOM_COLUMNS = "customColumns"; - public static final String TIMELINE = "timeline"; - public static final String ATTRIBUTE_KEYS = "attributeKeys"; - public static final String MIN_PASSING_RATE = "minPassingRate"; + public static final String RESULT = "result"; + public static final String LATEST_OPTION = "latest"; + public static final String LATEST_LAUNCH = "latestLaunch"; + public static final String LAUNCH_NAME_FIELD = "launchNameFilter"; + public static final String USER = "user"; + public static final String ACTION_TYPE = "actionType"; + public static final String ATTRIBUTES = "attributes"; + public static final String ATTRIBUTE_KEY = "attributeKey"; + public static final String PATTERN_TEMPLATE_NAME = "patternTemplateName"; + public static final String ITEM_TYPE = "type"; + public static final String INCLUDE_METHODS = "includeMethods"; + public static final String FLAKY = "flaky"; + public static final String CUSTOM_COLUMNS = "customColumns"; + public static final String TIMELINE = "timeline"; + public static final String ATTRIBUTE_KEYS = "attributeKeys"; + public static final String MIN_PASSING_RATE = "minPassingRate"; - private ContentLoaderConstants() { - //static only - } + private ContentLoaderConstants() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/AbstractStatisticsFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/AbstractStatisticsFilterStrategy.java index cec5d9641d..823d330b40 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/AbstractStatisticsFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/AbstractStatisticsFilterStrategy.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.BuildFilterStrategy; import com.epam.ta.reportportal.entity.filter.FilterSort; @@ -23,45 +25,44 @@ import com.epam.ta.reportportal.entity.widget.Widget; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.springframework.data.domain.Sort; - import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - -import static java.util.Optional.ofNullable; +import org.springframework.data.domain.Sort; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractStatisticsFilterStrategy implements BuildFilterStrategy { - @Override - public Map<Filter, Sort> buildFilter(Widget widget) { - return buildFilterSortMap(widget, widget.getProject().getId()); - } + @Override + public Map<Filter, Sort> buildFilter(Widget widget) { + return buildFilterSortMap(widget, widget.getProject().getId()); + } - protected Map<Filter, Sort> buildFilterSortMap(Widget widget, Long projectId) { - Map<Filter, Sort> filterSortMap = Maps.newLinkedHashMap(); - Set<UserFilter> userFilters = Optional.ofNullable(widget.getFilters()).orElse(Collections.emptySet()); - Filter defaultFilter = buildDefaultFilter(widget, projectId); - Optional.ofNullable(defaultFilter).ifPresent(f -> filterSortMap.put(defaultFilter, Sort.unsorted())); - userFilters.forEach(userFilter -> { - Filter filter = new Filter(userFilter.getId(), - userFilter.getTargetClass().getClassObject(), - Lists.newArrayList(userFilter.getFilterCondition()) - ); - Optional<Set<FilterSort>> filterSorts = ofNullable(userFilter.getFilterSorts()); - Sort sort = Sort.by(filterSorts.map(filterSort -> filterSort.stream() - .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) - .collect(Collectors.toList())).orElseGet(Collections::emptyList)); - filterSortMap.put(filter, sort); - }); + protected Map<Filter, Sort> buildFilterSortMap(Widget widget, Long projectId) { + Map<Filter, Sort> filterSortMap = Maps.newLinkedHashMap(); + Set<UserFilter> userFilters = Optional.ofNullable(widget.getFilters()) + .orElse(Collections.emptySet()); + Filter defaultFilter = buildDefaultFilter(widget, projectId); + Optional.ofNullable(defaultFilter) + .ifPresent(f -> filterSortMap.put(defaultFilter, Sort.unsorted())); + userFilters.forEach(userFilter -> { + Filter filter = new Filter(userFilter.getId(), + userFilter.getTargetClass().getClassObject(), + Lists.newArrayList(userFilter.getFilterCondition()) + ); + Optional<Set<FilterSort>> filterSorts = ofNullable(userFilter.getFilterSorts()); + Sort sort = Sort.by(filterSorts.map(filterSort -> filterSort.stream() + .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) + .collect(Collectors.toList())).orElseGet(Collections::emptyList)); + filterSortMap.put(filter, sort); + }); - return filterSortMap; - } + return filterSortMap; + } - protected abstract Filter buildDefaultFilter(Widget widget, Long projectId); + protected abstract Filter buildDefaultFilter(Widget widget, Long projectId); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ActivityFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ActivityFilterStrategy.java index a2f095acd3..75eddc9b58 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ActivityFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ActivityFilterStrategy.java @@ -16,36 +16,36 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.activity.Activity; import com.epam.ta.reportportal.entity.widget.Widget; import com.google.common.collect.Lists; +import java.util.Map; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service("activityFilterStrategy") public class ActivityFilterStrategy extends AbstractStatisticsFilterStrategy { - @Override - public Map<Filter, Sort> buildFilter(Widget widget) { + @Override + public Map<Filter, Sort> buildFilter(Widget widget) { - return super.buildFilter(widget); - } + return super.buildFilter(widget); + } - @Override - protected Filter buildDefaultFilter(Widget widget, Long projectId) { - return new Filter( - Activity.class, - Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), CRITERIA_PROJECT_ID)) - ); - } + @Override + protected Filter buildDefaultFilter(Widget widget, Long projectId) { + return new Filter( + Activity.class, + Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), + CRITERIA_PROJECT_ID)) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/GeneralLaunchFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/GeneralLaunchFilterStrategy.java index 13d7657840..b389158520 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/GeneralLaunchFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/GeneralLaunchFilterStrategy.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -23,25 +26,22 @@ import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.ws.model.launch.Mode; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_MODE; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; - /** * @author Pavel Bortnik */ @Service("generalLaunchFilterStrategy") public class GeneralLaunchFilterStrategy extends ProjectFilterStrategy { - @Override - protected Filter buildDefaultFilter(Widget widget, Long projectId) { - Filter filter = super.buildDefaultFilter(widget, projectId); - filter.withConditions(Lists.newArrayList( - new FilterCondition(Condition.NOT_EQUALS, false, StatusEnum.IN_PROGRESS.name(), CRITERIA_LAUNCH_STATUS), - new FilterCondition(Condition.EQUALS, false, Mode.DEFAULT.toString(), CRITERIA_LAUNCH_MODE) - )); - return filter; - } + @Override + protected Filter buildDefaultFilter(Widget widget, Long projectId) { + Filter filter = super.buildDefaultFilter(widget, projectId); + filter.withConditions(Lists.newArrayList( + new FilterCondition(Condition.NOT_EQUALS, false, StatusEnum.IN_PROGRESS.name(), + CRITERIA_LAUNCH_STATUS), + new FilterCondition(Condition.EQUALS, false, Mode.DEFAULT.toString(), CRITERIA_LAUNCH_MODE) + )); + return filter; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/LaunchHistoryFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/LaunchHistoryFilterStrategy.java index cc4d404e3d..ff500d15ff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/LaunchHistoryFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/LaunchHistoryFilterStrategy.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static java.util.stream.Collectors.joining; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -25,43 +30,42 @@ import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; -import static java.util.stream.Collectors.joining; - /** * @author Pavel Bortnik */ @Service("launchHistoryFilterStrategy") public class LaunchHistoryFilterStrategy extends GeneralLaunchFilterStrategy { - @Override - protected Filter buildDefaultFilter(Widget widget, Long projectId) { - validateWidgetOptions(widget.getWidgetOptions()); - String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widget.getWidgetOptions()); - Filter filter = super.buildDefaultFilter(widget, projectId); - return filter.withCondition(new FilterCondition(Condition.EQUALS, false, launchName, CRITERIA_NAME)) - .withCondition(new FilterCondition( - Condition.IN, - false, - Stream.of(StatusEnum.FAILED, StatusEnum.PASSED, StatusEnum.STOPPED).map(Enum::name).collect(joining(",")), - CRITERIA_LAUNCH_STATUS - )); - } + @Override + protected Filter buildDefaultFilter(Widget widget, Long projectId) { + validateWidgetOptions(widget.getWidgetOptions()); + String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, + widget.getWidgetOptions()); + Filter filter = super.buildDefaultFilter(widget, projectId); + return filter.withCondition( + new FilterCondition(Condition.EQUALS, false, launchName, CRITERIA_NAME)) + .withCondition(new FilterCondition( + Condition.IN, + false, + Stream.of(StatusEnum.FAILED, StatusEnum.PASSED, StatusEnum.STOPPED).map(Enum::name) + .collect(joining(",")), + CRITERIA_LAUNCH_STATUS + )); + } - /** - * Validate provided widget options. For current widget launch name should be specified. - * - * @param widgetOptions Map of stored widget options. - */ - private void validateWidgetOptions(WidgetOptions widgetOptions) { - BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), StringUtils::isNotBlank) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, LAUNCH_NAME_FIELD + " should be specified for widget."); - } + /** + * Validate provided widget options. For current widget launch name should be specified. + * + * @param widgetOptions Map of stored widget options. + */ + private void validateWidgetOptions(WidgetOptions widgetOptions) { + BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), + StringUtils::isNotBlank) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + LAUNCH_NAME_FIELD + " should be specified for widget."); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProductStatusFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProductStatusFilterStrategy.java index fbfdda3a03..2e8ae64098 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProductStatusFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProductStatusFilterStrategy.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -24,18 +27,13 @@ import com.epam.ta.reportportal.entity.widget.Widget; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static java.util.Optional.ofNullable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; /** * @author Pavel Bortnik @@ -43,32 +41,33 @@ @Service("productStatusFilterStrategy") public class ProductStatusFilterStrategy extends AbstractStatisticsFilterStrategy { - @Override - protected Map<Filter, Sort> buildFilterSortMap(Widget widget, Long projectId) { - Map<Filter, Sort> filterSortMap = Maps.newLinkedHashMap(); - Optional.ofNullable(widget.getFilters()).orElse(Collections.emptySet()).forEach(userFilter -> { - Filter filter = new Filter( - userFilter.getId(), - userFilter.getTargetClass().getClassObject(), - Lists.newArrayList(userFilter.getFilterCondition()) - ); - filter.withConditions(buildDefaultFilter(widget, projectId).getFilterConditions()); + @Override + protected Map<Filter, Sort> buildFilterSortMap(Widget widget, Long projectId) { + Map<Filter, Sort> filterSortMap = Maps.newLinkedHashMap(); + Optional.ofNullable(widget.getFilters()).orElse(Collections.emptySet()).forEach(userFilter -> { + Filter filter = new Filter( + userFilter.getId(), + userFilter.getTargetClass().getClassObject(), + Lists.newArrayList(userFilter.getFilterCondition()) + ); + filter.withConditions(buildDefaultFilter(widget, projectId).getFilterConditions()); - Optional<Set<FilterSort>> filterSorts = ofNullable(userFilter.getFilterSorts()); + Optional<Set<FilterSort>> filterSorts = ofNullable(userFilter.getFilterSorts()); - Sort sort = Sort.by(filterSorts.map(filterSort -> filterSort.stream() - .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) - .collect(Collectors.toList())).orElseGet(Collections::emptyList)); + Sort sort = Sort.by(filterSorts.map(filterSort -> filterSort.stream() + .map(s -> Sort.Order.by(s.getField()).with(s.getDirection())) + .collect(Collectors.toList())).orElseGet(Collections::emptyList)); - filterSortMap.put(filter, sort); - }); - return filterSortMap; - } + filterSortMap.put(filter, sort); + }); + return filterSortMap; + } - protected Filter buildDefaultFilter(Widget widget, Long projectId) { - return new Filter( - Launch.class, - Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), CRITERIA_PROJECT_ID)) - ); - } + protected Filter buildDefaultFilter(Widget widget, Long projectId) { + return new Filter( + Launch.class, + Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), + CRITERIA_PROJECT_ID)) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProjectFilterStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProjectFilterStrategy.java index 382f571375..6a0cff29e2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProjectFilterStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/filter/ProjectFilterStrategy.java @@ -16,27 +16,27 @@ package com.epam.ta.reportportal.core.widget.content.filter; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.Widget; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; - /** * @author Pavel Bortnik */ @Service("projectFilterStrategy") public class ProjectFilterStrategy extends AbstractStatisticsFilterStrategy { - @Override - protected Filter buildDefaultFilter(Widget widget, Long projectId) { - return new Filter(Launch.class, - Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), CRITERIA_PROJECT_ID)) - ); - } + @Override + protected Filter buildDefaultFilter(Widget widget, Long projectId) { + return new Filter(Launch.class, + Lists.newArrayList(new FilterCondition(Condition.EQUALS, false, String.valueOf(projectId), + CRITERIA_PROJECT_ID)) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/AbstractStatisticsContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/AbstractStatisticsContentLoader.java index a74dc68339..49785a7618 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/AbstractStatisticsContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/AbstractStatisticsContentLoader.java @@ -16,143 +16,197 @@ package com.epam.ta.reportportal.core.widget.content.loader; -import com.epam.ta.reportportal.entity.widget.content.AbstractLaunchStatisticsContent; -import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; -import org.apache.commons.collections.MapUtils; -import org.joda.time.DateTime; +import static java.util.Optional.ofNullable; +import static net.sf.jasperreports.types.date.FixedDate.DATE_PATTERN; -import java.time.format.DateTimeFormatter; -import java.util.*; +import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.LongSummaryStatistics; +import java.util.Map; +import java.util.Optional; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; - -import static java.util.Optional.ofNullable; -import static net.sf.jasperreports.types.date.FixedDate.DATE_PATTERN; +import org.apache.commons.collections.MapUtils; +import org.joda.time.DateTime; /** * @author Andrei_Ramanchuk */ public abstract class AbstractStatisticsContentLoader { - /** - * Return lists of objects grouped by specified period - * - * @param input - * @param period - * @return - */ - protected Map<String, ChartStatisticsContent> groupByDate(List<ChartStatisticsContent> input, Period period) { - if (input.isEmpty()) { - return Collections.emptyMap(); - } - final Map<String, ChartStatisticsContent> chart = new LinkedHashMap<>(); - - switch (period) { - case DAY: - case WEEK: - proceedDailyChart(chart, input); - groupStatistics(DATE_PATTERN, input, chart); - break; - case MONTH: - proceedDailyChart(chart, input); - groupStatistics("yyyy-MM", input, chart); - break; - } - - return chart; - } - - protected Map<String, ChartStatisticsContent> maxByDate(List<ChartStatisticsContent> statisticsContents, Period period, - String contentField) { - final Function<ChartStatisticsContent, String> chartObjectToDate = chartObject -> new DateTime(chartObject.getStartTime().getTime()) - .toString(DATE_PATTERN); - final BinaryOperator<ChartStatisticsContent> chartObjectReducer = (o1, o2) -> Integer.parseInt(o1.getValues().get(contentField)) > Integer.parseInt(o2.getValues().get(contentField)) ? - o1 : - o2; - final Map<String, Optional<ChartStatisticsContent>> groupByDate = statisticsContents.stream() - .filter(content -> MapUtils.isNotEmpty(content.getValues()) && ofNullable(content.getValues() - .get(contentField)).isPresent()) - .sorted(Comparator.comparing(ChartStatisticsContent::getStartTime)) - .collect(Collectors.groupingBy(chartObjectToDate, LinkedHashMap::new, Collectors.reducing(chartObjectReducer))); - final Map<String, ChartStatisticsContent> range = groupByDate(statisticsContents, period); - final LinkedHashMap<String, ChartStatisticsContent> result = new LinkedHashMap<>(); - // used forEach cause aspectj compiler can't infer types properly - range.forEach((key, value) -> result.put(key, - groupByDate.getOrDefault(key, Optional.of(createChartObject(statisticsContents.get(0)))).get() - )); - return result; - } - - private void groupStatistics(String groupingPattern, List<ChartStatisticsContent> statisticsContents, - Map<String, ChartStatisticsContent> chart) { - - Map<String, List<ChartStatisticsContent>> groupedStatistics = statisticsContents.stream() - .collect(Collectors.groupingBy(c -> new DateTime(c.getStartTime()).toString(groupingPattern), - LinkedHashMap::new, - Collectors.toList() - )); - - groupedStatistics.forEach((key, contents) -> chart.keySet().stream().filter(k -> k.startsWith(key)).findFirst().ifPresent(k -> { - ChartStatisticsContent content = chart.get(k); - contents.add(content); - Map<String, String> values = contents.stream() - .map(v -> v.getValues().entrySet()) - .flatMap(Collection::stream) - .collect(Collectors.toMap(Map.Entry::getKey, - entry -> ofNullable(entry.getValue()).orElse("0"), - (prev, curr) -> prev = String.valueOf(Double.parseDouble(prev) + Double.parseDouble(curr)) - )); - - content.setValues(values); - - chart.put(k, content); - })); - } - - private void proceedDailyChart(Map<String, ChartStatisticsContent> chart, List<ChartStatisticsContent> statisticsContents) { - statisticsContents.stream().sorted(Comparator.comparing(AbstractLaunchStatisticsContent::getStartTime)).forEach(sc -> { - chart.put( - sc.getStartTime().toLocalDateTime().format(DateTimeFormatter.ISO_DATE), - createChartObject(sc) - ); - }); - } - - private ChartStatisticsContent createChartObject(ChartStatisticsContent input) { - final ChartStatisticsContent chartObject = new ChartStatisticsContent(); - chartObject.setValues(input.getValues().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> "0"))); - return chartObject; - } - - /** - * Timeline periods enumerator - * - * @author Andrei_Ramanchuk - */ - public enum Period { - // @formatter:off - DAY(1), - WEEK(7), - MONTH(30); - // @formatter:on - - private int value; - - Period(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static boolean isPresent(String name) { - return findByName(name).isPresent(); - } - - public static Optional<Period> findByName(String name) { - return Arrays.stream(Period.values()).filter(time -> time.name().equalsIgnoreCase(name)).findAny(); - } - } + /** + * Return lists of objects grouped by specified period + * + * @param input A list of {@link ChartStatisticsContent} objects to be grouped + * @param period The {@link Period} that defines the desired time grouping (e.g., DAY, WEEK, MONTH) + * @return A map where keys represent the grouped time periods, and values are instances of + * {@link ChartStatisticsContent} containing aggregated statistical data for each group + */ + protected Map<String, ChartStatisticsContent> groupByDate(List<ChartStatisticsContent> input, + Period period) { + + final LongSummaryStatistics statistics = input.stream() + .mapToLong(object -> object.getStartTime().getTime()).summaryStatistics(); + final DateTime start = new DateTime(statistics.getMin()); + final DateTime end = new DateTime(statistics.getMax()); + if (input.isEmpty()) { + return Collections.emptyMap(); + } + final Map<String, ChartStatisticsContent> chart = new LinkedHashMap<>(); + + switch (period) { + case DAY: + proceedDailyChart(chart, start, end, input); + groupStatistics(DATE_PATTERN, input, chart); + break; + case WEEK: + proceedDailyChart(chart, start, end, input); + groupStatistics(DATE_PATTERN, input, chart); + break; + case MONTH: + proceedMonthlyChart(chart, start, end, input); + groupStatistics("yyyy-MM", input, chart); + break; + } + + return chart; + } + + protected Map<String, ChartStatisticsContent> maxByDate( + List<ChartStatisticsContent> statisticsContents, Period period, + String contentField) { + final Function<ChartStatisticsContent, String> chartObjectToDate = chartObject -> new DateTime( + chartObject.getStartTime().getTime()) + .toString(DATE_PATTERN); + final BinaryOperator<ChartStatisticsContent> chartObjectReducer = (o1, o2) -> + Integer.parseInt(o1.getValues().get(contentField)) > Integer.parseInt( + o2.getValues().get(contentField)) ? + o1 : + o2; + final Map<String, Optional<ChartStatisticsContent>> groupByDate = statisticsContents.stream() + .filter( + content -> MapUtils.isNotEmpty(content.getValues()) && ofNullable(content.getValues() + .get(contentField)).isPresent()) + .sorted(Comparator.comparing(ChartStatisticsContent::getStartTime)) + .collect(Collectors.groupingBy(chartObjectToDate, LinkedHashMap::new, + Collectors.reducing(chartObjectReducer))); + final Map<String, ChartStatisticsContent> range = groupByDate(statisticsContents, period); + final LinkedHashMap<String, ChartStatisticsContent> result = new LinkedHashMap<>(); + // used forEach cause aspectj compiler can't infer types properly + range.forEach((key, value) -> result.put(key, + groupByDate.getOrDefault(key, Optional.of(createChartObject(statisticsContents.get(0)))) + .get() + )); + return result; + } + + private void groupStatistics(String groupingPattern, + List<ChartStatisticsContent> statisticsContents, + Map<String, ChartStatisticsContent> chart) { + + Map<String, List<ChartStatisticsContent>> groupedStatistics = statisticsContents.stream() + .collect( + Collectors.groupingBy(c -> new DateTime(c.getStartTime()).toString(groupingPattern), + LinkedHashMap::new, + Collectors.toList() + )); + + groupedStatistics.forEach( + (key, contents) -> chart.keySet().stream().filter(k -> k.startsWith(key)).findFirst() + .ifPresent(k -> { + ChartStatisticsContent content = chart.get(k); + contents.add(content); + Map<String, String> values = contents.stream() + .map(v -> v.getValues().entrySet()) + .flatMap(Collection::stream) + .collect(Collectors.toMap(Map.Entry::getKey, + entry -> ofNullable(entry.getValue()).orElse("0"), + (prev, curr) -> prev = String.valueOf( + Double.parseDouble(prev) + Double.parseDouble(curr)) + )); + + content.setValues(values); + + chart.put(k, content); + })); + } + + private void proceedDailyChart(Map<String, ChartStatisticsContent> chart, DateTime intermediate, + DateTime end, + List<ChartStatisticsContent> statisticsContents) { + + while (intermediate.isBefore(end)) { + chart.put(intermediate.toString(DATE_PATTERN), createChartObject(statisticsContents.get(0))); + intermediate = intermediate.plusDays(1); + } + + chart.put(end.toString(DATE_PATTERN), createChartObject(statisticsContents.get(0))); + + } + + private void proceedMonthlyChart(Map<String, ChartStatisticsContent> chart, DateTime intermediate, + DateTime end, + List<ChartStatisticsContent> statisticsContents) { + while (intermediate.isBefore(end)) { + if (intermediate.getYear() == end.getYear()) { + if (intermediate.getMonthOfYear() != end.getMonthOfYear()) { + chart.put(intermediate.toString(DATE_PATTERN), + createChartObject(statisticsContents.get(0))); + } + } else { + chart.put(intermediate.toString(DATE_PATTERN), + createChartObject(statisticsContents.get(0))); + } + + intermediate = intermediate.plusMonths(1); + } + + chart.put(end.toString(DATE_PATTERN), createChartObject(statisticsContents.get(0))); + + } + + private ChartStatisticsContent createChartObject(ChartStatisticsContent input) { + final ChartStatisticsContent chartObject = new ChartStatisticsContent(); + chartObject.setValues(input.getValues().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> "0"))); + return chartObject; + } + + /** + * Timeline periods enumerator + * + * @author Andrei_Ramanchuk + */ + public enum Period { + // @formatter:off + DAY(1), + WEEK(7), + MONTH(30); + // @formatter:on + + private int value; + + Period(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static boolean isPresent(String name) { + return findByName(name).isPresent(); + } + + public static Optional<Period> findByName(String name) { + return Arrays.stream(Period.values()).filter(time -> time.name().equalsIgnoreCase(name)) + .findAny(); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/BugTrendChartContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/BugTrendChartContentLoader.java index 9763ecba16..bffbe3a570 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/BugTrendChartContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/BugTrendChartContentLoader.java @@ -16,42 +16,43 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class BugTrendChartContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<ChartStatisticsContent> result = widgetContentRepository.bugTrendStatistics(filter, contentFields, sort, limit); - return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); - } + List<ChartStatisticsContent> result = widgetContentRepository.bugTrendStatistics(filter, + contentFields, sort, limit); + return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/CasesTrendContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/CasesTrendContentLoader.java index 3998e75572..5f258d58cd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/CasesTrendContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/CasesTrendContentLoader.java @@ -16,93 +16,101 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DELTA; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DELTA; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service -public class CasesTrendContentLoader extends AbstractStatisticsContentLoader implements LoadContentStrategy { - - @Autowired - private WidgetContentRepository widgetContentRepository; - - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { - - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - - String contentField = contentFields.get(0); - List<ChartStatisticsContent> content = widgetContentRepository.casesTrendStatistics(filter, contentField, sort, limit); - - return CollectionUtils.isEmpty(content) ? emptyMap() : calculateStatistics(widgetOptions, content, contentField, sort); - } - - private Map<String, ?> calculateStatistics(WidgetOptions widgetOptions, List<ChartStatisticsContent> content, String contentField, - Sort sort) { - String timeLineOption = WidgetOptionUtil.getValueByKey(TIMELINE, widgetOptions); - - if (StringUtils.isNotBlank(timeLineOption)) { - Optional<Period> period = Period.findByName(timeLineOption); - if (period.isPresent()) { - Map<String, ChartStatisticsContent> statistics = maxByDate(content, period.get(), contentField); - calculateDelta(statistics, sort, contentField); - return singletonMap(RESULT, statistics); - } - - } - - return singletonMap(RESULT, content); - } - - private void calculateDelta(Map<String, ChartStatisticsContent> statistics, Sort sort, String contentField) { - - if (sort.get().anyMatch(Sort.Order::isAscending)) { - ArrayList<String> keys = new ArrayList<>(statistics.keySet()); - /* Last element in map */ - int previous = Integer.parseInt(statistics.get(keys.get(keys.size() - 1)).getValues().get(contentField)); - /* Iteration in reverse order */ - for (int i = keys.size() - 1; i >= 0; i--) { - int current = Integer.parseInt(statistics.get(keys.get(i)).getValues().get(contentField)); - statistics.get(keys.get(i)).getValues().put(DELTA, String.valueOf(current - previous)); - previous = current; - } - } else { - int previousValue = Integer.parseInt(new ArrayList<>(statistics.values()).get(0).getValues().get(contentField)); - for (ChartStatisticsContent content : statistics.values()) { - Map<String, String> values = content.getValues(); - int currentValue = Integer.parseInt(values.get(contentField)); - values.put(DELTA, String.valueOf(currentValue - previousValue)); - previousValue = currentValue; - } - } - - } +public class CasesTrendContentLoader extends AbstractStatisticsContentLoader implements + LoadContentStrategy { + + @Autowired + private WidgetContentRepository widgetContentRepository; + + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { + + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + + String contentField = contentFields.get(0); + List<ChartStatisticsContent> content = widgetContentRepository.casesTrendStatistics(filter, + contentField, sort, limit); + + return CollectionUtils.isEmpty(content) ? emptyMap() + : calculateStatistics(widgetOptions, content, contentField, sort); + } + + private Map<String, ?> calculateStatistics(WidgetOptions widgetOptions, + List<ChartStatisticsContent> content, String contentField, + Sort sort) { + String timeLineOption = WidgetOptionUtil.getValueByKey(TIMELINE, widgetOptions); + + if (StringUtils.isNotBlank(timeLineOption)) { + Optional<Period> period = Period.findByName(timeLineOption); + if (period.isPresent()) { + Map<String, ChartStatisticsContent> statistics = maxByDate(content, period.get(), + contentField); + calculateDelta(statistics, sort, contentField); + return singletonMap(RESULT, statistics); + } + + } + + return singletonMap(RESULT, content); + } + + private void calculateDelta(Map<String, ChartStatisticsContent> statistics, Sort sort, + String contentField) { + + if (sort.get().anyMatch(Sort.Order::isAscending)) { + ArrayList<String> keys = new ArrayList<>(statistics.keySet()); + /* Last element in map */ + int previous = Integer.parseInt( + statistics.get(keys.get(keys.size() - 1)).getValues().get(contentField)); + /* Iteration in reverse order */ + for (int i = keys.size() - 1; i >= 0; i--) { + int current = Integer.parseInt(statistics.get(keys.get(i)).getValues().get(contentField)); + statistics.get(keys.get(i)).getValues().put(DELTA, String.valueOf(current - previous)); + previous = current; + } + } else { + int previousValue = Integer.parseInt( + new ArrayList<>(statistics.values()).get(0).getValues().get(contentField)); + for (ChartStatisticsContent content : statistics.values()) { + Map<String, String> values = content.getValues(); + int currentValue = Integer.parseInt(values.get(contentField)); + values.put(DELTA, String.valueOf(currentValue - previousValue)); + previousValue = currentValue; + } + } + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ChartInvestigatedContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ChartInvestigatedContentLoader.java index 5a77ada6a7..3f08ce5405 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ChartInvestigatedContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ChartInvestigatedContentLoader.java @@ -16,12 +16,27 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.INVESTIGATED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.PERCENTAGE_MULTIPLIER; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.TO_INVESTIGATE; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; @@ -29,75 +44,69 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service -public class ChartInvestigatedContentLoader extends AbstractStatisticsContentLoader implements LoadContentStrategy { - - @Autowired - private WidgetContentRepository widgetContentRepository; - - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { - - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - - String timeLineOption = WidgetOptionUtil.getValueByKey(TIMELINE, widgetOptions); - - if (StringUtils.isNotBlank(timeLineOption)) { - Optional<Period> period = Period.findByName(timeLineOption); - if (period.isPresent()) { - Map<String, ChartStatisticsContent> statistics = groupByDate(widgetContentRepository.timelineInvestigatedStatistics(filter, - sort, - limit - ), period.get()); - return MapUtils.isEmpty(statistics) ? emptyMap() : calculateInvestigatedPercentage(statistics); - } - - } - - List<ChartStatisticsContent> content = widgetContentRepository.investigatedStatistics(filter, sort, limit); - - return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); - } - - private Map<String, ?> calculateInvestigatedPercentage(Map<String, ChartStatisticsContent> investigatedStatistics) { - - investigatedStatistics.values().forEach(c -> { - Map<String, String> values = c.getValues(); - BigDecimal divisor = BigDecimal.valueOf(Double.parseDouble(values.get(INVESTIGATED))); - if (0 != divisor.intValue()) { - values.put(TO_INVESTIGATE, - String.valueOf(BigDecimal.valueOf(PERCENTAGE_MULTIPLIER * Double.parseDouble(values.get(TO_INVESTIGATE))) - .divide(divisor, 2, RoundingMode.FLOOR) - .doubleValue()) - ); - values.put(INVESTIGATED, String.valueOf(PERCENTAGE_MULTIPLIER - Double.parseDouble(values.get(TO_INVESTIGATE)))); - } else { - values.put(INVESTIGATED, "0"); - values.put(TO_INVESTIGATE, "0"); - } - }); - - return singletonMap(RESULT, investigatedStatistics); - } +public class ChartInvestigatedContentLoader extends AbstractStatisticsContentLoader implements + LoadContentStrategy { + + @Autowired + private WidgetContentRepository widgetContentRepository; + + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { + + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + + String timeLineOption = WidgetOptionUtil.getValueByKey(TIMELINE, widgetOptions); + + if (StringUtils.isNotBlank(timeLineOption)) { + Optional<Period> period = Period.findByName(timeLineOption); + if (period.isPresent()) { + Map<String, ChartStatisticsContent> statistics = groupByDate( + widgetContentRepository.timelineInvestigatedStatistics(filter, + sort, + limit + ), period.get()); + return MapUtils.isEmpty(statistics) ? emptyMap() + : calculateInvestigatedPercentage(statistics); + } + + } + + List<ChartStatisticsContent> content = widgetContentRepository.investigatedStatistics(filter, + sort, limit); + + return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); + } + + private Map<String, ?> calculateInvestigatedPercentage( + Map<String, ChartStatisticsContent> investigatedStatistics) { + + investigatedStatistics.values().forEach(c -> { + Map<String, String> values = c.getValues(); + BigDecimal divisor = BigDecimal.valueOf(Double.parseDouble(values.get(INVESTIGATED))); + if (0 != divisor.intValue()) { + values.put(TO_INVESTIGATE, + String.valueOf(BigDecimal.valueOf( + PERCENTAGE_MULTIPLIER * Double.parseDouble(values.get(TO_INVESTIGATE))) + .divide(divisor, 2, RoundingMode.FLOOR) + .doubleValue()) + ); + values.put(INVESTIGATED, + String.valueOf(PERCENTAGE_MULTIPLIER - Double.parseDouble(values.get(TO_INVESTIGATE)))); + } else { + values.put(INVESTIGATED, "0"); + values.put(TO_INVESTIGATE, "0"); + } + }); + + return singletonMap(RESULT, investigatedStatistics); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ComponentHealthCheckContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ComponentHealthCheckContentLoader.java index 14506d4832..574804d49b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ComponentHealthCheckContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ComponentHealthCheckContentLoader.java @@ -16,7 +16,27 @@ package com.epam.ta.reportportal.core.widget.content.loader; -import com.epam.ta.reportportal.commons.querygen.*; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_COMPOSITE_ATTRIBUTE; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.KEY_VALUE_SEPARATOR; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_CHILDREN; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_STATS; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_RETRY_PARENT_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_STATUS; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_TYPE; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.joining; + +import com.epam.ta.reportportal.commons.querygen.CompositeFilterCondition; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.content.MultilevelLoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; @@ -28,27 +48,16 @@ import com.epam.ta.reportportal.entity.widget.content.healthcheck.ComponentHealthCheckContent; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Lists; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; -import org.springframework.util.MultiValueMap; - import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.IntStream; - -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_COMPOSITE_ATTRIBUTE; -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.KEY_VALUE_SEPARATOR; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.*; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.joining; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -56,86 +65,91 @@ @Service public class ComponentHealthCheckContentLoader implements MultilevelLoadContentStrategy { - public static final Integer MAX_LEVEL_NUMBER = 10; - - private final WidgetContentRepository widgetContentRepository; - - @Autowired - public ComponentHealthCheckContentLoader(WidgetContentRepository widgetContentRepository) { - this.widgetContentRepository = widgetContentRepository; - } - - @Override - public Map<String, Object> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - String[] attributes, MultiValueMap<String, String> params, int limit) { - - List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); - List<String> attributeValues = ofNullable(attributes).map(Arrays::asList).orElseGet(Collections::emptyList); - - int currentLevel = attributeValues.size(); - BusinessRule.expect(attributeKeys, keys -> keys.size() > currentLevel) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Incorrect level definition"); - - Filter launchesFilter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort launchesSort = GROUP_SORTS.apply(filterSortMapping.values()); - - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - - Filter testItemFilter = Filter.builder() - .withTarget(TestItem.class) - .withCondition(getTestItemCondition(attributeKeys, attributeValues)) - .build(); - - String currentLevelKey = attributeKeys.get(currentLevel); - - List<ComponentHealthCheckContent> content = widgetContentRepository.componentHealthCheck(launchesFilter, - launchesSort, - latestMode, - limit, - testItemFilter, - currentLevelKey - ); - - return CollectionUtils.isNotEmpty(content) ? Collections.singletonMap(RESULT, content) : emptyMap(); - } - - private ConvertibleCondition getTestItemCondition(List<String> attributeKeys, List<String> attributeValues) { - - List<ConvertibleCondition> conditions = Lists.newArrayList(FilterCondition.builder() - .eq(CRITERIA_HAS_STATS, String.valueOf(Boolean.TRUE)) - .build(), - FilterCondition.builder().eq(CRITERIA_HAS_CHILDREN, String.valueOf(Boolean.FALSE)).build(), - FilterCondition.builder().eq(CRITERIA_TYPE, TestItemTypeEnum.STEP.name()).build(), - FilterCondition.builder() - .withCondition(Condition.EXISTS) - .withNegative(true) - .withSearchCriteria(CRITERIA_RETRY_PARENT_ID) - .withValue(String.valueOf(0L)) - .build(), - FilterCondition.builder() - .withCondition(Condition.NOT_EQUALS) - .withNegative(false) - .withSearchCriteria(CRITERIA_STATUS) - .withValue(StatusEnum.IN_PROGRESS.name()) - .build() - ); - - if (CollectionUtils.isNotEmpty(attributeValues)) { - String attributeCriteria = IntStream.range(0, attributeValues.size()).mapToObj(index -> { - String attributeKey = attributeKeys.get(index); - String attributeValue = attributeValues.get(index); - return String.join(KEY_VALUE_SEPARATOR, attributeKey, attributeValue); - }).collect(joining(",")); - - conditions.add(FilterCondition.builder() - .withCondition(Condition.HAS) - .withNegative(false) - .withSearchCriteria(CRITERIA_COMPOSITE_ATTRIBUTE) - .withValue(attributeCriteria) - .build()); - } - - return new CompositeFilterCondition(conditions); - - } + public static final Integer MAX_LEVEL_NUMBER = 10; + + private final WidgetContentRepository widgetContentRepository; + + @Autowired + public ComponentHealthCheckContentLoader(WidgetContentRepository widgetContentRepository) { + this.widgetContentRepository = widgetContentRepository; + } + + @Override + public Map<String, Object> loadContent(List<String> contentFields, + Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, + String[] attributes, MultiValueMap<String, String> params, int limit) { + + List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); + List<String> attributeValues = ofNullable(attributes).map(Arrays::asList) + .orElseGet(Collections::emptyList); + + int currentLevel = attributeValues.size(); + BusinessRule.expect(attributeKeys, keys -> keys.size() > currentLevel) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Incorrect level definition"); + + Filter launchesFilter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort launchesSort = GROUP_SORTS.apply(filterSortMapping.values()); + + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + + Filter testItemFilter = Filter.builder() + .withTarget(TestItem.class) + .withCondition(getTestItemCondition(attributeKeys, attributeValues)) + .build(); + + String currentLevelKey = attributeKeys.get(currentLevel); + + List<ComponentHealthCheckContent> content = widgetContentRepository.componentHealthCheck( + launchesFilter, + launchesSort, + latestMode, + limit, + testItemFilter, + currentLevelKey + ); + + return CollectionUtils.isNotEmpty(content) ? Collections.singletonMap(RESULT, content) + : emptyMap(); + } + + private ConvertibleCondition getTestItemCondition(List<String> attributeKeys, + List<String> attributeValues) { + + List<ConvertibleCondition> conditions = Lists.newArrayList(FilterCondition.builder() + .eq(CRITERIA_HAS_STATS, String.valueOf(Boolean.TRUE)) + .build(), + FilterCondition.builder().eq(CRITERIA_HAS_CHILDREN, String.valueOf(Boolean.FALSE)).build(), + FilterCondition.builder().eq(CRITERIA_TYPE, TestItemTypeEnum.STEP.name()).build(), + FilterCondition.builder() + .withCondition(Condition.EXISTS) + .withNegative(true) + .withSearchCriteria(CRITERIA_RETRY_PARENT_ID) + .withValue(String.valueOf(0L)) + .build(), + FilterCondition.builder() + .withCondition(Condition.NOT_EQUALS) + .withNegative(false) + .withSearchCriteria(CRITERIA_STATUS) + .withValue(StatusEnum.IN_PROGRESS.name()) + .build() + ); + + if (CollectionUtils.isNotEmpty(attributeValues)) { + String attributeCriteria = IntStream.range(0, attributeValues.size()).mapToObj(index -> { + String attributeKey = attributeKeys.get(index); + String attributeValue = attributeValues.get(index); + return String.join(KEY_VALUE_SEPARATOR, attributeKey, attributeValue); + }).collect(joining(",")); + + conditions.add(FilterCondition.builder() + .withCondition(Condition.HAS) + .withNegative(false) + .withSearchCriteria(CRITERIA_COMPOSITE_ATTRIBUTE) + .withValue(attributeCriteria) + .build()); + } + + return new CompositeFilterCondition(conditions); + + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/FlakyCasesTableContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/FlakyCasesTableContentLoader.java index f12c470966..585e1e3cfa 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/FlakyCasesTableContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/FlakyCasesTableContentLoader.java @@ -16,6 +16,15 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.FLAKY; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.INCLUDE_METHODS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_LAUNCH; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -28,58 +37,56 @@ import com.epam.ta.reportportal.entity.widget.content.FlakyCasesTableContent; import com.epam.ta.reportportal.entity.widget.content.LatestLaunchContent; import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static java.util.Collections.emptyMap; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class FlakyCasesTableContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetRepository; + @Autowired + private WidgetContentRepository widgetRepository; - @Autowired - private LaunchRepository launchRepository; + @Autowired + private LaunchRepository launchRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); - filter.withCondition(new FilterCondition(Condition.EQUALS, false, launchName, CRITERIA_NAME)); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); + filter.withCondition(new FilterCondition(Condition.EQUALS, false, launchName, CRITERIA_NAME)); - return launchRepository.findLatestByFilter(filter) - .map(l -> loadContent(l, filter, widgetOptions, limit)) - .orElseGet(Collections::emptyMap); + return launchRepository.findLatestByFilter(filter) + .map(l -> loadContent(l, filter, widgetOptions, limit)) + .orElseGet(Collections::emptyMap); - } + } - private Map<String, ?> loadContent(Launch launch, Filter filter, WidgetOptions widgetOptions, int limit) { - LatestLaunchContent latestLaunchContent = new LatestLaunchContent(launch); + private Map<String, ?> loadContent(Launch launch, Filter filter, WidgetOptions widgetOptions, + int limit) { + LatestLaunchContent latestLaunchContent = new LatestLaunchContent(launch); - List<FlakyCasesTableContent> flakyCasesTableContent = widgetRepository.flakyCasesStatistics(filter, - ofNullable(widgetOptions.getOptions().get(INCLUDE_METHODS)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))) - .orElse(false), - limit - ); - return CollectionUtils.isEmpty(flakyCasesTableContent) ? - emptyMap() : - ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, latestLaunchContent).put(FLAKY, flakyCasesTableContent).build(); - } + List<FlakyCasesTableContent> flakyCasesTableContent = widgetRepository.flakyCasesStatistics( + filter, + ofNullable(widgetOptions.getOptions().get(INCLUDE_METHODS)).map( + v -> BooleanUtils.toBoolean(String.valueOf(v))) + .orElse(false), + limit + ); + return CollectionUtils.isEmpty(flakyCasesTableContent) ? + emptyMap() : + ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, latestLaunchContent) + .put(FLAKY, flakyCasesTableContent).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchExecutionAndIssueStatisticsContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchExecutionAndIssueStatisticsContentLoader.java index 73034fdad1..693dbff593 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchExecutionAndIssueStatisticsContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchExecutionAndIssueStatisticsContentLoader.java @@ -16,43 +16,44 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class LaunchExecutionAndIssueStatisticsContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<ChartStatisticsContent> content = widgetContentRepository.launchStatistics(filter, contentFields, sort, limit); + List<ChartStatisticsContent> content = widgetContentRepository.launchStatistics(filter, + contentFields, sort, limit); - return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); - } + return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesComparisonContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesComparisonContentLoader.java index 6c1adf2880..5e3422d4c5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesComparisonContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesComparisonContentLoader.java @@ -16,25 +16,24 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_NUMBER; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_START_TIME; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_NUMBER; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; /** * @author Pavel Bortnik @@ -42,24 +41,27 @@ @Service public class LaunchesComparisonContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = Sort.by(Sort.Order.desc(CRITERIA_START_TIME), Sort.Order.desc(CRITERIA_LAUNCH_NUMBER)); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = Sort.by(Sort.Order.desc(CRITERIA_START_TIME), + Sort.Order.desc(CRITERIA_LAUNCH_NUMBER)); - List<ChartStatisticsContent> result = widgetContentRepository.launchesComparisonStatistics(filter, contentFields, sort, limit); + List<ChartStatisticsContent> result = widgetContentRepository.launchesComparisonStatistics( + filter, contentFields, sort, limit); - if (result.isEmpty()) { - return emptyMap(); - } else { - Collections.reverse(result); - return singletonMap(RESULT, result); - } - } + if (result.isEmpty()) { + return emptyMap(); + } else { + Collections.reverse(result); + return singletonMap(RESULT, result); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesDurationContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesDurationContentLoader.java index 6928cb1478..206aa12bed 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesDurationContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesDurationContentLoader.java @@ -16,48 +16,49 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.LaunchesDurationContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class LaunchesDurationContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - List<LaunchesDurationContent> result = widgetContentRepository.launchesDurationStatistics(filter, sort, latestMode, limit); + List<LaunchesDurationContent> result = widgetContentRepository.launchesDurationStatistics( + filter, sort, latestMode, limit); - return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); - } + return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesTableContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesTableContentLoader.java index 6bb2ef1993..a9f9ba9e9e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesTableContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LaunchesTableContentLoader.java @@ -16,44 +16,45 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.LaunchesTableContent; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class LaunchesTableContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<LaunchesTableContent> content = widgetContentRepository.launchesTableStatistics(filter, contentFields, sort, limit); + List<LaunchesTableContent> content = widgetContentRepository.launchesTableStatistics(filter, + contentFields, sort, limit); - return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); - } + return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LineChartContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LineChartContentLoader.java index 4048bd0486..d6400b492c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LineChartContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/LineChartContentLoader.java @@ -16,12 +16,23 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.util.Strings; @@ -29,46 +40,39 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.TIMELINE; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; -import static java.util.Optional.ofNullable; - /** * @author Pavel Bortnik */ @Service -public class LineChartContentLoader extends AbstractStatisticsContentLoader implements LoadContentStrategy { +public class LineChartContentLoader extends AbstractStatisticsContentLoader implements + LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<ChartStatisticsContent> content = widgetContentRepository.launchStatistics(filter, contentFields, sort, limit); + List<ChartStatisticsContent> content = widgetContentRepository.launchStatistics(filter, + contentFields, sort, limit); - String timeLineOption = ofNullable(widgetOptions).map(wo -> WidgetOptionUtil.getValueByKey(TIMELINE, wo)).orElse(Strings.EMPTY); - if (StringUtils.isNotBlank(timeLineOption)) { - Optional<Period> period = Period.findByName(timeLineOption); - if (period.isPresent()) { - return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, groupByDate(content, period.get())); - } + String timeLineOption = ofNullable(widgetOptions).map( + wo -> WidgetOptionUtil.getValueByKey(TIMELINE, wo)).orElse(Strings.EMPTY); + if (StringUtils.isNotBlank(timeLineOption)) { + Optional<Period> period = Period.findByName(timeLineOption); + if (period.isPresent()) { + return CollectionUtils.isEmpty(content) ? emptyMap() + : singletonMap(RESULT, groupByDate(content, period.get())); + } - } + } - return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); - } + return CollectionUtils.isEmpty(content) ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/MostTimeConsumingContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/MostTimeConsumingContentLoader.java index 8e6b406042..830dcce37a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/MostTimeConsumingContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/MostTimeConsumingContentLoader.java @@ -16,6 +16,23 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_CHILDREN; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_HAS_STATS; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_STATUS; +import static com.epam.ta.reportportal.core.filter.predefined.PredefinedFilters.HAS_METHOD_OR_CLASS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.CONTENT_FIELDS_DELIMITER; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.INCLUDE_METHODS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ITEM_TYPE; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_LAUNCH; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.jooq.enums.JTestItemTypeEnum.STEP; +import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -32,6 +49,10 @@ import com.epam.ta.reportportal.entity.widget.content.MostTimeConsumingTestCasesContent; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -39,109 +60,107 @@ import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.*; -import static com.epam.ta.reportportal.core.filter.predefined.PredefinedFilters.HAS_METHOD_OR_CLASS; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.jooq.enums.JTestItemTypeEnum.STEP; -import static java.util.Collections.emptyMap; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class MostTimeConsumingContentLoader implements LoadContentStrategy { - public static final int MOST_TIME_CONSUMING_CASES_COUNT = 20; - - private final LaunchRepository launchRepository; - private final WidgetContentRepository widgetContentRepository; - - @Autowired - public MostTimeConsumingContentLoader(LaunchRepository launchRepository, WidgetContentRepository widgetContentRepository) { - this.launchRepository = launchRepository; - this.widgetContentRepository = widgetContentRepository; - } - - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, int limit) { - - Filter filter = GROUP_FILTERS.apply(filterSortMap.keySet()); - String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); - - return launchRepository.findLatestByFilter(filter.withCondition(FilterCondition.builder().eq(CRITERIA_NAME, launchName).build())) - .map(l -> loadContent(l, widgetOptions, contentFields)) - .orElseGet(Collections::emptyMap); - - } - - private Map<String, ?> loadContent(Launch launch, WidgetOptions widgetOptions, List<String> contentFields) { - final List<MostTimeConsumingTestCasesContent> content = widgetContentRepository.mostTimeConsumingTestCasesStatistics(buildItemFilter( - launch.getId(), - widgetOptions, - contentFields - ), MOST_TIME_CONSUMING_CASES_COUNT); - - return content.isEmpty() ? - emptyMap() : - ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, new LatestLaunchContent(launch)).put(RESULT, content).build(); - } - - private Filter buildItemFilter(Long launchId, WidgetOptions widgetOptions, List<String> contentFields) { - Filter filter = Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) - .build(); - filter = updateFilterWithStatuses(filter, contentFields); - filter = updateFilterWithTestItemTypes(filter, - ofNullable(widgetOptions.getOptions().get(INCLUDE_METHODS)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))) - .orElse(false) - ); - return filter.withCondition(FilterCondition.builder().eq(CRITERIA_HAS_CHILDREN, Boolean.FALSE.toString()).build()) - .withCondition(FilterCondition.builder().eq(CRITERIA_HAS_STATS, Boolean.TRUE.toString()).build()); - } - - private Filter updateFilterWithStatuses(Filter filter, List<String> contentFields) { - if (CollectionUtils.isNotEmpty(contentFields)) { - String statusCriteria = contentFields.stream() - .filter(StringUtils::isNotBlank) - .map(it -> it.split("\\$")) - .map(split -> split[split.length - 1].toUpperCase()) - .filter(cf -> StatusEnum.fromValue(cf).isPresent()) - .collect(Collectors.joining(", ")); - return filter.withCondition(FilterCondition.builder() - .withSearchCriteria(CRITERIA_STATUS) - .withCondition(Condition.IN) - .withValue(statusCriteria) - .build()); - } - return filter; - } - - private Filter updateFilterWithTestItemTypes(Filter filter, boolean includeMethodsFlag) { - return includeMethodsFlag ? updateFilterWithStepAndBeforeAfterMethods(filter) : updateFilterWithStepTestItem(filter); - } - - private Filter updateFilterWithStepTestItem(Filter filter) { - return filter.withCondition(FilterCondition.builder().eq(ITEM_TYPE, STEP.getLiteral()).build()); - } - - private Filter updateFilterWithStepAndBeforeAfterMethods(Filter filter) { - List<TestItemTypeEnum> itemTypes = Lists.newArrayList(TestItemTypeEnum.STEP); - itemTypes.addAll(HAS_METHOD_OR_CLASS); - - return filter.withCondition(FilterCondition.builder() - .withCondition(Condition.IN) - .withSearchCriteria(ITEM_TYPE) - .withValue(itemTypes.stream().map(TestItemTypeEnum::name).collect(Collectors.joining(CONTENT_FIELDS_DELIMITER))) - .build()); - } + public static final int MOST_TIME_CONSUMING_CASES_COUNT = 20; + + private final LaunchRepository launchRepository; + private final WidgetContentRepository widgetContentRepository; + + @Autowired + public MostTimeConsumingContentLoader(LaunchRepository launchRepository, + WidgetContentRepository widgetContentRepository) { + this.launchRepository = launchRepository; + this.widgetContentRepository = widgetContentRepository; + } + + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, int limit) { + + Filter filter = GROUP_FILTERS.apply(filterSortMap.keySet()); + String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); + + return launchRepository.findLatestByFilter( + filter.withCondition(FilterCondition.builder().eq(CRITERIA_NAME, launchName).build())) + .map(l -> loadContent(l, widgetOptions, contentFields)) + .orElseGet(Collections::emptyMap); + + } + + private Map<String, ?> loadContent(Launch launch, WidgetOptions widgetOptions, + List<String> contentFields) { + final List<MostTimeConsumingTestCasesContent> content = widgetContentRepository.mostTimeConsumingTestCasesStatistics( + buildItemFilter( + launch.getId(), + widgetOptions, + contentFields + ), MOST_TIME_CONSUMING_CASES_COUNT); + + return content.isEmpty() ? + emptyMap() : + ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, new LatestLaunchContent(launch)) + .put(RESULT, content).build(); + } + + private Filter buildItemFilter(Long launchId, WidgetOptions widgetOptions, + List<String> contentFields) { + Filter filter = Filter.builder() + .withTarget(TestItem.class) + .withCondition( + FilterCondition.builder().eq(CRITERIA_LAUNCH_ID, String.valueOf(launchId)).build()) + .build(); + filter = updateFilterWithStatuses(filter, contentFields); + filter = updateFilterWithTestItemTypes(filter, + ofNullable(widgetOptions.getOptions().get(INCLUDE_METHODS)).map( + v -> BooleanUtils.toBoolean(String.valueOf(v))) + .orElse(false) + ); + return filter.withCondition( + FilterCondition.builder().eq(CRITERIA_HAS_CHILDREN, Boolean.FALSE.toString()).build()) + .withCondition( + FilterCondition.builder().eq(CRITERIA_HAS_STATS, Boolean.TRUE.toString()).build()); + } + + private Filter updateFilterWithStatuses(Filter filter, List<String> contentFields) { + if (CollectionUtils.isNotEmpty(contentFields)) { + String statusCriteria = contentFields.stream() + .filter(StringUtils::isNotBlank) + .map(it -> it.split("\\$")) + .map(split -> split[split.length - 1].toUpperCase()) + .filter(cf -> StatusEnum.fromValue(cf).isPresent()) + .collect(Collectors.joining(", ")); + return filter.withCondition(FilterCondition.builder() + .withSearchCriteria(CRITERIA_STATUS) + .withCondition(Condition.IN) + .withValue(statusCriteria) + .build()); + } + return filter; + } + + private Filter updateFilterWithTestItemTypes(Filter filter, boolean includeMethodsFlag) { + return includeMethodsFlag ? updateFilterWithStepAndBeforeAfterMethods(filter) + : updateFilterWithStepTestItem(filter); + } + + private Filter updateFilterWithStepTestItem(Filter filter) { + return filter.withCondition(FilterCondition.builder().eq(ITEM_TYPE, STEP.getLiteral()).build()); + } + + private Filter updateFilterWithStepAndBeforeAfterMethods(Filter filter) { + List<TestItemTypeEnum> itemTypes = Lists.newArrayList(TestItemTypeEnum.STEP); + itemTypes.addAll(HAS_METHOD_OR_CLASS); + + return filter.withCondition(FilterCondition.builder() + .withCondition(Condition.IN) + .withSearchCriteria(ITEM_TYPE) + .withValue(itemTypes.stream().map(TestItemTypeEnum::name) + .collect(Collectors.joining(CONTENT_FIELDS_DELIMITER))) + .build()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/NotPassedTestsContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/NotPassedTestsContentLoader.java index 55f2585d9b..1ef5293bbc 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/NotPassedTestsContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/NotPassedTestsContentLoader.java @@ -16,43 +16,44 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.NotPassedCasesContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class NotPassedTestsContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<NotPassedCasesContent> result = widgetContentRepository.notPassedCasesStatistics(filter, sort, limit); + List<NotPassedCasesContent> result = widgetContentRepository.notPassedCasesStatistics(filter, + sort, limit); - return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); - } + return result.isEmpty() ? emptyMap() : singletonMap(RESULT, result); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/OverallStatisticsContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/OverallStatisticsContentLoader.java index aa73d15389..ad8f1c878b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/OverallStatisticsContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/OverallStatisticsContentLoader.java @@ -16,49 +16,51 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.OverallStatisticsContent; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class OverallStatisticsContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - OverallStatisticsContent content = widgetContentRepository.overallStatisticsContent(filter, sort, contentFields, latestMode, limit); + OverallStatisticsContent content = widgetContentRepository.overallStatisticsContent(filter, + sort, contentFields, latestMode, limit); - return MapUtils.isEmpty(content.getValues()) ? emptyMap() : singletonMap(RESULT, Collections.singletonList(content)); - } + return MapUtils.isEmpty(content.getValues()) ? emptyMap() + : singletonMap(RESULT, Collections.singletonList(content)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRatePerLaunchContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRatePerLaunchContentLoader.java index 15f48292d0..bad29eb139 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRatePerLaunchContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRatePerLaunchContentLoader.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -26,20 +33,12 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.PassingRateStatisticsResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -47,30 +46,33 @@ @Service public class PassingRatePerLaunchContentLoader implements LoadContentStrategy { - @Autowired - private LaunchRepository launchRepository; + @Autowired + private LaunchRepository launchRepository; - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + String launchName = WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - return launchRepository.findLatestByFilter(filter.withCondition(new FilterCondition(Condition.EQUALS, - false, - launchName, - CRITERIA_NAME - ))).map(this::loadContent).orElseGet(Collections::emptyMap); + return launchRepository.findLatestByFilter( + filter.withCondition(new FilterCondition(Condition.EQUALS, + false, + launchName, + CRITERIA_NAME + ))).map(this::loadContent).orElseGet(Collections::emptyMap); - } + } - private Map<String, ?> loadContent(Launch launch) { - PassingRateStatisticsResult result = widgetContentRepository.passingRatePerLaunchStatistics(launch.getId()); - return result.getTotal() != 0 ? singletonMap(RESULT, result) : emptyMap(); - } + private Map<String, ?> loadContent(Launch launch) { + PassingRateStatisticsResult result = widgetContentRepository.passingRatePerLaunchStatistics( + launch.getId()); + return result.getTotal() != 0 ? singletonMap(RESULT, result) : emptyMap(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRateSummaryContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRateSummaryContentLoader.java index c26a3e510e..a23f0c2bc6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRateSummaryContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/PassingRateSummaryContentLoader.java @@ -16,42 +16,43 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.PassingRateStatisticsResult; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class PassingRateSummaryContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - PassingRateStatisticsResult result = widgetContentRepository.summaryPassingRateStatistics(filter, sort, limit); - return result.getTotal() != 0 ? singletonMap(RESULT, result) : emptyMap(); - } + PassingRateStatisticsResult result = widgetContentRepository.summaryPassingRateStatistics( + filter, sort, limit); + return result.getTotal() != 0 ? singletonMap(RESULT, result) : emptyMap(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusContentLoader.java index 5c55a6446b..39ee85a339 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusContentLoader.java @@ -22,4 +22,5 @@ * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface ProductStatusContentLoader extends LoadContentStrategy { + } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusFilterGroupedContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusFilterGroupedContentLoader.java index 43dc545c1f..fc2be5abbd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusFilterGroupedContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusFilterGroupedContentLoader.java @@ -16,47 +16,51 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.CUSTOM_COLUMNS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ProductStatusStatisticsContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProductStatusFilterGroupedContentLoader implements ProductStatusContentLoader { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Map<String, String> attributeColumns = WidgetOptionUtil.getMapByKey(CUSTOM_COLUMNS, widgetOptions); + Map<String, String> attributeColumns = WidgetOptionUtil.getMapByKey(CUSTOM_COLUMNS, + widgetOptions); - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - final Map<String, List<ProductStatusStatisticsContent>> content = widgetContentRepository.productStatusGroupedByFilterStatistics(filterSortMapping, - contentFields, - attributeColumns, - latestMode, - limit - ); + final Map<String, List<ProductStatusStatisticsContent>> content = widgetContentRepository.productStatusGroupedByFilterStatistics( + filterSortMapping, + contentFields, + attributeColumns, + latestMode, + limit + ); - return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); - } + return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusLaunchGroupedContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusLaunchGroupedContentLoader.java index dedfbc031b..7778419b26 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusLaunchGroupedContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/ProductStatusLaunchGroupedContentLoader.java @@ -16,53 +16,57 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.CUSTOM_COLUMNS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.ProductStatusStatisticsContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProductStatusLaunchGroupedContentLoader implements ProductStatusContentLoader { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Map<String, String> attributeColumns = WidgetOptionUtil.getMapByKey(CUSTOM_COLUMNS, widgetOptions); + Map<String, String> attributeColumns = WidgetOptionUtil.getMapByKey(CUSTOM_COLUMNS, + widgetOptions); - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - final List<ProductStatusStatisticsContent> content = widgetContentRepository.productStatusGroupedByLaunchesStatistics(filter, - contentFields, - attributeColumns, - sort, - latestMode, - limit - ); + final List<ProductStatusStatisticsContent> content = widgetContentRepository.productStatusGroupedByLaunchesStatistics( + filter, + contentFields, + attributeColumns, + sort, + latestMode, + limit + ); - return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); - } + return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopPatternContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopPatternContentLoader.java index 0ddacd1536..6a14deaa57 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopPatternContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopPatternContentLoader.java @@ -16,57 +16,61 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEY; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.PATTERN_TEMPLATE_NAME; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.MultilevelLoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.TopPatternTemplatesContent; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class TopPatternContentLoader implements MultilevelLoadContentStrategy { - public static final Integer TOP_PATTERN_TEMPLATES_ATTRIBUTES_COUNT = 15; + public static final Integer TOP_PATTERN_TEMPLATES_ATTRIBUTES_COUNT = 15; - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, Object> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - String[] attributes, MultiValueMap<String, String> params, int limit) { - final List<TopPatternTemplatesContent> content = getContent(filterSortMapping, widgetOptions, params, limit); - return content.isEmpty() ? Collections.emptyMap() : Collections.singletonMap(RESULT, content); - } + @Override + public Map<String, Object> loadContent(List<String> contentFields, + Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, + String[] attributes, MultiValueMap<String, String> params, int limit) { + final List<TopPatternTemplatesContent> content = getContent(filterSortMapping, widgetOptions, + params, limit); + return content.isEmpty() ? Collections.emptyMap() : Collections.singletonMap(RESULT, content); + } - private List<TopPatternTemplatesContent> getContent(Map<Filter, Sort> filterSortMapping, - WidgetOptions widgetOptions, MultiValueMap<String, String> params, int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + private List<TopPatternTemplatesContent> getContent(Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, MultiValueMap<String, String> params, int limit) { + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - List<TopPatternTemplatesContent> content = widgetContentRepository.patternTemplate(filter, - sort, - WidgetOptionUtil.getValueByKey(ATTRIBUTE_KEY, widgetOptions), - params.getFirst(PATTERN_TEMPLATE_NAME), - WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions), limit, - TOP_PATTERN_TEMPLATES_ATTRIBUTES_COUNT - ); - Collections.reverse(content); - return content; - } + List<TopPatternTemplatesContent> content = widgetContentRepository.patternTemplate(filter, + sort, + WidgetOptionUtil.getValueByKey(ATTRIBUTE_KEY, widgetOptions), + params.getFirst(PATTERN_TEMPLATE_NAME), + WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions), limit, + TOP_PATTERN_TEMPLATES_ATTRIBUTES_COUNT + ); + Collections.reverse(content); + return content; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopTestCasesContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopTestCasesContentLoader.java index 19fb7baead..5c96974860 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopTestCasesContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/TopTestCasesContentLoader.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.INCLUDE_METHODS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_LAUNCH; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; @@ -26,21 +34,15 @@ import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.converter.converters.LaunchConverter; import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static java.util.Optional.ofNullable; - /** * Content loader for {@link com.epam.ta.reportportal.entity.widget.WidgetType#TOP_TEST_CASES} * @@ -49,45 +51,48 @@ @Service public class TopTestCasesContentLoader implements LoadContentStrategy { - private final LaunchRepository launchRepository; + private final LaunchRepository launchRepository; - private final LaunchConverter launchConverter; + private final LaunchConverter launchConverter; - private final WidgetContentRepository widgetContentRepository; + private final WidgetContentRepository widgetContentRepository; - @Autowired - public TopTestCasesContentLoader(LaunchRepository launchRepository, LaunchConverter launchConverter, - WidgetContentRepository widgetContentRepository) { - this.launchRepository = launchRepository; - this.launchConverter = launchConverter; - this.widgetContentRepository = widgetContentRepository; - } + @Autowired + public TopTestCasesContentLoader(LaunchRepository launchRepository, + LaunchConverter launchConverter, + WidgetContentRepository widgetContentRepository) { + this.launchRepository = launchRepository; + this.launchConverter = launchConverter; + this.widgetContentRepository = widgetContentRepository; + } - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { - String criteria = contentFields.get(0); - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()) - .withCondition(new FilterCondition(Condition.EQUALS, - false, - WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), - CRITERIA_NAME - )); + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { + String criteria = contentFields.get(0); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()) + .withCondition(new FilterCondition(Condition.EQUALS, + false, + WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), + CRITERIA_NAME + )); - return launchRepository.findLatestByFilter(filter) - .map(it -> Pair.of(it, - widgetContentRepository.topItemsByCriteria(filter, - criteria, - limit, - ofNullable(widgetOptions.getOptions() - .get(INCLUDE_METHODS)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))).orElse(false) - ) - )) - .filter(it -> !it.getRight().isEmpty()) - .map(it -> (Map<String, ?>) ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, - launchConverter.TO_RESOURCE.apply(it.getLeft()) - ).put(RESULT, it.getRight()).build()) - .orElse(Collections.emptyMap()); - } + return launchRepository.findLatestByFilter(filter) + .map(it -> Pair.of(it, + widgetContentRepository.topItemsByCriteria(filter, + criteria, + limit, + ofNullable(widgetOptions.getOptions() + .get(INCLUDE_METHODS)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))) + .orElse(false) + ) + )) + .filter(it -> !it.getRight().isEmpty()) + .map(it -> (Map<String, ?>) ImmutableMap.<String, Object>builder().put(LATEST_LAUNCH, + launchConverter.TO_RESOURCE.apply(it.getLeft()) + ).put(RESULT, it.getRight()).build()) + .orElse(Collections.emptyMap()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/UniqueBugContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/UniqueBugContentLoader.java index d5f54c93cc..43ea8b56c6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/UniqueBugContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/UniqueBugContentLoader.java @@ -16,47 +16,48 @@ package com.epam.ta.reportportal.core.widget.content.loader; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; +import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.content.UniqueBugContent; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_FILTERS; -import static com.epam.ta.reportportal.core.widget.util.WidgetFilterUtil.GROUP_SORTS; -import static java.util.Collections.emptyMap; -import static java.util.Collections.singletonMap; - /** * @author Pavel Bortnik */ @Service public class UniqueBugContentLoader implements LoadContentStrategy { - @Autowired - private WidgetContentRepository widgetRepository; + @Autowired + private WidgetContentRepository widgetRepository; - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); - Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); + Filter filter = GROUP_FILTERS.apply(filterSortMapping.keySet()); + Sort sort = GROUP_SORTS.apply(filterSortMapping.values()); - boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); + boolean latestMode = WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widgetOptions); - Map<String, UniqueBugContent> content = widgetRepository.uniqueBugStatistics(filter, sort, latestMode, limit); + Map<String, UniqueBugContent> content = widgetRepository.uniqueBugStatistics(filter, sort, + latestMode, limit); - return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); - } + return content.isEmpty() ? emptyMap() : singletonMap(RESULT, content); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/CumulativeTrendChartContentLoaderImpl.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/CumulativeTrendChartContentLoaderImpl.java index be71ac9583..5e29129ce2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/CumulativeTrendChartContentLoaderImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/CumulativeTrendChartContentLoaderImpl.java @@ -16,29 +16,28 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.KEY_VALUE_SEPARATOR; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.content.CumulativeTrendChartEntry; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.ImmutableMap; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.MultiValueMap; - import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.KEY_VALUE_SEPARATOR; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> @@ -46,40 +45,44 @@ @Service public class CumulativeTrendChartContentLoaderImpl implements MaterializedWidgetContentLoader { - @Autowired - private WidgetContentRepository widgetContentRepository; + @Autowired + private WidgetContentRepository widgetContentRepository; - @Override - public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { - List<CumulativeTrendChartEntry> content; - List<String> storedAttributes = WidgetOptionUtil.getListByKey(ATTRIBUTES, widget.getWidgetOptions()); - List<String> providedAttributes = ofNullable(params.get(ATTRIBUTES)).map(attributes -> attributes.stream() - .filter(StringUtils::isNotBlank) - .collect(Collectors.toList())).orElseGet(Collections::emptyList); - if (providedAttributes.isEmpty()) { - content = widgetContentRepository.cumulativeTrendChart( - (String) widget.getWidgetOptions().getOptions().get(VIEW_NAME), - storedAttributes.get(0), - storedAttributes.size() > 1 ? storedAttributes.get(1) : null, - null - ); - } else { - verifyProvidedAttributes(storedAttributes, providedAttributes); - content = widgetContentRepository.cumulativeTrendChart( - (String) widget.getWidgetOptions().getOptions().get(VIEW_NAME), - storedAttributes.get(1), - null, - providedAttributes.get(0) - ); - } + @Override + public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { + List<CumulativeTrendChartEntry> content; + List<String> storedAttributes = WidgetOptionUtil.getListByKey(ATTRIBUTES, + widget.getWidgetOptions()); + List<String> providedAttributes = ofNullable(params.get(ATTRIBUTES)).map( + attributes -> attributes.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList())).orElseGet(Collections::emptyList); + if (providedAttributes.isEmpty()) { + content = widgetContentRepository.cumulativeTrendChart( + (String) widget.getWidgetOptions().getOptions().get(VIEW_NAME), + storedAttributes.get(0), + storedAttributes.size() > 1 ? storedAttributes.get(1) : null, + null + ); + } else { + verifyProvidedAttributes(storedAttributes, providedAttributes); + content = widgetContentRepository.cumulativeTrendChart( + (String) widget.getWidgetOptions().getOptions().get(VIEW_NAME), + storedAttributes.get(1), + null, + providedAttributes.get(0) + ); + } - return ImmutableMap.<String, Object>builder().put(RESULT, content).build(); - } + return ImmutableMap.<String, Object>builder().put(RESULT, content).build(); + } - private void verifyProvidedAttributes(List<String> storedKeys, List<String> providedAttributes) { - String[] split = providedAttributes.get(0).split(KEY_VALUE_SEPARATOR); - expect(split.length, Predicate.isEqual(2)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); - expect(storedKeys.contains(split[0]), Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); - expect(StringUtils.isNoneEmpty(split[1]), Predicate.isEqual(true)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); - } + private void verifyProvidedAttributes(List<String> storedKeys, List<String> providedAttributes) { + String[] split = providedAttributes.get(0).split(KEY_VALUE_SEPARATOR); + expect(split.length, Predicate.isEqual(2)).verify(ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); + expect(storedKeys.contains(split[0]), Predicate.isEqual(true)).verify( + ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); + expect(StringUtils.isNoneEmpty(split[1]), Predicate.isEqual(true)).verify( + ErrorType.BAD_REQUEST_ERROR, ATTRIBUTES); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/HealthCheckTableReadyContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/HealthCheckTableReadyContentLoader.java index d824c61e25..8e68f5a94d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/HealthCheckTableReadyContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/HealthCheckTableReadyContentLoader.java @@ -1,5 +1,15 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.RESULT; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.groupingBy; + import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; @@ -14,13 +24,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; -import org.springframework.util.MultiValueMap; - import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Collection; @@ -29,14 +32,12 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.*; -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; -import static java.util.Collections.emptyMap; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.groupingBy; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -44,94 +45,108 @@ @Service(value = "healthCheckTableReadyContentLoader") public class HealthCheckTableReadyContentLoader implements MaterializedWidgetContentLoader { - public static final String SORT = "sort"; - public static final String CUSTOM_COLUMN = "customColumn"; - - public static final String TOTAL = "total"; - public static final String STATISTICS = "statistics"; - public static final String PASSING_RATE = "passingRate"; - - private final WidgetContentRepository widgetContentRepository; - private final ObjectMapper objectMapper; - - @Autowired - public HealthCheckTableReadyContentLoader(WidgetContentRepository widgetContentRepository, ObjectMapper objectMapper) { - this.widgetContentRepository = widgetContentRepository; - this.objectMapper = objectMapper; - } - - @Override - public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { - HealthCheckTableGetParams getParams = getParams(widget.getWidgetOptions(), - ofNullable(params.get(ATTRIBUTES)).map(attributes -> attributes.stream() - .filter(StringUtils::isNotBlank) - .collect(Collectors.toList())).orElseGet(Collections::emptyList) - ); - List<HealthCheckTableContent> content = widgetContentRepository.componentHealthCheckTable(getParams); - - if (CollectionUtils.isEmpty(content)) { - return emptyMap(); - } - - Map<String, Integer> totalStatistics = content.stream() - .map(HealthCheckTableContent::getStatistics) - .map(Map::entrySet) - .flatMap(Collection::stream) - .collect(groupingBy(Map.Entry::getKey, Collectors.summingInt(Map.Entry::getValue))); - - return ImmutableMap.<String, Object>builder().put(RESULT, content) - .put(TOTAL, - ImmutableMap.<String, Object>builder().put(STATISTICS, totalStatistics) - .put(PASSING_RATE, calculatePassingRate(totalStatistics)) - .build() - ) - .build(); - } - - private HealthCheckTableGetParams getParams(WidgetOptions widgetOptions, List<String> attributeValues) { - List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); - int currentLevel = attributeValues.size(); - BusinessRule.expect(attributeKeys, keys -> keys.size() > currentLevel) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Incorrect level definition"); - - String viewName = ofNullable(WidgetOptionUtil.getValueByKey(VIEW_NAME, widgetOptions)).orElseThrow(() -> new ReportPortalException( - ErrorType.UNABLE_LOAD_WIDGET_CONTENT, - "Widget view name not provided" - )); - String currentLevelKey = attributeKeys.get(currentLevel); - boolean includeCustomColumn = ofNullable(WidgetOptionUtil.getValueByKey(CUSTOM_COLUMN, widgetOptions)).isPresent(); - - return HealthCheckTableGetParams.of(viewName, - currentLevelKey, - resolveSort(widgetOptions), - includeCustomColumn, - getLevelEntries(attributeKeys, attributeValues) - ); - - } - - private Sort resolveSort(WidgetOptions widgetOptions) { - return ofNullable(widgetOptions).flatMap(wo -> ofNullable(wo.getOptions()).map(options -> options.get(SORT))).map(s -> { - try { - SortEntry sortEntry = objectMapper.readValue(objectMapper.writeValueAsString(s), SortEntry.class); - return Sort.by(sortEntry.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC, sortEntry.getSortingColumn()); - } catch (JsonProcessingException e) { - throw new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Sort format error: " + e.getMessage()); - } - }).orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Sort parameter not provided")); - } - - private List<LevelEntry> getLevelEntries(List<String> attributeKeys, List<String> attributeValues) { - return IntStream.range(0, attributeValues.size()).mapToObj(index -> { - String attributeKey = attributeKeys.get(index); - String attributeValue = attributeValues.get(index); - return LevelEntry.of(attributeKey, attributeValue); - }).collect(Collectors.toList()); - } - - private double calculatePassingRate(Map<String, Integer> totalStatistics) { - double passingRate = 100.0 * totalStatistics.getOrDefault(EXECUTIONS_PASSED, 0) / totalStatistics.getOrDefault(EXECUTIONS_TOTAL, 1); - return new BigDecimal(passingRate).setScale(2, RoundingMode.HALF_UP).doubleValue(); - } + public static final String SORT = "sort"; + public static final String CUSTOM_COLUMN = "customColumn"; + + public static final String TOTAL = "total"; + public static final String STATISTICS = "statistics"; + public static final String PASSING_RATE = "passingRate"; + + private final WidgetContentRepository widgetContentRepository; + private final ObjectMapper objectMapper; + + @Autowired + public HealthCheckTableReadyContentLoader(WidgetContentRepository widgetContentRepository, + ObjectMapper objectMapper) { + this.widgetContentRepository = widgetContentRepository; + this.objectMapper = objectMapper; + } + + @Override + public Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params) { + HealthCheckTableGetParams getParams = getParams(widget.getWidgetOptions(), + ofNullable(params.get(ATTRIBUTES)).map(attributes -> attributes.stream() + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList())).orElseGet(Collections::emptyList) + ); + List<HealthCheckTableContent> content = widgetContentRepository.componentHealthCheckTable( + getParams); + + if (CollectionUtils.isEmpty(content)) { + return emptyMap(); + } + + Map<String, Integer> totalStatistics = content.stream() + .map(HealthCheckTableContent::getStatistics) + .map(Map::entrySet) + .flatMap(Collection::stream) + .collect(groupingBy(Map.Entry::getKey, Collectors.summingInt(Map.Entry::getValue))); + + return ImmutableMap.<String, Object>builder().put(RESULT, content) + .put(TOTAL, + ImmutableMap.<String, Object>builder().put(STATISTICS, totalStatistics) + .put(PASSING_RATE, calculatePassingRate(totalStatistics)) + .build() + ) + .build(); + } + + private HealthCheckTableGetParams getParams(WidgetOptions widgetOptions, + List<String> attributeValues) { + List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); + int currentLevel = attributeValues.size(); + BusinessRule.expect(attributeKeys, keys -> keys.size() > currentLevel) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Incorrect level definition"); + + String viewName = ofNullable( + WidgetOptionUtil.getValueByKey(VIEW_NAME, widgetOptions)).orElseThrow( + () -> new ReportPortalException( + ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Widget view name not provided" + )); + String currentLevelKey = attributeKeys.get(currentLevel); + boolean includeCustomColumn = ofNullable( + WidgetOptionUtil.getValueByKey(CUSTOM_COLUMN, widgetOptions)).isPresent(); + + return HealthCheckTableGetParams.of(viewName, + currentLevelKey, + resolveSort(widgetOptions), + includeCustomColumn, + getLevelEntries(attributeKeys, attributeValues) + ); + + } + + private Sort resolveSort(WidgetOptions widgetOptions) { + return ofNullable(widgetOptions).flatMap( + wo -> ofNullable(wo.getOptions()).map(options -> options.get(SORT))).map(s -> { + try { + SortEntry sortEntry = objectMapper.readValue(objectMapper.writeValueAsString(s), + SortEntry.class); + return Sort.by(sortEntry.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC, + sortEntry.getSortingColumn()); + } catch (JsonProcessingException e) { + throw new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Sort format error: " + e.getMessage()); + } + }).orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Sort parameter not provided")); + } + + private List<LevelEntry> getLevelEntries(List<String> attributeKeys, + List<String> attributeValues) { + return IntStream.range(0, attributeValues.size()).mapToObj(index -> { + String attributeKey = attributeKeys.get(index); + String attributeValue = attributeValues.get(index); + return LevelEntry.of(attributeKey, attributeValue); + }).collect(Collectors.toList()); + } + + private double calculatePassingRate(Map<String, Integer> totalStatistics) { + double passingRate = + 100.0 * totalStatistics.getOrDefault(EXECUTIONS_PASSED, 0) / totalStatistics.getOrDefault( + EXECUTIONS_TOTAL, 1); + return new BigDecimal(passingRate).setScale(2, RoundingMode.HALF_UP).doubleValue(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/MaterializedWidgetContentLoader.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/MaterializedWidgetContentLoader.java index f5b3c5fd9b..7e72360a15 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/MaterializedWidgetContentLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/MaterializedWidgetContentLoader.java @@ -1,14 +1,13 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.util.MultiValueMap; - import java.util.Map; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface MaterializedWidgetContentLoader { - Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params); + Map<String, Object> loadContent(Widget widget, MultiValueMap<String, String> params); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/AbstractViewGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/AbstractViewGenerator.java index d11638f56a..6993b9f8c3 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/AbstractViewGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/AbstractViewGenerator.java @@ -16,58 +16,59 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.generator; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetRepository; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetState; import com.epam.ta.reportportal.ws.converter.builders.WidgetBuilder; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.MultiValueMap; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Date; - -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public abstract class AbstractViewGenerator implements ViewGenerator { - public static final Logger LOGGER = LoggerFactory.getLogger(AbstractViewGenerator.class); + public static final Logger LOGGER = LoggerFactory.getLogger(AbstractViewGenerator.class); - private static final String LAST_REFRESH = "lastRefresh"; + private static final String LAST_REFRESH = "lastRefresh"; - private final WidgetRepository widgetRepository; + private final WidgetRepository widgetRepository; - public AbstractViewGenerator(WidgetRepository widgetRepository) { - this.widgetRepository = widgetRepository; - } + public AbstractViewGenerator(WidgetRepository widgetRepository) { + this.widgetRepository = widgetRepository; + } - protected abstract void generateView(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params); + protected abstract void generateView(boolean refresh, String viewName, Widget widget, + Filter launchesFilter, Sort launchesSort, + MultiValueMap<String, String> params); - @Transactional - public void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params) { - LOGGER.debug("Widget {} - {}. Generation started", widget.getWidgetType(), widget.getId()); - generateView(refresh, viewName, widget, launchesFilter, launchesSort, params); - LOGGER.debug("Widget {} - {}. Generation finished", widget.getWidgetType(), widget.getId()); - widgetRepository.save(new WidgetBuilder(widget).addOption(STATE, WidgetState.READY.getValue()) - .addOption(VIEW_NAME, viewName) - .addOption(LAST_REFRESH, Date.from(LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant())) - .get()); - LOGGER.debug("Widget {} - {}. State updated to: {}", - widget.getWidgetType(), - widget.getId(), - WidgetOptionUtil.getValueByKey(STATE, widget.getWidgetOptions()) - ); - } + @Transactional + public void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, + Sort launchesSort, + MultiValueMap<String, String> params) { + LOGGER.debug("Widget {} - {}. Generation started", widget.getWidgetType(), widget.getId()); + generateView(refresh, viewName, widget, launchesFilter, launchesSort, params); + LOGGER.debug("Widget {} - {}. Generation finished", widget.getWidgetType(), widget.getId()); + widgetRepository.save(new WidgetBuilder(widget).addOption(STATE, WidgetState.READY.getValue()) + .addOption(VIEW_NAME, viewName) + .addOption(LAST_REFRESH, Date.from(LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant())) + .get()); + LOGGER.debug("Widget {} - {}. State updated to: {}", + widget.getWidgetType(), + widget.getId(), + WidgetOptionUtil.getValueByKey(STATE, widget.getWidgetOptions()) + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/CumulativeTrendChartViewGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/CumulativeTrendChartViewGenerator.java index fbfcac48bc..1be9646c51 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/CumulativeTrendChartViewGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/CumulativeTrendChartViewGenerator.java @@ -16,38 +16,40 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.generator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.dao.WidgetRepository; import com.epam.ta.reportportal.entity.widget.Widget; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.List; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Service public class CumulativeTrendChartViewGenerator extends AbstractViewGenerator { - private final WidgetContentRepository widgetContentRepository; - - @Autowired - public CumulativeTrendChartViewGenerator(WidgetRepository widgetRepository, WidgetContentRepository widgetContentRepository) { - super(widgetRepository); - this.widgetContentRepository = widgetContentRepository; - } - - @Override - protected void generateView(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params) { - List<String> attributes = WidgetOptionUtil.getListByKey(ATTRIBUTES, widget.getWidgetOptions()); - widgetContentRepository.generateCumulativeTrendChartView(refresh, viewName, launchesFilter, launchesSort, attributes, widget.getItemsCount()); - } + private final WidgetContentRepository widgetContentRepository; + + @Autowired + public CumulativeTrendChartViewGenerator(WidgetRepository widgetRepository, + WidgetContentRepository widgetContentRepository) { + super(widgetRepository); + this.widgetContentRepository = widgetContentRepository; + } + + @Override + protected void generateView(boolean refresh, String viewName, Widget widget, + Filter launchesFilter, Sort launchesSort, + MultiValueMap<String, String> params) { + List<String> attributes = WidgetOptionUtil.getListByKey(ATTRIBUTES, widget.getWidgetOptions()); + widgetContentRepository.generateCumulativeTrendChartView(refresh, viewName, launchesFilter, + launchesSort, attributes, widget.getItemsCount()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGenerator.java index 10bbdb4f21..fceca05e7e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGenerator.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.generator; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetRepository; @@ -27,36 +29,36 @@ import org.springframework.data.domain.Sort; import org.springframework.util.MultiValueMap; -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class FailedViewStateGenerator implements ViewGenerator { - public static final Logger LOGGER = LoggerFactory.getLogger(FailedViewStateGenerator.class); - - private final ViewGenerator delegate; - private final WidgetRepository widgetRepository; - - public FailedViewStateGenerator(ViewGenerator delegate, WidgetRepository widgetRepository) { - this.delegate = delegate; - this.widgetRepository = widgetRepository; - } - - @Override - public void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params) { - try { - delegate.generate(refresh, viewName, widget, launchesFilter, launchesSort, params); - } catch (Exception exc) { - LOGGER.error("Error during view creation: " + exc.getMessage()); - widgetRepository.save(new WidgetBuilder(widget).addOption(STATE, WidgetState.FAILED.getValue()).get()); - LOGGER.error("Generation failed. Widget {} - {}. State updated to: {}", - widget.getWidgetType(), - widget.getId(), - WidgetOptionUtil.getValueByKey(STATE, widget.getWidgetOptions()) - ); - } - } + public static final Logger LOGGER = LoggerFactory.getLogger(FailedViewStateGenerator.class); + + private final ViewGenerator delegate; + private final WidgetRepository widgetRepository; + + public FailedViewStateGenerator(ViewGenerator delegate, WidgetRepository widgetRepository) { + this.delegate = delegate; + this.widgetRepository = widgetRepository; + } + + @Override + public void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, + Sort launchesSort, + MultiValueMap<String, String> params) { + try { + delegate.generate(refresh, viewName, widget, launchesFilter, launchesSort, params); + } catch (Exception exc) { + LOGGER.error("Error during view creation: " + exc.getMessage()); + widgetRepository.save( + new WidgetBuilder(widget).addOption(STATE, WidgetState.FAILED.getValue()).get()); + LOGGER.error("Generation failed. Widget {} - {}. State updated to: {}", + widget.getWidgetType(), + widget.getId(), + WidgetOptionUtil.getValueByKey(STATE, widget.getWidgetOptions()) + ); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/HealthCheckTableGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/HealthCheckTableGenerator.java index dc98f49b9b..f1418d25e6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/HealthCheckTableGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/HealthCheckTableGenerator.java @@ -1,53 +1,57 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.generator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.dao.WidgetRepository; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.content.healthcheck.HealthCheckTableInitParams; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.List; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LATEST_OPTION; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class HealthCheckTableGenerator extends AbstractViewGenerator { - public static final String CUSTOM_COLUMN = "customColumn"; - - private final WidgetContentRepository widgetContentRepository; - - @Autowired - public HealthCheckTableGenerator(WidgetRepository widgetRepository, WidgetContentRepository widgetContentRepository) { - super(widgetRepository); - this.widgetContentRepository = widgetContentRepository; - } - - @Override - protected void generateView(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params) { - widgetContentRepository.generateComponentHealthCheckTable(refresh, - getInitParams(widget, viewName), - launchesFilter, - launchesSort, - widget.getItemsCount(), - WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widget.getWidgetOptions()) - ); - } - - private HealthCheckTableInitParams getInitParams(Widget widget, String viewName) { - List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widget.getWidgetOptions()); - return ofNullable(WidgetOptionUtil.getValueByKey(CUSTOM_COLUMN, widget.getWidgetOptions())).map(custom -> HealthCheckTableInitParams - .of(viewName, attributeKeys, custom)).orElseGet(() -> HealthCheckTableInitParams.of(viewName, attributeKeys)); - } + public static final String CUSTOM_COLUMN = "customColumn"; + + private final WidgetContentRepository widgetContentRepository; + + @Autowired + public HealthCheckTableGenerator(WidgetRepository widgetRepository, + WidgetContentRepository widgetContentRepository) { + super(widgetRepository); + this.widgetContentRepository = widgetContentRepository; + } + + @Override + protected void generateView(boolean refresh, String viewName, Widget widget, + Filter launchesFilter, Sort launchesSort, + MultiValueMap<String, String> params) { + widgetContentRepository.generateComponentHealthCheckTable(refresh, + getInitParams(widget, viewName), + launchesFilter, + launchesSort, + widget.getItemsCount(), + WidgetOptionUtil.getBooleanByKey(LATEST_OPTION, widget.getWidgetOptions()) + ); + } + + private HealthCheckTableInitParams getInitParams(Widget widget, String viewName) { + List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, + widget.getWidgetOptions()); + return ofNullable(WidgetOptionUtil.getValueByKey(CUSTOM_COLUMN, widget.getWidgetOptions())).map( + custom -> HealthCheckTableInitParams + .of(viewName, attributeKeys, custom)) + .orElseGet(() -> HealthCheckTableInitParams.of(viewName, attributeKeys)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/ViewGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/ViewGenerator.java index 35739bcaf7..0e0873f9a5 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/ViewGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/ViewGenerator.java @@ -10,6 +10,7 @@ */ public interface ViewGenerator { - void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, Sort launchesSort, - MultiValueMap<String, String> params); + void generate(boolean refresh, String viewName, Widget widget, Filter launchesFilter, + Sort launchesSort, + MultiValueMap<String, String> params); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/CreatedMaterializedWidgetStateHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/CreatedMaterializedWidgetStateHandler.java index 360943ec30..0f696d3e0a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/CreatedMaterializedWidgetStateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/CreatedMaterializedWidgetStateHandler.java @@ -1,40 +1,41 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.handler; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; +import static java.util.Collections.emptyMap; + import com.epam.ta.reportportal.core.events.widget.GenerateWidgetViewEvent; import com.epam.ta.reportportal.dao.WidgetRepository; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetState; import com.epam.ta.reportportal.ws.converter.builders.WidgetBuilder; +import java.util.Map; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; -import static java.util.Collections.emptyMap; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class CreatedMaterializedWidgetStateHandler implements MaterializedWidgetStateHandler { - private final WidgetRepository widgetRepository; - protected ApplicationEventPublisher eventPublisher; - - public CreatedMaterializedWidgetStateHandler(WidgetRepository widgetRepository, - @Qualifier("webApplicationContext") ApplicationEventPublisher eventPublisher) { - this.widgetRepository = widgetRepository; - this.eventPublisher = eventPublisher; - } - - @Override - public Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params) { - widgetRepository.save(new WidgetBuilder(widget).addOption(STATE, WidgetState.RENDERING.getValue()).get()); - eventPublisher.publishEvent(new GenerateWidgetViewEvent(widget.getId(), params)); - return emptyMap(); - } + private final WidgetRepository widgetRepository; + protected ApplicationEventPublisher eventPublisher; + + public CreatedMaterializedWidgetStateHandler(WidgetRepository widgetRepository, + @Qualifier("webApplicationContext") ApplicationEventPublisher eventPublisher) { + this.widgetRepository = widgetRepository; + this.eventPublisher = eventPublisher; + } + + @Override + public Map<String, Object> handleWidgetState(Widget widget, + MultiValueMap<String, String> params) { + widgetRepository.save( + new WidgetBuilder(widget).addOption(STATE, WidgetState.RENDERING.getValue()).get()); + eventPublisher.publishEvent(new GenerateWidgetViewEvent(widget.getId(), params)); + return emptyMap(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/EmptyMaterializedWidgetStateHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/EmptyMaterializedWidgetStateHandler.java index bf12f40845..280bba84ff 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/EmptyMaterializedWidgetStateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/EmptyMaterializedWidgetStateHandler.java @@ -1,11 +1,10 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.handler; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.stereotype.Service; -import org.springframework.util.MultiValueMap; - import java.util.Collections; import java.util.Map; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -13,8 +12,9 @@ @Service public class EmptyMaterializedWidgetStateHandler implements MaterializedWidgetStateHandler { - @Override - public Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params) { - return Collections.emptyMap(); - } + @Override + public Map<String, Object> handleWidgetState(Widget widget, + MultiValueMap<String, String> params) { + return Collections.emptyMap(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/FailedMaterializedWidgetStateHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/FailedMaterializedWidgetStateHandler.java index 026fbf94b1..3e1b31e03a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/FailedMaterializedWidgetStateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/FailedMaterializedWidgetStateHandler.java @@ -1,34 +1,34 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.handler; import com.epam.ta.reportportal.entity.widget.Widget; +import java.util.Collections; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.Collections; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class FailedMaterializedWidgetStateHandler implements MaterializedWidgetStateHandler { - private final MaterializedWidgetStateHandler refreshWidgetStateHandler; + private final MaterializedWidgetStateHandler refreshWidgetStateHandler; - @Autowired - public FailedMaterializedWidgetStateHandler( - @Qualifier("createdMaterializedWidgetStateHandler") MaterializedWidgetStateHandler refreshWidgetStateHandler) { - this.refreshWidgetStateHandler = refreshWidgetStateHandler; - } + @Autowired + public FailedMaterializedWidgetStateHandler( + @Qualifier("createdMaterializedWidgetStateHandler") MaterializedWidgetStateHandler refreshWidgetStateHandler) { + this.refreshWidgetStateHandler = refreshWidgetStateHandler; + } - @Override - public Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params) { - if (BooleanUtils.toBoolean(params.getFirst(REFRESH))) { - return refreshWidgetStateHandler.handleWidgetState(widget, params); - } - return Collections.emptyMap(); - } + @Override + public Map<String, Object> handleWidgetState(Widget widget, + MultiValueMap<String, String> params) { + if (BooleanUtils.toBoolean(params.getFirst(REFRESH))) { + return refreshWidgetStateHandler.handleWidgetState(widget, params); + } + return Collections.emptyMap(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/MaterializedWidgetStateHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/MaterializedWidgetStateHandler.java index 7a45f48660..08fbdf7c5d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/MaterializedWidgetStateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/MaterializedWidgetStateHandler.java @@ -1,17 +1,16 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.handler; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.util.MultiValueMap; - import java.util.Map; +import org.springframework.util.MultiValueMap; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public interface MaterializedWidgetStateHandler { - String REFRESH = "refresh"; - String VIEW_NAME = "viewName"; + String REFRESH = "refresh"; + String VIEW_NAME = "viewName"; - Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params); + Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/ReadyMaterializedWidgetStateHandler.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/ReadyMaterializedWidgetStateHandler.java index 661d0bbef3..1bd3eb099b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/ReadyMaterializedWidgetStateHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/handler/ReadyMaterializedWidgetStateHandler.java @@ -1,51 +1,52 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.handler; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.content.loader.materialized.MaterializedWidgetContentLoader; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetType; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Collections; +import java.util.Map; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.util.MultiValueMap; -import java.util.Collections; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ReadyMaterializedWidgetStateHandler implements MaterializedWidgetStateHandler { - private final MaterializedWidgetStateHandler refreshWidgetStateHandler; - private final Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping; - - public ReadyMaterializedWidgetStateHandler( - @Qualifier("createdMaterializedWidgetStateHandler") MaterializedWidgetStateHandler refreshWidgetStateHandler, - @Qualifier("materializedWidgetContentLoaderMapping") - Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping) { - this.refreshWidgetStateHandler = refreshWidgetStateHandler; - this.materializedWidgetContentLoaderMapping = materializedWidgetContentLoaderMapping; - } - - @Override - public Map<String, Object> handleWidgetState(Widget widget, MultiValueMap<String, String> params) { - - if (BooleanUtils.toBoolean(params.getFirst(REFRESH))) { - return refreshWidgetStateHandler.handleWidgetState(widget, params); - } - - WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_TO_CREATE_WIDGET, - formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) - )); - - return ofNullable(materializedWidgetContentLoaderMapping.get(widgetType)).map(loader -> loader.loadContent(widget, params)) - .orElseGet(Collections::emptyMap); - } + private final MaterializedWidgetStateHandler refreshWidgetStateHandler; + private final Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping; + + public ReadyMaterializedWidgetStateHandler( + @Qualifier("createdMaterializedWidgetStateHandler") MaterializedWidgetStateHandler refreshWidgetStateHandler, + @Qualifier("materializedWidgetContentLoaderMapping") + Map<WidgetType, MaterializedWidgetContentLoader> materializedWidgetContentLoaderMapping) { + this.refreshWidgetStateHandler = refreshWidgetStateHandler; + this.materializedWidgetContentLoaderMapping = materializedWidgetContentLoaderMapping; + } + + @Override + public Map<String, Object> handleWidgetState(Widget widget, + MultiValueMap<String, String> params) { + + if (BooleanUtils.toBoolean(params.getFirst(REFRESH))) { + return refreshWidgetStateHandler.handleWidgetState(widget, params); + } + + WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_TO_CREATE_WIDGET, + formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) + )); + + return ofNullable(materializedWidgetContentLoaderMapping.get(widgetType)).map( + loader -> loader.loadContent(widget, params)) + .orElseGet(Collections::emptyMap); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/util/ProductStatusContentLoaderManager.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/util/ProductStatusContentLoaderManager.java index a81482fb09..93daa4e7eb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/util/ProductStatusContentLoaderManager.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/loader/util/ProductStatusContentLoaderManager.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.widget.content.loader.util; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.content.LoadContentStrategy; import com.epam.ta.reportportal.core.widget.content.loader.ProductStatusContentLoader; @@ -23,38 +25,37 @@ import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProductStatusContentLoaderManager implements LoadContentStrategy { - private final Map<String, ProductStatusContentLoader> productStatusContentLoader; + private final Map<String, ProductStatusContentLoader> productStatusContentLoader; - @Autowired - public ProductStatusContentLoaderManager( - @Qualifier("productStatusContentLoader") Map<String, ProductStatusContentLoader> productStatusContentLoader) { - this.productStatusContentLoader = productStatusContentLoader; - } + @Autowired + public ProductStatusContentLoaderManager( + @Qualifier("productStatusContentLoader") Map<String, ProductStatusContentLoader> productStatusContentLoader) { + this.productStatusContentLoader = productStatusContentLoader; + } - @Override - public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, - int limit) { + @Override + public Map<String, ?> loadContent(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, + int limit) { - String strategy = WidgetOptionUtil.getValueByKey("strategy", widgetOptions); + String strategy = WidgetOptionUtil.getValueByKey("strategy", widgetOptions); - return ofNullable(productStatusContentLoader.get(strategy)).orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - "Wrong strategy type. Allowed: \"filter\", \"launch\". But found: " + strategy - )).loadContent(contentFields, filterSortMapping, widgetOptions, limit); - } + return ofNullable(productStatusContentLoader.get(strategy)).orElseThrow( + () -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Wrong strategy type. Allowed: \"filter\", \"launch\". But found: " + strategy + )).loadContent(contentFields, filterSortMapping, widgetOptions, limit); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGenerator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGenerator.java index e61fafa329..8b0a6ffcc9 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGenerator.java @@ -25,10 +25,11 @@ @Component public class MaterializedViewNameGenerator { - private static final String VIEW_PREFIX = "widget"; - private static final String NAME_SEPARATOR = "_"; + private static final String VIEW_PREFIX = "widget"; + private static final String NAME_SEPARATOR = "_"; - public String generate(Widget widget) { - return String.join(NAME_SEPARATOR, VIEW_PREFIX, String.valueOf(widget.getProject().getId()), String.valueOf(widget.getId())); - } + public String generate(Widget widget) { + return String.join(NAME_SEPARATOR, VIEW_PREFIX, String.valueOf(widget.getProject().getId()), + String.valueOf(widget.getId())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/state/WidgetStateResolver.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/state/WidgetStateResolver.java index 3f4861da24..c04bb3c612 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/state/WidgetStateResolver.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/materialized/state/WidgetStateResolver.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.widget.content.materialized.state; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.WidgetState; @@ -23,17 +26,16 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import org.springframework.stereotype.Component; -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Component public class WidgetStateResolver { - public WidgetState resolve(WidgetOptions widgetOptions) { - return ofNullable(WidgetOptionUtil.getValueByKey(STATE, widgetOptions)).flatMap(WidgetState::findByName) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Widget state not provided")); - } + public WidgetState resolve(WidgetOptions widgetOptions) { + return ofNullable(WidgetOptionUtil.getValueByKey(STATE, widgetOptions)).flatMap( + WidgetState::findByName) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Widget state not provided")); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemover.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemover.java index 5ff4462ae8..5a568315ca 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemover.java @@ -16,44 +16,46 @@ package com.epam.ta.reportportal.core.widget.content.remover; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.content.materialized.state.WidgetStateResolver; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetState; import com.epam.ta.reportportal.entity.widget.WidgetType; import com.google.common.collect.Lists; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Map; - -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class DelegatingStateContentRemover implements WidgetContentRemover { - private final WidgetStateResolver widgetStateResolver; - private final Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping; - - @Autowired - public DelegatingStateContentRemover(WidgetStateResolver widgetStateResolver, Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping) { - this.widgetStateResolver = widgetStateResolver; - this.widgetContentRemoverMapping = widgetContentRemoverMapping; - } - - @Override - public void removeContent(Widget widget) { - if (supports(widget)) { - final WidgetState state = widgetStateResolver.resolve(widget.getWidgetOptions()); - ofNullable(widgetContentRemoverMapping.get(state)).ifPresent(remover -> remover.removeContent(widget)); - } - } - - private boolean supports(Widget widget) { - return Lists.newArrayList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType(), WidgetType.CUMULATIVE.getType()) - .contains(widget.getWidgetType()); - } + private final WidgetStateResolver widgetStateResolver; + private final Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping; + + @Autowired + public DelegatingStateContentRemover(WidgetStateResolver widgetStateResolver, + Map<WidgetState, WidgetContentRemover> widgetContentRemoverMapping) { + this.widgetStateResolver = widgetStateResolver; + this.widgetContentRemoverMapping = widgetContentRemoverMapping; + } + + @Override + public void removeContent(Widget widget) { + if (supports(widget)) { + final WidgetState state = widgetStateResolver.resolve(widget.getWidgetOptions()); + ofNullable(widgetContentRemoverMapping.get(state)).ifPresent( + remover -> remover.removeContent(widget)); + } + } + + private boolean supports(Widget widget) { + return Lists.newArrayList(WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType(), + WidgetType.CUMULATIVE.getType()) + .contains(widget.getWidgetType()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemover.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemover.java index 1c73a0df8e..76555600e4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemover.java @@ -16,32 +16,32 @@ package com.epam.ta.reportportal.core.widget.content.remover; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.Widget; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class MaterializedViewRemover implements WidgetContentRemover { - private final WidgetContentRepository widgetContentRepository; + private final WidgetContentRepository widgetContentRepository; - @Autowired - public MaterializedViewRemover(WidgetContentRepository widgetContentRepository) { - this.widgetContentRepository = widgetContentRepository; - } + @Autowired + public MaterializedViewRemover(WidgetContentRepository widgetContentRepository) { + this.widgetContentRepository = widgetContentRepository; + } - @Override - public void removeContent(Widget widget) { - ofNullable(WidgetOptionUtil.getValueByKey(VIEW_NAME, - widget.getWidgetOptions() - )).ifPresent(widgetContentRepository::removeWidgetView); - } + @Override + public void removeContent(Widget widget) { + ofNullable(WidgetOptionUtil.getValueByKey(VIEW_NAME, + widget.getWidgetOptions() + )).ifPresent(widgetContentRepository::removeWidgetView); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemover.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemover.java index d5886e64c1..766a16e215 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemover.java @@ -20,10 +20,9 @@ import com.epam.ta.reportportal.dao.StaleMaterializedViewRepository; import com.epam.ta.reportportal.entity.materialized.StaleMaterializedView; import com.epam.ta.reportportal.entity.widget.Widget; -import org.springframework.stereotype.Service; - import java.time.LocalDateTime; import java.time.ZoneOffset; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -31,26 +30,26 @@ @Service public class StaleMaterializedViewRemover implements WidgetContentRemover { - private final MaterializedViewNameGenerator materializedViewNameGenerator; - private final StaleMaterializedViewRepository staleMaterializedViewRepository; - - public StaleMaterializedViewRemover(MaterializedViewNameGenerator materializedViewNameGenerator, - StaleMaterializedViewRepository staleMaterializedViewRepository) { - this.materializedViewNameGenerator = materializedViewNameGenerator; - this.staleMaterializedViewRepository = staleMaterializedViewRepository; - } - - @Override - public void removeContent(Widget widget) { - final StaleMaterializedView staleView = getStaleView(widget); - staleMaterializedViewRepository.insert(staleView); - } - - private StaleMaterializedView getStaleView(Widget widget) { - final String viewName = materializedViewNameGenerator.generate(widget); - final StaleMaterializedView view = new StaleMaterializedView(); - view.setName(viewName); - view.setCreationDate(LocalDateTime.now(ZoneOffset.UTC)); - return view; - } + private final MaterializedViewNameGenerator materializedViewNameGenerator; + private final StaleMaterializedViewRepository staleMaterializedViewRepository; + + public StaleMaterializedViewRemover(MaterializedViewNameGenerator materializedViewNameGenerator, + StaleMaterializedViewRepository staleMaterializedViewRepository) { + this.materializedViewNameGenerator = materializedViewNameGenerator; + this.staleMaterializedViewRepository = staleMaterializedViewRepository; + } + + @Override + public void removeContent(Widget widget) { + final StaleMaterializedView staleView = getStaleView(widget); + staleMaterializedViewRepository.insert(staleView); + } + + private StaleMaterializedView getStaleView(Widget widget) { + final String viewName = materializedViewNameGenerator.generate(widget); + final StaleMaterializedView view = new StaleMaterializedView(); + view.setName(viewName); + view.setCreationDate(LocalDateTime.now(ZoneOffset.UTC)); + return view; + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/WidgetContentRemover.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/WidgetContentRemover.java index 9a2b6ba652..2852c0ee82 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/WidgetContentRemover.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/remover/WidgetContentRemover.java @@ -23,6 +23,6 @@ */ public interface WidgetContentRemover { - void removeContent(Widget widget); + void removeContent(Widget widget); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckPostProcessor.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckPostProcessor.java index 9cbfb5dd2d..4130fd1ada 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckPostProcessor.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckPostProcessor.java @@ -12,22 +12,22 @@ @Component public class ComponentHealthCheckPostProcessor implements WidgetPostProcessor { - private final WidgetValidator componentHealthCheckValidator; + private final WidgetValidator componentHealthCheckValidator; - @Autowired - public ComponentHealthCheckPostProcessor(WidgetValidator componentHealthCheckValidator) { - this.componentHealthCheckValidator = componentHealthCheckValidator; - } + @Autowired + public ComponentHealthCheckPostProcessor(WidgetValidator componentHealthCheckValidator) { + this.componentHealthCheckValidator = componentHealthCheckValidator; + } - @Override - public boolean supports(Widget widget) { - return WidgetType.COMPONENT_HEALTH_CHECK.getType().equalsIgnoreCase(widget.getWidgetType()); - } + @Override + public boolean supports(Widget widget) { + return WidgetType.COMPONENT_HEALTH_CHECK.getType().equalsIgnoreCase(widget.getWidgetType()); + } - @Override - public void postProcess(Widget widget) { - if (supports(widget)) { - componentHealthCheckValidator.validate(widget); - } - } + @Override + public void postProcess(Widget widget) { + if (supports(widget)) { + componentHealthCheckValidator.validate(widget); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckTablePostProcessor.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckTablePostProcessor.java index 1496ebc100..b3361bc852 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckTablePostProcessor.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/ComponentHealthCheckTablePostProcessor.java @@ -12,26 +12,27 @@ @Component public class ComponentHealthCheckTablePostProcessor implements WidgetPostProcessor { - private final WidgetValidator componentHealthCheckTableValidator; - private final WidgetUpdater materializedWidgetStateUpdater; + private final WidgetValidator componentHealthCheckTableValidator; + private final WidgetUpdater materializedWidgetStateUpdater; - @Autowired - public ComponentHealthCheckTablePostProcessor(WidgetValidator componentHealthCheckTableValidator, - WidgetUpdater materializedWidgetStateUpdater) { - this.componentHealthCheckTableValidator = componentHealthCheckTableValidator; - this.materializedWidgetStateUpdater = materializedWidgetStateUpdater; - } + @Autowired + public ComponentHealthCheckTablePostProcessor(WidgetValidator componentHealthCheckTableValidator, + WidgetUpdater materializedWidgetStateUpdater) { + this.componentHealthCheckTableValidator = componentHealthCheckTableValidator; + this.materializedWidgetStateUpdater = materializedWidgetStateUpdater; + } - @Override - public boolean supports(Widget widget) { - return WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType().equalsIgnoreCase(widget.getWidgetType()); - } + @Override + public boolean supports(Widget widget) { + return WidgetType.COMPONENT_HEALTH_CHECK_TABLE.getType() + .equalsIgnoreCase(widget.getWidgetType()); + } - @Override - public void postProcess(Widget widget) { - if (supports(widget)) { - componentHealthCheckTableValidator.validate(widget); - materializedWidgetStateUpdater.update(widget); - } - } + @Override + public void postProcess(Widget widget) { + if (supports(widget)) { + componentHealthCheckTableValidator.validate(widget); + materializedWidgetStateUpdater.update(widget); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/CumulativeTrendChartPostProcessor.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/CumulativeTrendChartPostProcessor.java index e847b7a677..9da422bc27 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/CumulativeTrendChartPostProcessor.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/CumulativeTrendChartPostProcessor.java @@ -12,26 +12,27 @@ @Component public class CumulativeTrendChartPostProcessor implements WidgetPostProcessor { - private final WidgetValidator cumulativeTrendChartValidator; + private final WidgetValidator cumulativeTrendChartValidator; - private final WidgetUpdater materializedWidgetStateUpdater; + private final WidgetUpdater materializedWidgetStateUpdater; - @Autowired - public CumulativeTrendChartPostProcessor(WidgetValidator cumulativeTrendChartValidator, WidgetUpdater materializedWidgetStateUpdater) { - this.cumulativeTrendChartValidator = cumulativeTrendChartValidator; - this.materializedWidgetStateUpdater = materializedWidgetStateUpdater; - } + @Autowired + public CumulativeTrendChartPostProcessor(WidgetValidator cumulativeTrendChartValidator, + WidgetUpdater materializedWidgetStateUpdater) { + this.cumulativeTrendChartValidator = cumulativeTrendChartValidator; + this.materializedWidgetStateUpdater = materializedWidgetStateUpdater; + } - @Override - public boolean supports(Widget widget) { - return WidgetType.CUMULATIVE.getType().equalsIgnoreCase(widget.getWidgetType()); - } + @Override + public boolean supports(Widget widget) { + return WidgetType.CUMULATIVE.getType().equalsIgnoreCase(widget.getWidgetType()); + } - @Override - public void postProcess(Widget widget) { - if (supports(widget)) { - cumulativeTrendChartValidator.validate(widget); - materializedWidgetStateUpdater.update(widget); - } - } + @Override + public void postProcess(Widget widget) { + if (supports(widget)) { + cumulativeTrendChartValidator.validate(widget); + materializedWidgetStateUpdater.update(widget); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/MaterializedWidgetStateUpdater.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/MaterializedWidgetStateUpdater.java index 83dc5f37ed..65406e8336 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/MaterializedWidgetStateUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/MaterializedWidgetStateUpdater.java @@ -11,10 +11,10 @@ @Component public class MaterializedWidgetStateUpdater implements WidgetUpdater { - public static final String STATE = "state"; + public static final String STATE = "state"; - @Override - public void update(Widget widget) { - new WidgetBuilder(widget).addOption(STATE, WidgetState.CREATED.getValue()); - } + @Override + public void update(Widget widget) { + new WidgetBuilder(widget).addOption(STATE, WidgetState.CREATED.getValue()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetPostProcessor.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetPostProcessor.java index eb2f90e93e..e053e98b47 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetPostProcessor.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetPostProcessor.java @@ -9,14 +9,14 @@ */ public interface WidgetPostProcessor { - /** - * @param widget {@link Widget} - * @return 'true' if provided widget is supported by post processor otherwise 'false' - */ - boolean supports(Widget widget); + /** + * @param widget {@link Widget} + * @return 'true' if provided widget is supported by post processor otherwise 'false' + */ + boolean supports(Widget widget); - /** - * @param widget {@link Widget} for post processing - */ - void postProcess(Widget widget); + /** + * @param widget {@link Widget} for post processing + */ + void postProcess(Widget widget); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetUpdater.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetUpdater.java index e8de22a0ac..383f22645d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/WidgetUpdater.java @@ -9,9 +9,9 @@ */ public interface WidgetUpdater { - /** - * @param widget {@link Widget} to update - */ - void update(Widget widget); + /** + * @param widget {@link Widget} to update + */ + void update(Widget widget); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidator.java index af64ca24bb..e5c1d36b58 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidator.java @@ -16,39 +16,41 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * @author Pavel Bortnik */ @Service public class ActivityContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "Filter-Sort mapping should not be empty" - ); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify( + ErrorType.BAD_REQUEST_ERROR, + "Filter-Sort mapping should not be empty" + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidator.java index ffdcae2cde..5c66db1dad 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidator.java @@ -16,57 +16,59 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.EXECUTIONS_FAILED_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.EXECUTIONS_FAILED_REGEX; - /** * @author Pavel Bortnik */ @Service public class BugTrendChartContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * - * <p> - * The value of content field should not be empty. - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#DEFECTS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(ContentFieldMatcherUtil.match(EXECUTIONS_FAILED_REGEX, contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. + * + * <p> + * The value of content field should not be empty. All content fields should match the pattern + * {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#DEFECTS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(ContentFieldMatcherUtil.match(EXECUTIONS_FAILED_REGEX, contentFields), + equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidator.java index 622603ec40..af92dacbc6 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidator.java @@ -16,60 +16,64 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.EXECUTIONS_TOTAL_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.EXECUTIONS_TOTAL_REGEX; - /** * @author Pavel Bortnik */ @Service public class CasesTrendContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * <p> - * The value of content field should not be empty - * Content fields should contain only 1 value - * Content field value should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#EXECUTIONS_TOTAL_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(contentFields.size(), equalTo(1)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Test cases growth widget content fields should contain only 1 value"); - BusinessRule.expect(ContentFieldMatcherUtil.match(EXECUTIONS_TOTAL_REGEX, contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. + * <p> + * The value of content field should not be empty Content fields should contain only 1 value + * Content field value should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#EXECUTIONS_TOTAL_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(contentFields.size(), equalTo(1)) + .verify(ErrorType.BAD_REQUEST_ERROR, + "Test cases growth widget content fields should contain only 1 value"); + BusinessRule.expect(ContentFieldMatcherUtil.match(EXECUTIONS_TOTAL_REGEX, contentFields), + equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidator.java index 3c53a552c2..cf52c58ce0 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidator.java @@ -16,38 +16,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class ChartInvestigatedContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidator.java index 7919985188..4d317b31bf 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidator.java @@ -16,68 +16,75 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.MIN_PASSING_RATE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.*; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.MIN_PASSING_RATE; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ComponentHealthCheckContentValidator implements MultilevelValidatorStrategy { - public static final Integer MAX_LEVEL_NUMBER = 10; + public static final Integer MAX_LEVEL_NUMBER = 10; - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, String[] attributes, - Map<String, String> params, int limit) { + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, String[] attributes, + Map<String, String> params, int limit) { - validateWidgetOptions(widgetOptions); + validateWidgetOptions(widgetOptions); - List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); - validateAttributeKeys(attributeKeys); + List<String> attributeKeys = WidgetOptionUtil.getListByKey(ATTRIBUTE_KEYS, widgetOptions); + validateAttributeKeys(attributeKeys); - List<String> attributeValues = ofNullable(attributes).map(Arrays::asList).orElseGet(Collections::emptyList); + List<String> attributeValues = ofNullable(attributes).map(Arrays::asList) + .orElseGet(Collections::emptyList); - validateAttributeValues(attributeValues); - } + validateAttributeValues(attributeValues); + } - private void validateAttributeKeys(List<String> attributeKeys) { - BusinessRule.expect(attributeKeys, CollectionUtils::isNotEmpty) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "No keys were specified"); - BusinessRule.expect(attributeKeys, cf -> cf.size() <= MAX_LEVEL_NUMBER) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Keys number is incorrect. Maximum keys count = " + MAX_LEVEL_NUMBER); - attributeKeys.forEach(cf -> BusinessRule.expect(cf, StringUtils::isNotBlank) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Current level key should be not blank")); - } + private void validateAttributeKeys(List<String> attributeKeys) { + BusinessRule.expect(attributeKeys, CollectionUtils::isNotEmpty) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "No keys were specified"); + BusinessRule.expect(attributeKeys, cf -> cf.size() <= MAX_LEVEL_NUMBER) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Keys number is incorrect. Maximum keys count = " + MAX_LEVEL_NUMBER); + attributeKeys.forEach(cf -> BusinessRule.expect(cf, StringUtils::isNotBlank) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Current level key should be not blank")); + } - private void validateWidgetOptions(WidgetOptions widgetOptions) { - BusinessRule.expect(widgetOptions, Objects::nonNull).verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Widgets options not provided"); - Integer passingRate = WidgetOptionUtil.getIntegerByKey(MIN_PASSING_RATE, widgetOptions) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, - "Minimum passing rate option was not specified" - )); - BusinessRule.expect(passingRate, v -> v >= 0 && v <= 100) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, - "Minimum passing rate value should be greater or equal to 0 and less or equal to 100" - ); - } + private void validateWidgetOptions(WidgetOptions widgetOptions) { + BusinessRule.expect(widgetOptions, Objects::nonNull) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, "Widgets options not provided"); + Integer passingRate = WidgetOptionUtil.getIntegerByKey(MIN_PASSING_RATE, widgetOptions) + .orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Minimum passing rate option was not specified" + )); + BusinessRule.expect(passingRate, v -> v >= 0 && v <= 100) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + "Minimum passing rate value should be greater or equal to 0 and less or equal to 100" + ); + } - private void validateAttributeValues(List<String> attributeValues) { - attributeValues.forEach(value -> BusinessRule.expect(value, Objects::nonNull) - .verify(ErrorType.BAD_REQUEST_ERROR, "Attribute value should be not null")); - } + private void validateAttributeValues(List<String> attributeValues) { + attributeValues.forEach(value -> BusinessRule.expect(value, Objects::nonNull) + .verify(ErrorType.BAD_REQUEST_ERROR, "Attribute value should be not null")); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidator.java index a77bc12c65..9a43600aec 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidator.java @@ -16,59 +16,63 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class CumulativeTrendChartValidator implements MultilevelValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, String[] attributes, - Map<String, String> params, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, String[] attributes, + Map<String, String> params, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "Filter-Sort mapping should not be empty" - ); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify( + ErrorType.BAD_REQUEST_ERROR, + "Filter-Sort mapping should not be empty" + ); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "Content fields should not be empty" - ); - expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), - equalTo(true) - ).verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. The value of content field should not be empty All content + * fields should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)).verify( + ErrorType.BAD_REQUEST_ERROR, + "Content fields should not be empty" + ); + expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), + equalTo(true) + ).verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidator.java index d9b8c8ad60..5bd00c4856 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidator.java @@ -16,22 +16,21 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @@ -48,7 +47,7 @@ public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap /** * Mapping should not be empty * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as* value for each filter */ private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidator.java index f67f6991a4..c3520738cd 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidator.java @@ -16,55 +16,58 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; - /** * @author Pavel Bortnik */ @Service public class LaunchExecutionAndIssueStatisticsContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. The value of content field should not be empty All content + * fields should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), + equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidator.java index 9071a6b0bd..24e5b15175 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidator.java @@ -16,56 +16,59 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; - /** * @author Pavel Bortnik */ @Service public class LaunchesComparisonContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. The value of content field should not be empty All content + * fields should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), + equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidator.java index 71beabf5bc..7419b57e7e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidator.java @@ -16,38 +16,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class LaunchesDurationContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidator.java index 2e59de36a0..56eae71d8a 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidator.java @@ -16,50 +16,50 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class LaunchesTableContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - } + /** + * Validate provided content fields. The value of content field should not be empty + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LineChartContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LineChartContentValidator.java index 0f4381ee75..dd2ea8f2e7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LineChartContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LineChartContentValidator.java @@ -16,55 +16,58 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.ContentFieldMatcherUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; - /** * @author Pavel Bortnik */ @Service public class LineChartContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateContentFields(contentFields); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); - } + /** + * Validate provided content fields. The value of content field should not be empty All content + * fields should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, contentFields), + equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Bad content fields format"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidator.java index 139862dcad..6764f9062e 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidator.java @@ -16,52 +16,55 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class MostTimeConsumingContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMap); - validateWidgetOptions(widgetOptions); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMap); + validateWidgetOptions(widgetOptions); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided widget options. For current widget launch name should be specified. - * - * @param widgetOptions Map of stored widget options. - */ - private void validateWidgetOptions(WidgetOptions widgetOptions) { - BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), StringUtils::isNotBlank) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, LAUNCH_NAME_FIELD + " should be specified for widget."); - } + /** + * Validate provided widget options. For current widget launch name should be specified. + * + * @param widgetOptions Map of stored widget options. + */ + private void validateWidgetOptions(WidgetOptions widgetOptions) { + BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), + StringUtils::isNotBlank) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + LAUNCH_NAME_FIELD + " should be specified for widget."); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MultilevelValidatorStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MultilevelValidatorStrategy.java index 9bc705678e..ae4737f04b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MultilevelValidatorStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MultilevelValidatorStrategy.java @@ -2,12 +2,13 @@ import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; -import org.springframework.data.domain.Sort; - import java.util.List; import java.util.Map; +import org.springframework.data.domain.Sort; public interface MultilevelValidatorStrategy { - void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, - String[] attributes, Map<String, String> params, int limit); + + void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, + String[] attributes, Map<String, String> params, int limit); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidator.java index b0c05e8d68..ce922ca15d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidator.java @@ -16,37 +16,38 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class NotPassedTestsContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/OverallStatisticsContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/OverallStatisticsContentValidator.java index 7ab2d1c2ee..1d7a6652a2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/OverallStatisticsContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/OverallStatisticsContentValidator.java @@ -16,39 +16,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class OverallStatisticsContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateContentFields(contentFields); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateContentFields(contentFields); + } - /** - * Validate provided content fields. - * <p> - * The value of at least one of the content fields should not be empty - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - } + /** + * Validate provided content fields. + * <p> + * The value of at least one of the content fields should not be empty + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidator.java index 0f869ceac5..4b6dca07e4 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidator.java @@ -16,52 +16,55 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class PassingRatePerLaunchContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - validateWidgetOptions(widgetOptions); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + validateWidgetOptions(widgetOptions); + } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided widget options. For current widget launch name should be specified. - * - * @param widgetOptions Map of stored widget options. - */ - private void validateWidgetOptions(WidgetOptions widgetOptions) { - BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), StringUtils::isNotEmpty) - .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, LAUNCH_NAME_FIELD + " should be specified for widget."); - } + /** + * Validate provided widget options. For current widget launch name should be specified. + * + * @param widgetOptions Map of stored widget options. + */ + private void validateWidgetOptions(WidgetOptions widgetOptions) { + BusinessRule.expect(WidgetOptionUtil.getValueByKey(LAUNCH_NAME_FIELD, widgetOptions), + StringUtils::isNotEmpty) + .verify(ErrorType.UNABLE_LOAD_WIDGET_CONTENT, + LAUNCH_NAME_FIELD + " should be specified for widget."); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidator.java index 31d1bc819b..bf23857362 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidator.java @@ -16,38 +16,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class PassingRateSummaryContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ProductStatusContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ProductStatusContentValidator.java index 7f158a176f..2c0aa0d1d1 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ProductStatusContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ProductStatusContentValidator.java @@ -1,49 +1,52 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class ProductStatusContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMap); - validateContentFields(contentFields); - } - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMap); + validateContentFields(contentFields); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } - /** - * Validate provided content fields. - * The value of content field should not be empty - * All content fields should match the pattern {@link com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - } + /** + * Validate provided content fields. The value of content field should not be empty All content + * fields should match the pattern + * {@link + * com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants#COMBINED_CONTENT_FIELDS_REGEX} + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidator.java index bd1db7fc92..636166d07c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidator.java @@ -16,40 +16,42 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class TopPatternContentValidator implements MultilevelValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, String[] attributes, - Map<String, String> params, int limit) { - - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify(ErrorType.BAD_REQUEST_ERROR, - "Filter-Sort mapping should not be empty" - ); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, String[] attributes, + Map<String, String> params, int limit) { + + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)).verify( + ErrorType.BAD_REQUEST_ERROR, + "Filter-Sort mapping should not be empty" + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopTestCasesContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopTestCasesContentValidator.java index b80fee461b..52c976971b 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopTestCasesContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopTestCasesContentValidator.java @@ -16,19 +16,18 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.apache.commons.collections.CollectionUtils; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Map; import java.util.function.Predicate; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; /** * Content loader for {@link com.epam.ta.reportportal.entity.widget.WidgetType#TOP_TEST_CASES} @@ -44,18 +43,19 @@ public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap validateWidgetLimit(limit); } - /** - * Validate provided content fields. For current widget it should be only one field specified in content fields. - * Example is 'executions$failed', so widget would be created by 'failed' criteria. - * - * @param contentFields List of provided content. - */ - private void validateContentFields(List<String> contentFields) { - BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); - BusinessRule.expect(contentFields.size(), Predicate.isEqual(1)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Only one content field could be specified."); - } + /** + * Validate provided content fields. For current widget it should be only one field specified in + * content fields. Example is 'executions$failed', so widget would be created by 'failed' + * criteria. + * + * @param contentFields List of provided content. + */ + private void validateContentFields(List<String> contentFields) { + BusinessRule.expect(CollectionUtils.isNotEmpty(contentFields), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Content fields should not be empty"); + BusinessRule.expect(contentFields.size(), Predicate.isEqual(1)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Only one content field could be specified."); + } /** * Validate provided widget launches count. For current widget launches count should in the range from 2 to 100. diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidator.java index 6c00b19dd6..7c0066a3fb 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidator.java @@ -16,38 +16,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; - /** * @author Pavel Bortnik */ @Service public class UniqueBugContentValidator implements WidgetValidatorStrategy { - @Override - public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, WidgetOptions widgetOptions, int limit) { - validateFilterSortMapping(filterSortMapping); - } - - /** - * Mapping should not be empty - * - * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as value for each filter - */ - private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { - BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) - .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); - } + @Override + public void validate(List<String> contentFields, Map<Filter, Sort> filterSortMapping, + WidgetOptions widgetOptions, int limit) { + validateFilterSortMapping(filterSortMapping); + } + + /** + * Mapping should not be empty + * + * @param filterSortMapping Map of ${@link Filter} for query building as key and ${@link Sort} as + * value for each filter + */ + private void validateFilterSortMapping(Map<Filter, Sort> filterSortMapping) { + BusinessRule.expect(MapUtils.isNotEmpty(filterSortMapping), equalTo(true)) + .verify(ErrorType.BAD_REQUEST_ERROR, "Filter-Sort mapping should not be empty"); + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetContentFieldsValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetContentFieldsValidator.java index 484c5aad1d..9482202977 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetContentFieldsValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetContentFieldsValidator.java @@ -1,69 +1,71 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; + import com.epam.ta.reportportal.core.widget.content.BuildFilterStrategy; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetType; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Lists; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import java.util.Map; - -import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; - @Component("widgetContentFieldsValidator") public class WidgetContentFieldsValidator implements WidgetValidator { - private Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping; + private Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping; - private Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader; + private Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader; - private Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader; + private Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader; - @Autowired - @Qualifier("buildFilterStrategy") - public void setBuildFilterStrategy(Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping) { - this.buildFilterStrategyMapping = buildFilterStrategyMapping; - } + @Autowired + @Qualifier("buildFilterStrategy") + public void setBuildFilterStrategy( + Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping) { + this.buildFilterStrategyMapping = buildFilterStrategyMapping; + } - @Autowired - @Qualifier("widgetValidatorLoader") - public void setWidgetValidatorLoader(Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader) { - this.widgetValidatorLoader = widgetValidatorLoader; - } + @Autowired + @Qualifier("widgetValidatorLoader") + public void setWidgetValidatorLoader( + Map<WidgetType, WidgetValidatorStrategy> widgetValidatorLoader) { + this.widgetValidatorLoader = widgetValidatorLoader; + } - @Autowired - @Qualifier("multilevelValidatorLoader") - public void setMultilevelValidatorLoader(Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader) { - this.multilevelValidatorLoader = multilevelValidatorLoader; - } + @Autowired + @Qualifier("multilevelValidatorLoader") + public void setMultilevelValidatorLoader( + Map<WidgetType, MultilevelValidatorStrategy> multilevelValidatorLoader) { + this.multilevelValidatorLoader = multilevelValidatorLoader; + } - @Override - public void validate(Widget widget) { - WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) - .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_REQUEST, - formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) - )); + @Override + public void validate(Widget widget) { + WidgetType widgetType = WidgetType.findByName(widget.getWidgetType()) + .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_REQUEST, + formattedSupplier("Unsupported widget type '{}'", widget.getWidgetType()) + )); - if (widgetType.isSupportMultilevelStructure()) { - multilevelValidatorLoader.get(widgetType) - .validate(Lists.newArrayList(widget.getContentFields()), - buildFilterStrategyMapping.get(widgetType).buildFilter(widget), - widget.getWidgetOptions(), - null, - null, - widget.getItemsCount() - ); - } else { - widgetValidatorLoader.get(widgetType) - .validate(Lists.newArrayList(widget.getContentFields()), - buildFilterStrategyMapping.get(widgetType).buildFilter(widget), - widget.getWidgetOptions(), - widget.getItemsCount() - ); - } - } + if (widgetType.isSupportMultilevelStructure()) { + multilevelValidatorLoader.get(widgetType) + .validate(Lists.newArrayList(widget.getContentFields()), + buildFilterStrategyMapping.get(widgetType).buildFilter(widget), + widget.getWidgetOptions(), + null, + null, + widget.getItemsCount() + ); + } else { + widgetValidatorLoader.get(widgetType) + .validate(Lists.newArrayList(widget.getContentFields()), + buildFilterStrategyMapping.get(widgetType).buildFilter(widget), + widget.getWidgetOptions(), + widget.getItemsCount() + ); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidator.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidator.java index fe236452a8..e4f0604c2d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidator.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidator.java @@ -4,5 +4,5 @@ public interface WidgetValidator { - void validate(Widget widget); + void validate(Widget widget); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidatorStrategy.java b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidatorStrategy.java index acb7e55555..6d06e6e3a7 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidatorStrategy.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/content/updater/validator/WidgetValidatorStrategy.java @@ -2,10 +2,9 @@ import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.entity.widget.WidgetOptions; -import org.springframework.data.domain.Sort; - import java.util.List; import java.util.Map; +import org.springframework.data.domain.Sort; /** * Interface for widget parameters validation. @@ -14,5 +13,6 @@ */ public interface WidgetValidatorStrategy { - void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, WidgetOptions widgetOptions, int limit); + void validate(List<String> contentFields, Map<Filter, Sort> filterSortMap, + WidgetOptions widgetOptions, int limit); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtil.java b/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtil.java index dd9a282a28..50395b0c1f 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtil.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtil.java @@ -25,13 +25,13 @@ */ public final class ContentFieldMatcherUtil { - private ContentFieldMatcherUtil() { - //static only - } + private ContentFieldMatcherUtil() { + //static only + } - public static boolean match(final String patternValue, Collection<String> contentFields) { - Pattern pattern = Pattern.compile(patternValue); - return contentFields.stream().map(pattern::matcher).allMatch(Matcher::matches); + public static boolean match(final String patternValue, Collection<String> contentFields) { + Pattern pattern = Pattern.compile(patternValue); + return contentFields.stream().map(pattern::matcher).allMatch(Matcher::matches); - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldPatternConstants.java b/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldPatternConstants.java index 31da00efbe..4be5380364 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldPatternConstants.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/util/ContentFieldPatternConstants.java @@ -16,63 +16,73 @@ package com.epam.ta.reportportal.core.widget.util; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_KEY; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_KEY; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.TOTAL; + import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; - import java.util.Arrays; import java.util.stream.Collectors; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> * <p> - * Regex patterns for @{@link com.epam.ta.reportportal.entity.widget.Widget#contentFields} validation + * Regex patterns for @{@link com.epam.ta.reportportal.entity.widget.Widget#contentFields} + * validation */ public final class ContentFieldPatternConstants { - private static final String CONTENT_FIELD_SPLITTER = "\\$"; - - static { - - EXECUTIONS_REGEX = "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER + "(" + Arrays.stream( - StatusEnum.values()).map(StatusEnum::getExecutionCounterField).collect(Collectors.joining("|")) + "|" + TOTAL + ")" + "$"; - - DEFECTS_REGEX = "^" + "statistics" + CONTENT_FIELD_SPLITTER + DEFECTS_KEY + CONTENT_FIELD_SPLITTER + "(" + Arrays.stream( - TestItemIssueGroup.values()).map(ig -> ig.getValue().toLowerCase()).collect(Collectors.joining("|")) + ")" - + CONTENT_FIELD_SPLITTER + "[\\w\\d]+" + "$"; - } - - /* - ^statistics\\$executions\\$total$ - */ - public static final String EXECUTIONS_TOTAL_REGEX = - "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER + TOTAL + "$"; - - /* - ^statistics\\$executions\\$(passed|failed|skipped|total)$ - */ - public static final String EXECUTIONS_REGEX; - - /* - ^statistics\\$executions\\$failed$ - */ - public static final String EXECUTIONS_FAILED_REGEX = - "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER - + StatusEnum.FAILED.getExecutionCounterField() + "$"; - - /* - ^statistics\\$defects\\$(automation_bug|product_bug|no_defect|system_issue|to_investigate)\\$[\\w\\d]+$ - */ - public static final String DEFECTS_REGEX; - - /* - ((^statistics\\$defects\\$(automation_bug|product_bug|no_defect|system_issue|to_investigate)\\$[\\w\\d]+$)|(^statistics\\$executions\\$(passed|failed|skipped|total)$)) - */ - public static final String COMBINED_CONTENT_FIELDS_REGEX = "(" + DEFECTS_REGEX + ")" + "|" + "(" + EXECUTIONS_REGEX + ")"; - - private ContentFieldPatternConstants() { - //static only - } + private static final String CONTENT_FIELD_SPLITTER = "\\$"; + + static { + + EXECUTIONS_REGEX = + "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER + "(" + + Arrays.stream( + StatusEnum.values()).map(StatusEnum::getExecutionCounterField) + .collect(Collectors.joining("|")) + "|" + TOTAL + ")" + "$"; + + DEFECTS_REGEX = + "^" + "statistics" + CONTENT_FIELD_SPLITTER + DEFECTS_KEY + CONTENT_FIELD_SPLITTER + "(" + + Arrays.stream( + TestItemIssueGroup.values()).map(ig -> ig.getValue().toLowerCase()) + .collect(Collectors.joining("|")) + ")" + + CONTENT_FIELD_SPLITTER + "[\\w\\d]+" + "$"; + } + + /* + ^statistics\\$executions\\$total$ + */ + public static final String EXECUTIONS_TOTAL_REGEX = + "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER + TOTAL + + "$"; + + /* + ^statistics\\$executions\\$(passed|failed|skipped|total)$ + */ + public static final String EXECUTIONS_REGEX; + + /* + ^statistics\\$executions\\$failed$ + */ + public static final String EXECUTIONS_FAILED_REGEX = + "^" + "statistics" + CONTENT_FIELD_SPLITTER + EXECUTIONS_KEY + CONTENT_FIELD_SPLITTER + + StatusEnum.FAILED.getExecutionCounterField() + "$"; + + /* + ^statistics\\$defects\\$(automation_bug|product_bug|no_defect|system_issue|to_investigate)\\$[\\w\\d]+$ + */ + public static final String DEFECTS_REGEX; + + /* + ((^statistics\\$defects\\$(automation_bug|product_bug|no_defect|system_issue|to_investigate)\\$[\\w\\d]+$)|(^statistics\\$executions\\$(passed|failed|skipped|total)$)) + */ + public static final String COMBINED_CONTENT_FIELDS_REGEX = + "(" + DEFECTS_REGEX + ")" + "|" + "(" + EXECUTIONS_REGEX + ")"; + + private ContentFieldPatternConstants() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetFilterUtil.java b/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetFilterUtil.java index c97367978a..370bf584c2 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetFilterUtil.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetFilterUtil.java @@ -16,40 +16,44 @@ package com.epam.ta.reportportal.core.widget.util; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.collect.Lists; -import org.springframework.data.domain.Sort; - import java.util.Collection; import java.util.Set; import java.util.function.Function; - -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; +import org.springframework.data.domain.Sort; /** * @author Pavel Bortnik */ public class WidgetFilterUtil { - private WidgetFilterUtil() { - //static only - } - - public static final Function<Set<Filter>, Filter> GROUP_FILTERS = filters -> { - Filter filter = ofNullable(filters).map(Collection::stream) - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Filters set should not be empty")) - .findFirst() - .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "No filters for widget were found")); - filter.withConditions(filters.stream().map(Filter::getFilterConditions).flatMap(Collection::stream).collect(toList())); - - return filter; - }; - - public static final Function<Collection<Sort>, Sort> GROUP_SORTS = sorts -> Sort.by(ofNullable(sorts).map(s -> s.stream() - .flatMap(sortStream -> Lists.newArrayList(sortStream.iterator()).stream()) - .collect(toList())).orElseGet(Lists::newArrayList)); + private WidgetFilterUtil() { + //static only + } + + public static final Function<Set<Filter>, Filter> GROUP_FILTERS = filters -> { + Filter filter = ofNullable(filters).map(Collection::stream) + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Filters set should not be empty")) + .findFirst() + .orElseThrow(() -> new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "No filters for widget were found")); + filter.withConditions( + filters.stream().map(Filter::getFilterConditions).flatMap(Collection::stream) + .collect(toList())); + + return filter; + }; + + public static final Function<Collection<Sort>, Sort> GROUP_SORTS = sorts -> Sort.by( + ofNullable(sorts).map(s -> s.stream() + .flatMap(sortStream -> Lists.newArrayList(sortStream.iterator()).stream()) + .collect(toList())).orElseGet(Lists::newArrayList)); } diff --git a/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtil.java b/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtil.java index 622d19fbeb..39a035942d 100644 --- a/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtil.java +++ b/src/main/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtil.java @@ -16,78 +16,88 @@ package com.epam.ta.reportportal.core.widget.util; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.apache.commons.collections.MapUtils; -import org.apache.commons.lang3.BooleanUtils; - -import javax.annotation.Nullable; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; -import static java.util.Optional.ofNullable; +import javax.annotation.Nullable; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.BooleanUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public final class WidgetOptionUtil { - private WidgetOptionUtil() { - //static only - } - - @Nullable - public static String getValueByKey(String key, WidgetOptions widgetOptions) { - - Optional<Object> value = ofNullable(widgetOptions).flatMap(wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); - - value.ifPresent(v -> expect(v, String.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, - Suppliers.formattedSupplier("Wrong widget option value type for key = '{}'. String expected.", key) - )); - - return (String) value.orElse(null); - } - - public static <K, V> Map<K, V> getMapByKey(String key, WidgetOptions widgetOptions) { - Optional<Object> value = ofNullable(widgetOptions).flatMap(wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); - - value.ifPresent(v -> expect(v, Map.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, - Suppliers.formattedSupplier("Wrong widget option value type for key = '{}'. Map expected.", key) - )); - - return (Map<K, V>) value.orElseGet(Collections::emptyMap); - } - - public static boolean getBooleanByKey(String key, WidgetOptions widgetOptions) { - - return ofNullable(widgetOptions).map(wo -> MapUtils.isNotEmpty(wo.getOptions()) && ofNullable(wo.getOptions() - .get(key)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))).orElse(false)).orElse(false); - } - - public static Optional<Integer> getIntegerByKey(String key, WidgetOptions widgetOptions) { - return ofNullable(widgetOptions).flatMap(wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))).map(value -> { - try { - return Integer.parseInt(String.valueOf(value)); - } catch (NumberFormatException ex) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Error during parsing integer value of key = '{}'", key).get() - ); - } - }); - } - - public static <T> List<T> getListByKey(String key, WidgetOptions widgetOptions) { - Optional<Object> value = ofNullable(widgetOptions).flatMap(wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); - - value.ifPresent(v -> expect(v, List.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, - Suppliers.formattedSupplier("Wrong widget option value type for key = '{}'. List expected.", key) - )); - - return (List<T>) value.orElse(Collections.emptyList()); - } + private WidgetOptionUtil() { + //static only + } + + @Nullable + public static String getValueByKey(String key, WidgetOptions widgetOptions) { + + Optional<Object> value = ofNullable(widgetOptions).flatMap( + wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); + + value.ifPresent( + v -> expect(v, String.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, + Suppliers.formattedSupplier( + "Wrong widget option value type for key = '{}'. String expected.", key) + )); + + return (String) value.orElse(null); + } + + public static <K, V> Map<K, V> getMapByKey(String key, WidgetOptions widgetOptions) { + Optional<Object> value = ofNullable(widgetOptions).flatMap( + wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); + + value.ifPresent(v -> expect(v, Map.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, + Suppliers.formattedSupplier("Wrong widget option value type for key = '{}'. Map expected.", + key) + )); + + return (Map<K, V>) value.orElseGet(Collections::emptyMap); + } + + public static boolean getBooleanByKey(String key, WidgetOptions widgetOptions) { + + return ofNullable(widgetOptions).map( + wo -> MapUtils.isNotEmpty(wo.getOptions()) && ofNullable(wo.getOptions() + .get(key)).map(v -> BooleanUtils.toBoolean(String.valueOf(v))).orElse(false)) + .orElse(false); + } + + public static Optional<Integer> getIntegerByKey(String key, WidgetOptions widgetOptions) { + return ofNullable(widgetOptions).flatMap( + wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))).map(value -> { + try { + return Integer.parseInt(String.valueOf(value)); + } catch (NumberFormatException ex) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Error during parsing integer value of key = '{}'", key) + .get() + ); + } + }); + } + + public static <T> List<T> getListByKey(String key, WidgetOptions widgetOptions) { + Optional<Object> value = ofNullable(widgetOptions).flatMap( + wo -> ofNullable(wo.getOptions()).map(options -> options.get(key))); + + value.ifPresent(v -> expect(v, List.class::isInstance).verify(ErrorType.OBJECT_RETRIEVAL_ERROR, + Suppliers.formattedSupplier("Wrong widget option value type for key = '{}'. List expected.", + key) + )); + + return (List<T>) value.orElse(Collections.emptyList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRq.java b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRq.java index 892391e328..73b11af39a 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRq.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRq.java @@ -22,22 +22,22 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class DemoDataRq { - @JsonProperty(defaultValue = "true") - private boolean createDashboard = true; + @JsonProperty(defaultValue = "true") + private boolean createDashboard = true; - public boolean isCreateDashboard() { - return createDashboard; - } + public boolean isCreateDashboard() { + return createDashboard; + } - public void setCreateDashboard(boolean createDashboard) { - this.createDashboard = createDashboard; - } + public void setCreateDashboard(boolean createDashboard) { + this.createDashboard = createDashboard; + } - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DemoDataRq{"); - sb.append("createDashboard=").append(createDashboard); - sb.append('}'); - return sb.toString(); - } + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DemoDataRq{"); + sb.append("createDashboard=").append(createDashboard); + sb.append('}'); + return sb.toString(); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRs.java b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRs.java index 6b8ad738f4..9b5066d1f0 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRs.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoDataRs.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; /** @@ -27,25 +26,25 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class DemoDataRs { - @JsonProperty - private Long dashboardId; + @JsonProperty + private Long dashboardId; - @JsonProperty - private List<Long> launchIds; + @JsonProperty + private List<Long> launchIds; - public Long getDashboardId() { - return dashboardId; - } + public Long getDashboardId() { + return dashboardId; + } - public void setDashboardId(Long dashboardId) { - this.dashboardId = dashboardId; - } + public void setDashboardId(Long dashboardId) { + this.dashboardId = dashboardId; + } - public List<Long> getLaunchIds() { - return launchIds; - } + public List<Long> getLaunchIds() { + return launchIds; + } - public void setLaunchIds(List<Long> launchIds) { - this.launchIds = launchIds; - } + public void setLaunchIds(List<Long> launchIds) { + this.launchIds = launchIds; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoItemMetadata.java b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoItemMetadata.java index a11e2f1ae4..ec2631efd3 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoItemMetadata.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoItemMetadata.java @@ -24,91 +24,91 @@ */ public class DemoItemMetadata { - private String name; + private String name; - private String parentId; + private String parentId; - private boolean retry; + private boolean retry; - private boolean nested; + private boolean nested; - private TestItemTypeEnum type; + private TestItemTypeEnum type; - private StatusEnum status; + private StatusEnum status; - private String issue; + private String issue; - private int logCount; + private int logCount; - public DemoItemMetadata withName(String name) { - this.name = name; - return this; - } + public DemoItemMetadata withName(String name) { + this.name = name; + return this; + } - public DemoItemMetadata withParentId(String parentId) { - this.parentId = parentId; - return this; - } + public DemoItemMetadata withParentId(String parentId) { + this.parentId = parentId; + return this; + } - public DemoItemMetadata withRetry(boolean retry) { - this.retry = retry; - return this; - } + public DemoItemMetadata withRetry(boolean retry) { + this.retry = retry; + return this; + } - public DemoItemMetadata withNested(boolean nested) { - this.nested = nested; - return this; - } + public DemoItemMetadata withNested(boolean nested) { + this.nested = nested; + return this; + } - public DemoItemMetadata withType(TestItemTypeEnum type) { - this.type = type; - return this; - } + public DemoItemMetadata withType(TestItemTypeEnum type) { + this.type = type; + return this; + } - public DemoItemMetadata withStatus(StatusEnum status) { - this.status = status; - return this; - } + public DemoItemMetadata withStatus(StatusEnum status) { + this.status = status; + return this; + } - public DemoItemMetadata withIssue(String issue) { - this.issue = issue; - return this; - } + public DemoItemMetadata withIssue(String issue) { + this.issue = issue; + return this; + } - public DemoItemMetadata withLogCount(int logCount) { - this.logCount = logCount; - return this; - } + public DemoItemMetadata withLogCount(int logCount) { + this.logCount = logCount; + return this; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getParentId() { - return parentId; - } + public String getParentId() { + return parentId; + } - public boolean isRetry() { - return retry; - } + public boolean isRetry() { + return retry; + } - public boolean isNested() { - return nested; - } + public boolean isNested() { + return nested; + } - public TestItemTypeEnum getType() { - return type; - } + public TestItemTypeEnum getType() { + return type; + } - public StatusEnum getStatus() { - return status; - } + public StatusEnum getStatus() { + return status; + } - public String getIssue() { - return issue; - } + public String getIssue() { + return issue; + } - public int getLogCount() { - return logCount; - } + public int getLogCount() { + return logCount; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoLaunch.java b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoLaunch.java index 284fbfc484..63da75a7e1 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/DemoLaunch.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/DemoLaunch.java @@ -1,22 +1,21 @@ package com.epam.ta.reportportal.demodata.model; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class DemoLaunch { - @JsonProperty(value = "suites") - private List<Suite> suites; + @JsonProperty(value = "suites") + private List<Suite> suites; - public DemoLaunch() { - } + public DemoLaunch() { + } - public List<Suite> getSuites() { - return suites; - } + public List<Suite> getSuites() { + return suites; + } - public void setSuites(List<Suite> suites) { - this.suites = suites; - } + public void setSuites(List<Suite> suites) { + this.suites = suites; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/RootMetaData.java b/src/main/java/com/epam/ta/reportportal/demodata/model/RootMetaData.java index a27aed18bb..840afefbc1 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/RootMetaData.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/RootMetaData.java @@ -4,29 +4,31 @@ public class RootMetaData { - private final String launchUuid; - private final ReportPortalUser user; - private final ReportPortalUser.ProjectDetails projectDetails; - - private RootMetaData(String launchUuid, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - this.launchUuid = launchUuid; - this.user = user; - this.projectDetails = projectDetails; - } - - public String getLaunchUuid() { - return launchUuid; - } - - public ReportPortalUser getUser() { - return user; - } - - public ReportPortalUser.ProjectDetails getProjectDetails() { - return projectDetails; - } - - public static RootMetaData of(String launchUuid, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - return new RootMetaData(launchUuid, user, projectDetails); - } + private final String launchUuid; + private final ReportPortalUser user; + private final ReportPortalUser.ProjectDetails projectDetails; + + private RootMetaData(String launchUuid, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + this.launchUuid = launchUuid; + this.user = user; + this.projectDetails = projectDetails; + } + + public String getLaunchUuid() { + return launchUuid; + } + + public ReportPortalUser getUser() { + return user; + } + + public ReportPortalUser.ProjectDetails getProjectDetails() { + return projectDetails; + } + + public static RootMetaData of(String launchUuid, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + return new RootMetaData(launchUuid, user, projectDetails); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/Step.java b/src/main/java/com/epam/ta/reportportal/demodata/model/Step.java index 6e4fa55940..45c0a6977b 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/Step.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/Step.java @@ -2,34 +2,34 @@ public class Step extends TestingModel { - private String name; - private String status; - private String issue; + private String name; + private String status; + private String issue; - public Step() { - } + public Step() { + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getStatus() { - return status; - } + public String getStatus() { + return status; + } - public void setStatus(String status) { - this.status = status; - } + public void setStatus(String status) { + this.status = status; + } - public String getIssue() { - return issue; - } + public String getIssue() { + return issue; + } - public void setIssue(String issue) { - this.issue = issue; - } + public void setIssue(String issue) { + this.issue = issue; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/Suite.java b/src/main/java/com/epam/ta/reportportal/demodata/model/Suite.java index 0cc316919f..2d102ad686 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/Suite.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/Suite.java @@ -4,43 +4,43 @@ public class Suite extends TestingModel { - private String type; - private String name; - private String status; - private List<Test> tests; + private String type; + private String name; + private String status; + private List<Test> tests; - public Suite() { - } + public Suite() { + } - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getStatus() { - return status; - } + public String getStatus() { + return status; + } - public void setStatus(String status) { - this.status = status; - } + public void setStatus(String status) { + this.status = status; + } - public List<Test> getTests() { - return tests; - } + public List<Test> getTests() { + return tests; + } - public void setTests(List<Test> tests) { - this.tests = tests; - } + public void setTests(List<Test> tests) { + this.tests = tests; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/Test.java b/src/main/java/com/epam/ta/reportportal/demodata/model/Test.java index 17ebe432c2..6662e2dd90 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/Test.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/Test.java @@ -4,43 +4,43 @@ public class Test extends TestingModel { - private String name; - private String status; - private String issue; - private List<Step> steps; + private String name; + private String status; + private String issue; + private List<Step> steps; - public Test() { - } + public Test() { + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getStatus() { - return status; - } + public String getStatus() { + return status; + } - public void setStatus(String status) { - this.status = status; - } + public void setStatus(String status) { + this.status = status; + } - public String getIssue() { - return issue; - } + public String getIssue() { + return issue; + } - public void setIssue(String issue) { - this.issue = issue; - } + public void setIssue(String issue) { + this.issue = issue; + } - public List<Step> getSteps() { - return steps; - } + public List<Step> getSteps() { + return steps; + } - public void setSteps(List<Step> steps) { - this.steps = steps; - } + public void setSteps(List<Step> steps) { + this.steps = steps; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/model/TestingModel.java b/src/main/java/com/epam/ta/reportportal/demodata/model/TestingModel.java index 16b4aabd4f..effdb029f9 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/model/TestingModel.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/model/TestingModel.java @@ -2,25 +2,25 @@ public class TestingModel { - private boolean hasBefore; - private boolean hasAfter; + private boolean hasBefore; + private boolean hasAfter; - public TestingModel() { - } + public TestingModel() { + } - public boolean isHasBefore() { - return hasBefore; - } + public boolean isHasBefore() { + return hasBefore; + } - public void setHasBefore(boolean hasBefore) { - this.hasBefore = hasBefore; - } + public void setHasBefore(boolean hasBefore) { + this.hasBefore = hasBefore; + } - public boolean isHasAfter() { - return hasAfter; - } + public boolean isHasAfter() { + return hasAfter; + } - public void setHasAfter(boolean hasAfter) { - this.hasAfter = hasAfter; - } + public void setHasAfter(boolean hasAfter) { + this.hasAfter = hasAfter; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/Attachment.java b/src/main/java/com/epam/ta/reportportal/demodata/service/Attachment.java index 41f76b6b0f..853efe596f 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/Attachment.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/Attachment.java @@ -16,9 +16,14 @@ package com.epam.ta.reportportal.demodata.service; -import org.springframework.core.io.ClassPathResource; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_PDF_VALUE; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; +import static org.springframework.http.MediaType.IMAGE_PNG_VALUE; +import static org.springframework.http.MediaType.TEXT_HTML_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import static org.springframework.http.MediaType.*; +import org.springframework.core.io.ClassPathResource; /** * @author Pavel_Bortnik diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/Constants.java b/src/main/java/com/epam/ta/reportportal/demodata/service/Constants.java index 98fc8286d1..131c1afd05 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/Constants.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/Constants.java @@ -21,14 +21,14 @@ */ class Constants { - private Constants() { - //static only - } + private Constants() { + //static only + } - static final String NAME = "Demo Api Tests"; - static final String PACKAGE = "com.epam.ta.reportportal.demodata."; - static final String ITEM_WITH_NESTED_STEPS_NAME = "Test with nested steps"; - static final int STORY_PROBABILITY = 30; - static final int CONTENT_PROBABILITY = 60; - static final int ATTRIBUTES_COUNT = 3; + static final String NAME = "Demo Api Tests"; + static final String PACKAGE = "com.epam.ta.reportportal.demodata."; + static final String ITEM_WITH_NESTED_STEPS_NAME = "Test with nested steps"; + static final int STORY_PROBABILITY = 30; + static final int CONTENT_PROBABILITY = 60; + static final int ATTRIBUTES_COUNT = 3; } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/ContentUtils.java b/src/main/java/com/epam/ta/reportportal/demodata/service/ContentUtils.java index 19240e300c..ddf95cfb71 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/ContentUtils.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/ContentUtils.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.demodata.service; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.AUTOMATION_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.PRODUCT_BUG; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.SYSTEM_ISSUE; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.TO_INVESTIGATE; +import static java.nio.charset.StandardCharsets.UTF_8; + import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; import com.epam.ta.reportportal.exception.ReportPortalException; @@ -24,9 +30,6 @@ import com.google.common.base.CaseFormat; import com.google.common.base.Preconditions; import com.google.common.collect.Range; -import org.apache.commons.lang3.tuple.Pair; -import org.springframework.core.io.ClassPathResource; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -37,146 +40,152 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; - -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.*; -import static java.nio.charset.StandardCharsets.UTF_8; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.core.io.ClassPathResource; /** - * By reason of demo data generation is used not so often, - * we don't need to cache the files' content. + * By reason of demo data generation is used not so often, we don't need to cache the files' + * content. * * @author Pavel_Bortnik */ public final class ContentUtils { - private static final int MAX_ERROR_LOGS_COUNT = 2; - - private static final int ERRORS_COUNT = 9; - - private static final Range<Integer> PROBABILITY_RANGE = Range.openClosed(0, 100); - - private static SplittableRandom random = new SplittableRandom(); - - private static final Map<TestItemIssueGroup, Supplier<Issue>> ISSUE_MAPPING = Map.of(PRODUCT_BUG, - () -> getIssue(PRODUCT_BUG.getLocator(), bugDescription("demo/content/comments/product.txt")), - AUTOMATION_BUG, - () -> getIssue(AUTOMATION_BUG.getLocator(), bugDescription("demo/content/comments/automation.txt")), - SYSTEM_ISSUE, - () -> getIssue(SYSTEM_ISSUE.getLocator(), bugDescription("demo/content/comments/system.txt")), - TO_INVESTIGATE, - () -> getIssue(TO_INVESTIGATE.getLocator(), bugDescription("demo/content/comments/investigate.txt")) - ); - - private ContentUtils() { - //static only - } - - public static String getNameFromType(TestItemTypeEnum type) { - return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, type.name()); - } - - public static Set<ItemAttributesRQ> getAttributesInRange(int limit) { - List<Pair<String, String>> content = readAttributes("demo/content/attributes.txt"); - int fromIndex = random.nextInt(content.size() - limit); - return content.subList(fromIndex, fromIndex + limit).stream().map(it -> { - if (it.getKey().isEmpty()) { - return new ItemAttributesRQ(null, it.getValue()); - } else { - return new ItemAttributesRQ(it.getKey(), it.getValue()); - } - }).collect(Collectors.toSet()); - - } - - public static String getSuiteDescription() { - List<String> content = readToList("demo/content/suite-description.txt"); - return content.get(random.nextInt(content.size())); - } - - public static String getStepDescription() { - List<String> content = readToList("demo/content/step-description.txt"); - return content.get(random.nextInt(content.size())); - } - - public static String getTestDescription() { - List<String> content = readToList("demo/content/test-description.txt"); - return content.get(random.nextInt(content.size())); - } - - public static String getLaunchDescription() { - return readToString("demo/content/description.txt"); - } - - public static List<String> getErrorLogs() { - return IntStream.range(0, MAX_ERROR_LOGS_COUNT).mapToObj(i -> { - int errorNumber = random.nextInt(1, ERRORS_COUNT); - return readToString("demo/errors/" + errorNumber + ".txt"); - }).collect(Collectors.toList()); - } - - public static String getLogMessage() { - List<String> logs = readToList("demo/content/demo_logs.txt"); - return logs.get(random.nextInt(logs.size())); - } - - public static boolean getWithProbability(int probability) { - Preconditions.checkArgument(PROBABILITY_RANGE.contains(probability), "%s is not in range [%s]", probability, PROBABILITY_RANGE); - return Range.closedOpen(PROBABILITY_RANGE.lowerEndpoint(), probability).contains(random.nextInt(PROBABILITY_RANGE.upperEndpoint())); - } - - public static Issue getIssue(TestItemIssueGroup group) { - return ISSUE_MAPPING.get(group).get(); - } - - private static Issue getIssue(String locator, String comment) { - Issue issue = new Issue(); - issue.setIssueType(locator); - issue.setComment(comment); - return issue; - } - - private static String bugDescription(String resource) { - String description = null; - if (random.nextBoolean()) { - List<String> descriptions = readToList(resource); - description = descriptions.get(random.nextInt(descriptions.size())); - } - return description; - } - - private static List<String> readToList(String resource) { - List<String> content; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { - content = reader.lines().collect(Collectors.toList()); - } catch (IOException e) { - throw new ReportPortalException("Missing demo content.", e); - } - return content; - } - - private static List<Pair<String, String>> readAttributes(String resource) { - List<Pair<String, String>> content; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { - content = reader.lines().map(it -> { - if (it.contains(":")) { - return Pair.of(it.split(":")[0], it.split(":")[1]); - } else { - return Pair.of("", it); - } - }).collect(Collectors.toList()); - } catch (IOException e) { - throw new ReportPortalException("Missing demo content.", e); - } - return content; - } - - private static String readToString(String resource) { - String content; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { - content = reader.lines().collect(Collectors.joining("\n")); - } catch (IOException e) { - throw new ReportPortalException("Missing demo content.", e); - } - return content; - } + private static final int MAX_ERROR_LOGS_COUNT = 2; + + private static final int ERRORS_COUNT = 9; + + private static final Range<Integer> PROBABILITY_RANGE = Range.openClosed(0, 100); + + private static SplittableRandom random = new SplittableRandom(); + + private static final Map<TestItemIssueGroup, Supplier<Issue>> ISSUE_MAPPING = Map.of(PRODUCT_BUG, + () -> getIssue(PRODUCT_BUG.getLocator(), bugDescription("demo/content/comments/product.txt")), + AUTOMATION_BUG, + () -> getIssue(AUTOMATION_BUG.getLocator(), + bugDescription("demo/content/comments/automation.txt")), + SYSTEM_ISSUE, + () -> getIssue(SYSTEM_ISSUE.getLocator(), bugDescription("demo/content/comments/system.txt")), + TO_INVESTIGATE, + () -> getIssue(TO_INVESTIGATE.getLocator(), + bugDescription("demo/content/comments/investigate.txt")) + ); + + private ContentUtils() { + //static only + } + + public static String getNameFromType(TestItemTypeEnum type) { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, type.name()); + } + + public static Set<ItemAttributesRQ> getAttributesInRange(int limit) { + List<Pair<String, String>> content = readAttributes("demo/content/attributes.txt"); + int fromIndex = random.nextInt(content.size() - limit); + return content.subList(fromIndex, fromIndex + limit).stream().map(it -> { + if (it.getKey().isEmpty()) { + return new ItemAttributesRQ(null, it.getValue()); + } else { + return new ItemAttributesRQ(it.getKey(), it.getValue()); + } + }).collect(Collectors.toSet()); + + } + + public static String getSuiteDescription() { + List<String> content = readToList("demo/content/suite-description.txt"); + return content.get(random.nextInt(content.size())); + } + + public static String getStepDescription() { + List<String> content = readToList("demo/content/step-description.txt"); + return content.get(random.nextInt(content.size())); + } + + public static String getTestDescription() { + List<String> content = readToList("demo/content/test-description.txt"); + return content.get(random.nextInt(content.size())); + } + + public static String getLaunchDescription() { + return readToString("demo/content/description.txt"); + } + + public static List<String> getErrorLogs() { + return IntStream.range(0, MAX_ERROR_LOGS_COUNT).mapToObj(i -> { + int errorNumber = random.nextInt(1, ERRORS_COUNT); + return readToString("demo/errors/" + errorNumber + ".txt"); + }).collect(Collectors.toList()); + } + + public static String getLogMessage() { + List<String> logs = readToList("demo/content/demo_logs.txt"); + return logs.get(random.nextInt(logs.size())); + } + + public static boolean getWithProbability(int probability) { + Preconditions.checkArgument(PROBABILITY_RANGE.contains(probability), "%s is not in range [%s]", + probability, PROBABILITY_RANGE); + return Range.closedOpen(PROBABILITY_RANGE.lowerEndpoint(), probability) + .contains(random.nextInt(PROBABILITY_RANGE.upperEndpoint())); + } + + public static Issue getIssue(TestItemIssueGroup group) { + return ISSUE_MAPPING.get(group).get(); + } + + private static Issue getIssue(String locator, String comment) { + Issue issue = new Issue(); + issue.setIssueType(locator); + issue.setComment(comment); + return issue; + } + + private static String bugDescription(String resource) { + String description = null; + if (random.nextBoolean()) { + List<String> descriptions = readToList(resource); + description = descriptions.get(random.nextInt(descriptions.size())); + } + return description; + } + + private static List<String> readToList(String resource) { + List<String> content; + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { + content = reader.lines().collect(Collectors.toList()); + } catch (IOException e) { + throw new ReportPortalException("Missing demo content.", e); + } + return content; + } + + private static List<Pair<String, String>> readAttributes(String resource) { + List<Pair<String, String>> content; + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { + content = reader.lines().map(it -> { + if (it.contains(":")) { + return Pair.of(it.split(":")[0], it.split(":")[1]); + } else { + return Pair.of("", it); + } + }).collect(Collectors.toList()); + } catch (IOException e) { + throw new ReportPortalException("Missing demo content.", e); + } + return content; + } + + private static String readToString(String resource) { + String content; + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(new ClassPathResource(resource).getInputStream(), UTF_8))) { + content = reader.lines().collect(Collectors.joining("\n")); + } catch (IOException e) { + throw new ReportPortalException("Missing demo content.", e); + } + return content; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DefaultDemoDataFacade.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DefaultDemoDataFacade.java index c3dbfb2c49..cc147439b8 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DefaultDemoDataFacade.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DefaultDemoDataFacade.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.demodata.service; +import static com.epam.ta.reportportal.demodata.service.Constants.NAME; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.UserRepository; import com.epam.ta.reportportal.demodata.model.DemoLaunch; @@ -30,84 +33,87 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.task.TaskExecutor; import org.springframework.stereotype.Service; import org.springframework.util.ResourceUtils; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; - -import static com.epam.ta.reportportal.demodata.service.Constants.NAME; -import static java.util.stream.Collectors.toList; - /** * @author Ihar Kahadouski */ @Service public class DefaultDemoDataFacade implements DemoDataFacade { - public static final int LAUNCH_LOGS_COUNT = 10; - - private final ObjectMapper objectMapper; - - private final DemoDataLaunchService demoDataLaunchService; - private final DemoLogsService demoLogsService; - private final SuiteGeneratorResolver suiteGeneratorResolver; - - private final TaskExecutor executor; - - private final UserRepository userRepository; - - @Value("classpath:demo/launch/") - private String resourceFolder; - - @Value("${rp.environment.variable.demo.source}") - private String[] sources; - - public DefaultDemoDataFacade(DemoDataLaunchService demoDataLaunchService, DemoLogsService demoLogsService, ObjectMapper objectMapper, - SuiteGeneratorResolver suiteGeneratorResolver, UserRepository userRepository, - @Qualifier("demoDataTaskExecutor") TaskExecutor executor) { - this.demoDataLaunchService = demoDataLaunchService; - this.suiteGeneratorResolver = suiteGeneratorResolver; - this.demoLogsService = demoLogsService; - this.objectMapper = objectMapper; - this.userRepository = userRepository; - this.executor = executor; - } - - @Override - public List<Long> generateDemoLaunches(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - return CompletableFuture.supplyAsync(() -> Stream.of(sources).map(source -> resourceFolder + source).map(source -> { - try { - final DemoLaunch demoLaunch = objectMapper.readValue(ResourceUtils.getURL(source), new TypeReference<DemoLaunch>() { - }); - return generateLaunch(demoLaunch, user, projectDetails); - } catch (IOException e) { - throw new ReportPortalException("Unable to load suites description. " + e.getMessage(), e); - } - }).collect(toList()), executor).join(); - } - - private Long generateLaunch(DemoLaunch demoLaunch, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - - final User creator = userRepository.findById(user.getUserId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, user.getUsername())); - - final Launch launch = demoDataLaunchService.startLaunch(NAME, creator, projectDetails); - - demoLaunch.getSuites().forEach(suite -> { - final SuiteGeneratorType suiteGeneratorType = SuiteGeneratorType.valueOf(suite.getType()); - final SuiteGenerator suiteGenerator = suiteGeneratorResolver.resolve(suiteGeneratorType); - suiteGenerator.generateSuites(suite, RootMetaData.of(launch.getUuid(), user, projectDetails)); - }); - - demoDataLaunchService.finishLaunch(launch.getUuid()); - final List<Log> logs = demoLogsService.generateLaunchLogs(LAUNCH_LOGS_COUNT, launch.getUuid(), launch.getStatus()); - demoLogsService.attachFiles(logs, projectDetails.getProjectId(), launch.getUuid()); - return launch.getId(); - } + public static final int LAUNCH_LOGS_COUNT = 10; + + private final ObjectMapper objectMapper; + + private final DemoDataLaunchService demoDataLaunchService; + private final DemoLogsService demoLogsService; + private final SuiteGeneratorResolver suiteGeneratorResolver; + + private final TaskExecutor executor; + + private final UserRepository userRepository; + + @Value("classpath:demo/launch/") + private String resourceFolder; + + @Value("${rp.environment.variable.demo.source}") + private String[] sources; + + public DefaultDemoDataFacade(DemoDataLaunchService demoDataLaunchService, + DemoLogsService demoLogsService, ObjectMapper objectMapper, + SuiteGeneratorResolver suiteGeneratorResolver, UserRepository userRepository, + @Qualifier("demoDataTaskExecutor") TaskExecutor executor) { + this.demoDataLaunchService = demoDataLaunchService; + this.suiteGeneratorResolver = suiteGeneratorResolver; + this.demoLogsService = demoLogsService; + this.objectMapper = objectMapper; + this.userRepository = userRepository; + this.executor = executor; + } + + @Override + public List<Long> generateDemoLaunches(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + return CompletableFuture.supplyAsync( + () -> Stream.of(sources).map(source -> resourceFolder + source).map(source -> { + try { + final DemoLaunch demoLaunch = objectMapper.readValue(ResourceUtils.getURL(source), + new TypeReference<DemoLaunch>() { + }); + return generateLaunch(demoLaunch, user, projectDetails); + } catch (IOException e) { + throw new ReportPortalException("Unable to load suites description. " + e.getMessage(), + e); + } + }).collect(toList()), executor).join(); + } + + private Long generateLaunch(DemoLaunch demoLaunch, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + + final User creator = userRepository.findById(user.getUserId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.USER_NOT_FOUND, user.getUsername())); + + final Launch launch = demoDataLaunchService.startLaunch(NAME, creator, projectDetails); + + demoLaunch.getSuites().forEach(suite -> { + final SuiteGeneratorType suiteGeneratorType = SuiteGeneratorType.valueOf(suite.getType()); + final SuiteGenerator suiteGenerator = suiteGeneratorResolver.resolve(suiteGeneratorType); + suiteGenerator.generateSuites(suite, RootMetaData.of(launch.getUuid(), user, projectDetails)); + }); + + final List<Log> logs = demoLogsService.generateLaunchLogs(LAUNCH_LOGS_COUNT, launch.getUuid(), + launch.getStatus()); + demoDataLaunchService.finishLaunch(launch.getUuid()); + demoLogsService.attachFiles(logs, projectDetails.getProjectId(), launch.getUuid()); + return launch.getId(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataFacade.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataFacade.java index ced9588b35..164beb4f2f 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataFacade.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataFacade.java @@ -19,19 +19,20 @@ package com.epam.ta.reportportal.demodata.service; import com.epam.ta.reportportal.commons.ReportPortalUser; - import java.util.List; /** * @author Pavel Bortnik */ public interface DemoDataFacade { - /** - * Generates demo launches - * - * @param user - * @param projectDetails - * @return {@link List} of generated launch ids - */ - List<Long> generateDemoLaunches(ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails); + + /** + * Generates demo launches + * + * @param user {@link ReportPortalUser} + * @param projectDetails {@link ReportPortalUser.ProjectDetails} + * @return {@link List} of generated launch ids + */ + List<Long> generateDemoLaunches(ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails); } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataLaunchService.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataLaunchService.java index 3f331cee07..9f6fdf2ebb 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataLaunchService.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataLaunchService.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.demodata.service; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; + +import com.epam.reportportal.extension.event.LaunchFinishedPluginEvent; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.TestItemRepository; @@ -28,19 +32,16 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.collect.Sets; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.Random; import java.util.Set; import java.util.UUID; - -import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; -import static com.epam.ta.reportportal.ws.model.ErrorType.LAUNCH_NOT_FOUND; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -48,62 +49,73 @@ @Service public class DemoDataLaunchService { - private final String[] platformValues = { "linux", "windows", "macos", "ios", "android", "windows mobile", "ubuntu", "mint", "arch", - "windows 10", "windows 7", "windows server", "debian", "alpine" }; + private final String[] platformValues = {"linux", "windows", "macos", "ios", "android", + "windows mobile", "ubuntu", "mint", "arch", + "windows 10", "windows 7", "windows server", "debian", "alpine"}; - private final LaunchRepository launchRepository; - private final TestItemRepository testItemRepository; + private final LaunchRepository launchRepository; + private final TestItemRepository testItemRepository; + private final ApplicationEventPublisher eventPublisher; - @Autowired - public DemoDataLaunchService(LaunchRepository launchRepository, TestItemRepository testItemRepository) { - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - } + @Autowired + public DemoDataLaunchService(LaunchRepository launchRepository, + TestItemRepository testItemRepository, + ApplicationEventPublisher eventPublisher) { + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.eventPublisher = eventPublisher; + } - @Transactional - public Launch startLaunch(String name, User user, ReportPortalUser.ProjectDetails projectDetails) { - StartLaunchRQ rq = new StartLaunchRQ(); - rq.setMode(Mode.DEFAULT); - rq.setDescription(ContentUtils.getLaunchDescription()); - LocalDateTime now = LocalDateTime.now(); - rq.setName(name); - rq.setStartTime(Date.from(now.atZone(ZoneId.systemDefault()).toInstant())); - rq.setUuid(UUID.randomUUID().toString()); - Set<ItemAttributesRQ> attributes = Sets.newHashSet(new ItemAttributesRQ("platform", - platformValues[new Random().nextInt(platformValues.length)] - ), - new ItemAttributesRQ(null, "demo"), - new ItemAttributesRQ("build", - "3." + now.getDayOfMonth() + "." + now.getHour() + "." + now.getMinute() + "." + now.getSecond() - ) - ); - Launch launch = new LaunchBuilder().addStartRQ(rq).addAttributes(attributes).addProject(projectDetails.getProjectId()).get(); - launch.setUserId(user.getId()); - launchRepository.save(launch); - launchRepository.refresh(launch); - return launch; - } + @Transactional + public Launch startLaunch(String name, User user, + ReportPortalUser.ProjectDetails projectDetails) { + StartLaunchRQ rq = new StartLaunchRQ(); + rq.setMode(Mode.DEFAULT); + rq.setDescription(ContentUtils.getLaunchDescription()); + LocalDateTime now = LocalDateTime.now(); + rq.setName(name); + rq.setStartTime(Date.from(now.atZone(ZoneId.systemDefault()).toInstant())); + rq.setUuid(UUID.randomUUID().toString()); + Set<ItemAttributesRQ> attributes = Sets.newHashSet(new ItemAttributesRQ("platform", + platformValues[new Random().nextInt(platformValues.length)] + ), + new ItemAttributesRQ(null, "demo"), + new ItemAttributesRQ("build", + "3." + now.getDayOfMonth() + "." + now.getHour() + "." + now.getMinute() + "." + + now.getSecond() + ) + ); + Launch launch = new LaunchBuilder().addStartRQ(rq).addAttributes(attributes) + .addProject(projectDetails.getProjectId()).get(); + launch.setUserId(user.getId()); + launchRepository.save(launch); + launchRepository.refresh(launch); + return launch; + } - @Transactional - public void finishLaunch(String launchId) { - Launch launch = launchRepository.findByUuid(launchId).orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); + @Transactional + public void finishLaunch(String launchId) { + Launch launch = launchRepository.findByUuid(launchId) + .orElseThrow(() -> new ReportPortalException(LAUNCH_NOT_FOUND, launchId)); - if (testItemRepository.hasItemsInStatusByLaunch(launch.getId(), StatusEnum.IN_PROGRESS)) { - testItemRepository.interruptInProgressItems(launch.getId()); - } + if (testItemRepository.hasItemsInStatusByLaunch(launch.getId(), StatusEnum.IN_PROGRESS)) { + testItemRepository.interruptInProgressItems(launch.getId()); + } - launch = new LaunchBuilder(launch).addEndTime(new Date()).get(); + launch = new LaunchBuilder(launch).addEndTime(new Date()).get(); - StatusEnum fromStatisticsStatus = PASSED; - if (launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), - StatusEnum.PASSED.name(), - StatusEnum.INFO.name(), - StatusEnum.WARN.name() - )) { - fromStatisticsStatus = StatusEnum.FAILED; - } - launch.setStatus(fromStatisticsStatus); + StatusEnum fromStatisticsStatus = PASSED; + if (launchRepository.hasRootItemsWithStatusNotEqual(launch.getId(), + StatusEnum.PASSED.name(), + StatusEnum.INFO.name(), + StatusEnum.WARN.name() + )) { + fromStatisticsStatus = StatusEnum.FAILED; + } + launch.setStatus(fromStatisticsStatus); - launchRepository.save(launch); - } + launchRepository.save(launch); + eventPublisher.publishEvent( + new LaunchFinishedPluginEvent(launch.getId(), launch.getProjectId())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataService.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataService.java index 4f338679f3..88c2b66253 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataService.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataService.java @@ -19,34 +19,36 @@ import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.demodata.model.DemoDataRq; import com.epam.ta.reportportal.demodata.model.DemoDataRs; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - /** * @author Ihar Kahadouski */ @Service public class DemoDataService { - private final DemoDashboardsService demoDashboardsService; - private final DemoDataFacade demoDataFacade; - - @Autowired - public DemoDataService(DemoDashboardsService demoDashboardsService, DemoDataFacade demoDataFacade) { - this.demoDashboardsService = demoDashboardsService; - this.demoDataFacade = demoDataFacade; - } - - public DemoDataRs generate(DemoDataRq demoDataRq, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user) { - DemoDataRs demoDataRs = new DemoDataRs(); - final List<Long> launchIds = demoDataFacade.generateDemoLaunches(user, projectDetails); - demoDataRs.setLaunchIds(launchIds); - if (demoDataRq.isCreateDashboard()) { - demoDashboardsService.generate(user, projectDetails.getProjectId()).ifPresent(it -> demoDataRs.setDashboardId(it.getId())); - } - - return demoDataRs; - } + private final DemoDashboardsService demoDashboardsService; + private final DemoDataFacade demoDataFacade; + + @Autowired + public DemoDataService(DemoDashboardsService demoDashboardsService, + DemoDataFacade demoDataFacade) { + this.demoDashboardsService = demoDashboardsService; + this.demoDataFacade = demoDataFacade; + } + + public DemoDataRs generate(DemoDataRq demoDataRq, ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user) { + DemoDataRs demoDataRs = new DemoDataRs(); + final List<Long> launchIds = demoDataFacade.generateDemoLaunches(user, projectDetails); + demoDataRs.setLaunchIds(launchIds); + if (demoDataRq.isCreateDashboard()) { + demoDashboardsService.generate(user, projectDetails.getProjectId()) + .ifPresent(it -> demoDataRs.setDashboardId(it.getId())); + } + + return demoDataRs; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataTestItemService.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataTestItemService.java index d238942ef2..8d41ab3fde 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataTestItemService.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoDataTestItemService.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.demodata.service; +import static com.epam.ta.reportportal.demodata.service.Constants.ATTRIBUTES_COUNT; +import static com.epam.ta.reportportal.demodata.service.Constants.PACKAGE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.SUITE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.TEST; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; import com.epam.ta.reportportal.core.item.StartTestItemHandler; @@ -26,97 +31,99 @@ import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Date; - -import static com.epam.ta.reportportal.demodata.service.Constants.ATTRIBUTES_COUNT; -import static com.epam.ta.reportportal.demodata.service.Constants.PACKAGE; -import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.SUITE; -import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.TEST; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Service public class DemoDataTestItemService { - private final StartTestItemHandler startTestItemHandler; - private final FinishTestItemHandler finishTestItemHandler; - - @Autowired - public DemoDataTestItemService(StartTestItemHandler startTestItemHandler, FinishTestItemHandler finishTestItemHandler) { - this.startTestItemHandler = startTestItemHandler; - this.finishTestItemHandler = finishTestItemHandler; - } - - @Transactional - public String startRootItem(DemoItemMetadata metadata, RootMetaData rootMetaData) { - - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setName(metadata.getName()); - rq.setCodeRef(PACKAGE + metadata.getName()); - rq.setLaunchUuid(rootMetaData.getLaunchUuid()); - rq.setStartTime(new Date()); - rq.setType(metadata.getType().name()); - if (metadata.getType().sameLevel(SUITE)) { - rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); - rq.setDescription(ContentUtils.getSuiteDescription()); - } - - return startTestItemHandler.startRootItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), rq).getId(); - } - - @Transactional - public void finishRootItem(String rootItemId, ReportPortalUser user, ReportPortalUser.ProjectDetails projectDetails) { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setEndTime(new Date()); - finishTestItemHandler.finishTestItem(user, projectDetails, rootItemId, rq); - } - - @Transactional - public String startTestItem(DemoItemMetadata metadata, RootMetaData rootMetaData) { - - StartTestItemRQ rq = new StartTestItemRQ(); - if (hasChildren(metadata.getType())) { - rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); - rq.setDescription(ContentUtils.getTestDescription()); - } else { - rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); - rq.setDescription(ContentUtils.getStepDescription()); - } - rq.setHasStats(!metadata.isNested()); - rq.setCodeRef(PACKAGE + metadata.getName()); - rq.setRetry(metadata.isRetry()); - rq.setLaunchUuid(rootMetaData.getLaunchUuid()); - rq.setStartTime(new Date()); - rq.setName(metadata.getName()); - rq.setType(metadata.getType().name()); - - return startTestItemHandler.startChildItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), rq, metadata.getParentId()) - .getId(); - } - - @Transactional - public void finishTestItem(String testItemId, StatusEnum status, RootMetaData rootMetaData) { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setEndTime(new Date()); - rq.setStatus(status.name()); - finishTestItemHandler.finishTestItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), testItemId, rq); - } - - @Transactional - public void finishTestItem(String testItemId, StatusEnum status, RootMetaData rootMetaData, String issue) { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setEndTime(new Date()); - rq.setStatus(status.name()); - TestItemIssueGroup.fromValue(issue).ifPresent(group -> rq.setIssue(ContentUtils.getIssue(group))); - finishTestItemHandler.finishTestItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), testItemId, rq); - } - - private boolean hasChildren(TestItemTypeEnum testItemType) { - return testItemType == TEST || testItemType == SUITE; - } + private final StartTestItemHandler startTestItemHandler; + private final FinishTestItemHandler finishTestItemHandler; + + @Autowired + public DemoDataTestItemService(StartTestItemHandler startTestItemHandler, + FinishTestItemHandler finishTestItemHandler) { + this.startTestItemHandler = startTestItemHandler; + this.finishTestItemHandler = finishTestItemHandler; + } + + @Transactional + public String startRootItem(DemoItemMetadata metadata, RootMetaData rootMetaData) { + + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setName(metadata.getName()); + rq.setCodeRef(PACKAGE + metadata.getName()); + rq.setLaunchUuid(rootMetaData.getLaunchUuid()); + rq.setStartTime(new Date()); + rq.setType(metadata.getType().name()); + if (metadata.getType().sameLevel(SUITE)) { + rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); + rq.setDescription(ContentUtils.getSuiteDescription()); + } + + return startTestItemHandler.startRootItem(rootMetaData.getUser(), + rootMetaData.getProjectDetails(), rq).getId(); + } + + @Transactional + public void finishRootItem(String rootItemId, ReportPortalUser user, + ReportPortalUser.ProjectDetails projectDetails) { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setEndTime(new Date()); + finishTestItemHandler.finishTestItem(user, projectDetails, rootItemId, rq); + } + + @Transactional + public String startTestItem(DemoItemMetadata metadata, RootMetaData rootMetaData) { + + StartTestItemRQ rq = new StartTestItemRQ(); + if (hasChildren(metadata.getType())) { + rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); + rq.setDescription(ContentUtils.getTestDescription()); + } else { + rq.setAttributes(ContentUtils.getAttributesInRange(ATTRIBUTES_COUNT)); + rq.setDescription(ContentUtils.getStepDescription()); + } + rq.setHasStats(!metadata.isNested()); + rq.setCodeRef(PACKAGE + metadata.getName()); + rq.setRetry(metadata.isRetry()); + rq.setLaunchUuid(rootMetaData.getLaunchUuid()); + rq.setStartTime(new Date()); + rq.setName(metadata.getName()); + rq.setType(metadata.getType().name()); + + return startTestItemHandler.startChildItem(rootMetaData.getUser(), + rootMetaData.getProjectDetails(), rq, metadata.getParentId()) + .getId(); + } + + @Transactional + public void finishTestItem(String testItemId, StatusEnum status, RootMetaData rootMetaData) { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setEndTime(new Date()); + rq.setStatus(status.name()); + finishTestItemHandler.finishTestItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), + testItemId, rq); + } + + @Transactional + public void finishTestItem(String testItemId, StatusEnum status, RootMetaData rootMetaData, + String issue) { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setEndTime(new Date()); + rq.setStatus(status.name()); + TestItemIssueGroup.fromValue(issue) + .ifPresent(group -> rq.setIssue(ContentUtils.getIssue(group))); + finishTestItemHandler.finishTestItem(rootMetaData.getUser(), rootMetaData.getProjectDetails(), + testItemId, rq); + } + + private boolean hasChildren(TestItemTypeEnum testItemType) { + return testItemType == TEST || testItemType == SUITE; + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoLogsService.java b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoLogsService.java index f41b4fbf2c..ce21a02fb7 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/DemoLogsService.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/DemoLogsService.java @@ -27,8 +27,11 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.HashMap; +import java.util.Map; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -43,7 +46,9 @@ import static com.epam.ta.reportportal.entity.enums.LogLevel.*; import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; import static com.epam.ta.reportportal.util.MultipartFileUtils.getMultipartFile; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_FULL_TO_LOG; import static java.util.stream.Collectors.toList; +import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; @Service public class DemoLogsService { @@ -74,55 +79,75 @@ public DemoLogsService(@Value("${rp.environment.variable.demo.attachment.probabi public List<Log> generateLaunchLogs(int count, String launchUUid, StatusEnum status) { final Launch launch = launchRepository.findByUuid(launchUUid) .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, launchUUid)); - final List<Log> logs = IntStream.range(0, count) - .mapToObj(it -> getLog(launch, ContentUtils.getLogMessage(), infoLevel())) + final List<LogFull> logFulls = IntStream.range(0, count) + .mapToObj(it -> getLogFull(launch, ContentUtils.getLogMessage(), infoLevel())) .collect(toList()); if (FAILED.equals(status)) { List<String> errors = ContentUtils.getErrorLogs(); - logs.addAll(errors.stream().map(msg -> getLog(launch, msg, errorLevel())).collect(toList())); + logFulls.addAll( + errors.stream().map(msg -> getLogFull(launch, msg, errorLevel())).collect(toList())); } + List<Log> logs = logFulls.stream().map(LOG_FULL_TO_LOG).collect(toList()); logRepository.saveAll(logs); - logService.saveLogMessageListToElasticSearch(logs, launch.getId()); + fillIdByUuid(logFulls, logs); + logService.saveLogMessageList(logFulls, launch.getId()); return logs; } - private Log getLog(Launch launch, String message, LogLevel logLevel) { - Log log = new Log(); - log.setLogLevel(logLevel.toInt()); - log.setLogTime(LocalDateTime.now()); - log.setLaunch(launch); - log.setProjectId(launch.getProjectId()); - log.setLogMessage(message); - log.setUuid(UUID.randomUUID().toString()); - return log; + private LogFull getLogFull(Launch launch, String message, LogLevel logLevel) { + LogFull logFull = new LogFull(); + logFull.setLogLevel(logLevel.toInt()); + logFull.setLogTime(LocalDateTime.now()); + logFull.setLaunch(launch); + logFull.setProjectId(launch.getProjectId()); + logFull.setLogMessage(message); + logFull.setUuid(UUID.randomUUID().toString()); + return logFull; } public List<Log> generateItemLogs(int count, Long projectId, String itemUuid, StatusEnum status) { final TestItem testItem = testItemRepository.findByUuid(itemUuid) .orElseThrow(() -> new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, itemUuid)); - List<Log> logs = IntStream.range(0, count) - .mapToObj(it -> getLog(projectId, testItem, infoLevel(), ContentUtils.getLogMessage())) + List<LogFull> logFulls = IntStream.range(0, count) + .mapToObj(it -> getLogFull(projectId, testItem, infoLevel(), ContentUtils.getLogMessage())) .collect(toList()); if (FAILED.equals(status)) { List<String> errors = ContentUtils.getErrorLogs(); - logs.addAll(errors.stream().map(msg -> getLog(projectId, testItem, errorLevel(), msg)).collect(toList())); + logFulls.addAll(errors.stream().map(msg -> getLogFull(projectId, testItem, errorLevel(), msg)) + .collect(toList())); } + List<Log> logs = logFulls.stream().map(LOG_FULL_TO_LOG).collect(toList()); logRepository.saveAll(logs); - logService.saveLogMessageListToElasticSearch(logs, testItem.getLaunchId()); + fillIdByUuid(logFulls, logs); + logService.saveLogMessageList(logFulls, testItem.getLaunchId()); return logs; } - private Log getLog(Long projectId, TestItem testItem, LogLevel logLevel, String logMessage) { - Log log = new Log(); - log.setLogLevel(logLevel.toInt()); - log.setLogTime(LocalDateTime.now()); - log.setTestItem(testItem); - log.setProjectId(projectId); - log.setLogMessage(logMessage); - log.setUuid(UUID.randomUUID().toString()); - return log; + private LogFull getLogFull(Long projectId, TestItem testItem, LogLevel logLevel, + String logMessage) { + LogFull logFull = new LogFull(); + logFull.setLogLevel(logLevel.toInt()); + logFull.setLogTime(LocalDateTime.now()); + logFull.setTestItem(testItem); + logFull.setProjectId(projectId); + logFull.setLogMessage(logMessage); + logFull.setUuid(UUID.randomUUID().toString()); + return logFull; + } + + private void fillIdByUuid(List<LogFull> logFulls, List<Log> logs) { + if (isNotEmpty(logFulls) && isNotEmpty(logs)) { + Map<String, Long> logIdsMap = new HashMap<>(logs.size()); + for (Log log : logs) { + logIdsMap.put(log.getUuid(), log.getId()); + } + + for (LogFull logFull : logFulls) { + logFull.setId(logIdsMap.get(logFull.getUuid())); + } + } } public void attachFiles(List<Log> logs, Long projectId, String launchUuid) { diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/DefaultSuiteGenerator.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/DefaultSuiteGenerator.java index 46cb2858fa..71c01d913f 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/DefaultSuiteGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/DefaultSuiteGenerator.java @@ -1,149 +1,173 @@ package com.epam.ta.reportportal.demodata.service.generator; -import com.epam.ta.reportportal.demodata.model.*; +import static com.epam.ta.reportportal.demodata.service.ContentUtils.getNameFromType; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.AFTER_CLASS; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.AFTER_METHOD; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.AFTER_SUITE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.BEFORE_CLASS; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.BEFORE_METHOD; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.BEFORE_SUITE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.STEP; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.SUITE; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.TEST; +import static java.util.Optional.ofNullable; + +import com.epam.ta.reportportal.demodata.model.DemoItemMetadata; +import com.epam.ta.reportportal.demodata.model.RootMetaData; +import com.epam.ta.reportportal.demodata.model.Suite; +import com.epam.ta.reportportal.demodata.model.Test; import com.epam.ta.reportportal.demodata.service.DemoDataTestItemService; import com.epam.ta.reportportal.demodata.service.DemoLogsService; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; import com.epam.ta.reportportal.entity.log.Log; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - -import static com.epam.ta.reportportal.demodata.service.ContentUtils.getNameFromType; -import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.*; -import static java.util.Optional.ofNullable; - @Service public class DefaultSuiteGenerator implements SuiteGenerator { - public static final int BEFORE_AFTER_LOGS_COUNT = 2; - public static final int SUITE_LOGS_COUNT = 3; - public static final int TEST_LOGS_COUNT = 3; - public static final int STEP_LOGS_COUNT = 5; - - protected final DemoDataTestItemService demoDataTestItemService; - private final DemoLogsService demoLogsService; - - @Autowired - public DefaultSuiteGenerator(DemoDataTestItemService demoDataTestItemService, DemoLogsService demoLogsService) { - this.demoDataTestItemService = demoDataTestItemService; - this.demoLogsService = demoLogsService; - } - - @Override - public void generateSuites(Suite suite, RootMetaData rootMetaData) { - - final StatusEnum suiteStatus = StatusEnum.valueOf(suite.getStatus()); - - if (suite.isHasBefore()) { - final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_SUITE), - BEFORE_SUITE, - suiteStatus, - null - ).withLogCount(BEFORE_AFTER_LOGS_COUNT); - createStep(beforeMetaData, rootMetaData); - } - - final DemoItemMetadata suiteMetaData = getMetadata(suite.getName(), SUITE, suiteStatus, null); - final String suiteId = demoDataTestItemService.startRootItem(suiteMetaData, rootMetaData); - - suite.getTests().forEach(test -> { - final StatusEnum testStatus = StatusEnum.valueOf(test.getStatus()); - - if (test.isHasBefore()) { - final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_CLASS), - BEFORE_CLASS, - testStatus, - suiteId - ).withLogCount(BEFORE_AFTER_LOGS_COUNT); - createStep(beforeMetaData, rootMetaData); - } - generateTest(suiteId, rootMetaData, test, testStatus); - if (test.isHasAfter()) { - final DemoItemMetadata afterMetaData = getMetadata(getNameFromType(AFTER_CLASS), - AFTER_CLASS, - testStatus, - suiteId - ).withLogCount(BEFORE_AFTER_LOGS_COUNT); - createStep(afterMetaData, rootMetaData); - } - }); - - demoDataTestItemService.finishTestItem(suiteId, suiteStatus, rootMetaData); - generateLogs(SUITE_LOGS_COUNT, suiteId, suiteStatus, rootMetaData); - - if (suite.isHasAfter()) { - createStep(getMetadata(getNameFromType(AFTER_SUITE), AFTER_SUITE, suiteStatus, null).withLogCount(BEFORE_AFTER_LOGS_COUNT), - rootMetaData - ); - } - } - - protected DemoItemMetadata getMetadata(String name, TestItemTypeEnum type, StatusEnum status, String parentId) { - return new DemoItemMetadata().withName(name).withType(type).withStatus(status).withParentId(parentId); - } - - protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { - final String stepId = ofNullable(stepMetaData.getParentId()).map(parentId -> demoDataTestItemService.startTestItem(stepMetaData, - rootMetaData - )).orElseGet(() -> demoDataTestItemService.startRootItem(stepMetaData, rootMetaData)); - - generateLogs(stepMetaData.getLogCount(), stepId, stepMetaData.getStatus(), rootMetaData); - ofNullable(stepMetaData.getIssue()).ifPresentOrElse(issue -> demoDataTestItemService.finishTestItem(stepId, - stepMetaData.getStatus(), - rootMetaData, - issue - ), () -> demoDataTestItemService.finishTestItem(stepId, stepMetaData.getStatus(), rootMetaData)); - } - - protected void generateTest(String suiteId, RootMetaData rootMetaData, Test test, StatusEnum testStatus) { - final String testId = startTest(suiteId, rootMetaData, test, testStatus); - generateSteps(rootMetaData, test, testId); - - ofNullable(test.getIssue()).ifPresentOrElse(issue -> demoDataTestItemService.finishTestItem(testId, - testStatus, - rootMetaData, - issue - ), () -> demoDataTestItemService.finishTestItem(testId, testStatus, rootMetaData)); - generateLogs(TEST_LOGS_COUNT, testId, testStatus, rootMetaData); - } - - protected String startTest(String suiteId, RootMetaData rootMetaData, Test test, StatusEnum testStatus) { - final DemoItemMetadata testMetaData = getMetadata(test.getName(), TEST, testStatus, suiteId).withIssue(test.getIssue()); - return demoDataTestItemService.startTestItem(testMetaData, rootMetaData); - } - - private void generateSteps(RootMetaData rootMetaData, Test test, String testId) { - test.getSteps().forEach(step -> { - final StatusEnum stepStatus = StatusEnum.valueOf(step.getStatus()); - if (step.isHasBefore()) { - final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_METHOD), - BEFORE_METHOD, - stepStatus, - testId - ).withLogCount(BEFORE_AFTER_LOGS_COUNT); - createStep(beforeMetaData, rootMetaData); - } - final DemoItemMetadata stepMetaData = getMetadata(step.getName(), STEP, stepStatus, testId).withLogCount(STEP_LOGS_COUNT) - .withIssue(step.getIssue()); - createStep(stepMetaData, rootMetaData); - if (step.isHasBefore()) { - final DemoItemMetadata afterMetaData = getMetadata(getNameFromType(AFTER_METHOD), - AFTER_METHOD, - stepStatus, - testId - ).withLogCount(BEFORE_AFTER_LOGS_COUNT); - createStep(afterMetaData, rootMetaData); - } - }); - } - - private void generateLogs(int count, String itemId, StatusEnum status, RootMetaData rootMetaData) { - final Long projectId = rootMetaData.getProjectDetails().getProjectId(); - List<Log> logs = demoLogsService.generateItemLogs(count, projectId, itemId, status); - demoLogsService.attachFiles(logs, projectId, itemId, rootMetaData.getLaunchUuid()); - } + public static final int BEFORE_AFTER_LOGS_COUNT = 2; + public static final int SUITE_LOGS_COUNT = 3; + public static final int TEST_LOGS_COUNT = 3; + public static final int STEP_LOGS_COUNT = 5; + + protected final DemoDataTestItemService demoDataTestItemService; + private final DemoLogsService demoLogsService; + + @Autowired + public DefaultSuiteGenerator(DemoDataTestItemService demoDataTestItemService, + DemoLogsService demoLogsService) { + this.demoDataTestItemService = demoDataTestItemService; + this.demoLogsService = demoLogsService; + } + + @Override + public void generateSuites(Suite suite, RootMetaData rootMetaData) { + + final StatusEnum suiteStatus = StatusEnum.valueOf(suite.getStatus()); + + if (suite.isHasBefore()) { + final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_SUITE), + BEFORE_SUITE, + suiteStatus, + null + ).withLogCount(BEFORE_AFTER_LOGS_COUNT); + createStep(beforeMetaData, rootMetaData); + } + + final DemoItemMetadata suiteMetaData = getMetadata(suite.getName(), SUITE, suiteStatus, null); + final String suiteId = demoDataTestItemService.startRootItem(suiteMetaData, rootMetaData); + + suite.getTests().forEach(test -> { + final StatusEnum testStatus = StatusEnum.valueOf(test.getStatus()); + + if (test.isHasBefore()) { + final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_CLASS), + BEFORE_CLASS, + testStatus, + suiteId + ).withLogCount(BEFORE_AFTER_LOGS_COUNT); + createStep(beforeMetaData, rootMetaData); + } + generateTest(suiteId, rootMetaData, test, testStatus); + if (test.isHasAfter()) { + final DemoItemMetadata afterMetaData = getMetadata(getNameFromType(AFTER_CLASS), + AFTER_CLASS, + testStatus, + suiteId + ).withLogCount(BEFORE_AFTER_LOGS_COUNT); + createStep(afterMetaData, rootMetaData); + } + }); + + demoDataTestItemService.finishTestItem(suiteId, suiteStatus, rootMetaData); + generateLogs(SUITE_LOGS_COUNT, suiteId, suiteStatus, rootMetaData); + + if (suite.isHasAfter()) { + createStep( + getMetadata(getNameFromType(AFTER_SUITE), AFTER_SUITE, suiteStatus, null).withLogCount( + BEFORE_AFTER_LOGS_COUNT), + rootMetaData + ); + } + } + + protected DemoItemMetadata getMetadata(String name, TestItemTypeEnum type, StatusEnum status, + String parentId) { + return new DemoItemMetadata().withName(name).withType(type).withStatus(status) + .withParentId(parentId); + } + + protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { + final String stepId = ofNullable(stepMetaData.getParentId()).map( + parentId -> demoDataTestItemService.startTestItem(stepMetaData, + rootMetaData + )).orElseGet(() -> demoDataTestItemService.startRootItem(stepMetaData, rootMetaData)); + + generateLogs(stepMetaData.getLogCount(), stepId, stepMetaData.getStatus(), rootMetaData); + ofNullable(stepMetaData.getIssue()).ifPresentOrElse( + issue -> demoDataTestItemService.finishTestItem(stepId, + stepMetaData.getStatus(), + rootMetaData, + issue + ), () -> demoDataTestItemService.finishTestItem(stepId, stepMetaData.getStatus(), + rootMetaData)); + } + + protected void generateTest(String suiteId, RootMetaData rootMetaData, Test test, + StatusEnum testStatus) { + final String testId = startTest(suiteId, rootMetaData, test, testStatus); + generateSteps(rootMetaData, test, testId); + + ofNullable(test.getIssue()).ifPresentOrElse( + issue -> demoDataTestItemService.finishTestItem(testId, + testStatus, + rootMetaData, + issue + ), () -> demoDataTestItemService.finishTestItem(testId, testStatus, rootMetaData)); + generateLogs(TEST_LOGS_COUNT, testId, testStatus, rootMetaData); + } + + protected String startTest(String suiteId, RootMetaData rootMetaData, Test test, + StatusEnum testStatus) { + final DemoItemMetadata testMetaData = getMetadata(test.getName(), TEST, testStatus, + suiteId).withIssue(test.getIssue()); + return demoDataTestItemService.startTestItem(testMetaData, rootMetaData); + } + + private void generateSteps(RootMetaData rootMetaData, Test test, String testId) { + test.getSteps().forEach(step -> { + final StatusEnum stepStatus = StatusEnum.valueOf(step.getStatus()); + if (step.isHasBefore()) { + final DemoItemMetadata beforeMetaData = getMetadata(getNameFromType(BEFORE_METHOD), + BEFORE_METHOD, + stepStatus, + testId + ).withLogCount(BEFORE_AFTER_LOGS_COUNT); + createStep(beforeMetaData, rootMetaData); + } + final DemoItemMetadata stepMetaData = getMetadata(step.getName(), STEP, stepStatus, + testId).withLogCount(STEP_LOGS_COUNT) + .withIssue(step.getIssue()); + createStep(stepMetaData, rootMetaData); + if (step.isHasBefore()) { + final DemoItemMetadata afterMetaData = getMetadata(getNameFromType(AFTER_METHOD), + AFTER_METHOD, + stepStatus, + testId + ).withLogCount(BEFORE_AFTER_LOGS_COUNT); + createStep(afterMetaData, rootMetaData); + } + }); + } + + private void generateLogs(int count, String itemId, StatusEnum status, + RootMetaData rootMetaData) { + final Long projectId = rootMetaData.getProjectDetails().getProjectId(); + List<Log> logs = demoLogsService.generateItemLogs(count, projectId, itemId, status); + demoLogsService.attachFiles(logs, projectId, itemId, rootMetaData.getLaunchUuid()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGenerator.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGenerator.java index 9bcc578d4a..1001c23639 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGenerator.java @@ -5,6 +5,6 @@ public interface SuiteGenerator { - void generateSuites(Suite suite, RootMetaData rootMetaData); + void generateSuites(Suite suite, RootMetaData rootMetaData); } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGeneratorResolver.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGeneratorResolver.java index d68ecf6848..1a2d8ff76f 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGeneratorResolver.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteGeneratorResolver.java @@ -1,18 +1,17 @@ package com.epam.ta.reportportal.demodata.service.generator; import com.epam.ta.reportportal.demodata.service.generator.model.SuiteGeneratorType; - import java.util.Map; public class SuiteGeneratorResolver { - private final Map<SuiteGeneratorType, SuiteGenerator> suiteGeneratorMapping; + private final Map<SuiteGeneratorType, SuiteGenerator> suiteGeneratorMapping; - public SuiteGeneratorResolver(Map<SuiteGeneratorType, SuiteGenerator> suiteGeneratorMapping) { - this.suiteGeneratorMapping = suiteGeneratorMapping; - } + public SuiteGeneratorResolver(Map<SuiteGeneratorType, SuiteGenerator> suiteGeneratorMapping) { + this.suiteGeneratorMapping = suiteGeneratorMapping; + } - public SuiteGenerator resolve(SuiteGeneratorType type) { - return suiteGeneratorMapping.get(type); - } + public SuiteGenerator resolve(SuiteGeneratorType type) { + return suiteGeneratorMapping.get(type); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithNestedStepsGenerator.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithNestedStepsGenerator.java index f5de74e2b0..23763f970f 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithNestedStepsGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithNestedStepsGenerator.java @@ -1,5 +1,7 @@ package com.epam.ta.reportportal.demodata.service.generator; +import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.STEP; + import com.epam.ta.reportportal.demodata.model.DemoItemMetadata; import com.epam.ta.reportportal.demodata.model.RootMetaData; import com.epam.ta.reportportal.demodata.model.Test; @@ -9,26 +11,27 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import static com.epam.ta.reportportal.entity.enums.TestItemTypeEnum.STEP; - @Service public class SuiteWithNestedStepsGenerator extends DefaultSuiteGenerator { - @Autowired - public SuiteWithNestedStepsGenerator(DemoDataTestItemService demoDataTestItemService, DemoLogsService demoLogsService) { - super(demoDataTestItemService, demoLogsService); - } + @Autowired + public SuiteWithNestedStepsGenerator(DemoDataTestItemService demoDataTestItemService, + DemoLogsService demoLogsService) { + super(demoDataTestItemService, demoLogsService); + } - @Override - protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { - super.createStep(stepMetaData.withNested(true), rootMetaData); - } + @Override + protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { + super.createStep(stepMetaData.withNested(true), rootMetaData); + } - @Override - protected String startTest(String suiteId, RootMetaData rootMetaData, Test test, StatusEnum testStatus) { - final String testId = super.startTest(suiteId, rootMetaData, test, testStatus); - final DemoItemMetadata stepParentMetadata = getMetadata(test.getName(), STEP, testStatus, testId); - return demoDataTestItemService.startTestItem(stepParentMetadata, rootMetaData); - } + @Override + protected String startTest(String suiteId, RootMetaData rootMetaData, Test test, + StatusEnum testStatus) { + final String testId = super.startTest(suiteId, rootMetaData, test, testStatus); + final DemoItemMetadata stepParentMetadata = getMetadata(test.getName(), STEP, testStatus, + testId); + return demoDataTestItemService.startTestItem(stepParentMetadata, rootMetaData); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithRetriesGenerator.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithRetriesGenerator.java index d74c4aa130..b269ac455b 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithRetriesGenerator.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/SuiteWithRetriesGenerator.java @@ -5,37 +5,37 @@ import com.epam.ta.reportportal.demodata.service.DemoDataTestItemService; import com.epam.ta.reportportal.demodata.service.DemoLogsService; import com.epam.ta.reportportal.entity.enums.StatusEnum; +import java.util.stream.IntStream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.stream.IntStream; - @Service public class SuiteWithRetriesGenerator extends DefaultSuiteGenerator { - private static final int RETRIES_COUNT = 3; + private static final int RETRIES_COUNT = 3; - @Autowired - public SuiteWithRetriesGenerator(DemoDataTestItemService demoDataTestItemService, DemoLogsService demoLogsService) { - super(demoDataTestItemService, demoLogsService); - } + @Autowired + public SuiteWithRetriesGenerator(DemoDataTestItemService demoDataTestItemService, + DemoLogsService demoLogsService) { + super(demoDataTestItemService, demoLogsService); + } - @Override - protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { - super.createStep(stepMetaData, rootMetaData); - if (stepMetaData.getStatus() != StatusEnum.PASSED) { - generateRetries(stepMetaData, rootMetaData); - } - } + @Override + protected void createStep(DemoItemMetadata stepMetaData, RootMetaData rootMetaData) { + super.createStep(stepMetaData, rootMetaData); + if (stepMetaData.getStatus() != StatusEnum.PASSED) { + generateRetries(stepMetaData, rootMetaData); + } + } - private void generateRetries(final DemoItemMetadata metadata, RootMetaData rootMetaData) { - IntStream.range(0, RETRIES_COUNT).forEach(i -> { - final DemoItemMetadata retryMetaData = getMetadata(metadata.getName(), - metadata.getType(), - metadata.getStatus(), - metadata.getParentId() - ).withIssue(metadata.getIssue()).withRetry(true); - super.createStep(retryMetaData, rootMetaData); - }); - } + private void generateRetries(final DemoItemMetadata metadata, RootMetaData rootMetaData) { + IntStream.range(0, RETRIES_COUNT).forEach(i -> { + final DemoItemMetadata retryMetaData = getMetadata(metadata.getName(), + metadata.getType(), + metadata.getStatus(), + metadata.getParentId() + ).withIssue(metadata.getIssue()).withRetry(true); + super.createStep(retryMetaData, rootMetaData); + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/model/SuiteGeneratorType.java b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/model/SuiteGeneratorType.java index 23034b944d..c97039bfb8 100644 --- a/src/main/java/com/epam/ta/reportportal/demodata/service/generator/model/SuiteGeneratorType.java +++ b/src/main/java/com/epam/ta/reportportal/demodata/service/generator/model/SuiteGeneratorType.java @@ -1,5 +1,5 @@ package com.epam.ta.reportportal.demodata.service.generator.model; public enum SuiteGeneratorType { - DEFAULT, RETRY, NESTED; + DEFAULT, RETRY, NESTED; } diff --git a/src/main/java/com/epam/ta/reportportal/exception/DataStorageException.java b/src/main/java/com/epam/ta/reportportal/exception/DataStorageException.java index 0c0688031a..4723799721 100644 --- a/src/main/java/com/epam/ta/reportportal/exception/DataStorageException.java +++ b/src/main/java/com/epam/ta/reportportal/exception/DataStorageException.java @@ -24,15 +24,15 @@ // TODO add binding to this exception public class DataStorageException extends ReportPortalException { - private static final long serialVersionUID = -6822780391660931103L; + private static final long serialVersionUID = -6822780391660931103L; - public DataStorageException(String message) { - super(message); + public DataStorageException(String message) { + super(message); - } + } - public DataStorageException(String message, Throwable e) { - super(message, e); - } + public DataStorageException(String message, Throwable e) { + super(message, e); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/exception/HandlerNotDefinedException.java b/src/main/java/com/epam/ta/reportportal/exception/HandlerNotDefinedException.java index ed67888b5b..3f1f852d9b 100644 --- a/src/main/java/com/epam/ta/reportportal/exception/HandlerNotDefinedException.java +++ b/src/main/java/com/epam/ta/reportportal/exception/HandlerNotDefinedException.java @@ -24,10 +24,10 @@ // TODO add mapping for this exception public class HandlerNotDefinedException extends RuntimeException { - private static final long serialVersionUID = 7447853618838625617L; + private static final long serialVersionUID = 7447853618838625617L; - public HandlerNotDefinedException(String message) { - super(message); - } + public HandlerNotDefinedException(String message) { + super(message); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/exception/PermissionNotDefinedException.java b/src/main/java/com/epam/ta/reportportal/exception/PermissionNotDefinedException.java index 472004eac4..28c406bcdc 100644 --- a/src/main/java/com/epam/ta/reportportal/exception/PermissionNotDefinedException.java +++ b/src/main/java/com/epam/ta/reportportal/exception/PermissionNotDefinedException.java @@ -24,10 +24,10 @@ // TODO add exception mapping public class PermissionNotDefinedException extends RuntimeException { - private static final long serialVersionUID = 843053936838256383L; + private static final long serialVersionUID = 843053936838256383L; - public PermissionNotDefinedException(String exception) { - super(exception); - } + public PermissionNotDefinedException(String exception) { + super(exception); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/exception/UserAccountExpiredException.java b/src/main/java/com/epam/ta/reportportal/exception/UserAccountExpiredException.java index 9da477393d..35fa3d3da0 100644 --- a/src/main/java/com/epam/ta/reportportal/exception/UserAccountExpiredException.java +++ b/src/main/java/com/epam/ta/reportportal/exception/UserAccountExpiredException.java @@ -20,9 +20,9 @@ public class UserAccountExpiredException extends AccountExpiredException { - private static final long serialVersionUID = -1313818913697889296L; + private static final long serialVersionUID = -1313818913697889296L; - public UserAccountExpiredException(String msg) { - super(msg); - } + public UserAccountExpiredException(String msg) { + super(msg); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/health/JobsHealthIndicator.java b/src/main/java/com/epam/ta/reportportal/health/JobsHealthIndicator.java new file mode 100644 index 0000000000..337797d126 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/health/JobsHealthIndicator.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.health; + +import java.util.Map; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Health.Builder; +import org.springframework.boot.actuate.health.Status; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + + +/** + * Health Indicator for jobs service. + * + * @author Siarhei Hrabko + */ +@Component +public class JobsHealthIndicator extends AbstractHealthIndicator { + + private static Logger LOGGER = LoggerFactory.getLogger(JobsHealthIndicator.class); + private static final String ERROR_MESSAGE = "Jobs service health check failed"; + RestTemplate restTemplate; + + @Value("${rp.jobs.baseUrl}") + private String jobsBaseUrl; + + public JobsHealthIndicator() { + super(ERROR_MESSAGE); + this.restTemplate = new RestTemplate(); + } + + @Override + protected void doHealthCheck(Builder builder) { + try { + var jobsHealthRs = restTemplate.getForObject(jobsBaseUrl + "/health", Map.class); + + var jobsStatus = new Status((String) jobsHealthRs.get("status")); + builder.status(jobsStatus); + + Optional.ofNullable(jobsHealthRs.get("components")) + .map(Map.class::cast) + .ifPresent(builder::withDetails); + + builder.build(); + + } catch (Exception e) { + LOGGER.error("{} : {}", ERROR_MESSAGE, e.getMessage()); + builder.unknown() + .withException(e) + .build(); + } + } + + @Override + public Health getHealth(boolean includeDetails) { + return super.getHealth(includeDetails); + } + +} diff --git a/src/main/java/com/epam/ta/reportportal/info/AnalyzerInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/AnalyzerInfoContributor.java index 5ed6725d06..07aaff5c23 100644 --- a/src/main/java/com/epam/ta/reportportal/info/AnalyzerInfoContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/AnalyzerInfoContributor.java @@ -19,13 +19,12 @@ import com.epam.ta.reportportal.core.analyzer.auto.client.RabbitMqManagementClient; import com.google.common.collect.ImmutableMap; import com.rabbitmq.http.client.domain.ExchangeInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * Shows list of supported analyzers @@ -35,19 +34,19 @@ @Component public class AnalyzerInfoContributor implements ExtensionContributor { - private final RabbitMqManagementClient managementClient; + private final RabbitMqManagementClient managementClient; - @Autowired - public AnalyzerInfoContributor(RabbitMqManagementClient managementClient) { - this.managementClient = managementClient; - } + @Autowired + public AnalyzerInfoContributor(RabbitMqManagementClient managementClient) { + this.managementClient = managementClient; + } - @Override - public Map<String, ?> contribute() { - Set<Object> analyzersInfo = managementClient.getAnalyzerExchangesInfo() - .stream() - .map((Function<ExchangeInfo, Object>) ExchangeInfo::getArguments) - .collect(Collectors.toSet()); - return ImmutableMap.<String, Object>builder().put("analyzers", analyzersInfo).build(); - } + @Override + public Map<String, ?> contribute() { + Set<Object> analyzersInfo = managementClient.getAnalyzerExchangesInfo() + .stream() + .map((Function<ExchangeInfo, Object>) ExchangeInfo::getArguments) + .collect(Collectors.toSet()); + return ImmutableMap.<String, Object>builder().put("analyzers", analyzersInfo).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/info/EnvironmentVariablesInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/EnvironmentVariablesInfoContributor.java index d187e9422b..303624734e 100644 --- a/src/main/java/com/epam/ta/reportportal/info/EnvironmentVariablesInfoContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/EnvironmentVariablesInfoContributor.java @@ -17,11 +17,10 @@ package com.epam.ta.reportportal.info; import com.google.common.collect.ImmutableMap; -import org.springframework.boot.actuate.info.MapInfoContributor; -import org.springframework.stereotype.Component; - import java.util.Map; import java.util.stream.Collectors; +import org.springframework.boot.actuate.info.MapInfoContributor; +import org.springframework.stereotype.Component; /** * Collects provided environment variables with rp prefix. @@ -31,15 +30,16 @@ @Component public class EnvironmentVariablesInfoContributor extends MapInfoContributor { - private static final String RP_ENV_PREFIX = "RP_ENVIRONMENT_VARIABLE_"; + private static final String RP_ENV_PREFIX = "RP_ENVIRONMENT_VARIABLE_"; - public EnvironmentVariablesInfoContributor() { - super(ImmutableMap.<String, Object>builder().put("environment", - System.getenv() - .entrySet() - .stream() - .filter(it -> it.getKey().startsWith(RP_ENV_PREFIX)) - .collect(Collectors.toMap(e -> e.getKey().replaceFirst(RP_ENV_PREFIX, "").toLowerCase(), Map.Entry::getValue)) - ).build()); - } + public EnvironmentVariablesInfoContributor() { + super(ImmutableMap.<String, Object>builder().put("environment", + System.getenv() + .entrySet() + .stream() + .filter(it -> it.getKey().startsWith(RP_ENV_PREFIX)) + .collect(Collectors.toMap(e -> e.getKey().replaceFirst(RP_ENV_PREFIX, "").toLowerCase(), + Map.Entry::getValue)) + ).build()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/info/ExtensionContributor.java b/src/main/java/com/epam/ta/reportportal/info/ExtensionContributor.java index 148b56032b..5e44a1d93b 100644 --- a/src/main/java/com/epam/ta/reportportal/info/ExtensionContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/ExtensionContributor.java @@ -21,5 +21,6 @@ * @author Pavel_Bortnik */ public interface ExtensionContributor { - Map<String, ?> contribute(); + + Map<String, ?> contribute(); } diff --git a/src/main/java/com/epam/ta/reportportal/info/ExtensionsInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/ExtensionsInfoContributor.java index abd44a7238..43c577f7e1 100644 --- a/src/main/java/com/epam/ta/reportportal/info/ExtensionsInfoContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/ExtensionsInfoContributor.java @@ -18,12 +18,11 @@ import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; import com.epam.ta.reportportal.core.plugin.Plugin; import com.google.common.collect.ImmutableMap; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * Shows list of supported extensions providers. @@ -34,16 +33,17 @@ @Component public class ExtensionsInfoContributor implements ExtensionContributor { - private static final String EXTENSION_KEY = "extension"; + private static final String EXTENSION_KEY = "extension"; - private static final String BUGTRACKING_KEY = "bugtracking"; + private static final String BUGTRACKING_KEY = "bugtracking"; - @Autowired - private Pf4jPluginBox pluginBox; + @Autowired + private Pf4jPluginBox pluginBox; - @Override - public Map<String, ?> contribute() { - Set<String> names = pluginBox.getPlugins().stream().map(Plugin::getId).collect(Collectors.toSet()); - return ImmutableMap.<String, Object>builder().put(EXTENSION_KEY, names).build(); - } + @Override + public Map<String, ?> contribute() { + Set<String> names = pluginBox.getPlugins().stream().map(Plugin::getId) + .collect(Collectors.toSet()); + return ImmutableMap.<String, Object>builder().put(EXTENSION_KEY, names).build(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/info/InfoContributorComposite.java b/src/main/java/com/epam/ta/reportportal/info/InfoContributorComposite.java index 2248c5ef67..18ce35be7c 100644 --- a/src/main/java/com/epam/ta/reportportal/info/InfoContributorComposite.java +++ b/src/main/java/com/epam/ta/reportportal/info/InfoContributorComposite.java @@ -15,15 +15,14 @@ */ package com.epam.ta.reportportal.info; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.info.Info; import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - /** * @author Pavel Bortnik */ @@ -31,20 +30,20 @@ @Component public class InfoContributorComposite implements InfoContributor { - private static final String EXTENSIONS_KEY = "extensions"; + private static final String EXTENSIONS_KEY = "extensions"; - private final List<ExtensionContributor> infoContributors; + private final List<ExtensionContributor> infoContributors; - @Autowired - public InfoContributorComposite(List<ExtensionContributor> infoContributors) { - this.infoContributors = infoContributors; - } + @Autowired + public InfoContributorComposite(List<ExtensionContributor> infoContributors) { + this.infoContributors = infoContributors; + } - @Override - public void contribute(Info.Builder builder) { - builder.withDetail(EXTENSIONS_KEY, infoContributors.stream() - .map(ExtensionContributor::contribute) - .flatMap(map -> map.entrySet().stream()) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); - } + @Override + public void contribute(Info.Builder builder) { + builder.withDetail(EXTENSIONS_KEY, infoContributors.stream() + .map(ExtensionContributor::contribute) + .flatMap(map -> map.entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + } } diff --git a/src/main/java/com/epam/ta/reportportal/info/JobSchedulerInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/JobSchedulerInfoContributor.java index ce5051e328..493dbec833 100644 --- a/src/main/java/com/epam/ta/reportportal/info/JobSchedulerInfoContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/JobSchedulerInfoContributor.java @@ -17,6 +17,10 @@ import com.epam.ta.reportportal.core.configs.Conditions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.collections.MapUtils; import org.quartz.Scheduler; import org.quartz.SchedulerException; @@ -29,14 +33,8 @@ import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - /** - * Collects info about existing jobs and how much it is left - * to the next trigger execution + * Collects info about existing jobs and how much it is left to the next trigger execution * * @author Pavel Bortnik */ @@ -44,37 +42,39 @@ @Conditional(Conditions.NotTestCondition.class) public class JobSchedulerInfoContributor implements InfoContributor { - private static final Logger LOGGER = LoggerFactory.getLogger(JobSchedulerInfoContributor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JobSchedulerInfoContributor.class); - @Autowired - private Scheduler scheduler; + @Autowired + private Scheduler scheduler; - @Override - public void contribute(Info.Builder builder) { - try { - Map<String, Map<String, Long>> triggersInfo = scheduler.getTriggerGroupNames().stream().flatMap(name -> { - try { - return scheduler.getJobKeys(GroupMatcher.groupEquals(name)).stream(); - } catch (SchedulerException e) { - LOGGER.warn(e.getMessage()); - return Stream.empty(); - } - }).collect(Collectors.toList()).stream().flatMap(key -> { - try { - return scheduler.getTriggersOfJob(key).stream(); - } catch (SchedulerException e) { - LOGGER.warn(e.getMessage()); - return Stream.empty(); - } - }).collect(Collectors.toMap( - t -> t.getKey().getName(), - t -> Collections.singletonMap("triggersIn", t.getNextFireTime().getTime() - System.currentTimeMillis()) - )); - if (MapUtils.isNotEmpty(triggersInfo)) { - builder.withDetail("jobs", triggersInfo); - } - } catch (SchedulerException e) { - throw new ReportPortalException(e.getMessage()); - } - } + @Override + public void contribute(Info.Builder builder) { + try { + Map<String, Map<String, Long>> triggersInfo = scheduler.getTriggerGroupNames().stream() + .flatMap(name -> { + try { + return scheduler.getJobKeys(GroupMatcher.groupEquals(name)).stream(); + } catch (SchedulerException e) { + LOGGER.warn(e.getMessage()); + return Stream.empty(); + } + }).collect(Collectors.toList()).stream().flatMap(key -> { + try { + return scheduler.getTriggersOfJob(key).stream(); + } catch (SchedulerException e) { + LOGGER.warn(e.getMessage()); + return Stream.empty(); + } + }).collect(Collectors.toMap( + t -> t.getKey().getName(), + t -> Collections.singletonMap("triggersIn", + t.getNextFireTime().getTime() - System.currentTimeMillis()) + )); + if (MapUtils.isNotEmpty(triggersInfo)) { + builder.withDetail("jobs", triggersInfo); + } + } catch (SchedulerException e) { + throw new ReportPortalException(e.getMessage()); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/info/JobsInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/JobsInfoContributor.java new file mode 100644 index 0000000000..6f1a975e85 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/info/JobsInfoContributor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.info; + +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.validation.JaskonRequiredPropertiesValidator; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.info.Info.Builder; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + + +/** + * Picks actuator info from <i>jobs</i> service and shows it as part of <i>service-api</i>. + * + * @author Siarhei Hrabko + */ +@Component +public class JobsInfoContributor implements InfoContributor { + + private static final Logger LOGGER = LoggerFactory.getLogger(JobsInfoContributor.class); + + private final RestTemplate restTemplate; + + @Value("${rp.jobs.baseUrl}") + private String jobsBaseUrl; + + public JobsInfoContributor() { + this.restTemplate = new RestTemplate(); + } + + @Override + public void contribute(Builder builder) { + try { + var jobsInfoRs = restTemplate.getForObject(jobsBaseUrl + "/info", Map.class); + builder + .withDetail("jobsInfo", jobsInfoRs) + .build(); + } catch (Exception e) { + LOGGER.error("Jobs service was not found"); + } + } +} diff --git a/src/main/java/com/epam/ta/reportportal/info/ServerSettingsInfoContributor.java b/src/main/java/com/epam/ta/reportportal/info/ServerSettingsInfoContributor.java index 07eba5b043..9a494c5379 100644 --- a/src/main/java/com/epam/ta/reportportal/info/ServerSettingsInfoContributor.java +++ b/src/main/java/com/epam/ta/reportportal/info/ServerSettingsInfoContributor.java @@ -18,12 +18,11 @@ import com.epam.ta.reportportal.dao.ServerSettingsRepository; import com.epam.ta.reportportal.entity.ServerSettings; import com.epam.ta.reportportal.ws.converter.converters.ServerSettingsConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.HashMap; import java.util.List; import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * Shows list of supported analytics providers and other server settings. @@ -34,21 +33,21 @@ @Component public class ServerSettingsInfoContributor implements ExtensionContributor { - private final ServerSettingsRepository settingsRepository; + private final ServerSettingsRepository settingsRepository; - @Autowired - @SuppressWarnings("SpringJavaAutowiringInspection") - public ServerSettingsInfoContributor(ServerSettingsRepository settingsRepository) { - this.settingsRepository = settingsRepository; - } + @Autowired + @SuppressWarnings("SpringJavaAutowiringInspection") + public ServerSettingsInfoContributor(ServerSettingsRepository settingsRepository) { + this.settingsRepository = settingsRepository; + } - @Override - public Map<String, ?> contribute() { - Map<String, Object> info = new HashMap<>(); - List<ServerSettings> all = settingsRepository.selectServerSettings(); - Map<String, String> result = ServerSettingsConverter.TO_RESOURCE.apply(all); - info.put("result", result); - return info; + @Override + public Map<String, ?> contribute() { + Map<String, Object> info = new HashMap<>(); + List<ServerSettings> all = settingsRepository.selectServerSettings(); + Map<String, String> result = ServerSettingsConverter.TO_RESOURCE.apply(all); + info.put("result", result); + return info; - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/CleanExpiredCreationBidsJob.java b/src/main/java/com/epam/ta/reportportal/job/CleanExpiredCreationBidsJob.java index 14142edbf9..de8cb99f9b 100644 --- a/src/main/java/com/epam/ta/reportportal/job/CleanExpiredCreationBidsJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/CleanExpiredCreationBidsJob.java @@ -17,6 +17,9 @@ package com.epam.ta.reportportal.job; import com.epam.ta.reportportal.dao.UserCreationBidRepository; +import java.sql.Date; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @@ -26,24 +29,22 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.sql.Date; -import java.time.LocalDateTime; -import java.time.ZoneOffset; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Service public class CleanExpiredCreationBidsJob implements Job { - private static final Logger LOGGER = LoggerFactory.getLogger(CleanExpiredCreationBidsJob.class); - @Autowired - private UserCreationBidRepository repository; + private static final Logger LOGGER = LoggerFactory.getLogger(CleanExpiredCreationBidsJob.class); + + @Autowired + private UserCreationBidRepository repository; - @Override - @Transactional - public void execute(JobExecutionContext context) throws JobExecutionException { - int deletedCount = repository.expireBidsOlderThan(Date.from(LocalDateTime.now().minusDays(1).toInstant(ZoneOffset.UTC))); - LOGGER.info("Cleaning expired user creation bids finished. Deleted {} bids", deletedCount); - } + @Override + @Transactional + public void execute(JobExecutionContext context) throws JobExecutionException { + int deletedCount = repository.expireBidsOlderThan( + Date.from(LocalDateTime.now().minusDays(1).toInstant(ZoneOffset.UTC))); + LOGGER.info("Cleaning expired user creation bids finished. Deleted {} bids", deletedCount); + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJob.java b/src/main/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJob.java index d3750089c1..f9b332dfd7 100644 --- a/src/main/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJob.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.job; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.configs.Conditions; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; @@ -23,6 +25,14 @@ import com.epam.ta.reportportal.dao.IntegrationTypeRepository; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.job.service.PluginLoaderService; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.validation.constraints.NotNull; import org.pf4j.PluginWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,17 +42,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import javax.validation.constraints.NotNull; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @@ -50,96 +49,107 @@ @Service public class CleanOutdatedPluginsJob { - private static final Logger LOGGER = LoggerFactory.getLogger(CleanOutdatedPluginsJob.class); - - private final String pluginsTempPath; - - private final IntegrationTypeRepository integrationTypeRepository; - - private final Pf4jPluginBox pluginBox; - - private final PluginLoaderService pluginLoaderService; - - @Autowired - public CleanOutdatedPluginsJob(@Value("${rp.plugins.temp.path}") String pluginsTempPath, - IntegrationTypeRepository integrationTypeRepository, Pf4jPluginBox pf4jPluginBox, PluginLoaderService pluginLoaderService) { - this.pluginsTempPath = pluginsTempPath; - this.integrationTypeRepository = integrationTypeRepository; - this.pluginBox = pf4jPluginBox; - this.pluginLoaderService = pluginLoaderService; - } - - @Scheduled(fixedDelayString = "${com.ta.reportportal.job.clean.outdated.plugins.cron}") - public void execute() { - - removeTemporaryPlugins(); - - List<IntegrationType> integrationTypes = integrationTypeRepository.findAll(); - integrationTypes.stream() - .filter(it -> it.getDetails() == null || it.getDetails().getDetails() == null) - .forEach(pluginLoaderService::checkAndDeleteIntegrationType); - - unloadRemovedPlugins(integrationTypes); - unloadDisabledPlugins(integrationTypes); - } - - private void removeTemporaryPlugins() { - Path tempPluginsPath = Paths.get(pluginsTempPath); - - LOGGER.debug("Searching for temporary plugins..."); - try (Stream<Path> pathStream = Files.walk(tempPluginsPath)) { - pathStream.filter(Files::isRegularFile).forEach(path -> ofNullable(path.getFileName()).ifPresent(fileName -> { - if (!pluginBox.isInUploadingState(fileName.toString())) { - try { - Files.deleteIfExists(path); - LOGGER.debug(Suppliers.formattedSupplier("Temporary plugin - '{}' has been removed", path).get()); - } catch (IOException e) { - LOGGER.error("Error has occurred during temporary plugin file removing", e); - } - } else { - LOGGER.debug(Suppliers.formattedSupplier("Uploading of the plugin - '{}' is still in progress.", path).get()); - } - })); - } catch (IOException e) { - LOGGER.error("Error has occurred during temporary plugins folder listing", e); - } - LOGGER.debug("Temporary plugins removing has finished..."); - } - - private void unloadRemovedPlugins(List<IntegrationType> integrationTypes) { - - LOGGER.debug("Unloading of removed plugins..."); - - List<String> pluginIds = pluginBox.getPlugins().stream().map(Plugin::getId).collect(Collectors.toList()); - - pluginIds.removeAll(integrationTypes.stream().map(IntegrationType::getName).collect(Collectors.toList())); - - pluginIds.forEach(pluginId -> pluginBox.getPluginById(pluginId).ifPresent(plugin -> { - - if (!isPluginStillBeingUploaded(plugin)) { - if (!pluginBox.deletePlugin(plugin)) { - LOGGER.error("Error has occurred during plugin file removing from the plugins directory"); - } - } - })); - - LOGGER.debug("Unloading of removed plugins has finished..."); - } - - private boolean isPluginStillBeingUploaded(@NotNull PluginWrapper pluginWrapper) { - return pluginBox.isInUploadingState(pluginWrapper.getPluginPath().getFileName().toString()); - } - - private void unloadDisabledPlugins(List<IntegrationType> integrationTypes) { - - List<IntegrationType> disabledPlugins = integrationTypes.stream().filter(it -> !it.isEnabled()).collect(Collectors.toList()); - - disabledPlugins.forEach(dp -> pluginBox.getPluginById(dp.getName()).ifPresent(plugin -> { - if (pluginBox.unloadPlugin(dp)) { - LOGGER.debug(Suppliers.formattedSupplier("Plugin - '{}' has been successfully unloaded.", plugin.getPluginId()).get()); - } else { - LOGGER.error(Suppliers.formattedSupplier("Error during unloading the plugin with id = '{}'.", plugin.getPluginId()).get()); - } - })); - } + private static final Logger LOGGER = LoggerFactory.getLogger(CleanOutdatedPluginsJob.class); + + private final String pluginsTempPath; + + private final IntegrationTypeRepository integrationTypeRepository; + + private final Pf4jPluginBox pluginBox; + + private final PluginLoaderService pluginLoaderService; + + @Autowired + public CleanOutdatedPluginsJob(@Value("${rp.plugins.temp.path}") String pluginsTempPath, + IntegrationTypeRepository integrationTypeRepository, Pf4jPluginBox pf4jPluginBox, + PluginLoaderService pluginLoaderService) { + this.pluginsTempPath = pluginsTempPath; + this.integrationTypeRepository = integrationTypeRepository; + this.pluginBox = pf4jPluginBox; + this.pluginLoaderService = pluginLoaderService; + } + + @Scheduled(fixedDelayString = "${com.ta.reportportal.job.clean.outdated.plugins.cron}") + public void execute() { + + removeTemporaryPlugins(); + + List<IntegrationType> integrationTypes = integrationTypeRepository.findAll(); + integrationTypes.stream() + .filter(it -> it.getDetails() == null || it.getDetails().getDetails() == null) + .forEach(pluginLoaderService::checkAndDeleteIntegrationType); + + unloadRemovedPlugins(integrationTypes); + unloadDisabledPlugins(integrationTypes); + } + + private void removeTemporaryPlugins() { + Path tempPluginsPath = Paths.get(pluginsTempPath); + + LOGGER.debug("Searching for temporary plugins..."); + try (Stream<Path> pathStream = Files.walk(tempPluginsPath)) { + pathStream.filter(Files::isRegularFile) + .forEach(path -> ofNullable(path.getFileName()).ifPresent(fileName -> { + if (!pluginBox.isInUploadingState(fileName.toString())) { + try { + Files.deleteIfExists(path); + LOGGER.debug( + Suppliers.formattedSupplier("Temporary plugin - '{}' has been removed", path) + .get()); + } catch (IOException e) { + LOGGER.error("Error has occurred during temporary plugin file removing", e); + } + } else { + LOGGER.debug(Suppliers.formattedSupplier( + "Uploading of the plugin - '{}' is still in progress.", path).get()); + } + })); + } catch (IOException e) { + LOGGER.error("Error has occurred during temporary plugins folder listing", e); + } + LOGGER.debug("Temporary plugins removing has finished..."); + } + + private void unloadRemovedPlugins(List<IntegrationType> integrationTypes) { + + LOGGER.debug("Unloading of removed plugins..."); + + List<String> pluginIds = pluginBox.getPlugins().stream().map(Plugin::getId) + .collect(Collectors.toList()); + + pluginIds.removeAll( + integrationTypes.stream().map(IntegrationType::getName).collect(Collectors.toList())); + + pluginIds.forEach(pluginId -> pluginBox.getPluginById(pluginId).ifPresent(plugin -> { + + if (!isPluginStillBeingUploaded(plugin)) { + if (!pluginBox.deletePlugin(plugin)) { + LOGGER.error("Error has occurred during plugin file removing from the plugins directory"); + } + } + })); + + LOGGER.debug("Unloading of removed plugins has finished..."); + } + + private boolean isPluginStillBeingUploaded(@NotNull PluginWrapper pluginWrapper) { + return pluginBox.isInUploadingState(pluginWrapper.getPluginPath().getFileName().toString()); + } + + private void unloadDisabledPlugins(List<IntegrationType> integrationTypes) { + + List<IntegrationType> disabledPlugins = integrationTypes.stream().filter(it -> !it.isEnabled()) + .collect(Collectors.toList()); + + disabledPlugins.forEach(dp -> pluginBox.getPluginById(dp.getName()).ifPresent(plugin -> { + if (pluginBox.unloadPlugin(dp)) { + LOGGER.debug(Suppliers.formattedSupplier("Plugin - '{}' has been successfully unloaded.", + plugin.getPluginId()).get()); + } else { + LOGGER.error( + Suppliers.formattedSupplier("Error during unloading the plugin with id = '{}'.", + plugin.getPluginId()).get()); + } + })); + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/FlushingDataJob.java b/src/main/java/com/epam/ta/reportportal/job/FlushingDataJob.java index f357e0da80..7ab883321b 100644 --- a/src/main/java/com/epam/ta/reportportal/job/FlushingDataJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/FlushingDataJob.java @@ -99,7 +99,7 @@ public class FlushingDataJob implements Job { @Value("${datastore.bucketPostfix}") private String bucketPostfix; - @Value("${datastore.defaultBucketName") + @Value("${datastore.defaultBucketName}") private String defaultBucketName; @Override @@ -130,11 +130,7 @@ public void execute(JobExecutionContext context) { * Get exclusive lock. Kill all running transactions. Truncate tables */ private void truncateTables() { - jdbcTemplate.execute("BEGIN; " + "SELECT PG_ADVISORY_XACT_LOCK(1);" - + "SELECT PG_TERMINATE_BACKEND(pid) FROM pg_stat_activity WHERE datname = 'reportportal'\n" - + "AND pid <> PG_BACKEND_PID()\n" - + "AND state IN " - + "('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled'); " + jdbcTemplate.execute("BEGIN; " + "TRUNCATE TABLE launch RESTART IDENTITY CASCADE;" + "TRUNCATE TABLE activity RESTART IDENTITY CASCADE;" + "TRUNCATE TABLE owned_entity RESTART IDENTITY CASCADE;" @@ -145,7 +141,6 @@ private void truncateTables() { private void restartSequences() { jdbcTemplate.execute("ALTER SEQUENCE project_id_seq RESTART WITH 2"); jdbcTemplate.execute("ALTER SEQUENCE users_id_seq RESTART WITH 2"); - jdbcTemplate.execute("ALTER SEQUENCE oauth_access_token_id_seq RESTART WITH 2"); jdbcTemplate.execute("ALTER SEQUENCE project_attribute_attribute_id_seq RESTART WITH 15"); jdbcTemplate.execute("ALTER SEQUENCE statistics_field_sf_id_seq RESTART WITH 15"); } @@ -153,7 +148,7 @@ private void restartSequences() { private void createDefaultUser() { final CreateUserRQFull request = new CreateUserRQFull(); request.setLogin("default"); - request.setPassword(passwordEncoder.encode("1q2w3e")); + request.setPassword("1q2w3e"); request.setEmail("defaultemail@domain.com"); User user = new UserBuilder().addCreateUserFullRQ(request) .addUserRole(UserRole.USER) diff --git a/src/main/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJob.java b/src/main/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJob.java index c9d974c88d..362f728e3c 100644 --- a/src/main/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJob.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.job; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.job.PageUtil.iterateOverPages; +import static java.time.Duration.ofSeconds; + import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.LogRepository; @@ -25,6 +29,10 @@ import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.project.ProjectUtils; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.stream.Stream; import org.apache.commons.lang3.math.NumberUtils; import org.quartz.Job; import org.quartz.JobExecutionContext; @@ -36,15 +44,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.Duration; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static com.epam.ta.reportportal.job.PageUtil.iterateOverPages; -import static java.time.Duration.ofSeconds; - /** * Finds jobs witn duration more than defined and finishes them with interrupted * {@link StatusEnum#INTERRUPTED} status @@ -54,102 +53,110 @@ @Service public class InterruptBrokenLaunchesJob implements Job { - private static final Logger LOGGER = LoggerFactory.getLogger(InterruptBrokenLaunchesJob.class); - - private final ApplicationEventPublisher eventPublisher; - - private final LaunchRepository launchRepository; - - private final TestItemRepository testItemRepository; - - private final LogRepository logRepository; - - private final ProjectRepository projectRepository; - - @Autowired - public InterruptBrokenLaunchesJob(ApplicationEventPublisher eventPublisher, LaunchRepository launchRepository, TestItemRepository testItemRepository, LogRepository logRepository, - ProjectRepository projectRepository) { - this.eventPublisher = eventPublisher; - this.launchRepository = launchRepository; - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; - this.projectRepository = projectRepository; - } - - @Override - @Transactional - public void execute(JobExecutionContext context) { - LOGGER.info("Interrupt broken launches job has been started"); - iterateOverPages( - Sort.by(Sort.Order.asc(CRITERIA_ID)), - projectRepository::findAllIdsAndProjectAttributes, - projects -> projects.forEach(project -> { - ProjectUtils.extractAttributeValue(project, ProjectAttributeEnum.INTERRUPT_JOB_TIME).ifPresent(it -> { - Duration maxDuration = ofSeconds(NumberUtils.toLong(it, 0L)); - try (Stream<Long> ids = launchRepository.streamIdsWithStatusAndStartTimeBefore(project.getId(), - StatusEnum.IN_PROGRESS, - LocalDateTime.now(ZoneOffset.UTC).minus(maxDuration) - )) { - ids.forEach(launchId -> { - if (!testItemRepository.hasItemsInStatusByLaunch(launchId, StatusEnum.IN_PROGRESS)) { - /* - * There are no test items for this launch. Just INTERRUPT - * this launch - */ - interruptLaunch(launchId); - } else { - /* - * Well, there are some test items started for specified - * launch - */ - if (!testItemRepository.hasItemsInStatusAddedLately(launchId, maxDuration, StatusEnum.IN_PROGRESS)) { - /* - * If there are logs, we have to check whether them - * expired - */ - if (testItemRepository.hasLogs(launchId, maxDuration, StatusEnum.IN_PROGRESS)) { - /* - * If there are logs which are still valid - * (probably automation project keep writing - * something) - */ - if (!logRepository.hasLogsAddedLately(maxDuration, launchId, StatusEnum.IN_PROGRESS)) { - interruptItems(launchId); - } - } else { - /* - * If not just INTERRUPT all found items and launch - */ - interruptItems(launchId); - } - } - } - }); - } catch (Exception ex) { - LOGGER.error("Interrupting broken launches has been failed", ex); - //do nothing - } - }); - }) - ); - } - - private void interruptLaunch(Long launchId) { - launchRepository.findById(launchId).ifPresent(launch -> { - launch.setStatus(StatusEnum.INTERRUPTED); - launch.setEndTime(LocalDateTime.now(ZoneOffset.UTC)); - launchRepository.save(launch); - publishFinishEvent(launch); - }); - } - - private void publishFinishEvent(Launch launch) { - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch); - eventPublisher.publishEvent(event); - } - - private void interruptItems(Long launchId) { - testItemRepository.interruptInProgressItems(launchId); - interruptLaunch(launchId); - } + private static final Logger LOGGER = LoggerFactory.getLogger(InterruptBrokenLaunchesJob.class); + + private final ApplicationEventPublisher eventPublisher; + + private final LaunchRepository launchRepository; + + private final TestItemRepository testItemRepository; + + private final LogRepository logRepository; + + private final ProjectRepository projectRepository; + + @Autowired + public InterruptBrokenLaunchesJob(ApplicationEventPublisher eventPublisher, + LaunchRepository launchRepository, TestItemRepository testItemRepository, + LogRepository logRepository, + ProjectRepository projectRepository) { + this.eventPublisher = eventPublisher; + this.launchRepository = launchRepository; + this.testItemRepository = testItemRepository; + this.logRepository = logRepository; + this.projectRepository = projectRepository; + } + + @Override + @Transactional + public void execute(JobExecutionContext context) { + LOGGER.info("Interrupt broken launches job has been started"); + iterateOverPages( + Sort.by(Sort.Order.asc(CRITERIA_ID)), + projectRepository::findAllIdsAndProjectAttributes, + projects -> projects.forEach(project -> { + ProjectUtils.extractAttributeValue(project, ProjectAttributeEnum.INTERRUPT_JOB_TIME) + .ifPresent(it -> { + Duration maxDuration = ofSeconds(NumberUtils.toLong(it, 0L)); + try (Stream<Long> ids = launchRepository.streamIdsWithStatusAndStartTimeBefore( + project.getId(), + StatusEnum.IN_PROGRESS, + LocalDateTime.now(ZoneOffset.UTC).minus(maxDuration) + )) { + ids.forEach(launchId -> { + if (!testItemRepository.hasItemsInStatusByLaunch(launchId, + StatusEnum.IN_PROGRESS)) { + /* + * There are no test items for this launch. Just INTERRUPT + * this launch + */ + interruptLaunch(launchId); + } else { + /* + * Well, there are some test items started for specified + * launch + */ + if (!testItemRepository.hasItemsInStatusAddedLately(launchId, maxDuration, + StatusEnum.IN_PROGRESS)) { + /* + * If there are logs, we have to check whether them + * expired + */ + if (testItemRepository.hasLogs(launchId, maxDuration, + StatusEnum.IN_PROGRESS)) { + /* + * If there are logs which are still valid + * (probably automation project keep writing + * something) + */ + if (!logRepository.hasLogsAddedLately(maxDuration, launchId, + StatusEnum.IN_PROGRESS)) { + interruptItems(launchId); + } + } else { + /* + * If not just INTERRUPT all found items and launch + */ + interruptItems(launchId); + } + } + } + }); + } catch (Exception ex) { + LOGGER.error("Interrupting broken launches has been failed", ex); + //do nothing + } + }); + }) + ); + } + + private void interruptLaunch(Long launchId) { + launchRepository.findById(launchId).ifPresent(launch -> { + launch.setStatus(StatusEnum.INTERRUPTED); + launch.setEndTime(LocalDateTime.now(ZoneOffset.UTC)); + launchRepository.save(launch); + publishFinishEvent(launch); + }); + } + + private void publishFinishEvent(Launch launch) { + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch); + eventPublisher.publishEvent(event); + } + + private void interruptItems(Long launchId) { + testItemRepository.interruptInProgressItems(launchId); + interruptLaunch(launchId); + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/JobExecutorDelegate.java b/src/main/java/com/epam/ta/reportportal/job/JobExecutorDelegate.java index 4ea700ad56..38d92c5e40 100644 --- a/src/main/java/com/epam/ta/reportportal/job/JobExecutorDelegate.java +++ b/src/main/java/com/epam/ta/reportportal/job/JobExecutorDelegate.java @@ -28,20 +28,20 @@ @Service public class JobExecutorDelegate { - /** - * Default TaskScheduler - * - * @see org.springframework.scheduling.TaskScheduler - */ - @Autowired - private TaskScheduler taskScheduler; + /** + * Default TaskScheduler + * + * @see org.springframework.scheduling.TaskScheduler + */ + @Autowired + private TaskScheduler taskScheduler; - /** - * Submits self cancelable job - * - * @param selfCancelableJob - */ - public void submitJob(SelfCancelableJob selfCancelableJob) { - taskScheduler.schedule(selfCancelableJob, selfCancelableJob); - } + /** + * Submits self cancelable job + * + * @param selfCancelableJob link to job class + */ + public void submitJob(SelfCancelableJob selfCancelableJob) { + taskScheduler.schedule(selfCancelableJob, selfCancelableJob); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/job/LoadPluginsJob.java b/src/main/java/com/epam/ta/reportportal/job/LoadPluginsJob.java index 23fb87bc8d..5ab29ced26 100644 --- a/src/main/java/com/epam/ta/reportportal/job/LoadPluginsJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/LoadPluginsJob.java @@ -26,6 +26,12 @@ import com.epam.ta.reportportal.filesystem.DataStore; import com.epam.ta.reportportal.job.service.PluginLoaderService; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,13 +41,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @@ -49,61 +48,80 @@ @Service public class LoadPluginsJob { - private static final Logger LOGGER = LoggerFactory.getLogger(LoadPluginsJob.class); - - private final IntegrationTypeRepository integrationTypeRepository; - - private final PluginLoaderService pluginLoaderService; - - private final String pluginsRootPath; - - private final Pf4jPluginBox pluginBox; - - private final DataStore dataStore; - - @Autowired - public LoadPluginsJob(@Value("${rp.plugins.path}") String pluginsRootPath, IntegrationTypeRepository integrationTypeRepository, - PluginLoaderService pluginLoaderService, Pf4jPluginBox pf4jPluginBox, DataStore dataStore) { - this.integrationTypeRepository = integrationTypeRepository; - this.pluginLoaderService = pluginLoaderService; - this.pluginBox = pf4jPluginBox; - this.dataStore = dataStore; - this.pluginsRootPath = pluginsRootPath; - } - - @Scheduled(fixedDelayString = "${com.ta.reportportal.job.load.plugins.cron}") - public void execute() { - List<PluginInfo> notLoadedPlugins = pluginLoaderService.getNotLoadedPluginsInfo(); - - notLoadedPlugins.forEach(pluginInfo -> { - try (InputStream inputStream = dataStore.load(pluginInfo.getFileId())) { - LOGGER.debug("Plugin loading has started..."); - - if (!Files.exists(Paths.get(pluginsRootPath, pluginInfo.getFileName()))) { - LOGGER.debug("Copying plugin file..."); - FileUtils.copyToFile(inputStream, new File(pluginsRootPath, pluginInfo.getFileName())); - } - - if (pluginInfo.isEnabled()) { - IntegrationType integrationType = integrationTypeRepository.findByName(pluginInfo.getId()) - .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, pluginInfo.getId())); - - boolean isLoaded = pluginBox.loadPlugin(integrationType.getName(), integrationType.getDetails()); - - if (isLoaded) { - LOGGER.debug(Suppliers.formattedSupplier("Plugin - '{}' has been successfully started.", integrationType.getName()) - .get()); - } else { - LOGGER.error(Suppliers.formattedSupplier("Plugin - '{}' has not been started.", integrationType.getName()).get()); - } - } - - } catch (IOException ex) { - LOGGER.error("Error has occurred during plugin copying from the Data store", ex); - //do nothing - } - }); - - } + private static final Logger LOGGER = LoggerFactory.getLogger(LoadPluginsJob.class); + + private final IntegrationTypeRepository integrationTypeRepository; + + private final PluginLoaderService pluginLoaderService; + + private final String pluginsRootPath; + + private final Pf4jPluginBox pluginBox; + + private final DataStore dataStore; + + @Autowired + public LoadPluginsJob(@Value("${rp.plugins.path}") String pluginsRootPath, + IntegrationTypeRepository integrationTypeRepository, + PluginLoaderService pluginLoaderService, Pf4jPluginBox pf4jPluginBox, DataStore dataStore) { + this.integrationTypeRepository = integrationTypeRepository; + this.pluginLoaderService = pluginLoaderService; + this.pluginBox = pf4jPluginBox; + this.dataStore = dataStore; + this.pluginsRootPath = pluginsRootPath; + } + + @Scheduled(fixedDelayString = "${com.ta.reportportal.job.load.plugins.cron}") + public void execute() { + List<PluginInfo> notLoadedPlugins = pluginLoaderService.getNotLoadedPluginsInfo(); + + notLoadedPlugins.forEach(pluginInfo -> { + try (InputStream inputStream = dataStore.load(pluginInfo.getFileId())) { + LOGGER.debug("Plugin loading has started..."); + + if (!Files.exists(Paths.get(pluginsRootPath, pluginInfo.getFileName()))) { + LOGGER.debug("Copying plugin file..."); + FileUtils.copyToFile(inputStream, new File(pluginsRootPath, pluginInfo.getFileName())); + } + + if (pluginInfo.isEnabled()) { + IntegrationType integrationType = integrationTypeRepository.findByName(pluginInfo.getId()) + .orElseThrow(() -> new ReportPortalException(ErrorType.INTEGRATION_NOT_FOUND, + pluginInfo.getId())); + + unloadPlugin(integrationType); + + boolean isLoaded = pluginBox.loadPlugin(integrationType.getName(), + integrationType.getDetails()); + + if (isLoaded) { + LOGGER.debug(Suppliers.formattedSupplier("Plugin - '{}' has been successfully started.", + integrationType.getName()) + .get()); + } else { + LOGGER.error(Suppliers.formattedSupplier("Plugin - '{}' has not been started.", + integrationType.getName()).get()); + } + } + + } catch (IOException ex) { + LOGGER.error("Error has occurred during plugin copying from the Data store", ex); + //do nothing + } + }); + + } + + private void unloadPlugin(IntegrationType integrationType) { + pluginBox.getPluginById(integrationType.getName()).ifPresent(plugin -> { + + if (!pluginBox.unloadPlugin(integrationType)) { + throw new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + Suppliers.formattedSupplier("Error during unloading the plugin with id = '{}'", + integrationType.getName()).get() + ); + } + }); + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/PageUtil.java b/src/main/java/com/epam/ta/reportportal/job/PageUtil.java index c8a9200fa3..d25bcd7663 100644 --- a/src/main/java/com/epam/ta/reportportal/job/PageUtil.java +++ b/src/main/java/com/epam/ta/reportportal/job/PageUtil.java @@ -15,76 +15,80 @@ */ package com.epam.ta.reportportal.job; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class PageUtil { - private PageUtil() { - //static only - } + private PageUtil() { + //static only + } - private static final int DEFAULT_PAGE_SIZE = 50; + private static final int DEFAULT_PAGE_SIZE = 50; - /** - * Iterates over all pages found - * - * @param getFunc Get Page function - * @param consumer Page processor - * @param <T> Type of page entity - */ - public static <T> void iterateOverPages(Sort sort, Function<Pageable, Page<T>> getFunc, Consumer<List<T>> consumer) { - iterateOverPages(DEFAULT_PAGE_SIZE, sort, getFunc, consumer); - } + /** + * Iterates over all pages found + * + * @param getFunc Get Page function + * @param consumer Page processor + * @param sort Sort by + * @param <T> Type of page entity + */ + public static <T> void iterateOverPages(Sort sort, Function<Pageable, Page<T>> getFunc, + Consumer<List<T>> consumer) { + iterateOverPages(DEFAULT_PAGE_SIZE, sort, getFunc, consumer); + } - /** - * Iterates over all pages found - * - * @param pageSize page size - * @param getFunc Get Page function - * @param consumer Page processor - * @param <T> Type of page entity - */ - public static <T> void iterateOverPages(int pageSize, Sort sort, Function<Pageable, Page<T>> getFunc, Consumer<List<T>> consumer) { - //first page - Page<T> pageData = getFunc.apply(PageRequest.of(0, pageSize, sort)); - List<T> content = pageData.getContent(); - consumer.accept(content); + /** + * Iterates over all pages found + * + * @param pageSize page size + * @param getFunc Get Page function + * @param consumer Page processor + * @param sort Sort by + * @param <T> Type of page entity + */ + public static <T> void iterateOverPages(int pageSize, Sort sort, + Function<Pageable, Page<T>> getFunc, Consumer<List<T>> consumer) { + //first page + Page<T> pageData = getFunc.apply(PageRequest.of(0, pageSize, sort)); + List<T> content = pageData.getContent(); + consumer.accept(content); - while (!pageData.isLast()) { - pageData = getFunc.apply(pageData.nextPageable()); - consumer.accept(pageData.getContent()); - } - } + while (!pageData.isLast()) { + pageData = getFunc.apply(pageData.nextPageable()); + consumer.accept(pageData.getContent()); + } + } - /** - * Iterates over all pages found - * - * @param pageSize page size - * @param getFunc Get {@link List} content function - * @param consumer Page processor - * @param <T> Type of {@link List} entity - */ - public static <T> void iterateOverContent(int pageSize, Function<Pageable, List<T>> getFunc, Consumer<List<T>> consumer) { - //first page - Pageable pageRequest = PageRequest.of(0, pageSize); - List<T> content = getFunc.apply(pageRequest); - consumer.accept(content); + /** + * Iterates over all pages found + * + * @param pageSize page size + * @param getFunc Get {@link List} content function + * @param consumer Page processor + * @param <T> Type of {@link List} entity + */ + public static <T> void iterateOverContent(int pageSize, Function<Pageable, List<T>> getFunc, + Consumer<List<T>> consumer) { + //first page + Pageable pageRequest = PageRequest.of(0, pageSize); + List<T> content = getFunc.apply(pageRequest); + consumer.accept(content); - while (content.size() >= pageSize) { - pageRequest = pageRequest.next(); - content = getFunc.apply(pageRequest); - consumer.accept(content); - } - } + while (content.size() >= pageSize) { + pageRequest = pageRequest.next(); + content = getFunc.apply(pageRequest); + consumer.accept(content); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/job/SelfCancelableJob.java b/src/main/java/com/epam/ta/reportportal/job/SelfCancelableJob.java index 339b49e726..863c852f52 100644 --- a/src/main/java/com/epam/ta/reportportal/job/SelfCancelableJob.java +++ b/src/main/java/com/epam/ta/reportportal/job/SelfCancelableJob.java @@ -16,41 +16,40 @@ package com.epam.ta.reportportal.job; +import java.util.Date; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; -import java.util.Date; - /** - * Job contains run method and trigger. The main idea to provide possibility to - * cancel next execution from run method. User can override job, call - * {@link SelfCancelableJob#oneMoreTime(boolean)} method and this way cancel - * next execution. In case if we need job to keep executed, we do not call - * anything, next execution time calculation delegated to provided trigger + * Job contains run method and trigger. The main idea to provide possibility to cancel next + * execution from run method. User can override job, call + * {@link SelfCancelableJob#oneMoreTime(boolean)} method and this way cancel next execution. In case + * if we need job to keep executed, we do not call anything, next execution time calculation + * delegated to provided trigger * * @author Andrei Varabyeu */ public abstract class SelfCancelableJob implements Runnable, Trigger { - private Trigger triggerDelegate; + private Trigger triggerDelegate; - private boolean oneMoreTime = true; + private boolean oneMoreTime = true; - public SelfCancelableJob(Trigger trigger) { - this.triggerDelegate = trigger; - } + public SelfCancelableJob(Trigger trigger) { + this.triggerDelegate = trigger; + } - @Override - public Date nextExecutionTime(TriggerContext triggerContext) { - if (oneMoreTime) { - return triggerDelegate.nextExecutionTime(triggerContext); - } else { - return null; - } - } + @Override + public Date nextExecutionTime(TriggerContext triggerContext) { + if (oneMoreTime) { + return triggerDelegate.nextExecutionTime(triggerContext); + } else { + return null; + } + } - protected void oneMoreTime(boolean oneMoreTime) { - this.oneMoreTime = oneMoreTime; - } + protected void oneMoreTime(boolean oneMoreTime) { + this.oneMoreTime = oneMoreTime; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/job/service/PluginLoaderService.java b/src/main/java/com/epam/ta/reportportal/job/service/PluginLoaderService.java index 7898899f82..f13627e4f3 100644 --- a/src/main/java/com/epam/ta/reportportal/job/service/PluginLoaderService.java +++ b/src/main/java/com/epam/ta/reportportal/job/service/PluginLoaderService.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.core.plugin.PluginInfo; import com.epam.ta.reportportal.entity.integration.IntegrationType; - import java.util.List; /** @@ -26,7 +25,7 @@ */ public interface PluginLoaderService { - List<PluginInfo> getNotLoadedPluginsInfo(); + List<PluginInfo> getNotLoadedPluginsInfo(); - void checkAndDeleteIntegrationType(IntegrationType integrationType); + void checkAndDeleteIntegrationType(IntegrationType integrationType); } diff --git a/src/main/java/com/epam/ta/reportportal/job/service/impl/PluginLoaderServiceImpl.java b/src/main/java/com/epam/ta/reportportal/job/service/impl/PluginLoaderServiceImpl.java index 8e60707422..7f66702472 100644 --- a/src/main/java/com/epam/ta/reportportal/job/service/impl/PluginLoaderServiceImpl.java +++ b/src/main/java/com/epam/ta/reportportal/job/service/impl/PluginLoaderServiceImpl.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.job.service.impl; +import static com.epam.reportportal.extension.common.IntegrationTypeProperties.FILE_ID; +import static com.epam.reportportal.extension.common.IntegrationTypeProperties.FILE_NAME; +import static com.epam.reportportal.extension.common.IntegrationTypeProperties.VERSION; + import com.epam.reportportal.extension.common.IntegrationTypeProperties; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; @@ -26,13 +30,6 @@ import com.epam.ta.reportportal.job.service.PluginLoaderService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.pf4j.PluginWrapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.io.IOException; import java.nio.file.Files; import java.util.Arrays; @@ -40,8 +37,12 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Stream; - -import static com.epam.reportportal.extension.common.IntegrationTypeProperties.*; +import org.pf4j.PluginWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -49,95 +50,101 @@ @Service public class PluginLoaderServiceImpl implements PluginLoaderService { - private static final Logger LOGGER = LoggerFactory.getLogger(PluginLoaderServiceImpl.class); - - private final IntegrationTypeRepository integrationTypeRepository; - private final Pf4jPluginBox pluginBox; - - @Autowired - public PluginLoaderServiceImpl(IntegrationTypeRepository integrationTypeRepository, Pf4jPluginBox pluginBox) { - this.integrationTypeRepository = integrationTypeRepository; - this.pluginBox = pluginBox; - } - - @Override - public List<PluginInfo> getNotLoadedPluginsInfo() { - - LOGGER.debug("Searching for not loaded plugins..."); - - List<PluginInfo> notLoadedPlugins = Lists.newArrayList(); - - integrationTypeRepository.findAll() - .stream() - .filter(IntegrationType::isEnabled) - .filter(it -> it.getDetails() != null && it.getDetails().getDetails() != null) - .filter(this::isMandatoryFieldsExist) - .forEach(it -> { - - Map<IntegrationTypeProperties, Object> pluginProperties = retrievePluginProperties(it); - - Optional<PluginWrapper> pluginWrapper = pluginBox.getPluginById(it.getName()); - if (pluginWrapper.isEmpty() || !String.valueOf(pluginProperties.get(VERSION)) - .equalsIgnoreCase(pluginWrapper.get().getDescriptor().getVersion())) { - - PluginInfo pluginInfo = new PluginInfo(it.getName(), - String.valueOf(pluginProperties.get(VERSION)), - String.valueOf(pluginProperties.get(FILE_ID)), - String.valueOf(pluginProperties.get(FILE_NAME)), - it.isEnabled() - ); - - notLoadedPlugins.add(pluginInfo); - } - - }); - - LOGGER.debug(Suppliers.formattedSupplier("{} not loaded plugins have been found", notLoadedPlugins.size()).get()); - - return notLoadedPlugins; - } - - @Transactional - @Override - public void checkAndDeleteIntegrationType(IntegrationType integrationType) { - if (isIntegrationTypeAvailableForRemoving(integrationType)) { - integrationTypeRepository.deleteById(integrationType.getId()); - } - } - - private boolean isMandatoryFieldsExist(IntegrationType integrationType) { - Map<String, Object> details = integrationType.getDetails().getDetails(); - return Stream.of(FILE_ID, VERSION, FILE_NAME).allMatch(property -> property.getValue(details).isPresent()); - - } - - private Map<IntegrationTypeProperties, Object> retrievePluginProperties(IntegrationType integrationType) { - - Map<String, Object> details = integrationType.getDetails().getDetails(); - Map<IntegrationTypeProperties, Object> pluginProperties = Maps.newHashMapWithExpectedSize(IntegrationTypeProperties.values().length); - Arrays.stream(IntegrationTypeProperties.values()) - .forEach(property -> property.getValue(details).ifPresent(value -> pluginProperties.put(property, value))); - return pluginProperties; - } - - private boolean isIntegrationTypeAvailableForRemoving(IntegrationType integrationType) { - /* hack: while email, ad, ldap, saml aren't plugins - it shouldn't be proceeded as a plugin */ - if (ReservedIntegrationTypeEnum.fromName(integrationType.getName()).isPresent()) { - return false; - } else { - return pluginBox.getPluginById(integrationType.getName()).map(p -> { - if (pluginBox.unloadPlugin(integrationType)) { - try { - Files.deleteIfExists(p.getPluginPath()); - return true; - } catch (IOException ex) { - LOGGER.error("Error has occurred during plugin removing from the root directory", ex); - return false; - } - } else { - return false; - } - }).orElse(true); - } - } + private static final Logger LOGGER = LoggerFactory.getLogger(PluginLoaderServiceImpl.class); + + private final IntegrationTypeRepository integrationTypeRepository; + private final Pf4jPluginBox pluginBox; + + @Autowired + public PluginLoaderServiceImpl(IntegrationTypeRepository integrationTypeRepository, + Pf4jPluginBox pluginBox) { + this.integrationTypeRepository = integrationTypeRepository; + this.pluginBox = pluginBox; + } + + @Override + public List<PluginInfo> getNotLoadedPluginsInfo() { + + LOGGER.debug("Searching for not loaded plugins..."); + + List<PluginInfo> notLoadedPlugins = Lists.newArrayList(); + + integrationTypeRepository.findAll() + .stream() + .filter(IntegrationType::isEnabled) + .filter(it -> it.getDetails() != null && it.getDetails().getDetails() != null) + .filter(this::isMandatoryFieldsExist) + .forEach(it -> { + + Map<IntegrationTypeProperties, Object> pluginProperties = retrievePluginProperties(it); + + Optional<PluginWrapper> pluginWrapper = pluginBox.getPluginById(it.getName()); + if (pluginWrapper.isEmpty() || !String.valueOf(pluginProperties.get(VERSION)) + .equalsIgnoreCase(pluginWrapper.get().getDescriptor().getVersion())) { + + PluginInfo pluginInfo = new PluginInfo(it.getName(), + String.valueOf(pluginProperties.get(VERSION)), + String.valueOf(pluginProperties.get(FILE_ID)), + String.valueOf(pluginProperties.get(FILE_NAME)), + it.isEnabled() + ); + + notLoadedPlugins.add(pluginInfo); + } + + }); + + LOGGER.debug(Suppliers.formattedSupplier("{} not loaded plugins have been found", + notLoadedPlugins.size()).get()); + + return notLoadedPlugins; + } + + @Transactional + @Override + public void checkAndDeleteIntegrationType(IntegrationType integrationType) { + if (isIntegrationTypeAvailableForRemoving(integrationType)) { + integrationTypeRepository.deleteById(integrationType.getId()); + } + } + + private boolean isMandatoryFieldsExist(IntegrationType integrationType) { + Map<String, Object> details = integrationType.getDetails().getDetails(); + return Stream.of(FILE_ID, VERSION, FILE_NAME) + .allMatch(property -> property.getValue(details).isPresent()); + + } + + private Map<IntegrationTypeProperties, Object> retrievePluginProperties( + IntegrationType integrationType) { + + Map<String, Object> details = integrationType.getDetails().getDetails(); + Map<IntegrationTypeProperties, Object> pluginProperties = Maps.newHashMapWithExpectedSize( + IntegrationTypeProperties.values().length); + Arrays.stream(IntegrationTypeProperties.values()) + .forEach(property -> property.getValue(details) + .ifPresent(value -> pluginProperties.put(property, value))); + return pluginProperties; + } + + private boolean isIntegrationTypeAvailableForRemoving(IntegrationType integrationType) { + /* hack: while email, ad, ldap, saml aren't plugins - it shouldn't be proceeded as a plugin */ + if (ReservedIntegrationTypeEnum.fromName(integrationType.getName()).isPresent()) { + return false; + } else { + return pluginBox.getPluginById(integrationType.getName()).map(p -> { + if (pluginBox.unloadPlugin(integrationType)) { + try { + Files.deleteIfExists(p.getPluginPath()); + return true; + } catch (IOException ex) { + LOGGER.error("Error has occurred during plugin removing from the root directory", ex); + return false; + } + } else { + return false; + } + }).orElse(true); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/pipeline/PipelineConstructor.java b/src/main/java/com/epam/ta/reportportal/pipeline/PipelineConstructor.java index c02294706f..2c3a23b24b 100644 --- a/src/main/java/com/epam/ta/reportportal/pipeline/PipelineConstructor.java +++ b/src/main/java/com/epam/ta/reportportal/pipeline/PipelineConstructor.java @@ -24,13 +24,13 @@ */ public class PipelineConstructor<T> { - private final List<PipelinePartProvider<T>> providers; + private final List<PipelinePartProvider<T>> providers; - public PipelineConstructor(List<PipelinePartProvider<T>> providers) { - this.providers = providers; - } + public PipelineConstructor(List<PipelinePartProvider<T>> providers) { + this.providers = providers; + } - public List<PipelinePart> construct(T source) { - return providers.stream().map(p -> p.provide(source)).collect(Collectors.toList()); - } + public List<PipelinePart> construct(T source) { + return providers.stream().map(p -> p.provide(source)).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePart.java b/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePart.java index 4f69ae0d77..65e7549325 100644 --- a/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePart.java +++ b/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePart.java @@ -21,5 +21,5 @@ */ public interface PipelinePart { - void handle(); + void handle(); } diff --git a/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePartProvider.java b/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePartProvider.java index 59dad7450b..55b9e13a7a 100644 --- a/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePartProvider.java +++ b/src/main/java/com/epam/ta/reportportal/pipeline/PipelinePartProvider.java @@ -21,5 +21,5 @@ */ public interface PipelinePartProvider<T> { - PipelinePart provide(T source); + PipelinePart provide(T source); } diff --git a/src/main/java/com/epam/ta/reportportal/pipeline/TransactionalPipeline.java b/src/main/java/com/epam/ta/reportportal/pipeline/TransactionalPipeline.java index ca3d0b70a1..d5ed5f04c3 100644 --- a/src/main/java/com/epam/ta/reportportal/pipeline/TransactionalPipeline.java +++ b/src/main/java/com/epam/ta/reportportal/pipeline/TransactionalPipeline.java @@ -16,19 +16,18 @@ package com.epam.ta.reportportal.pipeline; +import java.util.List; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service public class TransactionalPipeline { - @Transactional - public void run(List<PipelinePart> parts) { - parts.forEach(PipelinePart::handle); - } + @Transactional + public void run(List<PipelinePart> parts) { + parts.forEach(PipelinePart::handle); + } } diff --git a/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java b/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java index 38c7e5daaa..07b539354e 100644 --- a/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java +++ b/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.plugin; +import static com.epam.ta.reportportal.commons.Predicates.equalTo; +import static java.util.Optional.ofNullable; + import com.epam.reportportal.extension.ReportPortalExtensionPoint; import com.epam.reportportal.extension.common.ExtensionPoint; import com.epam.reportportal.extension.common.IntegrationTypeProperties; @@ -37,6 +40,16 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; @@ -50,639 +63,700 @@ import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; import org.springframework.context.ApplicationEventPublisher; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.Predicates.equalTo; -import static java.util.Optional.ofNullable; - /** - * {@link Pf4jPluginManager#uploadingPlugins} Holder for the plugin cleaning job: {@link com.epam.ta.reportportal.job.CleanOutdatedPluginsJob} - * to prevent the removing of the plugins that are still being processed within the database transaction with + * {@link Pf4jPluginManager#uploadingPlugins} Holder for the plugin cleaning job: + * {@link com.epam.ta.reportportal.job.CleanOutdatedPluginsJob} to prevent the removing of the + * plugins that are still being processed within the database transaction with * {@link com.epam.ta.reportportal.entity.integration.IntegrationType} in uncommitted state */ public class Pf4jPluginManager implements Pf4jPluginBox { - public static final Logger LOGGER = LoggerFactory.getLogger(Pf4jPluginManager.class); - - public static final String LOAD_KEY = "load"; - public static final String UNLOAD_KEY = "unload"; - - private static final long MAXIMUM_UPLOADED_PLUGINS = 50; - private static final long PLUGIN_LIVE_TIME = 2; - - private final String pluginsDir; - private final String pluginsTempDir; - private final String resourcesDir; - - private final Cache<String, Path> uploadingPlugins; - - private final PluginLoader pluginLoader; - private final IntegrationTypeRepository integrationTypeRepository; - - private final PluginManager pluginManager; - private final AutowireCapableBeanFactory autowireCapableBeanFactory; - - private final ApplicationEventPublisher applicationEventPublisher; - - public Pf4jPluginManager(String pluginsDir, String pluginsTempPath, String resourcesDir, PluginLoader pluginLoader, - IntegrationTypeRepository integrationTypeRepository, PluginManager pluginManager, - AutowireCapableBeanFactory autowireCapableBeanFactory, ApplicationEventPublisher applicationEventPublisher) throws IOException { - this.pluginsDir = pluginsDir; - Files.createDirectories(Paths.get(this.pluginsDir)); - this.resourcesDir = resourcesDir; - Files.createDirectories(Paths.get(this.resourcesDir)); - this.pluginsTempDir = pluginsTempPath; - Files.createDirectories(Paths.get(this.pluginsTempDir)); - this.autowireCapableBeanFactory = autowireCapableBeanFactory; - this.applicationEventPublisher = applicationEventPublisher; - this.pluginLoader = pluginLoader; - this.integrationTypeRepository = integrationTypeRepository; - this.uploadingPlugins = CacheBuilder.newBuilder() - .maximumSize(MAXIMUM_UPLOADED_PLUGINS) - .expireAfterWrite(PLUGIN_LIVE_TIME, TimeUnit.MINUTES) - .build(); - this.pluginManager = pluginManager; - } - - @Override - public List<Plugin> getPlugins() { - return this.pluginManager.getPlugins() - .stream() - .flatMap(plugin -> pluginManager.getExtensionClasses(plugin.getPluginId()) - .stream() - .map(ExtensionPoint::findByExtension) - .filter(Optional::isPresent) - .map(it -> new Plugin(plugin.getPluginId(), it.get()))) - .collect(Collectors.toList()); - } - - @Override - public Optional<Plugin> getPlugin(String type) { - return getPlugins().stream().filter(p -> p.getType().name().equalsIgnoreCase(type)).findAny(); - } - - @Override - public <T> Optional<T> getInstance(String name, Class<T> extension) { - return pluginManager.getExtensions(extension, name).stream().findFirst(); - } - - @Override - public <T> Optional<T> getInstance(Class<T> extension) { - return pluginManager.getExtensions(extension).stream().findFirst(); - } - - @Override - public void startUp() { - // load and start all enabled plugins of application - integrationTypeRepository.findAll() - .stream() - .filter(IntegrationType::isEnabled) - .forEach(integrationType -> ofNullable(integrationType.getDetails()).ifPresent(integrationTypeDetails -> { - try { - loadPlugin(integrationType.getName(), integrationTypeDetails); - } catch (Exception ex) { - LOGGER.error("Unable to load plugin '{}'", integrationType.getName()); - } - })); - - } - - @Override - public void shutDown() { - // stop and unload all plugins - pluginManager.stopPlugins(); - pluginManager.getPlugins().forEach(p -> pluginManager.unloadPlugin(p.getPluginId())); - } - - @Override - public PluginState startUpPlugin(String pluginId) { - - PluginWrapper pluginWrapper = ofNullable(pluginManager.getPlugin(pluginId)).orElseThrow(() -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, - "Plugin not found: " + pluginId - )); - - return pluginManager.startPlugin(pluginWrapper.getPluginId()); - } - - @Override - public boolean loadPlugin(String pluginId, IntegrationTypeDetails integrationTypeDetails) { - return ofNullable(integrationTypeDetails.getDetails()).map(details -> { - String fileName = IntegrationTypeProperties.FILE_NAME.getValue(details) - .map(String::valueOf) - .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("'File name' property of the plugin - '{}' is not specified", pluginId).get() - )); - - Path pluginPath = Paths.get(pluginsDir, fileName); - if (Files.notExists(pluginPath)) { - String fileId = IntegrationTypeProperties.FILE_ID.getValue(details) - .map(String::valueOf) - .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("'File id' property of the plugin - '{}' is not specified", pluginId).get() - )); - try { - pluginLoader.copyFromDataStore(fileId, pluginPath, Paths.get(resourcesDir, pluginId)); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to load plugin - '{}' from the data store", pluginId).get() - ); - } - } else { - copyPluginResources(pluginPath, pluginId); - } - - return ofNullable(pluginManager.loadPlugin(pluginPath)).map(id -> { - if (PluginState.STARTED == pluginManager.startPlugin(pluginId)) { - Optional<org.pf4j.ExtensionPoint> extensionPoint = this.getInstance(pluginId, org.pf4j.ExtensionPoint.class); - extensionPoint.ifPresent(extension -> LOGGER.info(Suppliers.formattedSupplier("Plugin - '{}' initialized.", pluginId) - .get())); - applicationEventPublisher.publishEvent(new PluginEvent(pluginId, LOAD_KEY)); - return true; - } else { - return false; - } - }).orElse(Boolean.FALSE); - }).orElse(Boolean.FALSE); - - } - - private void copyPluginResources(Path pluginPath, String pluginId) { - try { - pluginLoader.copyPluginResource(pluginPath, Paths.get(resourcesDir, pluginId)); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to load resources of the - '{}' plugin", pluginId).get() - ); - } - } - - @Override - public boolean unloadPlugin(IntegrationType integrationType) { - applicationEventPublisher.publishEvent(new PluginEvent(integrationType.getName(), UNLOAD_KEY)); - destroyDependency(integrationType.getName()); - return pluginManager.unloadPlugin(integrationType.getName()); - } - - @Override - public boolean deletePlugin(String pluginId) { - return integrationTypeRepository.findByName(pluginId).map(this::deletePlugin).orElse(Boolean.TRUE); - } - - @Override - public boolean deletePlugin(PluginWrapper pluginWrapper) { - return integrationTypeRepository.findByName(pluginWrapper.getPluginId()).map(this::deletePlugin).orElseGet(() -> { - applicationEventPublisher.publishEvent(new PluginEvent(pluginWrapper.getPluginId(), UNLOAD_KEY)); - deletePluginResources(Paths.get(resourcesDir, pluginWrapper.getPluginId()).toString()); - destroyDependency(pluginWrapper.getPluginId()); - return pluginManager.deletePlugin(pluginWrapper.getPluginId()); - }); - } - - private boolean deletePlugin(IntegrationType integrationType) { - Optional<Map<String, Object>> pluginData = ofNullable(integrationType.getDetails()).map(IntegrationTypeDetails::getDetails); - pluginData.ifPresent(this::deletePluginResources); - - applicationEventPublisher.publishEvent(new PluginEvent(integrationType.getName(), UNLOAD_KEY)); - - boolean pluginRemoved = ofNullable(pluginManager.getPlugin(integrationType.getName())).map(pluginWrapper -> { - destroyDependency(pluginWrapper.getPluginId()); - if (integrationType.isEnabled()) { - return pluginManager.deletePlugin(integrationType.getName()); - } - return true; - }).orElse(Boolean.TRUE); - - boolean pluginFileRemoved = pluginData.map(this::deletePluginFile).orElse(Boolean.TRUE); - - return pluginRemoved && pluginFileRemoved; - } - - private void deletePluginResources(Map<String, Object> details) { - IntegrationTypeProperties.RESOURCES_DIRECTORY.getValue(details).map(String::valueOf).ifPresent(this::deletePluginResources); - IntegrationTypeProperties.FILE_ID.getValue(details).map(String::valueOf).ifPresent(pluginLoader::deleteFromDataStore); - } - - private void deletePluginResources(String resourcesDir) { - try { - FileUtils.deleteDirectory(FileUtils.getFile(resourcesDir)); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, "Unable to delete plugin resources."); - } - } - - private boolean deletePluginFile(Map<String, Object> details) { - return IntegrationTypeProperties.FILE_NAME.getValue(details) - .map(String::valueOf) - .map(fileName -> Paths.get(pluginsDir, fileName)) - .map(path -> { - try { - if (Files.exists(path)) { - return Files.deleteIfExists(path); - } else { - return true; - } - } catch (IOException e) { - throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, - "Error during plugin file removing from the filesystem: " + e.getMessage() - ); - } - - }) - .orElse(Boolean.TRUE); - } - - @Override - public Optional<PluginWrapper> getPluginById(String id) { - return ofNullable(pluginManager.getPlugin(id)); - } - - @Override - public boolean isInUploadingState(String fileName) { - return uploadingPlugins.asMap().containsKey(fileName); - } - - @Override - public IntegrationType uploadPlugin(final String uploadedPluginName, final InputStream fileStream) { - PluginInfo newPluginInfo = resolvePluginInfo(uploadedPluginName, fileStream); - IntegrationTypeDetails pluginDetails = pluginLoader.resolvePluginDetails(newPluginInfo); - - Optional<PluginWrapper> previousPlugin = getPluginById(newPluginInfo.getId()); - previousPlugin.ifPresent(this::unloadPreviousPlugin); - - return ofNullable(pluginManager.loadPlugin(Paths.get(pluginsTempDir, uploadedPluginName))).map(pluginId -> { - IntegrationTypeDetails newPluginDetails = copyPlugin(newPluginInfo, pluginDetails, uploadedPluginName); - try { - IntegrationType newIntegrationType = startUpPlugin(newPluginDetails); - applicationEventPublisher.publishEvent(new PluginEvent(newIntegrationType.getName(), LOAD_KEY)); - previousPlugin.ifPresent(this::deletePreviousPlugin); - deleteTempPlugin(uploadedPluginName); - return newIntegrationType; - } catch (Exception ex) { - previousPlugin.ifPresent(p -> loadPreviousPlugin(p, newPluginDetails)); - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, ex.getMessage()); - } - }).orElseThrow(() -> { - previousPlugin.ifPresent(p -> loadPreviousPlugin(p, pluginDetails)); - deleteTempPlugin(uploadedPluginName); - - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Failed to load new plugin from file = '{}'", uploadedPluginName).get() - ); - }); - } - - /** - * Uploads the plugin file to the temp directory and extracts it's info. - * Presence of the plugin version is mandatory - * - * @param fileName Plugin file name to upload - * @param fileStream {@link InputStream} of the plugin file - * @return {@link PluginInfo} - */ - private PluginInfo resolvePluginInfo(final String fileName, InputStream fileStream) { - Path tempPluginPath = uploadTempPlugin(fileName, fileStream); - - try { - PluginInfo newPluginInfo = pluginLoader.extractPluginInfo(tempPluginPath); - BusinessRule.expect(validatePluginMetaInfo(newPluginInfo), equalTo(Boolean.TRUE)) - .verify(ErrorType.PLUGIN_UPLOAD_ERROR, "Plugin version should be specified."); - return newPluginInfo; - } catch (PluginException e) { - removeUploadingPlugin(fileName); - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, e.getMessage()); - } - } - - /** - * Upload plugin file to the temporary plugins directory. - * - * @param fileName Plugin file name to upload - * @param fileStream {@link InputStream} of the plugin file - * @return {@link Path} to the temporary uploaded plugin file - */ - private Path uploadTempPlugin(String fileName, InputStream fileStream) { - Path pluginsTempDirPath = Paths.get(pluginsTempDir); - createTempPluginsFolderIfNotExists(pluginsTempDirPath); - - validateFileExtension(fileName); - - try { - Path pluginPath = Paths.get(pluginsTempDir, fileName); - addUploadingPlugin(fileName, pluginPath); - pluginLoader.savePlugin(pluginPath, fileStream); - return pluginPath; - } catch (IOException e) { - removeUploadingPlugin(fileName); - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to copy the new plugin file with name = '{}' to the temp directory", fileName).get() - ); - } - } - - /** - * Create a new temporary directory for plugins if not exists - * - * @param path Path of the new directory - */ - private void createTempPluginsFolderIfNotExists(Path path) { - if (!Files.isDirectory(path)) { - try { - Files.createDirectories(path); - } catch (IOException e) { - - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to create directory = '{}'", path).get() - ); - } - } - } - - /** - * Resolve and validate file type. - * Allowed values: {@link PluginFileExtension#values()} - * - * @param fileName uploaded plugin file name - */ - private void validateFileExtension(String fileName) { - String resolvedExtension = FilenameUtils.getExtension(fileName); - Optional<PluginFileExtension> byExtension = PluginFileExtension.findByExtension("." + resolvedExtension); - BusinessRule.expect(byExtension, Optional::isPresent) - .verify(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unsupported plugin file extension = '{}'", resolvedExtension).get() - ); - } - - /** - * Add plugin file name to the uploading plugins holder - * - * @param fileName Name of the plugin file to put to the {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} - * @param path Full path to the plugin file - * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager - */ - private void addUploadingPlugin(String fileName, Path path) { - uploadingPlugins.put(fileName, path); - } - - private boolean validatePluginMetaInfo(PluginInfo newPluginInfo) { - return ofNullable(newPluginInfo.getVersion()).map(StringUtils::isNotBlank).orElse(Boolean.FALSE); - } - - private void unloadPreviousPlugin(PluginWrapper pluginWrapper) { - destroyDependency(pluginWrapper.getPluginId()); - if (!pluginManager.unloadPlugin(pluginWrapper.getPluginId())) { - throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, - Suppliers.formattedSupplier("Failed to stop old plugin with id = '{}'", pluginWrapper.getPluginId()).get() - ); - } - } - - private void destroyDependency(String name) { - AbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) this.autowireCapableBeanFactory; - if (beanFactory.containsSingleton(name)) { - beanFactory.destroySingleton(name); - } - } - - /** - * Validates the new plugin in the temporary plugins' directory, uploads it to the root plugins' directory and to the {@link DataStore} - * - * @param newPluginInfo Resolved {@link PluginInfo} of the new plugin - * @param uploadedPluginName Original plugin file name - * @param pluginDetails {@link IntegrationTypeDetails} with the info about the new plugin - * @return updated {@link IntegrationTypeDetails} - */ - private IntegrationTypeDetails copyPlugin(PluginInfo newPluginInfo, IntegrationTypeDetails pluginDetails, String uploadedPluginName) { - String newPluginId = newPluginInfo.getId(); - startUpPlugin(newPluginId); - validateNewPluginExtensionClasses(newPluginId, uploadedPluginName); - pluginManager.unloadPlugin(newPluginId); - - final String newPluginFileName = generatePluginFileName(newPluginInfo, uploadedPluginName); - IntegrationTypeProperties.FILE_NAME.setValue(pluginDetails, newPluginFileName); - - final String fileId = savePlugin(uploadedPluginName, newPluginFileName); - IntegrationTypeProperties.FILE_ID.setValue(pluginDetails, fileId); - - copyPluginToRootDirectory(newPluginId, fileId, newPluginFileName); - removeUploadingPlugin(uploadedPluginName); - - return pluginDetails; - } - - /** - * Validates plugin's extension class/classes and reloads the previous plugin if it is present and the validation failed - * - * @param newPluginId Id of the new plugin - * @param newPluginFileName New plugin file name - * @see PluginLoader#validatePluginExtensionClasses(PluginWrapper)) - */ - private void validateNewPluginExtensionClasses(String newPluginId, String newPluginFileName) { - PluginWrapper newPlugin = getPluginById(newPluginId).orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Plugin with id = '{}' has not been found.", newPluginId).get() - )); - if (!pluginLoader.validatePluginExtensionClasses(newPlugin)) { - pluginManager.unloadPlugin(newPluginId); - deleteTempPlugin(newPluginFileName); - - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("New plugin with id = '{}' doesn't have mandatory extension classes.", newPluginId).get() - ); - - } - } - - private void deleteTempPlugin(String tempPluginFileName) { - try { - pluginLoader.deleteTempPlugin(pluginsTempDir, tempPluginFileName); - } catch (IOException e) { - //error during temp plugin is not crucial, temp files cleaning will be delegated to the plugins cleaning job - LOGGER.error("Error during temp plugin file removing: '{}'", e.getMessage()); - } finally { - removeUploadingPlugin(tempPluginFileName); - } - } - - private String generatePluginFileName(PluginInfo pluginInfo, final String originalFileName) { - return pluginInfo.getId() + "-" + pluginInfo.getVersion() + "." + FilenameUtils.getExtension(originalFileName); - } - - /** - * Saves plugin file to the instance of the configured {@link DataStore} - * - * @param uploadedPluginName Original plugin file name - * @param newPluginFileName New plugin file name - * @return File id - */ - private String savePlugin(final String uploadedPluginName, final String newPluginFileName) { - try (InputStream fileStream = FileUtils.openInputStream(FileUtils.getFile(pluginsTempDir, uploadedPluginName))) { - return pluginLoader.saveToDataStore(newPluginFileName, fileStream); - } catch (Exception e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to upload new plugin file = '{}' to the data store", uploadedPluginName).get() - ); - } - } - - private void copyPluginToRootDirectory(final String newPluginId, final String fileId, final String newPluginFileName) { - try { - pluginLoader.copyFromDataStore(fileId, Paths.get(pluginsDir, newPluginFileName), Paths.get(resourcesDir, newPluginId)); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to copy new plugin file = '{}' from the data store to the root directory", - newPluginFileName - ).get() - ); - } - } - - /** - * Remove plugin file name from the uploading plugins holder - * - * @param fileName Name of the plugin file to remove from the {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} - * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager - */ - private void removeUploadingPlugin(String fileName) { - uploadingPlugins.invalidate(fileName); - } - - /** - * Starts the new plugin and saves it's info as {@link IntegrationType} object in the database - * - * @param pluginDetails {@link IntegrationTypeDetails} with the info about the new plugin - * @return {@link IntegrationType} object with the updated info about the new plugin - */ - private IntegrationType startUpPlugin(final IntegrationTypeDetails pluginDetails) { - - String newPluginFileName = IntegrationTypeProperties.FILE_NAME.getValue(pluginDetails.getDetails()) - .map(String::valueOf) - .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, "Unable to resolve 'fileName' property")); - - return ofNullable(pluginManager.loadPlugin(Paths.get(pluginsDir, newPluginFileName))).map(newLoadedPluginId -> { - startUpPlugin(newLoadedPluginId); - - Optional<IntegrationType> oldIntegrationType = integrationTypeRepository.findByName(newLoadedPluginId); - oldIntegrationType.ifPresent(it -> IntegrationTypeProperties.FILE_ID.getValue(pluginDetails.getDetails()) - .map(String::valueOf) - .ifPresent(fileId -> deletePreviousPluginFile(it, fileId))); - - IntegrationTypeBuilder integrationTypeBuilder = oldIntegrationType.map(IntegrationTypeBuilder::new) - .orElseGet(IntegrationTypeBuilder::new); - integrationTypeBuilder.setName(newLoadedPluginId).setIntegrationGroup(IntegrationGroupEnum.OTHER); - - Optional<ReportPortalExtensionPoint> instance = getInstance(newLoadedPluginId, ReportPortalExtensionPoint.class); - - instance.ifPresent(extensionPoint -> { - pluginDetails.getDetails().putAll(extensionPoint.getPluginParams()); - pluginDetails.getDetails() - .put(IntegrationTypeProperties.RESOURCES_DIRECTORY.getAttribute(), - Paths.get(resourcesDir, newLoadedPluginId).toString() - ); - integrationTypeBuilder.setDetails(pluginDetails); - integrationTypeBuilder.setIntegrationGroup(IntegrationGroupEnum.valueOf(extensionPoint.getIntegrationGroup().name())); - }); - - integrationTypeBuilder.setEnabled(true); - return integrationTypeRepository.save(integrationTypeBuilder.get()); - - }) - .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Error during loading the plugin file = '{}'", newPluginFileName).get() - )); - - } - - private void deletePreviousPluginFile(IntegrationType oldIntegrationType, String newFileId) { - try { - ofNullable(oldIntegrationType.getDetails()).flatMap(details -> ofNullable(details.getDetails())) - .flatMap(IntegrationTypeProperties.FILE_ID::getValue) - .map(String::valueOf) - .ifPresent(oldFileId -> { - if (!oldFileId.equals(newFileId)) { - pluginLoader.deleteFromDataStore(oldFileId); - } - }); - } catch (Exception ex) { - LOGGER.error("Error during removing old plugin file from the Data store: {}", ex.getMessage()); - } - } - - private void deletePreviousPlugin(PluginWrapper previousPlugin) { - try { - Files.deleteIfExists(previousPlugin.getPluginPath()); - } catch (IOException e) { - LOGGER.error("Unable to delete the old plugin file with id = '{}'", previousPlugin.getPluginId()); - } - } - - /** - * Load and start up the previous plugin - * - * @param previousPlugin {@link PluginWrapper} with mandatory data for plugin loading: {@link PluginWrapper#getPluginPath()} - * @param newPluginDetails {@link IntegrationTypeDetails} of the plugin which uploading ended up with an error - * @return {@link PluginState} - */ - private PluginState loadPreviousPlugin(PluginWrapper previousPlugin, IntegrationTypeDetails newPluginDetails) { - if (previousPlugin.getPluginState() == PluginState.STARTED) { - return previousPlugin.getPluginState(); - } - - IntegrationTypeProperties.FILE_ID.getValue(newPluginDetails.getDetails()).map(String::valueOf).ifPresent(fileId -> { - try { - pluginLoader.deleteFromDataStore(fileId); - } catch (Exception e) { - LOGGER.error("Unable to delete new plugin file from the DataStore: '{}'", e.getMessage()); - } - }); - - PluginState pluginState = ofNullable(pluginManager.getPlugin(previousPlugin.getPluginId())).map(loadedPlugin -> { - if (previousPlugin.getDescriptor().getVersion().equals(loadedPlugin.getDescriptor().getVersion())) { - return loadedPlugin.getPluginState(); - } else { - pluginManager.deletePlugin(loadedPlugin.getPluginId()); - deletePluginResources(String.valueOf(Paths.get(resourcesDir, loadedPlugin.getPluginId()))); - return PluginState.DISABLED; - } - }).orElse(PluginState.DISABLED); - - if (pluginState != PluginState.STARTED) { - try { - Path oldPluginPath = previousPlugin.getPluginPath(); - PluginInfo oldPluginInfo = pluginLoader.extractPluginInfo(oldPluginPath); - String oldPluginFileName = generatePluginFileName(oldPluginInfo, oldPluginPath.toFile().getName()); - try (InputStream fileStream = Files.newInputStream(oldPluginPath)) { - pluginLoader.saveToDataStore(oldPluginFileName, fileStream); - } catch (Exception e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to upload old plugin file = '{}' to the data store", oldPluginFileName) - .get() - ); - } - copyPluginResources(oldPluginPath, previousPlugin.getPluginId()); - return startUpPlugin(ofNullable(pluginManager.loadPlugin(oldPluginPath)).orElseThrow(() -> new ReportPortalException( - ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to reload previousPlugin with id = '{}': '{}'", previousPlugin.getPluginId()) - .get() - ))); - } catch (PluginException e) { - throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, - Suppliers.formattedSupplier("Unable to reload previousPlugin with id = '{}': '{}'", - previousPlugin.getPluginId(), - e.getMessage() - ).get() - ); - } - } - - return PluginState.STARTED; - - } + public static final Logger LOGGER = LoggerFactory.getLogger(Pf4jPluginManager.class); + + public static final String LOAD_KEY = "load"; + public static final String UNLOAD_KEY = "unload"; + + private static final long MAXIMUM_UPLOADED_PLUGINS = 50; + private static final long PLUGIN_LIVE_TIME = 2; + + private final String pluginsDir; + private final String pluginsTempDir; + private final String resourcesDir; + + private final Cache<String, Path> uploadingPlugins; + + private final PluginLoader pluginLoader; + private final IntegrationTypeRepository integrationTypeRepository; + + private final PluginManager pluginManager; + private final AutowireCapableBeanFactory autowireCapableBeanFactory; + + private final ApplicationEventPublisher applicationEventPublisher; + + public Pf4jPluginManager(String pluginsDir, String pluginsTempPath, String resourcesDir, + PluginLoader pluginLoader, + IntegrationTypeRepository integrationTypeRepository, PluginManager pluginManager, + AutowireCapableBeanFactory autowireCapableBeanFactory, + ApplicationEventPublisher applicationEventPublisher) throws IOException { + this.pluginsDir = pluginsDir; + Files.createDirectories(Paths.get(this.pluginsDir)); + this.resourcesDir = resourcesDir; + Files.createDirectories(Paths.get(this.resourcesDir)); + this.pluginsTempDir = pluginsTempPath; + Files.createDirectories(Paths.get(this.pluginsTempDir)); + this.autowireCapableBeanFactory = autowireCapableBeanFactory; + this.applicationEventPublisher = applicationEventPublisher; + this.pluginLoader = pluginLoader; + this.integrationTypeRepository = integrationTypeRepository; + this.uploadingPlugins = CacheBuilder.newBuilder() + .maximumSize(MAXIMUM_UPLOADED_PLUGINS) + .expireAfterWrite(PLUGIN_LIVE_TIME, TimeUnit.MINUTES) + .build(); + this.pluginManager = pluginManager; + } + + @Override + public List<Plugin> getPlugins() { + return this.pluginManager.getPlugins() + .stream() + .flatMap(plugin -> pluginManager.getExtensionClasses(plugin.getPluginId()) + .stream() + .map(ExtensionPoint::findByExtension) + .filter(Optional::isPresent) + .map(it -> new Plugin(plugin.getPluginId(), it.get()))) + .collect(Collectors.toList()); + } + + @Override + public Optional<Plugin> getPlugin(String type) { + return getPlugins().stream().filter(p -> p.getType().name().equalsIgnoreCase(type)).findAny(); + } + + @Override + public <T> Optional<T> getInstance(String name, Class<T> extension) { + return pluginManager.getExtensions(extension, name).stream().findFirst(); + } + + @Override + public <T> Optional<T> getInstance(Class<T> extension) { + return pluginManager.getExtensions(extension).stream().findFirst(); + } + + @Override + public void startUp() { + // load and start all enabled plugins of application + integrationTypeRepository.findAll() + .stream() + .filter(IntegrationType::isEnabled) + .forEach(integrationType -> ofNullable(integrationType.getDetails()).ifPresent( + integrationTypeDetails -> { + try { + loadPlugin(integrationType.getName(), integrationTypeDetails); + } catch (Exception ex) { + LOGGER.error("Unable to load plugin '{}'", integrationType.getName()); + } + })); + + } + + @Override + public void shutDown() { + // stop and unload all plugins + pluginManager.stopPlugins(); + pluginManager.getPlugins().forEach(p -> pluginManager.unloadPlugin(p.getPluginId())); + } + + @Override + public PluginState startUpPlugin(String pluginId) { + + PluginWrapper pluginWrapper = ofNullable(pluginManager.getPlugin(pluginId)).orElseThrow( + () -> new ReportPortalException(ErrorType.UNABLE_INTERACT_WITH_INTEGRATION, + "Plugin not found: " + pluginId + )); + + return pluginManager.startPlugin(pluginWrapper.getPluginId()); + } + + @Override + public boolean loadPlugin(String pluginId, IntegrationTypeDetails integrationTypeDetails) { + return ofNullable(integrationTypeDetails.getDetails()).map(details -> { + String fileName = IntegrationTypeProperties.FILE_NAME.getValue(details) + .map(String::valueOf) + .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "'File name' property of the plugin - '{}' is not specified", pluginId).get() + )); + + Path pluginPath = Paths.get(pluginsDir, fileName); + if (Files.notExists(pluginPath)) { + String fileId = IntegrationTypeProperties.FILE_ID.getValue(details) + .map(String::valueOf) + .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "'File id' property of the plugin - '{}' is not specified", pluginId).get() + )); + try { + pluginLoader.copyFromDataStore(fileId, pluginPath, Paths.get(resourcesDir, pluginId)); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to load plugin - '{}' from the data store", + pluginId).get() + ); + } + } else { + copyPluginResources(pluginPath, pluginId); + } + + return ofNullable(pluginManager.loadPlugin(pluginPath)).map(id -> { + if (PluginState.STARTED == pluginManager.startPlugin(pluginId)) { + Optional<org.pf4j.ExtensionPoint> extensionPoint = this.getInstance(pluginId, + org.pf4j.ExtensionPoint.class); + extensionPoint.ifPresent(extension -> LOGGER.info( + Suppliers.formattedSupplier("Plugin - '{}' initialized.", pluginId) + .get())); + applicationEventPublisher.publishEvent(new PluginEvent(pluginId, LOAD_KEY)); + return true; + } else { + return false; + } + }).orElse(Boolean.FALSE); + }).orElse(Boolean.FALSE); + + } + + private void copyPluginResources(Path pluginPath, String pluginId) { + try { + pluginLoader.copyPluginResource(pluginPath, Paths.get(resourcesDir, pluginId)); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to load resources of the - '{}' plugin", pluginId) + .get() + ); + } + } + + @Override + public boolean unloadPlugin(IntegrationType integrationType) { + applicationEventPublisher.publishEvent(new PluginEvent(integrationType.getName(), UNLOAD_KEY)); + destroyDependency(integrationType.getName()); + return pluginManager.unloadPlugin(integrationType.getName()); + } + + @Override + public boolean deletePlugin(String pluginId) { + return integrationTypeRepository.findByName(pluginId).map(this::deletePlugin) + .orElse(Boolean.TRUE); + } + + @Override + public boolean deletePlugin(PluginWrapper pluginWrapper) { + return integrationTypeRepository.findByName(pluginWrapper.getPluginId()).map(this::deletePlugin) + .orElseGet(() -> { + applicationEventPublisher.publishEvent( + new PluginEvent(pluginWrapper.getPluginId(), UNLOAD_KEY)); + deletePluginResources(Paths.get(resourcesDir, pluginWrapper.getPluginId()).toString()); + destroyDependency(pluginWrapper.getPluginId()); + return pluginManager.deletePlugin(pluginWrapper.getPluginId()); + }); + } + + private boolean deletePlugin(IntegrationType integrationType) { + Optional<Map<String, Object>> pluginData = ofNullable(integrationType.getDetails()).map( + IntegrationTypeDetails::getDetails); + pluginData.ifPresent(this::deletePluginResources); + + applicationEventPublisher.publishEvent(new PluginEvent(integrationType.getName(), UNLOAD_KEY)); + + boolean pluginRemoved = ofNullable(pluginManager.getPlugin(integrationType.getName())).map( + pluginWrapper -> { + destroyDependency(pluginWrapper.getPluginId()); + if (integrationType.isEnabled()) { + return pluginManager.deletePlugin(integrationType.getName()); + } + return true; + }).orElse(Boolean.TRUE); + + boolean pluginFileRemoved = pluginData.map(this::deletePluginFile).orElse(Boolean.TRUE); + + return pluginRemoved && pluginFileRemoved; + } + + private void deletePluginResources(Map<String, Object> details) { + IntegrationTypeProperties.RESOURCES_DIRECTORY.getValue(details).map(String::valueOf) + .ifPresent(this::deletePluginResources); + IntegrationTypeProperties.FILE_ID.getValue(details).map(String::valueOf) + .ifPresent(pluginLoader::deleteFromDataStore); + } + + private void deletePluginResources(String resourcesDir) { + try { + FileUtils.deleteDirectory(FileUtils.getFile(resourcesDir)); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, + "Unable to delete plugin resources."); + } + } + + private boolean deletePluginFile(Map<String, Object> details) { + return IntegrationTypeProperties.FILE_NAME.getValue(details) + .map(String::valueOf) + .map(fileName -> Paths.get(pluginsDir, fileName)) + .map(path -> { + try { + if (Files.exists(path)) { + return Files.deleteIfExists(path); + } else { + return true; + } + } catch (IOException e) { + throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, + "Error during plugin file removing from the filesystem: " + e.getMessage() + ); + } + + }) + .orElse(Boolean.TRUE); + } + + @Override + public Optional<PluginWrapper> getPluginById(String id) { + return ofNullable(pluginManager.getPlugin(id)); + } + + @Override + public boolean isInUploadingState(String fileName) { + return uploadingPlugins.asMap().containsKey(fileName); + } + + @Override + public IntegrationType uploadPlugin(final String uploadedPluginName, + final InputStream fileStream) { + PluginInfo newPluginInfo = resolvePluginInfo(uploadedPluginName, fileStream); + IntegrationTypeDetails pluginDetails = pluginLoader.resolvePluginDetails(newPluginInfo); + + Optional<PluginWrapper> previousPlugin = getPluginById(newPluginInfo.getId()); + previousPlugin.ifPresent(this::unloadPreviousPlugin); + + return ofNullable(pluginManager.loadPlugin(Paths.get(pluginsTempDir, uploadedPluginName))).map( + pluginId -> { + IntegrationTypeDetails newPluginDetails = copyPlugin(newPluginInfo, pluginDetails, + uploadedPluginName); + try { + IntegrationType newIntegrationType = startUpPlugin(newPluginDetails); + applicationEventPublisher.publishEvent( + new PluginEvent(newIntegrationType.getName(), LOAD_KEY)); + previousPlugin.ifPresent(this::deletePreviousPlugin); + deleteTempPlugin(uploadedPluginName); + return newIntegrationType; + } catch (Exception ex) { + previousPlugin.ifPresent(p -> loadPreviousPlugin(p, newPluginDetails)); + Throwable exception = ex; + String exMessage = exception.toString(); + while (exception.getCause() != null) { + exception = exception.getCause(); + exMessage += exception.toString() + "\n"; + } + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, exMessage); + } + }).orElseThrow(() -> { + previousPlugin.ifPresent(p -> loadPreviousPlugin(p, pluginDetails)); + deleteTempPlugin(uploadedPluginName); + + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Failed to load new plugin from file = '{}'", + uploadedPluginName).get() + ); + }); + } + + /** + * Uploads the plugin file to the temp directory and extracts it's info. Presence of the plugin + * version is mandatory + * + * @param fileName Plugin file name to upload + * @param fileStream {@link InputStream} of the plugin file + * @return {@link PluginInfo} + */ + private PluginInfo resolvePluginInfo(final String fileName, InputStream fileStream) { + Path tempPluginPath = uploadTempPlugin(fileName, fileStream); + + try { + PluginInfo newPluginInfo = pluginLoader.extractPluginInfo(tempPluginPath); + BusinessRule.expect(validatePluginMetaInfo(newPluginInfo), equalTo(Boolean.TRUE)) + .verify(ErrorType.PLUGIN_UPLOAD_ERROR, "Plugin version should be specified."); + return newPluginInfo; + } catch (PluginException e) { + removeUploadingPlugin(fileName); + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, e.getMessage()); + } + } + + /** + * Upload plugin file to the temporary plugins directory. + * + * @param fileName Plugin file name to upload + * @param fileStream {@link InputStream} of the plugin file + * @return {@link Path} to the temporary uploaded plugin file + */ + private Path uploadTempPlugin(String fileName, InputStream fileStream) { + Path pluginsTempDirPath = Paths.get(pluginsTempDir); + createTempPluginsFolderIfNotExists(pluginsTempDirPath); + + validateFileExtension(fileName); + + try { + Path pluginPath = Paths.get(pluginsTempDir, fileName); + addUploadingPlugin(fileName, pluginPath); + pluginLoader.savePlugin(pluginPath, fileStream); + return pluginPath; + } catch (IOException e) { + removeUploadingPlugin(fileName); + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "Unable to copy the new plugin file with name = '{}' to the temp directory", fileName) + .get() + ); + } + } + + /** + * Create a new temporary directory for plugins if not exists + * + * @param path Path of the new directory + */ + private void createTempPluginsFolderIfNotExists(Path path) { + if (!Files.isDirectory(path)) { + try { + Files.createDirectories(path); + } catch (IOException e) { + + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to create directory = '{}'", path).get() + ); + } + } + } + + /** + * Resolve and validate file type. Allowed values: {@link PluginFileExtension#values()} + * + * @param fileName uploaded plugin file name + */ + private void validateFileExtension(String fileName) { + String resolvedExtension = FilenameUtils.getExtension(fileName); + Optional<PluginFileExtension> byExtension = PluginFileExtension.findByExtension( + "." + resolvedExtension); + BusinessRule.expect(byExtension, Optional::isPresent) + .verify(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unsupported plugin file extension = '{}'", + resolvedExtension).get() + ); + } + + /** + * Add plugin file name to the uploading plugins holder + * + * @param fileName Name of the plugin file to put to the + * {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} + * @param path Full path to the plugin file + * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager + */ + private void addUploadingPlugin(String fileName, Path path) { + uploadingPlugins.put(fileName, path); + } + + private boolean validatePluginMetaInfo(PluginInfo newPluginInfo) { + return ofNullable(newPluginInfo.getVersion()).map(StringUtils::isNotBlank) + .orElse(Boolean.FALSE); + } + + private void unloadPreviousPlugin(PluginWrapper pluginWrapper) { + destroyDependency(pluginWrapper.getPluginId()); + if (!pluginManager.unloadPlugin(pluginWrapper.getPluginId())) { + throw new ReportPortalException(ErrorType.PLUGIN_REMOVE_ERROR, + Suppliers.formattedSupplier("Failed to stop old plugin with id = '{}'", + pluginWrapper.getPluginId()).get() + ); + } + } + + private void destroyDependency(String name) { + AbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) this.autowireCapableBeanFactory; + if (beanFactory.containsSingleton(name)) { + beanFactory.destroySingleton(name); + } + } + + /** + * Validates the new plugin in the temporary plugins' directory, uploads it to the root plugins' + * directory and to the {@link DataStore} + * + * @param newPluginInfo Resolved {@link PluginInfo} of the new plugin + * @param uploadedPluginName Original plugin file name + * @param pluginDetails {@link IntegrationTypeDetails} with the info about the new plugin + * @return updated {@link IntegrationTypeDetails} + */ + private IntegrationTypeDetails copyPlugin(PluginInfo newPluginInfo, + IntegrationTypeDetails pluginDetails, String uploadedPluginName) { + String newPluginId = newPluginInfo.getId(); + startUpPlugin(newPluginId); + validateNewPluginExtensionClasses(newPluginId, uploadedPluginName); + pluginManager.unloadPlugin(newPluginId); + + final String newPluginFileName = generatePluginFileName(newPluginInfo, uploadedPluginName); + IntegrationTypeProperties.FILE_NAME.setValue(pluginDetails, newPluginFileName); + + final String fileId = savePlugin(uploadedPluginName, newPluginFileName); + IntegrationTypeProperties.FILE_ID.setValue(pluginDetails, fileId); + + copyPluginToRootDirectory(newPluginId, fileId, newPluginFileName); + removeUploadingPlugin(uploadedPluginName); + + return pluginDetails; + } + + /** + * Validates plugin's extension class/classes and reloads the previous plugin if it is present and + * the validation failed + * + * @param newPluginId Id of the new plugin + * @param newPluginFileName New plugin file name + * @see PluginLoader#validatePluginExtensionClasses(PluginWrapper)) + */ + private void validateNewPluginExtensionClasses(String newPluginId, String newPluginFileName) { + PluginWrapper newPlugin = getPluginById(newPluginId).orElseThrow( + () -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Plugin with id = '{}' has not been found.", newPluginId) + .get() + )); + if (!pluginLoader.validatePluginExtensionClasses(newPlugin)) { + pluginManager.unloadPlugin(newPluginId); + deleteTempPlugin(newPluginFileName); + + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "New plugin with id = '{}' doesn't have mandatory extension classes.", newPluginId) + .get() + ); + + } + } + + private void deleteTempPlugin(String tempPluginFileName) { + try { + pluginLoader.deleteTempPlugin(pluginsTempDir, tempPluginFileName); + } catch (IOException e) { + //error during temp plugin is not crucial, temp files cleaning will be delegated to the plugins cleaning job + LOGGER.error("Error during temp plugin file removing: '{}'", e.getMessage()); + } finally { + removeUploadingPlugin(tempPluginFileName); + } + } + + private String generatePluginFileName(PluginInfo pluginInfo, final String originalFileName) { + return pluginInfo.getId() + "-" + pluginInfo.getVersion() + "." + FilenameUtils.getExtension( + originalFileName); + } + + /** + * Saves plugin file to the instance of the configured {@link DataStore} + * + * @param uploadedPluginName Original plugin file name + * @param newPluginFileName New plugin file name + * @return File id + */ + private String savePlugin(final String uploadedPluginName, final String newPluginFileName) { + try (InputStream fileStream = FileUtils.openInputStream( + FileUtils.getFile(pluginsTempDir, uploadedPluginName))) { + return pluginLoader.saveToDataStore(newPluginFileName, fileStream); + } catch (Exception e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to upload new plugin file = '{}' to the data store", + uploadedPluginName).get() + ); + } + } + + private void copyPluginToRootDirectory(final String newPluginId, final String fileId, + final String newPluginFileName) { + try { + pluginLoader.copyFromDataStore(fileId, Paths.get(pluginsDir, newPluginFileName), + Paths.get(resourcesDir, newPluginId)); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "Unable to copy new plugin file = '{}' from the data store to the root directory", + newPluginFileName + ).get() + ); + } + } + + /** + * Remove plugin file name from the uploading plugins holder + * + * @param fileName Name of the plugin file to remove from the + * {@link com.epam.ta.reportportal.plugin.Pf4jPluginManager#uploadingPlugins} + * @see com.epam.ta.reportportal.plugin.Pf4jPluginManager + */ + private void removeUploadingPlugin(String fileName) { + uploadingPlugins.invalidate(fileName); + } + + /** + * Starts the new plugin and saves it's info as {@link IntegrationType} object in the database + * + * @param pluginDetails {@link IntegrationTypeDetails} with the info about the new plugin + * @return {@link IntegrationType} object with the updated info about the new plugin + */ + private IntegrationType startUpPlugin(final IntegrationTypeDetails pluginDetails) { + + String newPluginFileName = IntegrationTypeProperties.FILE_NAME.getValue( + pluginDetails.getDetails()) + .map(String::valueOf) + .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + "Unable to resolve 'fileName' property")); + + return ofNullable(pluginManager.loadPlugin(Paths.get(pluginsDir, newPluginFileName))).map( + newLoadedPluginId -> { + startUpPlugin(newLoadedPluginId); + + Optional<IntegrationType> oldIntegrationType = integrationTypeRepository.findByName( + newLoadedPluginId); + oldIntegrationType.ifPresent( + it -> IntegrationTypeProperties.FILE_ID.getValue(pluginDetails.getDetails()) + .map(String::valueOf) + .ifPresent(fileId -> deletePreviousPluginFile(it, fileId))); + + IntegrationTypeBuilder integrationTypeBuilder = oldIntegrationType.map( + IntegrationTypeBuilder::new) + .orElseGet(IntegrationTypeBuilder::new); + integrationTypeBuilder.setName(newLoadedPluginId) + .setIntegrationGroup(IntegrationGroupEnum.OTHER); + + Optional<ReportPortalExtensionPoint> instance = getInstance(newLoadedPluginId, + ReportPortalExtensionPoint.class); + + instance.ifPresent(extensionPoint -> { + pluginDetails.getDetails().putAll(extensionPoint.getPluginParams()); + pluginDetails.getDetails() + .put(IntegrationTypeProperties.RESOURCES_DIRECTORY.getAttribute(), + Paths.get(resourcesDir, newLoadedPluginId).toString() + ); + integrationTypeBuilder.setDetails(pluginDetails); + integrationTypeBuilder.setIntegrationGroup( + IntegrationGroupEnum.valueOf(extensionPoint.getIntegrationGroup().name())); + }); + + integrationTypeBuilder.setEnabled(true); + return integrationTypeRepository.save(integrationTypeBuilder.get()); + + }) + .orElseThrow(() -> new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Error during loading the plugin file = '{}'", + newPluginFileName).get() + )); + + } + + private void deletePreviousPluginFile(IntegrationType oldIntegrationType, String newFileId) { + try { + ofNullable(oldIntegrationType.getDetails()).flatMap( + details -> ofNullable(details.getDetails())) + .flatMap(IntegrationTypeProperties.FILE_ID::getValue) + .map(String::valueOf) + .ifPresent(oldFileId -> { + if (!oldFileId.equals(newFileId)) { + pluginLoader.deleteFromDataStore(oldFileId); + } + }); + } catch (Exception ex) { + LOGGER.error("Error during removing old plugin file from the Data store: {}", + ex.getMessage()); + } + } + + private void deletePreviousPlugin(PluginWrapper previousPlugin) { + try { + Files.deleteIfExists(previousPlugin.getPluginPath()); + } catch (IOException e) { + LOGGER.error("Unable to delete the old plugin file with id = '{}'", + previousPlugin.getPluginId()); + } + } + + /** + * Load and start up the previous plugin + * + * @param previousPlugin {@link PluginWrapper} with mandatory data for plugin loading: + * {@link PluginWrapper#getPluginPath()} + * @param newPluginDetails {@link IntegrationTypeDetails} of the plugin which uploading ended up + * with an error + * @return {@link PluginState} + */ + private PluginState loadPreviousPlugin(PluginWrapper previousPlugin, + IntegrationTypeDetails newPluginDetails) { + if (previousPlugin.getPluginState() == PluginState.STARTED) { + return previousPlugin.getPluginState(); + } + + IntegrationTypeProperties.FILE_ID.getValue(newPluginDetails.getDetails()).map(String::valueOf) + .ifPresent(fileId -> { + try { + pluginLoader.deleteFromDataStore(fileId); + } catch (Exception e) { + LOGGER.error("Unable to delete new plugin file from the DataStore: '{}'", + e.getMessage()); + } + }); + + PluginState pluginState = ofNullable(pluginManager.getPlugin(previousPlugin.getPluginId())).map( + loadedPlugin -> { + if (previousPlugin.getDescriptor().getVersion() + .equals(loadedPlugin.getDescriptor().getVersion())) { + return loadedPlugin.getPluginState(); + } else { + pluginManager.deletePlugin(loadedPlugin.getPluginId()); + deletePluginResources( + String.valueOf(Paths.get(resourcesDir, loadedPlugin.getPluginId()))); + return PluginState.DISABLED; + } + }).orElse(PluginState.DISABLED); + + if (pluginState != PluginState.STARTED) { + try { + Path oldPluginPath = previousPlugin.getPluginPath(); + PluginInfo oldPluginInfo = pluginLoader.extractPluginInfo(oldPluginPath); + String oldPluginFileName = generatePluginFileName(oldPluginInfo, + oldPluginPath.toFile().getName()); + try (InputStream fileStream = Files.newInputStream(oldPluginPath)) { + pluginLoader.saveToDataStore(oldPluginFileName, fileStream); + } catch (Exception e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier( + "Unable to upload old plugin file = '{}' to the data store", oldPluginFileName) + .get() + ); + } + copyPluginResources(oldPluginPath, previousPlugin.getPluginId()); + return startUpPlugin(ofNullable(pluginManager.loadPlugin(oldPluginPath)).orElseThrow( + () -> new ReportPortalException( + ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to reload previousPlugin with id = '{}': '{}'", + previousPlugin.getPluginId()) + .get() + ))); + } catch (PluginException e) { + throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, + Suppliers.formattedSupplier("Unable to reload previousPlugin with id = '{}': '{}'", + previousPlugin.getPluginId(), + e.getMessage() + ).get() + ); + } + } + + return PluginState.STARTED; + + } } diff --git a/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java b/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java index 429cd2402d..ec6db33aaa 100644 --- a/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java +++ b/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java @@ -17,6 +17,9 @@ package com.epam.ta.reportportal.plugin; import com.epam.reportportal.extension.common.IntegrationTypeProperties; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; import org.pf4j.DefaultExtensionFactory; import org.pf4j.PluginManager; import org.pf4j.PluginWrapper; @@ -24,60 +27,58 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class ReportPortalExtensionFactory extends DefaultExtensionFactory { - private final String resourcesDir; - private final PluginManager pluginManager; - private final AbstractAutowireCapableBeanFactory beanFactory; + private final String resourcesDir; + private final PluginManager pluginManager; + private final AbstractAutowireCapableBeanFactory beanFactory; - public ReportPortalExtensionFactory(String resourcesDir, PluginManager pluginManager, AutowireCapableBeanFactory context) { - this.resourcesDir = resourcesDir; - this.pluginManager = pluginManager; - this.beanFactory = (AbstractAutowireCapableBeanFactory) context; - } + public ReportPortalExtensionFactory(String resourcesDir, PluginManager pluginManager, + AutowireCapableBeanFactory context) { + this.resourcesDir = resourcesDir; + this.pluginManager = pluginManager; + this.beanFactory = (AbstractAutowireCapableBeanFactory) context; + } - @Override - public Object create(Class<?> extensionClass) { - PluginWrapper pluginWrapper = pluginManager.whichPlugin(extensionClass); - if (beanFactory.containsSingleton(pluginWrapper.getPluginId())) { - return beanFactory.getSingleton(pluginWrapper.getPluginId()); - } else { - return createExtension(extensionClass, pluginWrapper); - } - } + @Override + public Object create(Class<?> extensionClass) { + PluginWrapper pluginWrapper = pluginManager.whichPlugin(extensionClass); + if (beanFactory.containsSingleton(pluginWrapper.getPluginId())) { + return beanFactory.getSingleton(pluginWrapper.getPluginId()); + } else { + return createExtension(extensionClass, pluginWrapper); + } + } - private Object createExtension(Class<?> extensionClass, PluginWrapper pluginWrapper) { - Map<String, Object> initParams = getInitParams(pluginWrapper); - Object plugin = createPlugin(extensionClass, initParams); - beanFactory.autowireBean(plugin); - beanFactory.initializeBean(plugin, pluginWrapper.getDescriptor().getPluginId()); - beanFactory.registerSingleton(pluginWrapper.getDescriptor().getPluginId(), plugin); - if (DisposableBean.class.isAssignableFrom(extensionClass)) { - beanFactory.registerDisposableBean(pluginWrapper.getDescriptor().getPluginId(), (DisposableBean) plugin); - } - return plugin; - } + private Object createExtension(Class<?> extensionClass, PluginWrapper pluginWrapper) { + Map<String, Object> initParams = getInitParams(pluginWrapper); + Object plugin = createPlugin(extensionClass, initParams); + beanFactory.autowireBean(plugin); + beanFactory.initializeBean(plugin, pluginWrapper.getDescriptor().getPluginId()); + beanFactory.registerSingleton(pluginWrapper.getDescriptor().getPluginId(), plugin); + if (DisposableBean.class.isAssignableFrom(extensionClass)) { + beanFactory.registerDisposableBean(pluginWrapper.getDescriptor().getPluginId(), + (DisposableBean) plugin); + } + return plugin; + } - private Object createPlugin(Class<?> extensionClass, Map<String, Object> initParams) { - try { - return extensionClass.getDeclaredConstructor(Map.class).newInstance(initParams); - } catch (Exception ex) { - return super.create(extensionClass); - } - } + private Object createPlugin(Class<?> extensionClass, Map<String, Object> initParams) { + try { + return extensionClass.getDeclaredConstructor(Map.class).newInstance(initParams); + } catch (Exception ex) { + return super.create(extensionClass); + } + } - private Map<String, Object> getInitParams(PluginWrapper pluginWrapper) { - Map<String, Object> initParams = new HashMap<>(); - initParams.put(IntegrationTypeProperties.RESOURCES_DIRECTORY.getAttribute(), - Paths.get(resourcesDir, pluginWrapper.getPluginId()) - ); - return initParams; - } + private Map<String, Object> getInitParams(PluginWrapper pluginWrapper) { + Map<String, Object> initParams = new HashMap<>(); + initParams.put(IntegrationTypeProperties.RESOURCES_DIRECTORY.getAttribute(), + Paths.get(resourcesDir, pluginWrapper.getPluginId()) + ); + return initParams; + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBean.java b/src/main/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBean.java index 0d94bff420..e5ff3721f5 100644 --- a/src/main/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBean.java +++ b/src/main/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBean.java @@ -23,94 +23,92 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; import org.springframework.lang.NonNull; /** - * {@link FactoryBean} with access to {@link ApplicationContext} with lazy - * initialization + * {@link FactoryBean} with access to {@link ApplicationContext} with lazy initialization * * @param <T> - type of bean * @author Andrei Varabyeu */ -public abstract class ApplicationContextAwareFactoryBean<T> implements FactoryBean<T>, ApplicationContextAware, InitializingBean { +public abstract class ApplicationContextAwareFactoryBean<T> implements FactoryBean<T>, + ApplicationContextAware, InitializingBean { - /** - * Application context holder - */ - private ApplicationContext applicationContext; + /** + * Application context holder + */ + private ApplicationContext applicationContext; - /** - * Supplier of bean to be created - */ - private Supplier<T> beanSupplier; + /** + * Supplier of bean to be created + */ + private Supplier<T> beanSupplier; - /** - * Whether is bean to be creates going to be singleton - */ - private boolean singleton = true; + /** + * Whether is bean to be creates going to be singleton + */ + private boolean singleton = true; - /* - * (non-Javadoc) - * - * @see - * org.springframework.context.ApplicationContextAware#setApplicationContext - * (org.springframework.context.ApplicationContext) - */ - @Override - public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + /* + * (non-Javadoc) + * + * @see + * org.springframework.context.ApplicationContextAware#setApplicationContext + * (org.springframework.context.ApplicationContext) + */ + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } - /* - * (non-Javadoc) - * - * @see org.springframework.beans.factory.FactoryBean#getObject() - */ - @Override - public T getObject() { - return beanSupplier.get(); - } + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + @Override + public T getObject() { + return beanSupplier.get(); + } - /* - * (non-Javadoc) - * - * @see org.springframework.beans.factory.FactoryBean#isSingleton() - */ - @Override - public boolean isSingleton() { - return this.singleton; - } + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.FactoryBean#isSingleton() + */ + @Override + public boolean isSingleton() { + return this.singleton; + } - public void setSingleton(boolean singleton) { - this.singleton = singleton; - } + public void setSingleton(boolean singleton) { + this.singleton = singleton; + } - /** - * Instantiates supplier for bean to be created. This mades possible - * lazy-initialization - */ - @Override - public void afterPropertiesSet() { - Supplier<T> supplier = this::createInstance; + /** + * Instantiates supplier for bean to be created. This mades possible lazy-initialization + */ + @Override + public void afterPropertiesSet() { + Supplier<T> supplier = this::createInstance; - this.beanSupplier = isSingleton() ? Suppliers.memoize(supplier) : supplier; - } + this.beanSupplier = isSingleton() ? Suppliers.memoize(supplier) : supplier; + } - protected ApplicationContext getApplicationContext() { - return applicationContext; - } + protected ApplicationContext getApplicationContext() { + return applicationContext; + } - /** - * Template method that subclasses must override to construct the object - * returned by this factory. - * <p> - * Invoked on initialization of this FactoryBean in case of a singleton; - * else, on each {@link #getObject()} call. - * - * @return the object returned by this factory - * @see #getObject() - */ - protected abstract T createInstance(); + /** + * Template method that subclasses must override to construct the object returned by this + * factory. + * <p> + * Invoked on initialization of this FactoryBean in case of a singleton; else, on each + * {@link #getObject()} call. + * + * @return the object returned by this factory + * @see #getObject() + */ + protected abstract T createInstance(); } diff --git a/src/main/java/com/epam/ta/reportportal/util/BinaryDataResponseWriter.java b/src/main/java/com/epam/ta/reportportal/util/BinaryDataResponseWriter.java new file mode 100644 index 0000000000..463f002999 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/util/BinaryDataResponseWriter.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.util; + +import com.epam.ta.reportportal.entity.attachment.BinaryData; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.model.ErrorType; +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +public class BinaryDataResponseWriter { + + /** + * Copies data from provided {@link InputStream} to Response + * + * @param binaryData File data + * @param response Response object + */ + public void write(BinaryData binaryData, HttpServletResponse response) { + try { + response.setContentType(binaryData.getContentType()); + IOUtils.copy(binaryData.getInputStream(), response.getOutputStream()); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.UNABLE_TO_LOAD_BINARY_DATA, e.getMessage()); + } + } +} diff --git a/src/main/java/com/epam/ta/reportportal/util/ControllerUtils.java b/src/main/java/com/epam/ta/reportportal/util/ControllerUtils.java index 073f25a86a..3c0f441574 100644 --- a/src/main/java/com/epam/ta/reportportal/util/ControllerUtils.java +++ b/src/main/java/com/epam/ta/reportportal/util/ControllerUtils.java @@ -19,85 +19,94 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; - +import java.util.Iterator; +import java.util.List; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolation; import javax.validation.Path; import javax.validation.Validator; -import java.util.*; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; /** * @author Konstantin Antipin */ public class ControllerUtils { - /** - * Tries to find request part or file with specified name in multipart attachments - * map. - * - * @param filename File name - * @param files Files map - * @return Found file - */ - public static MultipartFile findByFileName(String filename, Map<String, MultipartFile> files) { - /* Request part name? */ - if (files.containsKey(filename)) { - return files.get(filename); - } - /* Filename? */ - for (MultipartFile file : files.values()) { - if (filename.equals(file.getOriginalFilename())) { - return file; - } - } - return null; - } + /** + * Tries to find request part or file with specified name in multipart attachments map. + * + * @param filename File name + * @param files Files map + * @return Found file + */ + public static MultipartFile findByFileName(String filename, MultiValuedMap<String, MultipartFile> files) { + /* Request part name? */ + if (files.containsKey(filename)) { + var multipartFile = files.get(filename).stream() + .findFirst() + .get(); + files.get(filename).remove(multipartFile); + return multipartFile; + } + /* Filename? */ + for (MultipartFile file : files.values()) { + if (filename.equals(file.getOriginalFilename())) { + return file; + } + } + return null; + } + + public static Long safeParseLong(String value) { + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "The provided parameter must be a number"); + } + } - public static Long safeParseLong(String value) { - try { - return Long.parseLong(value); - } catch (NumberFormatException e) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "The provided parameter must be a number"); - } - } - public static Integer safeParseInt(String value) { - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "The provided parameter must be a number"); - } - } + public static Integer safeParseInt(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "The provided parameter must be a number"); + } + } - public static void validateSaveRQ(Validator validator, SaveLogRQ saveLogRQ) { - Set<ConstraintViolation<SaveLogRQ>> constraintViolations = validator.validate(saveLogRQ); - if (constraintViolations != null && !constraintViolations.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder(); - for (ConstraintViolation<SaveLogRQ> constraintViolation : constraintViolations) { - messageBuilder.append("["); - messageBuilder.append("Incorrect value in save log request '"); - messageBuilder.append(constraintViolation.getInvalidValue()); - messageBuilder.append("' in field '"); - Iterator<Path.Node> iterator = constraintViolation.getPropertyPath().iterator(); - messageBuilder.append(iterator.hasNext() ? iterator.next().getName() : ""); - messageBuilder.append("'.]"); - } - throw new ReportPortalException(ErrorType.INCORRECT_REQUEST, messageBuilder.toString()); - } - } + public static void validateSaveRQ(Validator validator, SaveLogRQ saveLogRQ) { + Set<ConstraintViolation<SaveLogRQ>> constraintViolations = validator.validate(saveLogRQ); + if (constraintViolations != null && !constraintViolations.isEmpty()) { + StringBuilder messageBuilder = new StringBuilder(); + for (ConstraintViolation<SaveLogRQ> constraintViolation : constraintViolations) { + messageBuilder.append("["); + messageBuilder.append("Incorrect value in save log request '"); + messageBuilder.append(constraintViolation.getInvalidValue()); + messageBuilder.append("' in field '"); + Iterator<Path.Node> iterator = constraintViolation.getPropertyPath().iterator(); + messageBuilder.append(iterator.hasNext() ? iterator.next().getName() : ""); + messageBuilder.append("'.]"); + } + throw new ReportPortalException(ErrorType.INCORRECT_REQUEST, messageBuilder.toString()); + } + } - public static Map<String, MultipartFile> getUploadedFiles(HttpServletRequest request) { - Map<String, MultipartFile> uploadedFiles = new HashMap<>(); - if (request instanceof MultipartHttpServletRequest) { - MultiValueMap<String, MultipartFile> multiFileMap = (((MultipartHttpServletRequest) request)).getMultiFileMap(); - for (List<MultipartFile> multipartFiles : multiFileMap.values()) { - for (MultipartFile file : multipartFiles) { - uploadedFiles.put(file.getOriginalFilename(), file); - } - } - } - return uploadedFiles; - } + public static MultiValuedMap<String, MultipartFile> getUploadedFiles(HttpServletRequest request) { + MultiValuedMap<String, MultipartFile> uploadedFiles = new ArrayListValuedHashMap<>(); + if (request instanceof MultipartHttpServletRequest) { + MultiValueMap<String, MultipartFile> multiFileMap = (((MultipartHttpServletRequest) request)).getMultiFileMap(); + for (List<MultipartFile> multipartFiles : multiFileMap.values()) { + for (MultipartFile file : multipartFiles) { + uploadedFiles.put(file.getOriginalFilename(), file); + } + } + } + return uploadedFiles; + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/DateTimeProvider.java b/src/main/java/com/epam/ta/reportportal/util/DateTimeProvider.java index ab4faf9751..db9b4ffad2 100644 --- a/src/main/java/com/epam/ta/reportportal/util/DateTimeProvider.java +++ b/src/main/java/com/epam/ta/reportportal/util/DateTimeProvider.java @@ -16,9 +16,8 @@ package com.epam.ta.reportportal.util; -import org.springframework.stereotype.Component; - import java.time.LocalDateTime; +import org.springframework.stereotype.Component; /** * Class to ease writing/testing of date-based logic. @@ -28,7 +27,7 @@ @Component public class DateTimeProvider { - public LocalDateTime localDateTimeNow() { - return LocalDateTime.now(); - } + public LocalDateTime localDateTimeNow() { + return LocalDateTime.now(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/ItemInfoUtils.java b/src/main/java/com/epam/ta/reportportal/util/ItemInfoUtils.java index 89f22fbb5c..14890df9e4 100644 --- a/src/main/java/com/epam/ta/reportportal/util/ItemInfoUtils.java +++ b/src/main/java/com/epam/ta/reportportal/util/ItemInfoUtils.java @@ -16,83 +16,91 @@ package com.epam.ta.reportportal.util; +import static com.epam.ta.reportportal.util.Predicates.ITEM_ATTRIBUTE_EQUIVALENCE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.BulkInfoUpdateRQ; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.epam.ta.reportportal.ws.model.attribute.UpdateItemAttributeRQ; -import org.apache.commons.collections.CollectionUtils; - import java.util.Collection; import java.util.Objects; import java.util.Optional; import java.util.Set; - -import static com.epam.ta.reportportal.util.Predicates.ITEM_ATTRIBUTE_EQUIVALENCE; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import org.apache.commons.collections.CollectionUtils; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> * <p> * Util class. Contains methods for updating - * {@link com.epam.ta.reportportal.entity.launch.Launch}/{@link com.epam.ta.reportportal.entity.item.TestItem} attributes and description. + * {@link com.epam.ta.reportportal.entity.launch.Launch}/{@link + * com.epam.ta.reportportal.entity.item.TestItem} attributes and description. */ public class ItemInfoUtils { - private ItemInfoUtils() { - //static only - } + private ItemInfoUtils() { + //static only + } - public static Optional<String> updateDescription(BulkInfoUpdateRQ.Description descriptionRq, String existDescription) { - if (!Objects.isNull(descriptionRq) && !Objects.isNull(descriptionRq.getComment())) { - switch (descriptionRq.getAction()) { - case UPDATE: { - return Optional.of(existDescription + " " + descriptionRq.getComment()); - } - case CREATE: { - return Optional.of(descriptionRq.getComment()); - } - default: { - return Optional.empty(); - } - } - } else { - return Optional.empty(); - } - } + public static Optional<String> updateDescription(BulkInfoUpdateRQ.Description descriptionRq, + String existDescription) { + if (!Objects.isNull(descriptionRq) && !Objects.isNull(descriptionRq.getComment())) { + switch (descriptionRq.getAction()) { + case UPDATE: { + return Optional.of(existDescription + " " + descriptionRq.getComment()); + } + case CREATE: { + return Optional.of(descriptionRq.getComment()); + } + default: { + return Optional.empty(); + } + } + } else { + return Optional.empty(); + } + } - public static ItemAttribute findAttributeByResource(Set<ItemAttribute> attributes, ItemAttributeResource resource) { - return attributes.stream() - .filter(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, resource)) - .findAny() - .orElseThrow(() -> new ReportPortalException(INCORRECT_REQUEST, "Cannot delete not common attribute")); - } + public static ItemAttribute findAttributeByResource(Set<ItemAttribute> attributes, + ItemAttributeResource resource) { + return attributes.stream() + .filter(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, resource)) + .findAny() + .orElseThrow(() -> new ReportPortalException(INCORRECT_REQUEST, + "Cannot delete not common attribute")); + } - public static void updateAttribute(Set<ItemAttribute> attributes, UpdateItemAttributeRQ updateItemAttributeRQ) { - ItemAttribute itemAttribute = attributes.stream() - .filter(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, updateItemAttributeRQ.getFrom())) - .findAny() - .orElseThrow(() -> new ReportPortalException(INCORRECT_REQUEST, "Cannot update not common attribute")); - attributes.remove(itemAttribute); - itemAttribute.setKey(updateItemAttributeRQ.getTo().getKey()); - itemAttribute.setValue(updateItemAttributeRQ.getTo().getValue()); - attributes.add(itemAttribute); - } + public static void updateAttribute(Set<ItemAttribute> attributes, + UpdateItemAttributeRQ updateItemAttributeRQ) { + ItemAttribute itemAttribute = attributes.stream() + .filter(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, updateItemAttributeRQ.getFrom())) + .findAny() + .orElseThrow(() -> new ReportPortalException(INCORRECT_REQUEST, + "Cannot update not common attribute")); + attributes.remove(itemAttribute); + itemAttribute.setKey(updateItemAttributeRQ.getTo().getKey()); + itemAttribute.setValue(updateItemAttributeRQ.getTo().getValue()); + attributes.add(itemAttribute); + } - public static boolean containsAttribute(Set<ItemAttribute> attributes, ItemAttributeResource resource) { - return attributes.stream().noneMatch(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, resource)); - } + public static boolean containsAttribute(Set<ItemAttribute> attributes, + ItemAttributeResource resource) { + return attributes.stream().noneMatch(attr -> ITEM_ATTRIBUTE_EQUIVALENCE.test(attr, resource)); + } - public static Optional<ItemAttribute> extractAttribute(Collection<ItemAttribute> collection, String key) { - return CollectionUtils.isEmpty(collection) ? - Optional.empty() : - collection.stream().filter(it -> key.equalsIgnoreCase(it.getKey())).findAny(); - } + public static Optional<ItemAttribute> extractAttribute(Collection<ItemAttribute> collection, + String key) { + return CollectionUtils.isEmpty(collection) ? + Optional.empty() : + collection.stream().filter(it -> key.equalsIgnoreCase(it.getKey())).findAny(); + } - public static Optional<ItemAttributeResource> extractAttributeResource(Collection<ItemAttributeResource> collection, String key) { - return CollectionUtils.isEmpty(collection) ? - Optional.empty() : - collection.stream().filter(it -> key.equalsIgnoreCase(it.getKey())).findAny(); - } + public static Optional<ItemAttributeResource> extractAttributeResource( + Collection<ItemAttributeResource> collection, String key) { + return CollectionUtils.isEmpty(collection) ? + Optional.empty() : + collection.stream().filter(it -> key.equalsIgnoreCase(it.getKey())).findAny(); + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/Predicates.java b/src/main/java/com/epam/ta/reportportal/util/Predicates.java index 19d9aff7b0..40e840f958 100644 --- a/src/main/java/com/epam/ta/reportportal/util/Predicates.java +++ b/src/main/java/com/epam/ta/reportportal/util/Predicates.java @@ -23,7 +23,6 @@ import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.google.common.base.CharMatcher; - import java.util.Objects; import java.util.Set; import java.util.function.BiPredicate; @@ -36,39 +35,42 @@ */ public class Predicates { - private static final Set<TestItemTypeEnum> INDEXED_ITEM_TYPES = Set.of(TestItemTypeEnum.STEP, - TestItemTypeEnum.BEFORE_METHOD, - TestItemTypeEnum.AFTER_METHOD - ); + private static final Set<TestItemTypeEnum> INDEXED_ITEM_TYPES = Set.of(TestItemTypeEnum.STEP, + TestItemTypeEnum.BEFORE_METHOD, + TestItemTypeEnum.AFTER_METHOD + ); - /** - * Checks if the test item is suitable for indexing in analyzer. - */ - public static final Predicate<TestItem> ITEM_CAN_BE_INDEXED = testItem -> testItem != null - && INDEXED_ITEM_TYPES.contains(testItem.getType()) && testItem.getItemResults().getIssue() != null && !testItem.getItemResults() - .getIssue() - .getIgnoreAnalyzer(); - /** - * Checks if the launch is suitable for indexing in analyzer - */ - public static final Predicate<Launch> LAUNCH_CAN_BE_INDEXED = launch -> launch != null - && LaunchModeEnum.DEFAULT.equals(launch.getMode()); - /** - * Checks if not system item attribute has specified key and value - */ - public static final BiPredicate<ItemAttribute, ItemAttributeResource> ITEM_ATTRIBUTE_EQUIVALENCE = (attribute, resource) -> { - boolean valueAndSystemEquivalence = attribute.getValue().equals(resource.getValue()) && !attribute.isSystem(); - return Objects.isNull(attribute.getKey()) ? - Objects.isNull(resource.getKey()) && valueAndSystemEquivalence : - attribute.getKey().equals(resource.getKey()) && valueAndSystemEquivalence; - }; - private static final String SPECIAL_CHARACTERS = "-/@#$%^&_+=()"; - /** - * Checker whether string contains special characters only - */ - public static final Predicate<String> SPECIAL_CHARS_ONLY = str -> CharMatcher.anyOf(SPECIAL_CHARACTERS).matchesAllOf(str); + /** + * Checks if the test item is suitable for indexing in analyzer. + */ + public static final Predicate<TestItem> ITEM_CAN_BE_INDEXED = testItem -> testItem != null + && INDEXED_ITEM_TYPES.contains(testItem.getType()) + && testItem.getItemResults().getIssue() != null && !testItem.getItemResults() + .getIssue() + .getIgnoreAnalyzer(); + /** + * Checks if the launch is suitable for indexing in analyzer + */ + public static final Predicate<Launch> LAUNCH_CAN_BE_INDEXED = launch -> launch != null + && LaunchModeEnum.DEFAULT.equals(launch.getMode()); + /** + * Checks if not system item attribute has specified key and value + */ + public static final BiPredicate<ItemAttribute, ItemAttributeResource> ITEM_ATTRIBUTE_EQUIVALENCE = (attribute, resource) -> { + boolean valueAndSystemEquivalence = + attribute.getValue().equals(resource.getValue()) && !attribute.isSystem(); + return Objects.isNull(attribute.getKey()) ? + Objects.isNull(resource.getKey()) && valueAndSystemEquivalence : + attribute.getKey().equals(resource.getKey()) && valueAndSystemEquivalence; + }; + private static final String SPECIAL_CHARACTERS = "-/@#$%^&_+=()"; + /** + * Checker whether string contains special characters only + */ + public static final Predicate<String> SPECIAL_CHARS_ONLY = str -> CharMatcher.anyOf( + SPECIAL_CHARACTERS).matchesAllOf(str); - private Predicates() { - //statics only - } + private Predicates() { + //statics only + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/ReportingQueueService.java b/src/main/java/com/epam/ta/reportportal/util/ReportingQueueService.java index 1fc8897b06..754e127119 100644 --- a/src/main/java/com/epam/ta/reportportal/util/ReportingQueueService.java +++ b/src/main/java/com/epam/ta/reportportal/util/ReportingQueueService.java @@ -16,43 +16,42 @@ package com.epam.ta.reportportal.util; +import java.util.UUID; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import java.util.UUID; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component public class ReportingQueueService { - private static final String UUID_REGEX = "[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}"; - - private int queueAmount; - - public int getQueueAmount() { - return queueAmount; - } - - @Value("${rp.amqp.queues}") - public void setQueueAmount(int queueAmount) { - this.queueAmount = queueAmount; - } - - /** - * Mapping launchId to reporting queue key. - * Not sure if uniform distribution will be produced, intuitively would be uniform with random UUID input. - * As {@link UUID#hashCode} may return negative int, - * take absolute value by trimming high sign bit of complement representation - * - * @param launchUuid - * @return - */ - public String getReportingQueueKey(String launchUuid) { - int value = launchUuid.matches(UUID_REGEX) ? UUID.fromString(launchUuid).hashCode() : launchUuid.hashCode(); - value = value & 0x7fffffff; - return String.valueOf(value % queueAmount); - } + private static final String UUID_REGEX = "[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}"; + + private int queueAmount; + + public int getQueueAmount() { + return queueAmount; + } + + @Value("${rp.amqp.queues}") + public void setQueueAmount(int queueAmount) { + this.queueAmount = queueAmount; + } + + /** + * Mapping launchId to reporting queue key. Not sure if uniform distribution will be produced, + * intuitively would be uniform with random UUID input. As {@link UUID#hashCode} may return + * negative int, take absolute value by trimming high sign bit of complement representation + * + * @param launchUuid + * @return + */ + public String getReportingQueueKey(String launchUuid) { + int value = launchUuid.matches(UUID_REGEX) ? UUID.fromString(launchUuid).hashCode() + : launchUuid.hashCode(); + value = value & 0x7fffffff; + return String.valueOf(value % queueAmount); + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/email/EmailRulesValidator.java b/src/main/java/com/epam/ta/reportportal/util/email/EmailRulesValidator.java index 19ff559dc8..da4778c975 100644 --- a/src/main/java/com/epam/ta/reportportal/util/email/EmailRulesValidator.java +++ b/src/main/java/com/epam/ta/reportportal/util/email/EmailRulesValidator.java @@ -16,12 +16,6 @@ package com.epam.ta.reportportal.util.email; -import com.epam.ta.reportportal.entity.project.Project; -import com.epam.ta.reportportal.entity.project.ProjectUtils; -import com.epam.ta.reportportal.ws.model.ErrorType; -import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; -import org.apache.commons.lang3.StringUtils; - import static com.epam.ta.reportportal.commons.Predicates.equalTo; import static com.epam.ta.reportportal.commons.Predicates.notNull; import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; @@ -30,52 +24,66 @@ import static com.epam.ta.reportportal.util.UserUtils.isEmailValid; import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; import static com.epam.ta.reportportal.ws.model.ErrorType.USER_NOT_FOUND; -import static com.epam.ta.reportportal.ws.model.ValidationConstraints.*; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_LOGIN_LENGTH; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MAX_NAME_LENGTH; +import static com.epam.ta.reportportal.ws.model.ValidationConstraints.MIN_LOGIN_LENGTH; import static com.google.common.base.Strings.isNullOrEmpty; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.ProjectUtils; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; +import org.apache.commons.lang3.StringUtils; + /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public final class EmailRulesValidator { - private EmailRulesValidator() { + private EmailRulesValidator() { - //static only - } + //static only + } - public static void validateRecipient(Project project, String recipient) { - expect(recipient, notNull()).verify(BAD_REQUEST_ERROR, formattedSupplier("Provided recipient email '{}' is invalid", recipient)); - if (recipient.contains("@")) { - expect(isEmailValid(recipient), equalTo(true)).verify(BAD_REQUEST_ERROR, - formattedSupplier("Provided recipient email '{}' is invalid", recipient) - ); - } else { - final String login = recipient.trim(); - expect(MIN_LOGIN_LENGTH <= login.length() && login.length() <= MAX_LOGIN_LENGTH, equalTo(true)).verify(BAD_REQUEST_ERROR, - "Acceptable login length [" + MIN_LOGIN_LENGTH + ".." + MAX_LOGIN_LENGTH + "]" - ); - if (!getOwner().equals(login)) { - expect(ProjectUtils.doesHaveUser(project, login.toLowerCase()), equalTo(true)).verify(USER_NOT_FOUND, - login, - String.format("User not found in project %s", project.getId()) - ); - } - } - } + public static void validateRecipient(Project project, String recipient) { + expect(recipient, notNull()).verify(BAD_REQUEST_ERROR, + formattedSupplier("Provided recipient email '{}' is invalid", recipient)); + if (recipient.contains("@")) { + expect(isEmailValid(recipient), equalTo(true)).verify(BAD_REQUEST_ERROR, + formattedSupplier("Provided recipient email '{}' is invalid", recipient) + ); + } else { + final String login = recipient.trim(); + expect(MIN_LOGIN_LENGTH <= login.length() && login.length() <= MAX_LOGIN_LENGTH, + equalTo(true)).verify(BAD_REQUEST_ERROR, + "Acceptable login length [" + MIN_LOGIN_LENGTH + ".." + MAX_LOGIN_LENGTH + "]" + ); + if (!getOwner().equals(login)) { + expect(ProjectUtils.doesHaveUser(project, login.toLowerCase()), equalTo(true)).verify( + USER_NOT_FOUND, + login, + String.format("User not found in project %s", project.getId()) + ); + } + } + } - public static void validateLaunchName(String name) { - expect(StringUtils.isBlank(name), equalTo(false)).verify(BAD_REQUEST_ERROR, - "Launch name values cannot be empty. Please specify it or not include in request." - ); - expect(name.length() <= MAX_NAME_LENGTH, equalTo(true)).verify(BAD_REQUEST_ERROR, - formattedSupplier("One of provided launch names '{}' is too long. Acceptable name length is [1..256]", name) - ); - } + public static void validateLaunchName(String name) { + expect(StringUtils.isBlank(name), equalTo(false)).verify(BAD_REQUEST_ERROR, + "Launch name values cannot be empty. Please specify it or not include in request." + ); + expect(name.length() <= MAX_NAME_LENGTH, equalTo(true)).verify(BAD_REQUEST_ERROR, + formattedSupplier( + "One of provided launch names '{}' is too long. Acceptable name length is [1..256]", + name) + ); + } - public static void validateLaunchAttribute(ItemAttributeResource attribute) { - expect(attribute, notNull()).verify(ErrorType.BAD_REQUEST_ERROR, "Launch attribute cannot be null."); - expect(isNullOrEmpty(attribute.getValue()), equalTo(false)).verify(BAD_REQUEST_ERROR, - "Attribute' values cannot be empty. Please specify them or do not include in a request." - ); - } + public static void validateLaunchAttribute(ItemAttributeResource attribute) { + expect(attribute, notNull()).verify(ErrorType.BAD_REQUEST_ERROR, + "Launch attribute cannot be null."); + expect(isNullOrEmpty(attribute.getValue()), equalTo(false)).verify(BAD_REQUEST_ERROR, + "Attribute' values cannot be empty. Please specify them or do not include in a request." + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/email/EmailService.java b/src/main/java/com/epam/ta/reportportal/util/email/EmailService.java index f07b8b0b2f..60736fe8bd 100644 --- a/src/main/java/com/epam/ta/reportportal/util/email/EmailService.java +++ b/src/main/java/com/epam/ta/reportportal/util/email/EmailService.java @@ -45,6 +45,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -55,7 +56,8 @@ import javax.mail.internet.InternetAddress; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileUrlResource; +import org.springframework.core.io.Resource; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; @@ -73,10 +75,8 @@ public class EmailService extends JavaMailSenderImpl { private static final String FINISH_LAUNCH_EMAIL_SUBJECT = " ReportPortal Notification: [%s] launch '%s' #%s finished"; private static final String URL_FORMAT = "%s/launches/all"; - private static final String FULL_ATTRIBUTE_FILTER_FORMAT = - "%s?filter.has.key=%s&filter.has.value=%s"; - private static final String VALUE_ATTRIBUTE_FILTER_FORMAT = "%s?filter.has.value=%s"; - private static final String EMAIL_TEMPLATE_PREFIX = "templates/email/"; + private static final String COMPOSITE_ATTRIBUTE_FILTER_FORMAT = "%s?launchesParams=filter.has.compositeAttribute=%s"; + private static final String TEMPLATE_IMAGES_PREFIX = "templates/email/images/"; private TemplateEngine templateEngine; /* Default value for FROM project notifications field */ private String from; @@ -117,6 +117,7 @@ public void sendCreateUserConfirmationEmail(final String subject, final String[] * Finish launch notification * * @param recipients List of recipients + * @param project {@link Project} * @param url ReportPortal URL * @param launch Launch */ @@ -218,13 +219,13 @@ private String getUrl(String baseUrl) { private String buildAttributesLink(String basicUrl, ItemAttribute attribute) { if (null != attribute.getKey()) { - return format(FULL_ATTRIBUTE_FILTER_FORMAT, + return format(COMPOSITE_ATTRIBUTE_FILTER_FORMAT, basicUrl, - urlPathSegmentEscaper().escape(attribute.getKey()), + urlPathSegmentEscaper().escape(attribute.getKey()) + ":" + urlPathSegmentEscaper().escape(attribute.getValue()) ); } else { - return format(VALUE_ATTRIBUTE_FILTER_FORMAT, basicUrl, + return format(COMPOSITE_ATTRIBUTE_FILTER_FORMAT, basicUrl, urlPathSegmentEscaper().escape(attribute.getValue())); } } @@ -385,14 +386,17 @@ private boolean isAddressValid(String from) { } private void attachSocialImages(MimeMessageHelper message) throws MessagingException { - message.addInline("ic-github.png", emailTemplateResource("ic-github.png")); message.addInline("ic-twitter.png", emailTemplateResource("ic-twitter.png")); - message.addInline("ic-youtube.png", emailTemplateResource("ic-youtube.png")); message.addInline("ic-slack.png", emailTemplateResource("ic-slack.png")); + message.addInline("ic-youtube.png", emailTemplateResource("ic-youtube.png")); + message.addInline("ic-linkedin.png", emailTemplateResource("ic-linkedin.png")); + message.addInline("ic-facebook.png", emailTemplateResource("ic-facebook.png")); + message.addInline("ic-github.png", emailTemplateResource("ic-github.png")); } - private ClassPathResource emailTemplateResource(String resource) { - return new ClassPathResource(EMAIL_TEMPLATE_PREFIX + resource); + private Resource emailTemplateResource(String resource) { + return new FileUrlResource(Objects.requireNonNull( + EmailService.class.getClassLoader().getResource(TEMPLATE_IMAGES_PREFIX + resource))); } public void sendAccountSelfDeletionNotification(String recipient) { @@ -460,6 +464,7 @@ private void attachNewSocialImages(MimeMessageHelper message) throws MessagingEx message.addInline("new-ic-slack.png", emailTemplateResource("new-ic-slack.png")); message.addInline("new-ic-youtube.png", emailTemplateResource("new-ic-youtube.png")); message.addInline("new-ic-linkedin.png", emailTemplateResource("new-ic-linkedin.png")); + message.addInline("new-ic-facebook.png", emailTemplateResource("new-ic-facebook.png")); message.addInline("new-ic-github.png", emailTemplateResource("new-ic-github.png")); } diff --git a/src/main/java/com/epam/ta/reportportal/util/email/MailServiceFactory.java b/src/main/java/com/epam/ta/reportportal/util/email/MailServiceFactory.java index 5319fee8a2..02013f978b 100644 --- a/src/main/java/com/epam/ta/reportportal/util/email/MailServiceFactory.java +++ b/src/main/java/com/epam/ta/reportportal/util/email/MailServiceFactory.java @@ -149,6 +149,7 @@ public Optional<EmailService> getDefaultEmailService() { /** * Build mail service based on default server configs * + * @param integration {@link Integration} * @return Built email service */ public Optional<EmailService> getDefaultEmailService(Integration integration) { @@ -160,6 +161,8 @@ public Optional<EmailService> getDefaultEmailService(Integration integration) { /** * Build mail service based on default server configs and check connection * + * @param integration {@link Integration} + * @param checkConnection true if need to check connection with integration * @return Built email service */ @Transactional(propagation = Propagation.REQUIRES_NEW) @@ -179,6 +182,7 @@ public EmailService getEmailService(Integration integration, boolean checkConnec /** * Build mail service based on default server configs and check connection * + * @param checkConnection true if need to check connection with integration * @return Built email service */ @Transactional(propagation = Propagation.REQUIRES_NEW) diff --git a/src/main/java/com/epam/ta/reportportal/util/email/constant/IssueRegexConstant.java b/src/main/java/com/epam/ta/reportportal/util/email/constant/IssueRegexConstant.java index 126d4f4179..65e945375a 100644 --- a/src/main/java/com/epam/ta/reportportal/util/email/constant/IssueRegexConstant.java +++ b/src/main/java/com/epam/ta/reportportal/util/email/constant/IssueRegexConstant.java @@ -21,14 +21,14 @@ */ public final class IssueRegexConstant { - public static final String PRODUCT_BUG_ISSUE_REGEX = "^statistics\\$defects\\$product_bug\\$((?!total$).)+.*$"; - public static final String NO_DEFECT_ISSUE_REGEX = "^statistics\\$defects\\$no_defect\\$((?!total$).)+.*$"; - public static final String SYSTEM_ISSUE_REGEX = "^statistics\\$defects\\$system_issue\\$((?!total$).)+.*$"; - public static final String AUTOMATION_BUG_ISSUE_REGEX = "^statistics\\$defects\\$automation_bug\\$((?!total$).)+.*$"; - public static final String TO_INVESTIGATE_ISSUE_REGEX = "^statistics\\$defects\\$to_investigate\\$((?!total$).)+.*$"; + public static final String PRODUCT_BUG_ISSUE_REGEX = "^statistics\\$defects\\$product_bug\\$((?!total$).)+.*$"; + public static final String NO_DEFECT_ISSUE_REGEX = "^statistics\\$defects\\$no_defect\\$((?!total$).)+.*$"; + public static final String SYSTEM_ISSUE_REGEX = "^statistics\\$defects\\$system_issue\\$((?!total$).)+.*$"; + public static final String AUTOMATION_BUG_ISSUE_REGEX = "^statistics\\$defects\\$automation_bug\\$((?!total$).)+.*$"; + public static final String TO_INVESTIGATE_ISSUE_REGEX = "^statistics\\$defects\\$to_investigate\\$((?!total$).)+.*$"; - private IssueRegexConstant() { - //static only - } + private IssueRegexConstant() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/util/message/MessageProvider.java b/src/main/java/com/epam/ta/reportportal/util/message/MessageProvider.java index b6da102529..2365848d50 100644 --- a/src/main/java/com/epam/ta/reportportal/util/message/MessageProvider.java +++ b/src/main/java/com/epam/ta/reportportal/util/message/MessageProvider.java @@ -21,5 +21,5 @@ */ public interface MessageProvider<T> { - String provide(T source); + String provide(T source); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityController.java index 8623127a10..f35a45596f 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityController.java @@ -16,13 +16,16 @@ package com.epam.ta.reportportal.ws.controller; + import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; + import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; - import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.activity.ActivityHandler; import com.epam.ta.reportportal.entity.activity.Activity; import com.epam.ta.reportportal.util.ProjectExtractor; + import com.epam.ta.reportportal.ws.model.ActivityEventResource; import com.epam.ta.reportportal.ws.model.ActivityResource; import com.epam.ta.reportportal.ws.resolver.FilterFor; import com.epam.ta.reportportal.ws.resolver.SortFor; @@ -32,10 +35,11 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; - import org.springframework.web.bind.annotation.*; - - import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; - import static org.springframework.http.HttpStatus.OK; + import org.springframework.web.bind.annotation.PathVariable; + import org.springframework.web.bind.annotation.RequestMapping; + import org.springframework.web.bind.annotation.RequestMethod; + import org.springframework.web.bind.annotation.ResponseStatus; + import org.springframework.web.bind.annotation.RestController; /** * @author Ihar_Kahadouski @@ -70,7 +74,8 @@ public ActivityResource getActivity(@PathVariable String projectName, @PathVaria @RequestMapping(value = "/item/{itemId}", method = RequestMethod.GET) @ResponseStatus(OK) @ApiOperation("Get activities for test item") - public Iterable<ActivityResource> getTestItemActivities(@PathVariable String projectName, @PathVariable Long itemId, + public Iterable<ActivityEventResource> getTestItemActivities(@PathVariable String projectName, + @PathVariable Long itemId, @FilterFor(Activity.class) Filter filter, @SortFor(Activity.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { ReportPortalUser.ProjectDetails projectDetails = projectExtractor.extractProjectDetailsAdmin( diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityEventController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityEventController.java index b0dafd0c2b..bcfa33bdbc 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityEventController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ActivityEventController.java @@ -19,15 +19,19 @@ import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.activityevent.ActivityEventHandler; import com.epam.ta.reportportal.core.filter.SearchCriteriaService; import com.epam.ta.reportportal.core.filter.predefined.PredefinedFilterType; import com.epam.ta.reportportal.entity.activity.Activity; +import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.ActivityEventResource; import com.epam.ta.reportportal.ws.model.PagedResponse; import com.epam.ta.reportportal.ws.model.SearchCriteriaRQ; +import com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver; import io.swagger.annotations.ApiOperation; +import java.util.List; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import org.springframework.data.domain.PageRequest; @@ -37,6 +41,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -54,11 +60,14 @@ public class ActivityEventController { private final ActivityEventHandler activityEventHandler; + private final ProjectExtractor projectExtractor; private final SearchCriteriaService searchCriteriaService; public ActivityEventController(ActivityEventHandler activityEventHandler, + ProjectExtractor projectExtractor, SearchCriteriaService searchCriteriaService) { this.activityEventHandler = activityEventHandler; + this.projectExtractor = projectExtractor; this.searchCriteriaService = searchCriteriaService; } @@ -92,4 +101,14 @@ public PagedResponse<ActivityEventResource> getActivities( return activityEventHandler.getActivityEventsHistory(filter, pageable); } + @GetMapping("/{projectName}/subjectName") + @PreAuthorize(ADMIN_ONLY) + @ApiOperation(value = "Load project activities subjectNames by filter", notes = "Only for current project") + public List<String> getProjectSubjectName(@PathVariable String projectName, + @RequestParam(FilterCriteriaResolver.DEFAULT_FILTER_PREFIX + Condition.CNT + + "subjectName") String value, + @AuthenticationPrincipal ReportPortalUser user) { + return activityEventHandler.getSubjectNames( + projectExtractor.extractProjectDetails(user, projectName), value); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemController.java index 9d3361be33..82a0c12a6f 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemController.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.bts.handler.CreateTicketHandler; @@ -25,18 +28,21 @@ import com.epam.ta.reportportal.ws.model.externalsystem.PostTicketRQ; import com.epam.ta.reportportal.ws.model.externalsystem.Ticket; import io.swagger.annotations.ApiOperation; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; -import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** * Controller implementation for working with external systems. @@ -48,79 +54,90 @@ @RequestMapping("/v1/bts") public class BugTrackingSystemController { - private final ProjectExtractor projectExtractor; - private final CreateTicketHandler createTicketHandler; - private final GetTicketHandler getTicketHandler; + private final ProjectExtractor projectExtractor; + private final CreateTicketHandler createTicketHandler; + private final GetTicketHandler getTicketHandler; - @Autowired - public BugTrackingSystemController(ProjectExtractor projectExtractor, CreateTicketHandler createTicketHandler, GetTicketHandler getTicketHandler) { - this.projectExtractor = projectExtractor; - this.createTicketHandler = createTicketHandler; - this.getTicketHandler = getTicketHandler; - } + @Autowired + public BugTrackingSystemController(ProjectExtractor projectExtractor, + CreateTicketHandler createTicketHandler, GetTicketHandler getTicketHandler) { + this.projectExtractor = projectExtractor; + this.createTicketHandler = createTicketHandler; + this.getTicketHandler = getTicketHandler; + } - @Transactional(readOnly = true) - @GetMapping(value = "/{projectName}/{integrationId}/fields-set") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get list of fields required for posting ticket in concrete integration") - @PreAuthorize(PROJECT_MANAGER) - public List<PostFormField> getSetOfIntegrationSystemFields(@RequestParam(value = "issueType") String issuetype, - @PathVariable String projectName, @PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return getTicketHandler.getSubmitTicketFields(issuetype, - integrationId, - projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName)) - ); - } + @Transactional(readOnly = true) + @GetMapping(value = "/{projectName}/{integrationId}/fields-set") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get list of fields required for posting ticket in concrete integration") + @PreAuthorize(PROJECT_MANAGER) + public List<PostFormField> getSetOfIntegrationSystemFields( + @RequestParam(value = "issueType") String issuetype, + @PathVariable String projectName, @PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getTicketHandler.getSubmitTicketFields(issuetype, + integrationId, + projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName)) + ); + } - @Transactional(readOnly = true) - @GetMapping(value = "/{projectName}/{integrationId}/issue_types") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get list of allowable issue types for bug tracking system") - @PreAuthorize(PROJECT_MANAGER) - public List<String> getAllowableIssueTypes(@PathVariable String projectName, @PathVariable Long integrationId, - @AuthenticationPrincipal ReportPortalUser user) { - return getTicketHandler.getAllowableIssueTypes(integrationId, projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName))); - } + @Transactional(readOnly = true) + @GetMapping(value = "/{projectName}/{integrationId}/issue_types") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get list of allowable issue types for bug tracking system") + @PreAuthorize(PROJECT_MANAGER) + public List<String> getAllowableIssueTypes(@PathVariable String projectName, + @PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getTicketHandler.getAllowableIssueTypes(integrationId, + projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName))); + } - @Transactional(readOnly = true) - @GetMapping(value = "/{integrationId}/fields-set") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get list of fields required for posting ticket") - @PreAuthorize(ADMIN_ONLY) - public List<PostFormField> getSetOfIntegrationSystemFields(@RequestParam(value = "issueType") String issueType, - @PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return getTicketHandler.getSubmitTicketFields(issueType, integrationId); - } + @Transactional(readOnly = true) + @GetMapping(value = "/{integrationId}/fields-set") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get list of fields required for posting ticket") + @PreAuthorize(ADMIN_ONLY) + public List<PostFormField> getSetOfIntegrationSystemFields( + @RequestParam(value = "issueType") String issueType, + @PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { + return getTicketHandler.getSubmitTicketFields(issueType, integrationId); + } - @Transactional(readOnly = true) - @GetMapping(value = "/{integrationId}/issue_types") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get list of existed issue types in bts") - @PreAuthorize(ADMIN_ONLY) - public List<String> getAllowableIssueTypes(@PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return getTicketHandler.getAllowableIssueTypes(integrationId); - } + @Transactional(readOnly = true) + @GetMapping(value = "/{integrationId}/issue_types") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get list of existed issue types in bts") + @PreAuthorize(ADMIN_ONLY) + public List<String> getAllowableIssueTypes(@PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getTicketHandler.getAllowableIssueTypes(integrationId); + } - @Transactional - @PostMapping(value = "/{projectName}/{integrationId}/ticket") - @ResponseStatus(HttpStatus.CREATED) - @ApiOperation("Post ticket to the bts integration") - public Ticket createIssue(@Validated @RequestBody PostTicketRQ ticketRQ, @PathVariable String projectName, - @PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return createTicketHandler.createIssue(ticketRQ, - integrationId, - projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName)), - user - ); - } + @Transactional + @PostMapping(value = "/{projectName}/{integrationId}/ticket") + @ResponseStatus(HttpStatus.CREATED) + @ApiOperation("Post ticket to the bts integration") + public Ticket createIssue(@Validated @RequestBody PostTicketRQ ticketRQ, + @PathVariable String projectName, + @PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { + return createTicketHandler.createIssue(ticketRQ, + integrationId, + projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName)), + user + ); + } - @Transactional(readOnly = true) - @GetMapping(value = "/{projectName}/ticket/{ticketId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get ticket from the bts integration") - public Ticket getTicket(@PathVariable String ticketId, @PathVariable String projectName, @RequestParam(value = "btsUrl") String btsUrl, - @RequestParam(value = "btsProject") String btsProject, @AuthenticationPrincipal ReportPortalUser user) { - return getTicketHandler.getTicket(ticketId, btsUrl, btsProject, projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName))); - } + @Transactional(readOnly = true) + @GetMapping(value = "/{projectName}/ticket/{ticketId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get ticket from the bts integration") + public Ticket getTicket(@PathVariable String ticketId, @PathVariable String projectName, + @RequestParam(value = "btsUrl") String btsUrl, + @RequestParam(value = "btsProject") String btsProject, + @AuthenticationPrincipal ReportPortalUser user) { + return getTicketHandler.getTicket(ticketId, btsUrl, btsProject, + projectExtractor.extractProjectDetails(user, EntityUtils.normalizeId(projectName))); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/DashboardController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/DashboardController.java index f0378eafef..e1b8291bd6 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/DashboardController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/DashboardController.java @@ -79,14 +79,16 @@ public DashboardController(ProjectExtractor projectExtractor, this.deleteDashboardHandler = deleteDashboardHandler; } - @Transactional - @PostMapping - @ResponseStatus(CREATED) - @ApiOperation("Create dashboard for specified project") - public EntryCreatedRS createDashboard(@PathVariable String projectName, @RequestBody @Validated CreateDashboardRQ createRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return createDashboardHandler.createDashboard(projectExtractor.extractProjectDetails(user, projectName), createRQ, user); - } + @Transactional + @PostMapping + @ResponseStatus(CREATED) + @ApiOperation("Create dashboard for specified project") + public EntryCreatedRS createDashboard(@PathVariable String projectName, + @RequestBody @Validated CreateDashboardRQ createRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return createDashboardHandler.createDashboard( + projectExtractor.extractProjectDetails(user, projectName), createRQ, user); + } @Transactional(readOnly = true) @GetMapping @@ -138,12 +140,13 @@ public OperationCompletionRS deleteDashboard(@PathVariable String projectName, @ return deleteDashboardHandler.deleteDashboard(dashboardId, projectExtractor.extractProjectDetails(user, projectName), user); } - @Transactional - @GetMapping(value = "/{dashboardId}") - @ResponseStatus(OK) - @ApiOperation("Get specified dashboard by ID for specified project") - public DashboardResource getDashboard(@PathVariable String projectName, @PathVariable Long dashboardId, - @AuthenticationPrincipal ReportPortalUser user) { - return getDashboardHandler.getDashboard(dashboardId, projectExtractor.extractProjectDetails(user, projectName)); + @Transactional + @GetMapping(value = "/{dashboardId}") + @ResponseStatus(OK) + @ApiOperation("Get specified dashboard by ID for specified project") + public DashboardResource getDashboard(@PathVariable String projectName, + @PathVariable Long dashboardId, + @AuthenticationPrincipal ReportPortalUser user) { + return getDashboardHandler.getDashboard(dashboardId, projectExtractor.extractProjectDetails(user, projectName)); } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/DeprecatedUserController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/DeprecatedUserController.java new file mode 100644 index 0000000000..0c542985dd --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/DeprecatedUserController.java @@ -0,0 +1,268 @@ +package com.epam.ta.reportportal.ws.controller; + +import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_EDIT_USER; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.Queryable; +import com.epam.ta.reportportal.core.jasper.GetJasperReportHandler; +import com.epam.ta.reportportal.core.user.ApiKeyHandler; +import com.epam.ta.reportportal.core.user.CreateUserHandler; +import com.epam.ta.reportportal.core.user.DeleteUserHandler; +import com.epam.ta.reportportal.core.user.EditUserHandler; +import com.epam.ta.reportportal.core.user.GetUserHandler; +import com.epam.ta.reportportal.entity.user.User; +import com.epam.ta.reportportal.entity.user.UserRole; +import com.epam.ta.reportportal.ws.model.ApiKeyRQ; +import com.epam.ta.reportportal.ws.model.ApiKeyRS; +import com.epam.ta.reportportal.ws.model.ApiKeysRS; +import com.epam.ta.reportportal.ws.model.DeleteBulkRQ; +import com.epam.ta.reportportal.ws.model.DeleteBulkRS; +import com.epam.ta.reportportal.ws.model.ModelViews; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.YesNoRS; +import com.epam.ta.reportportal.ws.model.user.ChangePasswordRQ; +import com.epam.ta.reportportal.ws.model.user.CreateUserBidRS; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQ; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQConfirm; +import com.epam.ta.reportportal.ws.model.user.CreateUserRQFull; +import com.epam.ta.reportportal.ws.model.user.CreateUserRS; +import com.epam.ta.reportportal.ws.model.user.EditUserRQ; +import com.epam.ta.reportportal.ws.model.user.ResetPasswordRQ; +import com.epam.ta.reportportal.ws.model.user.RestorePasswordRQ; +import com.epam.ta.reportportal.ws.model.user.UserBidRS; +import com.epam.ta.reportportal.ws.model.user.UserResource; +import com.epam.ta.reportportal.ws.resolver.ActiveRole; +import com.epam.ta.reportportal.ws.resolver.FilterFor; +import com.epam.ta.reportportal.ws.resolver.ResponseView; +import com.epam.ta.reportportal.ws.resolver.SortFor; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/v1/user") +@Deprecated +@Api(tags = "deprecated-user-controller", hidden = false, description = "Deprecated UserController") +public class DeprecatedUserController extends UserController { + + @Autowired + public DeprecatedUserController(CreateUserHandler createUserMessageHandler, + EditUserHandler editUserMessageHandler, DeleteUserHandler deleteUserHandler, + GetUserHandler getUserHandler, + @Qualifier("userJasperReportHandler") GetJasperReportHandler<User> jasperReportHandler, + ApiKeyHandler apiKeyHandler) { + super(createUserMessageHandler, editUserMessageHandler, deleteUserHandler, getUserHandler, + jasperReportHandler, apiKeyHandler + ); + } + + @Override + @PostMapping + @ResponseStatus(CREATED) + @PreAuthorize(ADMIN_ONLY) + @ApiOperation(value = "Create specified user (DEPRECATED)", notes = "Allowable only for users with administrator role") + public CreateUserRS createUserByAdmin(@RequestBody @Validated CreateUserRQFull rq, + @AuthenticationPrincipal ReportPortalUser currentUser, HttpServletRequest request) { + return super.createUserByAdmin(rq, currentUser, request); + } + + @Transactional + @PostMapping(value = "/bid") + @ResponseStatus(CREATED) + @PreAuthorize("(hasPermission(#createUserRQ.getDefaultProject(), 'projectManagerPermission')) || hasRole('ADMINISTRATOR')") + @ApiOperation("Register invitation for user who will be created (DEPRECATED)") + public CreateUserBidRS createUserBid(@RequestBody @Validated CreateUserRQ createUserRQ, + @AuthenticationPrincipal ReportPortalUser currentUser, HttpServletRequest request) { + return super.createUserBid(createUserRQ, currentUser, request); + } + + @PostMapping(value = "/registration") + @ResponseStatus(CREATED) + @ApiOperation("Activate invitation and create user in system (DEPRECATED)") + public CreateUserRS createUser(@RequestBody @Validated CreateUserRQConfirm request, + @RequestParam(value = "uuid") String uuid) { + return super.createUser(request, uuid); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/registration") + @ApiOperation(value = "Get user's registration info (DEPRECATED)") + public UserBidRS getUserBidInfo(@RequestParam(value = "uuid") String uuid) { + return super.getUserBidInfo(uuid); + } + + @DeleteMapping(value = "/{id}") + @ApiOperation(value = "Delete specified user (DEPRECATED)") + public OperationCompletionRS deleteUser(@PathVariable(value = "id") Long userId, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.deleteUser(userId, currentUser); + } + + @DeleteMapping + @PreAuthorize(ADMIN_ONLY) + @ResponseStatus(OK) + @ApiOperation("Delete specified users by ids (DEPRECATED)") + public DeleteBulkRS deleteUsers(@RequestBody @Valid DeleteBulkRQ deleteBulkRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return super.deleteUsers(deleteBulkRQ, user); + } + + @Transactional + @PutMapping(value = "/{login}") + @PreAuthorize(ALLOWED_TO_EDIT_USER) + @ApiOperation(value = "Edit specified user (DEPRECATED)", notes = "Only for administrators and profile's owner") + public OperationCompletionRS editUser(@PathVariable String login, + @RequestBody @Validated EditUserRQ editUserRQ, @ActiveRole UserRole role, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.editUser(login, editUserRQ, role, currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{login}") + @ResponseView(ModelViews.FullUserView.class) + @PreAuthorize(ALLOWED_TO_EDIT_USER) + @ApiOperation(value = "Return information about specified user (DEPRECATED)", notes = "Only for administrators and profile's owner") + public UserResource getUser(@PathVariable String login, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.getUser(login, currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = { "", "/" }) + @ApiOperation("Return information about current logged-in user (DEPRECATED)") + public UserResource getMyself(@AuthenticationPrincipal ReportPortalUser currentUser) { + return super.getMyself(currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/all") + @ResponseView(ModelViews.FullUserView.class) + @PreAuthorize(ADMIN_ONLY) + @ApiOperation(value = "Return information about all users (DEPRECATED)", notes = "Allowable only for users with administrator role") + public Iterable<UserResource> getUsers(@FilterFor(User.class) Filter filter, + @SortFor(User.class) Pageable pageable, @FilterFor(User.class) Queryable queryable, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.getUsers(filter, pageable, queryable, currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/registration/info") + @ApiOperation(value = "Validate registration information (DEPRECATED)") + public YesNoRS validateInfo(@RequestParam(value = "username", required = false) String username, + @RequestParam(value = "email", required = false) String email) { + return super.validateInfo(username, email); + } + + @Transactional + @PostMapping(value = "/password/restore") + @ResponseStatus(OK) + @ApiOperation("Create a restore password request (DEPRECATED)") + public OperationCompletionRS restorePassword(@RequestBody @Validated RestorePasswordRQ rq, + HttpServletRequest request) { + return super.restorePassword(rq, request); + } + + @Transactional + @PostMapping(value = "/password/reset") + @ResponseStatus(OK) + @ApiOperation("Reset password (DEPRECATED") + public OperationCompletionRS resetPassword(@RequestBody @Validated ResetPasswordRQ rq) { + return super.resetPassword(rq); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/password/reset/{uuid}") + @ResponseStatus(OK) + @ApiOperation("Check if a restore password bid exists (DEPRECATED)") + public YesNoRS isRestorePasswordBidExist(@PathVariable String uuid) { + return super.isRestorePasswordBidExist(uuid); + } + + @Transactional + @PostMapping(value = "/password/change") + @ResponseStatus(OK) + @ApiOperation("Change own password (DEPRECATED)") + public OperationCompletionRS changePassword( + @RequestBody @Validated ChangePasswordRQ changePasswordRQ, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.changePassword(changePasswordRQ, currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{userName}/projects") + @ResponseStatus(OK) + @ApiOperation(value = "Get user's projects (DEPRECATED)") + public Map<String, UserResource.AssignedProject> getUserProjects(@PathVariable String userName, + @AuthenticationPrincipal ReportPortalUser currentUser) { + return super.getUserProjects(userName, currentUser); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/search") + @ResponseStatus(OK) + @PreAuthorize(ADMIN_ONLY) + @ApiOperation(value = "Find users by term (DEPRECATED)", notes = "Only for administrators") + public Iterable<UserResource> findUsers(@RequestParam(value = "term") String term, + Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + return super.findUsers(term, pageable, user); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/export") + @PreAuthorize(ADMIN_ONLY) + @ApiOperation(value = "Exports information about all users (DEPRECATED)", notes = "Allowable only for users with administrator role") + public void export(@ApiParam(allowableValues = "csv") + @RequestParam(value = "view", required = false, defaultValue = "csv") String view, + @FilterFor(User.class) Filter filter, @FilterFor(User.class) Queryable queryable, + @AuthenticationPrincipal ReportPortalUser currentUser, HttpServletResponse response) { + super.export(view, filter, queryable, currentUser, response); + } + + @PostMapping(value = "/{userId}/api-keys") + @ResponseStatus(CREATED) + @ApiOperation("Create new Api Key for current user (DEPRECATED)") + public ApiKeyRS createApiKey(@RequestBody @Validated ApiKeyRQ apiKeyRQ, + @AuthenticationPrincipal ReportPortalUser currentUser, @PathVariable Long userId) { + return super.createApiKey(apiKeyRQ, currentUser, userId); + } + + @DeleteMapping(value = "/{userId}/api-keys/{keyId}") + @ResponseStatus(OK) + @ApiOperation("Delete specified Api Key (DEPRECATED)") + public OperationCompletionRS deleteApiKey(@PathVariable Long keyId, @PathVariable Long userId) { + return super.deleteApiKey(keyId, userId); + } + + @GetMapping(value = "/{userId}/api-keys") + @ResponseStatus(OK) + @ApiOperation("Get List of users Api Keys (DEPRECATED)") + public ApiKeysRS getUsersApiKeys(@AuthenticationPrincipal ReportPortalUser currentUser, + @PathVariable Long userId) { + return super.getUsersApiKeys(currentUser, userId); + } +} \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/FileStorageController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/FileStorageController.java index 01c6ec14b9..c0dff7cca4 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/FileStorageController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/FileStorageController.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.NOT_CUSTOMER; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.file.DeleteFilesHandler; @@ -27,6 +31,9 @@ import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.google.common.net.HttpHeaders; import io.swagger.annotations.ApiOperation; +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -34,15 +41,15 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.InputStream; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.*; - /** * @author Dzianis_Shybeka */ @@ -50,74 +57,76 @@ @RequestMapping("/v1/data") public class FileStorageController { - private final ProjectExtractor projectExtractor; - private final EditUserHandler editUserHandler; - private final GetFileHandler getFileHandler; - private final DeleteFilesHandler deleteFilesHandler; + private final ProjectExtractor projectExtractor; + private final EditUserHandler editUserHandler; + private final GetFileHandler getFileHandler; + private final DeleteFilesHandler deleteFilesHandler; - @Autowired - public FileStorageController(ProjectExtractor projectExtractor, EditUserHandler editUserHandler, GetFileHandler getFileHandler, DeleteFilesHandler deleteFilesHandler) { - this.projectExtractor = projectExtractor; - this.editUserHandler = editUserHandler; - this.getFileHandler = getFileHandler; - this.deleteFilesHandler = deleteFilesHandler; - } + @Autowired + public FileStorageController(ProjectExtractor projectExtractor, EditUserHandler editUserHandler, + GetFileHandler getFileHandler, DeleteFilesHandler deleteFilesHandler) { + this.projectExtractor = projectExtractor; + this.editUserHandler = editUserHandler; + this.getFileHandler = getFileHandler; + this.deleteFilesHandler = deleteFilesHandler; + } - @Transactional(readOnly = true) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @GetMapping(value = "/{projectName}/{dataId}") - public void getFile(@PathVariable String projectName, @PathVariable("dataId") Long dataId, HttpServletResponse response, - @AuthenticationPrincipal ReportPortalUser user) { - toResponse(response, getFileHandler.loadFileById(dataId, projectExtractor.extractProjectDetails(user, projectName))); - } + @Transactional(readOnly = true) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @GetMapping(value = "/{projectName}/{dataId}") + public void getFile(@PathVariable String projectName, @PathVariable("dataId") Long dataId, + HttpServletResponse response, + @AuthenticationPrincipal ReportPortalUser user) { + toResponse(response, getFileHandler.loadFileById(dataId, + projectExtractor.extractProjectDetails(user, projectName))); + } - /** - * (non-Javadoc) - */ - @Transactional(readOnly = true) - @GetMapping(value = "/photo") - @ApiOperation("Get photo of current user") - public void getMyPhoto(@AuthenticationPrincipal ReportPortalUser user, HttpServletResponse response, - @RequestParam(value = "loadThumbnail", required = false) boolean loadThumbnail) { - toResponse(response, getFileHandler.getUserPhoto(user, loadThumbnail)); - } + @Transactional(readOnly = true) + @GetMapping(value = "/photo") + @ApiOperation("Get photo of current user") + public void getMyPhoto(@AuthenticationPrincipal ReportPortalUser user, + HttpServletResponse response, + @RequestParam(value = "loadThumbnail", required = false) boolean loadThumbnail) { + toResponse(response, getFileHandler.getUserPhoto(user, loadThumbnail)); + } - /** - * (non-Javadoc) - */ - @Transactional(readOnly = true) - @PreAuthorize(NOT_CUSTOMER) - @GetMapping(value = "/{projectName}/userphoto") - @ApiOperation("Get user's photo") - public void getUserPhoto(@PathVariable String projectName, @RequestParam(value = "id") String username, - @RequestParam(value = "loadThumbnail", required = false) boolean loadThumbnail, HttpServletResponse response, - @AuthenticationPrincipal ReportPortalUser user) { - BinaryData userPhoto = getFileHandler.getUserPhoto(EntityUtils.normalizeId(username), user, projectName, loadThumbnail); - toResponse(response, userPhoto); - } + @Transactional(readOnly = true) + @PreAuthorize(NOT_CUSTOMER) + @GetMapping(value = "/{projectName}/userphoto") + @ApiOperation("Get user's photo") + public void getUserPhoto(@PathVariable String projectName, + @RequestParam(value = "id") String username, + @RequestParam(value = "loadThumbnail", required = false) boolean loadThumbnail, + HttpServletResponse response, + @AuthenticationPrincipal ReportPortalUser user) { + BinaryData userPhoto = getFileHandler.getUserPhoto(EntityUtils.normalizeId(username), user, + projectName, loadThumbnail); + toResponse(response, userPhoto); + } - @Transactional - @PostMapping(value = "/photo", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) - @ApiOperation("Upload user's photo") - public OperationCompletionRS uploadPhoto(@RequestParam("file") MultipartFile file, @AuthenticationPrincipal ReportPortalUser user) { - return editUserHandler.uploadPhoto(EntityUtils.normalizeId(user.getUsername()), file); - } + @Transactional + @PostMapping(value = "/photo", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @ApiOperation("Upload user's photo") + public OperationCompletionRS uploadPhoto(@RequestParam("file") MultipartFile file, + @AuthenticationPrincipal ReportPortalUser user) { + return editUserHandler.uploadPhoto(EntityUtils.normalizeId(user.getUsername()), file); + } - @Transactional - @DeleteMapping(value = "/photo") - @ApiOperation("Delete user's photo") - public OperationCompletionRS deletePhoto(@AuthenticationPrincipal ReportPortalUser user) { - return editUserHandler.deletePhoto(EntityUtils.normalizeId(user.getUsername())); - } + @Transactional + @DeleteMapping(value = "/photo") + @ApiOperation("Delete user's photo") + public OperationCompletionRS deletePhoto(@AuthenticationPrincipal ReportPortalUser user) { + return editUserHandler.deletePhoto(EntityUtils.normalizeId(user.getUsername())); + } - @Transactional - @PreAuthorize(ADMIN_ONLY) - @PostMapping(value = "/clean", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) - @ApiOperation("Remove attachments from file storage according to uploaded csv file") - public OperationCompletionRS removeAttachmentsByCsv(@RequestParam("file") MultipartFile file, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteFilesHandler.removeFilesByCsv(file); - } + @Transactional + @PreAuthorize(ADMIN_ONLY) + @PostMapping(value = "/clean", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @ApiOperation("Remove attachments from file storage according to uploaded csv file") + public OperationCompletionRS removeAttachmentsByCsv(@RequestParam("file") MultipartFile file, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteFilesHandler.removeFilesByCsv(file); + } /** * Copies data from provided {@link InputStream} to Response diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/IntegrationController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/IntegrationController.java index 3627f1732b..69bcb8ab3b 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/IntegrationController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/IntegrationController.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.integration.CreateIntegrationHandler; import com.epam.ta.reportportal.core.integration.DeleteIntegrationHandler; @@ -27,20 +33,23 @@ import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; import io.swagger.annotations.ApiOperation; +import java.util.List; +import java.util.Map; +import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.*; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -49,192 +58,216 @@ @RequestMapping(value = "/v1/integration") public class IntegrationController { - private final ProjectExtractor projectExtractor; - private final DeleteIntegrationHandler deleteIntegrationHandler; - private final GetIntegrationHandler getIntegrationHandler; - private final CreateIntegrationHandler createIntegrationHandler; - private final ExecuteIntegrationHandler executeIntegrationHandler; - - @Autowired - public IntegrationController(ProjectExtractor projectExtractor, DeleteIntegrationHandler deleteIntegrationHandler, - GetIntegrationHandler getIntegrationHandler, CreateIntegrationHandler createIntegrationHandler, - ExecuteIntegrationHandler executeIntegrationHandler) { - this.projectExtractor = projectExtractor; - this.deleteIntegrationHandler = deleteIntegrationHandler; - this.getIntegrationHandler = getIntegrationHandler; - this.createIntegrationHandler = createIntegrationHandler; - this.executeIntegrationHandler = executeIntegrationHandler; - } - - @Transactional(readOnly = true) - @GetMapping("/global/all") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get available global integrations") - public List<IntegrationResource> getGlobalIntegrations(@AuthenticationPrincipal ReportPortalUser reportPortalUser) { - return getIntegrationHandler.getGlobalIntegrations(); - } - - @Transactional(readOnly = true) - @GetMapping("/global/all/{pluginName}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get available global integrations for plugin") - public List<IntegrationResource> getGlobalIntegrations(@AuthenticationPrincipal ReportPortalUser reportPortalUser, - @PathVariable String pluginName) { - return getIntegrationHandler.getGlobalIntegrations(pluginName); - } - - @Transactional(readOnly = true) - @GetMapping("/project/{projectName}/all") - @ResponseStatus(HttpStatus.OK) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @ApiOperation("Get available project integrations") - public List<IntegrationResource> getProjectIntegrations(@PathVariable String projectName, - @AuthenticationPrincipal ReportPortalUser reportPortalUser) { - return getIntegrationHandler.getProjectIntegrations(normalizeId(projectName)); - } - - @Transactional(readOnly = true) - @GetMapping("/project/{projectName}/all/{pluginName}") - @ResponseStatus(HttpStatus.OK) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @ApiOperation("Get available project integrations for plugin") - public List<IntegrationResource> getProjectIntegrations(@AuthenticationPrincipal ReportPortalUser reportPortalUser, - @PathVariable String projectName, @PathVariable String pluginName) { - return getIntegrationHandler.getProjectIntegrations(pluginName, normalizeId(projectName)); - } - - @Transactional - @PostMapping(value = "/{pluginName}") - @ResponseStatus(HttpStatus.CREATED) - @ApiOperation("Create global Report Portal integration instance") - @PreAuthorize(ADMIN_ONLY) - public EntryCreatedRS createGlobalIntegration(@RequestBody @Valid IntegrationRQ createRequest, @PathVariable String pluginName, - @AuthenticationPrincipal ReportPortalUser user) { - return createIntegrationHandler.createGlobalIntegration(createRequest, pluginName, user); - } - - @Transactional - @PostMapping(value = "/{projectName}/{pluginName}") - @ResponseStatus(HttpStatus.CREATED) - @ApiOperation("Create project Report Portal integration instance") - @PreAuthorize(PROJECT_MANAGER) - public EntryCreatedRS createProjectIntegration(@RequestBody @Valid IntegrationRQ createRequest, @PathVariable String pluginName, - @PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user) { - return createIntegrationHandler.createProjectIntegration(normalizeId(projectName), createRequest, pluginName, user); - - } - - @Transactional(readOnly = true) - @GetMapping(value = "{projectName}/{integrationId}/connection/test") - @ResponseStatus(HttpStatus.OK) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @ApiOperation("Test connection to the integration through the project config") - public boolean testIntegrationConnection(@PathVariable Long integrationId, @PathVariable String projectName, - @AuthenticationPrincipal ReportPortalUser user) { - return getIntegrationHandler.testConnection(integrationId, normalizeId(projectName)); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/{integrationId}/connection/test") - @ResponseStatus(HttpStatus.OK) - @PreAuthorize(ADMIN_ONLY) - @ApiOperation("Test connection to the global integration") - public boolean testIntegrationConnection(@PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return getIntegrationHandler.testConnection(integrationId); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get global Report Portal integration instance") - @PreAuthorize(ADMIN_ONLY) - public IntegrationResource getGlobalIntegration(@PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return getIntegrationHandler.getGlobalIntegrationById(integrationId); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/{projectName}/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Get integration instance") - @PreAuthorize(ASSIGNED_TO_PROJECT) - public IntegrationResource getProjectIntegration(@PathVariable String projectName, @PathVariable Long integrationId, - @AuthenticationPrincipal ReportPortalUser user) { - return getIntegrationHandler.getProjectIntegrationById(integrationId, normalizeId(projectName)); - } - - @Transactional - @PutMapping(value = "/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Update global Report Portal integration instance") - @PreAuthorize(ADMIN_ONLY) - public OperationCompletionRS updateGlobalIntegration(@PathVariable Long integrationId, @RequestBody @Valid IntegrationRQ updateRequest, - @AuthenticationPrincipal ReportPortalUser user) { - return createIntegrationHandler.updateGlobalIntegration(integrationId, updateRequest, user); - - } - - @Transactional - @PutMapping(value = "/{projectName}/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Update project integration instance") - @PreAuthorize(PROJECT_MANAGER) - public OperationCompletionRS updateProjectIntegration(@PathVariable Long integrationId, @RequestBody @Valid IntegrationRQ updateRequest, - @PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user) { - return createIntegrationHandler.updateProjectIntegration(integrationId, normalizeId(projectName), updateRequest, user); - - } - - @Transactional - @DeleteMapping(value = "/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Delete global integration instance") - @PreAuthorize(ADMIN_ONLY) - public OperationCompletionRS deleteGlobalIntegration(@PathVariable Long integrationId, @AuthenticationPrincipal ReportPortalUser user) { - return deleteIntegrationHandler.deleteGlobalIntegration(integrationId, user); - } - - @Transactional - @DeleteMapping(value = "/all/{type}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Delete all global integrations by type") - @PreAuthorize(ADMIN_ONLY) - public OperationCompletionRS deleteAllIntegrations(@PathVariable String type, @AuthenticationPrincipal ReportPortalUser user) { - return deleteIntegrationHandler.deleteGlobalIntegrationsByType(type, user); - } - - @Transactional - @DeleteMapping(value = "/{projectName}/{integrationId}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Delete project integration instance") - @PreAuthorize(PROJECT_MANAGER) - public OperationCompletionRS deleteProjectIntegration(@PathVariable String projectName, @PathVariable Long integrationId, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteIntegrationHandler.deleteProjectIntegration(integrationId, normalizeId(projectName), user); - } - - @Transactional - @DeleteMapping(value = "/{projectName}/all/{type}") - @ResponseStatus(HttpStatus.OK) - @ApiOperation("Delete all integrations assigned to specified project") - @PreAuthorize(PROJECT_MANAGER) - public OperationCompletionRS deleteAllProjectIntegrations(@PathVariable String type, @PathVariable String projectName, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteIntegrationHandler.deleteProjectIntegrationsByType(type, normalizeId(projectName), user); - } - - @Transactional - @PutMapping(value = "{projectName}/{integrationId}/{command}", consumes = { APPLICATION_JSON_VALUE }) - @ResponseStatus(HttpStatus.OK) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @ApiOperation("Execute command to the integration instance") - public Object executeIntegrationCommand(@PathVariable String projectName, @PathVariable("integrationId") Long integrationId, - @PathVariable("command") String command, @RequestBody Map<String, Object> executionParams, - @AuthenticationPrincipal ReportPortalUser user) { - return executeIntegrationHandler.executeCommand(projectExtractor.extractProjectDetails(user, projectName), - integrationId, - command, - executionParams - ); - } + private final ProjectExtractor projectExtractor; + private final DeleteIntegrationHandler deleteIntegrationHandler; + private final GetIntegrationHandler getIntegrationHandler; + private final CreateIntegrationHandler createIntegrationHandler; + private final ExecuteIntegrationHandler executeIntegrationHandler; + + @Autowired + public IntegrationController(ProjectExtractor projectExtractor, + DeleteIntegrationHandler deleteIntegrationHandler, + GetIntegrationHandler getIntegrationHandler, + CreateIntegrationHandler createIntegrationHandler, + ExecuteIntegrationHandler executeIntegrationHandler) { + this.projectExtractor = projectExtractor; + this.deleteIntegrationHandler = deleteIntegrationHandler; + this.getIntegrationHandler = getIntegrationHandler; + this.createIntegrationHandler = createIntegrationHandler; + this.executeIntegrationHandler = executeIntegrationHandler; + } + + @Transactional(readOnly = true) + @GetMapping("/global/all") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get available global integrations") + public List<IntegrationResource> getGlobalIntegrations( + @AuthenticationPrincipal ReportPortalUser reportPortalUser) { + return getIntegrationHandler.getGlobalIntegrations(); + } + + @Transactional(readOnly = true) + @GetMapping("/global/all/{pluginName}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get available global integrations for plugin") + public List<IntegrationResource> getGlobalIntegrations( + @AuthenticationPrincipal ReportPortalUser reportPortalUser, + @PathVariable String pluginName) { + return getIntegrationHandler.getGlobalIntegrations(pluginName); + } + + @Transactional(readOnly = true) + @GetMapping("/project/{projectName}/all") + @ResponseStatus(HttpStatus.OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation("Get available project integrations") + public List<IntegrationResource> getProjectIntegrations(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser reportPortalUser) { + return getIntegrationHandler.getProjectIntegrations(normalizeId(projectName)); + } + + @Transactional(readOnly = true) + @GetMapping("/project/{projectName}/all/{pluginName}") + @ResponseStatus(HttpStatus.OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation("Get available project integrations for plugin") + public List<IntegrationResource> getProjectIntegrations( + @AuthenticationPrincipal ReportPortalUser reportPortalUser, + @PathVariable String projectName, @PathVariable String pluginName) { + return getIntegrationHandler.getProjectIntegrations(pluginName, normalizeId(projectName)); + } + + @Transactional + @PostMapping(value = "/{pluginName}") + @ResponseStatus(HttpStatus.CREATED) + @ApiOperation("Create global Report Portal integration instance") + @PreAuthorize(ADMIN_ONLY) + public EntryCreatedRS createGlobalIntegration(@RequestBody @Valid IntegrationRQ createRequest, + @PathVariable String pluginName, + @AuthenticationPrincipal ReportPortalUser user) { + return createIntegrationHandler.createGlobalIntegration(createRequest, pluginName, user); + } + + @Transactional + @PostMapping(value = "/{projectName}/{pluginName}") + @ResponseStatus(HttpStatus.CREATED) + @ApiOperation("Create project Report Portal integration instance") + @PreAuthorize(PROJECT_MANAGER) + public EntryCreatedRS createProjectIntegration(@RequestBody @Valid IntegrationRQ createRequest, + @PathVariable String pluginName, + @PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user) { + return createIntegrationHandler.createProjectIntegration(normalizeId(projectName), + createRequest, pluginName, user); + + } + + @Transactional(readOnly = true) + @GetMapping(value = "{projectName}/{integrationId}/connection/test") + @ResponseStatus(HttpStatus.OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation("Test connection to the integration through the project config") + public boolean testIntegrationConnection(@PathVariable Long integrationId, + @PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user) { + return getIntegrationHandler.testConnection(integrationId, normalizeId(projectName)); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{integrationId}/connection/test") + @ResponseStatus(HttpStatus.OK) + @PreAuthorize(ADMIN_ONLY) + @ApiOperation("Test connection to the global integration") + public boolean testIntegrationConnection(@PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getIntegrationHandler.testConnection(integrationId); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get global Report Portal integration instance") + @PreAuthorize(ADMIN_ONLY) + public IntegrationResource getGlobalIntegration(@PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getIntegrationHandler.getGlobalIntegrationById(integrationId); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{projectName}/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get integration instance") + @PreAuthorize(ASSIGNED_TO_PROJECT) + public IntegrationResource getProjectIntegration(@PathVariable String projectName, + @PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return getIntegrationHandler.getProjectIntegrationById(integrationId, normalizeId(projectName)); + } + + @Transactional + @PutMapping(value = "/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Update global Report Portal integration instance") + @PreAuthorize(ADMIN_ONLY) + public OperationCompletionRS updateGlobalIntegration(@PathVariable Long integrationId, + @RequestBody @Valid IntegrationRQ updateRequest, + @AuthenticationPrincipal ReportPortalUser user) { + return createIntegrationHandler.updateGlobalIntegration(integrationId, updateRequest, user); + + } + + @Transactional + @PutMapping(value = "/{projectName}/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Update project integration instance") + @PreAuthorize(PROJECT_MANAGER) + public OperationCompletionRS updateProjectIntegration(@PathVariable Long integrationId, + @RequestBody @Valid IntegrationRQ updateRequest, + @PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user) { + return createIntegrationHandler.updateProjectIntegration(integrationId, + normalizeId(projectName), updateRequest, user); + + } + + @Transactional + @DeleteMapping(value = "/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Delete global integration instance") + @PreAuthorize(ADMIN_ONLY) + public OperationCompletionRS deleteGlobalIntegration(@PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteIntegrationHandler.deleteGlobalIntegration(integrationId, user); + } + + @Transactional + @DeleteMapping(value = "/all/{type}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Delete all global integrations by type") + @PreAuthorize(ADMIN_ONLY) + public OperationCompletionRS deleteAllIntegrations(@PathVariable String type, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteIntegrationHandler.deleteGlobalIntegrationsByType(type, user); + } + + @Transactional + @DeleteMapping(value = "/{projectName}/{integrationId}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Delete project integration instance") + @PreAuthorize(PROJECT_MANAGER) + public OperationCompletionRS deleteProjectIntegration(@PathVariable String projectName, + @PathVariable Long integrationId, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteIntegrationHandler.deleteProjectIntegration(integrationId, + normalizeId(projectName), user); + } + + @Transactional + @DeleteMapping(value = "/{projectName}/all/{type}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Delete all integrations assigned to specified project") + @PreAuthorize(PROJECT_MANAGER) + public OperationCompletionRS deleteAllProjectIntegrations(@PathVariable String type, + @PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteIntegrationHandler.deleteProjectIntegrationsByType(type, normalizeId(projectName), + user); + } + + @Transactional + @PutMapping(value = "{projectName}/{integrationId}/{command}", consumes = { + APPLICATION_JSON_VALUE}) + @ResponseStatus(HttpStatus.OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation("Execute command to the integration instance") + public Object executeIntegrationCommand(@PathVariable String projectName, + @PathVariable("integrationId") Long integrationId, + @PathVariable("command") String command, @RequestBody Map<String, Object> executionParams, + @AuthenticationPrincipal ReportPortalUser user) { + return executeIntegrationHandler.executeCommand( + projectExtractor.extractProjectDetails(user, projectName), + integrationId, + command, + executionParams + ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/InternalApiController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/InternalApiController.java index b39ed0bd44..45fb274192 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/InternalApiController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/InternalApiController.java @@ -20,8 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; /** - * Allowed for internal (other services) clients ONLY - * Provides direct access to DAO layer + * Allowed for internal (other services) clients ONLY Provides direct access to DAO layer * * @author Andrei Varabyeu */ @@ -30,20 +29,20 @@ //@PreAuthorize("hasRole('COMPONENT')") public class InternalApiController { - // private final ExternalSystemRepository externalSystemRepository; - // - // @Autowired - // public InternalApiController(ExternalSystemRepository externalSystemRepository) { - // this.externalSystemRepository = externalSystemRepository; - // } - // - // @RequestMapping(value = "/external-system/{systemId}", method = RequestMethod.GET) - // @ResponseBody - // @ResponseStatus(HttpStatus.OK) - // - // public ExternalSystemResource getExternalSystem(@PathVariable String systemId) { - // ExternalSystem externalSystem = externalSystemRepository.findOne(systemId); - // BusinessRule.expect(externalSystem, Predicates.notNull()).verify(ErrorType.EXTERNAL_SYSTEM_NOT_FOUND, systemId); - // return ExternalSystemConverter.TO_RESOURCE.apply(externalSystem); - // } + // private final ExternalSystemRepository externalSystemRepository; + // + // @Autowired + // public InternalApiController(ExternalSystemRepository externalSystemRepository) { + // this.externalSystemRepository = externalSystemRepository; + // } + // + // @RequestMapping(value = "/external-system/{systemId}", method = RequestMethod.GET) + // @ResponseBody + // @ResponseStatus(HttpStatus.OK) + // + // public ExternalSystemResource getExternalSystem(@PathVariable String systemId) { + // ExternalSystem externalSystem = externalSystemRepository.findOne(systemId); + // BusinessRule.expect(externalSystem, Predicates.notNull()).verify(ErrorType.EXTERNAL_SYSTEM_NOT_FOUND, systemId); + // return ExternalSystemConverter.TO_RESOURCE.apply(externalSystem); + // } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncController.java index 5b2cffec4c..ee4e818e9e 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncController.java @@ -15,6 +15,12 @@ */ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.composeBaseUrl; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.launch.FinishLaunchHandler; import com.epam.ta.reportportal.core.launch.MergeLaunchHandler; @@ -22,24 +28,27 @@ import com.epam.ta.reportportal.core.logging.HttpLogging; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; -import com.epam.ta.reportportal.ws.model.launch.*; +import com.epam.ta.reportportal.ws.model.launch.FinishLaunchRS; +import com.epam.ta.reportportal.ws.model.launch.LaunchResource; +import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.HttpServletRequest; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.composeBaseUrl; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** * Controller implementation for async reporting client API for @@ -51,58 +60,65 @@ @RequestMapping("/v2/{projectName}/launch") public class LaunchAsyncController { - private final ProjectExtractor projectExtractor; - private final StartLaunchHandler startLaunchHandler; - private final FinishLaunchHandler finishLaunchHandler; - private final MergeLaunchHandler mergeLaunchesHandler; + private final ProjectExtractor projectExtractor; + private final StartLaunchHandler startLaunchHandler; + private final FinishLaunchHandler finishLaunchHandler; + private final MergeLaunchHandler mergeLaunchesHandler; - @Autowired - public LaunchAsyncController(ProjectExtractor projectExtractor, @Qualifier("startLaunchHandlerAsync") StartLaunchHandler startLaunchHandler, - @Qualifier("finishLaunchHandlerAsync") FinishLaunchHandler finishLaunchHandler, MergeLaunchHandler mergeLaunchesHandler) { - this.projectExtractor = projectExtractor; - this.startLaunchHandler = startLaunchHandler; - this.finishLaunchHandler = finishLaunchHandler; - this.mergeLaunchesHandler = mergeLaunchesHandler; - } + @Autowired + public LaunchAsyncController(ProjectExtractor projectExtractor, + @Qualifier("startLaunchHandlerAsync") StartLaunchHandler startLaunchHandler, + @Qualifier("finishLaunchHandlerAsync") FinishLaunchHandler finishLaunchHandler, + MergeLaunchHandler mergeLaunchesHandler) { + this.projectExtractor = projectExtractor; + this.startLaunchHandler = startLaunchHandler; + this.finishLaunchHandler = finishLaunchHandler; + this.mergeLaunchesHandler = mergeLaunchesHandler; + } - @HttpLogging - @PostMapping - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(CREATED) - @ApiOperation("Starts launch for specified project") - public StartLaunchRS startLaunch(@PathVariable String projectName, - @ApiParam(value = "Start launch request body", required = true) @RequestBody @Validated StartLaunchRQ startLaunchRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return startLaunchHandler.startLaunch(user, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), startLaunchRQ); - } + @HttpLogging + @PostMapping + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(CREATED) + @ApiOperation("Starts launch for specified project") + public StartLaunchRS startLaunch(@PathVariable String projectName, + @ApiParam(value = "Start launch request body", required = true) @RequestBody @Validated StartLaunchRQ startLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return startLaunchHandler.startLaunch(user, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), startLaunchRQ); + } - @HttpLogging - @PutMapping(value = "/{launchId}/finish") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Finish launch for specified project") - public FinishLaunchRS finishLaunch(@PathVariable String projectName, @PathVariable String launchId, - @RequestBody @Validated FinishExecutionRQ finishLaunchRQ, @AuthenticationPrincipal ReportPortalUser user, - HttpServletRequest request) { - return finishLaunchHandler.finishLaunch( - launchId, - finishLaunchRQ, - projectExtractor.extractProjectDetails(user, normalizeId(projectName)), - user, - composeBaseUrl(request) - ); - } + @HttpLogging + @PutMapping(value = "/{launchId}/finish") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Finish launch for specified project") + public FinishLaunchRS finishLaunch(@PathVariable String projectName, + @PathVariable String launchId, + @RequestBody @Validated FinishExecutionRQ finishLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user, + HttpServletRequest request) { + return finishLaunchHandler.finishLaunch( + launchId, + finishLaunchRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), + user, + composeBaseUrl(request) + ); + } - @HttpLogging - @Transactional - @PostMapping("/merge") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Merge set of specified launches in common one") - public LaunchResource mergeLaunches(@PathVariable String projectName, - @ApiParam(value = "Merge launches request body", required = true) @RequestBody @Validated MergeLaunchesRQ mergeLaunchesRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return mergeLaunchesHandler.mergeLaunches(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, mergeLaunchesRQ); - } + @HttpLogging + @Transactional + @PostMapping("/merge") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Merge set of specified launches in common one") + public LaunchResource mergeLaunches(@PathVariable String projectName, + @ApiParam(value = "Merge launches request body", required = true) @RequestBody @Validated MergeLaunchesRQ mergeLaunchesRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return mergeLaunchesHandler.mergeLaunches( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, + mergeLaunchesRQ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java index 5949add2c2..30412173f8 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/LaunchController.java @@ -15,18 +15,45 @@ */ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER_OR_ADMIN; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.composeBaseUrl; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.core.imprt.ImportLaunchHandler; import com.epam.ta.reportportal.core.jasper.GetJasperReportHandler; -import com.epam.ta.reportportal.core.launch.*; +import com.epam.ta.reportportal.core.launch.DeleteLaunchHandler; +import com.epam.ta.reportportal.core.launch.FinishLaunchHandler; +import com.epam.ta.reportportal.core.launch.GetLaunchHandler; +import com.epam.ta.reportportal.core.launch.MergeLaunchHandler; +import com.epam.ta.reportportal.core.launch.StartLaunchHandler; +import com.epam.ta.reportportal.core.launch.StopLaunchHandler; +import com.epam.ta.reportportal.core.launch.UpdateLaunchHandler; import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.content.ChartStatisticsContent; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.model.*; -import com.epam.ta.reportportal.ws.model.launch.*; +import com.epam.ta.reportportal.ws.model.BulkInfoUpdateRQ; +import com.epam.ta.reportportal.ws.model.BulkRQ; +import com.epam.ta.reportportal.ws.model.DeleteBulkRQ; +import com.epam.ta.reportportal.ws.model.DeleteBulkRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; +import com.epam.ta.reportportal.ws.model.launch.FinishLaunchRS; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; +import com.epam.ta.reportportal.ws.model.launch.LaunchResource; +import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; +import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; +import com.epam.ta.reportportal.ws.model.launch.UpdateLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.cluster.ClusterInfoResource; import com.epam.ta.reportportal.ws.model.launch.cluster.CreateClustersRQ; import com.epam.ta.reportportal.ws.resolver.FilterFor; @@ -36,6 +63,13 @@ import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.domain.Pageable; @@ -44,30 +78,24 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.validation.Valid; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; -import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER_OR_ADMIN; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static com.epam.ta.reportportal.core.launch.util.LinkGenerator.composeBaseUrl; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; - /** - * Controller implementation for - * {@link com.epam.ta.reportportal.entity.launch.Launch} entity + * Controller implementation for {@link com.epam.ta.reportportal.entity.launch.Launch} entity * <p> - * Note: please use EntityUtils for forced lower case for user names and project - * names + * Note: please use EntityUtils for forced lower case for user names and project names * </p> * * @author Andrei Varabyeu @@ -78,343 +106,370 @@ @RequestMapping("/v1/{projectName}/launch") public class LaunchController { - private final ProjectExtractor projectExtractor; - private final StartLaunchHandler startLaunchHandler; - private final FinishLaunchHandler finishLaunchHandler; - private final StopLaunchHandler stopLaunchHandler; - private final DeleteLaunchHandler deleteLaunchMessageHandler; - private final GetLaunchHandler getLaunchMessageHandler; - private final UpdateLaunchHandler updateLaunchHandler; - private final MergeLaunchHandler mergeLaunchesHandler; - private final ImportLaunchHandler importLaunchHandler; - private final GetJasperReportHandler<Launch> getJasperHandler; - - @Autowired - public LaunchController(ProjectExtractor projectExtractor, StartLaunchHandler startLaunchHandler, FinishLaunchHandler finishLaunchHandler, - StopLaunchHandler stopLaunchHandler, DeleteLaunchHandler deleteLaunchMessageHandler, GetLaunchHandler getLaunchMessageHandler, - UpdateLaunchHandler updateLaunchHandler, MergeLaunchHandler mergeLaunchesHandler, ImportLaunchHandler importLaunchHandler, - @Qualifier("launchJasperReportHandler") GetJasperReportHandler<Launch> getJasperHandler) { - this.projectExtractor = projectExtractor; - this.startLaunchHandler = startLaunchHandler; - this.finishLaunchHandler = finishLaunchHandler; - this.stopLaunchHandler = stopLaunchHandler; - this.deleteLaunchMessageHandler = deleteLaunchMessageHandler; - this.getLaunchMessageHandler = getLaunchMessageHandler; - this.updateLaunchHandler = updateLaunchHandler; - this.mergeLaunchesHandler = mergeLaunchesHandler; - this.importLaunchHandler = importLaunchHandler; - this.getJasperHandler = getJasperHandler; - } - - /* Report client API */ - - @PostMapping - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(CREATED) - @ApiOperation("Starts launch for specified project") - public StartLaunchRS startLaunch(@PathVariable String projectName, - @ApiParam(value = "Start launch request body", required = true) @RequestBody @Validated @Valid StartLaunchRQ startLaunchRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return startLaunchHandler.startLaunch(user, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), startLaunchRQ); - } - - @PutMapping(value = "/{launchId}/finish") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Finish launch for specified project") - public FinishLaunchRS finishLaunch(@PathVariable String projectName, @PathVariable String launchId, - @RequestBody @Validated FinishExecutionRQ finishLaunchRQ, @AuthenticationPrincipal ReportPortalUser user, - HttpServletRequest request) { - return finishLaunchHandler.finishLaunch(launchId, - finishLaunchRQ, - projectExtractor.extractProjectDetails(user, normalizeId(projectName)), - user, - composeBaseUrl(request) - ); - } - - /* Frontend API */ - - @Transactional - @PutMapping("/{launchId}/stop") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Force finish launch for specified project") - public OperationCompletionRS forceFinishLaunch(@PathVariable String projectName, @PathVariable Long launchId, - @RequestBody @Validated FinishExecutionRQ finishExecutionRQ, @AuthenticationPrincipal ReportPortalUser user) { - return stopLaunchHandler.stopLaunch(launchId, finishExecutionRQ, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @Transactional - @PutMapping("/stop") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Force finish launch") - public List<OperationCompletionRS> bulkForceFinish(@PathVariable String projectName, - @RequestBody @Validated BulkRQ<Long, FinishExecutionRQ> rq, @AuthenticationPrincipal ReportPortalUser user) { - return stopLaunchHandler.stopLaunch(rq, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @Transactional - @PutMapping("/{launchId}/update") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Updates launch for specified project") - public OperationCompletionRS updateLaunch(@PathVariable String projectName, @PathVariable Long launchId, - @RequestBody @Validated UpdateLaunchRQ updateLaunchRQ, @AuthenticationPrincipal ReportPortalUser user) { - return updateLaunchHandler.updateLaunch(launchId, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, updateLaunchRQ); - } - - @Transactional - @PutMapping("/update") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Updates launches for specified project") - public List<OperationCompletionRS> updateLaunches(@PathVariable String projectName, - @RequestBody @Validated BulkRQ<Long, UpdateLaunchRQ> rq, @AuthenticationPrincipal ReportPortalUser user) { - return updateLaunchHandler.updateLaunch(rq, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @Transactional - @DeleteMapping("/{launchId}") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Delete specified launch by ID") - public OperationCompletionRS deleteLaunch(@PathVariable String projectName, @PathVariable Long launchId, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteLaunchMessageHandler.deleteLaunch(launchId, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @Transactional(readOnly = true) - @GetMapping("/{launchId}") - @ResponseStatus(OK) - @ApiOperation("Get specified launch by ID") - public LaunchResource getLaunch(@PathVariable String projectName, @PathVariable String launchId, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getLaunch(launchId, projectExtractor.extractProjectDetails(user, normalizeId(projectName))); - } - - @Transactional(readOnly = true) - @GetMapping("/uuid/{launchId}") - @ResponseStatus(OK) - @ApiOperation("Get specified launch by UUID") - public LaunchResource getLaunchByUuid(@PathVariable String projectName, @PathVariable String launchId, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getLaunch(launchId, projectExtractor.extractProjectDetails(user, normalizeId(projectName))); - } - - @Transactional(readOnly = true) - @GetMapping - @ResponseStatus(OK) - @ApiOperation("Get list of project launches by filter") - public Iterable<LaunchResource> getProjectLaunches(@PathVariable String projectName, @FilterFor(Launch.class) Filter filter, - @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getProjectLaunches(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), - filter, - pageable, - user.getUsername() - ); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/latest") - @ResponseStatus(OK) - @ApiOperation("Get list of latest project launches by filter") - public Iterable<LaunchResource> getLatestLaunches(@PathVariable String projectName, @FilterFor(Launch.class) Filter filter, - @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getLatestLaunches(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), filter, pageable); - } - - @GetMapping(value = "/mode") - @ResponseBody - @ResponseStatus(OK) - @ApiOperation("Get launches of specified project from DEBUG mode") - public Iterable<LaunchResource> getDebugLaunches(@PathVariable String projectName, @FilterFor(Launch.class) Filter filter, - @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getDebugLaunches(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), filter, pageable); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/attribute/keys") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute keys of project launches") - public List<String> getAttributeKeys(@PathVariable String projectName, - @RequestParam(value = "filter." + "cnt." + "attributeKey") String value, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getAttributeKeys(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/attribute/values") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute values of project launches") - public List<String> getAttributeValues(@PathVariable String projectName, - @RequestParam(value = "filter." + "eq." + "attributeKey", required = false) String key, - @RequestParam(value = "filter." + "cnt." + "attributeValue") String value, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getAttributeValues(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), key, value); - } - - @GetMapping(value = "/cluster/{launchId}") - @ResponseStatus(OK) - @ApiOperation("Get all index clusters of the launch") - public Iterable<ClusterInfoResource> getClusters(@PathVariable String projectName, @PathVariable String launchId, Pageable pageable, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getClusters(launchId, - projectExtractor.extractProjectDetails(user, normalizeId(projectName)), - pageable - ); - } - - @Transactional - @PutMapping(value = "/info") - @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) - @ResponseStatus(OK) - @ApiOperation("Bulk update attributes and description") - public OperationCompletionRS bulkUpdate(@PathVariable String projectName, @RequestBody @Validated BulkInfoUpdateRQ bulkInfoUpdateRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return updateLaunchHandler.bulkInfoUpdate(bulkInfoUpdateRQ, projectExtractor.extractProjectDetails(user, projectName)); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/owners") - @ResponseStatus(OK) - @ApiOperation("Get all unique owners of project launches") - public List<String> getAllOwners(@PathVariable String projectName, @RequestParam(value = "filter." + "cnt." + "user") String value, - @RequestParam(value = "mode", required = false, defaultValue = "DEFAULT") String mode, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getOwners(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value, mode); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/names") - @ResponseStatus(OK) - @ApiOperation("Get launch names of project") - public List<String> getAllLaunchNames(@PathVariable String projectName, @RequestParam(value = "filter." + "cnt." + "name") String value, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getLaunchNames(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/compare") - @ResponseStatus(OK) - @ApiOperation("Compare launches") - public Map<String, List<ChartStatisticsContent>> compareLaunches(@PathVariable String projectName, - @RequestParam(value = "ids") Long[] ids, @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getLaunchesComparisonInfo(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), ids); - } - - @Transactional - @PostMapping("/merge") - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Merge set of specified launches in common one") - public LaunchResource mergeLaunches(@PathVariable String projectName, - @ApiParam(value = "Merge launches request body", required = true) @RequestBody @Validated MergeLaunchesRQ mergeLaunchesRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return mergeLaunchesHandler.mergeLaunches(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, mergeLaunchesRQ); - } - - @Transactional - @PostMapping(value = "/analyze") - @ResponseStatus(OK) - @ApiOperation("Start launch auto-analyzer on demand") - public OperationCompletionRS startLaunchAnalyzer(@PathVariable String projectName, - @RequestBody @Validated AnalyzeLaunchRQ analyzeLaunchRQ, @AuthenticationPrincipal ReportPortalUser user) { - return updateLaunchHandler.startLaunchAnalyzer(analyzeLaunchRQ, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @PostMapping(value = "/cluster") - @ResponseStatus(OK) - @ApiOperation("Create launch clusters") - public OperationCompletionRS createClusters(@PathVariable String projectName, - @RequestBody @Validated CreateClustersRQ createClustersRQ, @AuthenticationPrincipal ReportPortalUser user) { - return updateLaunchHandler.createClusters(createClustersRQ, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/status") - @ResponseStatus(OK) - - public Map<String, String> getStatuses(@PathVariable String projectName, @RequestParam(value = "ids") Long[] ids, - @AuthenticationPrincipal ReportPortalUser user) { - return getLaunchMessageHandler.getStatuses(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), ids); - } - - @Transactional(readOnly = true) - @GetMapping(value = "/{launchId}/report") - @ResponseStatus(OK) - @ApiOperation(value = "Export specified launch", notes = "Only following formats are supported: pdf (by default), xls, html.") - public void getLaunchReport(@PathVariable String projectName, @PathVariable Long launchId, - @ApiParam(allowableValues = "pdf, xls, html") @RequestParam(value = "view", required = false, defaultValue = "pdf") String view, - @AuthenticationPrincipal ReportPortalUser user, HttpServletResponse response) { - - ReportFormat format = getJasperHandler.getReportFormat(view); - response.setContentType(format.getContentType()); - - response.setHeader(HttpHeaders.CONTENT_DISPOSITION, - String.format("attachment; filename=\"RP_LAUNCH_%s_Report.%s\"", format.name(), format.getValue()) - ); - - try (OutputStream outputStream = response.getOutputStream()) { - getLaunchMessageHandler.exportLaunch(launchId, format, outputStream, user); - } catch (IOException e) { - throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, "Unable to write data to the response."); - } - } - - @Transactional - @DeleteMapping - @PreAuthorize(ALLOWED_TO_REPORT) - @ResponseStatus(OK) - @ApiOperation("Delete specified launches by ids") - public DeleteBulkRS deleteLaunches(@PathVariable String projectName, @RequestBody @Valid DeleteBulkRQ deleteBulkRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteLaunchMessageHandler.deleteLaunches(deleteBulkRQ, projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); - } - - @ApiImplicitParams({ - @ApiImplicitParam( - name = "launchName", - dataType = "string", - paramType = "query", - value = "Override Launch Name" - ), - @ApiImplicitParam( - name = "description", - dataType = "string", - paramType = "query", - value = "Override Launch Description" - ), - @ApiImplicitParam( - name = "attributeKey", - dataType = "string", - paramType = "query", - value = "Add Launch attribute key" - ), - @ApiImplicitParam( - name = "attributeValue", - dataType = "string", - paramType = "query", - value = "Add Launch attribute value" - ), - @ApiImplicitParam( - name = "skippedIsNotIssue", - dataType = "boolean", - paramType = "query", - value = "true: no defect type is applied to skipped issue" - ) - }) - @PostMapping(value = "/import", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) + private final ProjectExtractor projectExtractor; + private final StartLaunchHandler startLaunchHandler; + private final FinishLaunchHandler finishLaunchHandler; + private final StopLaunchHandler stopLaunchHandler; + private final DeleteLaunchHandler deleteLaunchMessageHandler; + private final GetLaunchHandler getLaunchMessageHandler; + private final UpdateLaunchHandler updateLaunchHandler; + private final MergeLaunchHandler mergeLaunchesHandler; + private final ImportLaunchHandler importLaunchHandler; + private final GetJasperReportHandler<Launch> getJasperHandler; + + @Autowired + public LaunchController(ProjectExtractor projectExtractor, StartLaunchHandler startLaunchHandler, + FinishLaunchHandler finishLaunchHandler, + StopLaunchHandler stopLaunchHandler, DeleteLaunchHandler deleteLaunchMessageHandler, + GetLaunchHandler getLaunchMessageHandler, + UpdateLaunchHandler updateLaunchHandler, MergeLaunchHandler mergeLaunchesHandler, + ImportLaunchHandler importLaunchHandler, + @Qualifier("launchJasperReportHandler") GetJasperReportHandler<Launch> getJasperHandler) { + this.projectExtractor = projectExtractor; + this.startLaunchHandler = startLaunchHandler; + this.finishLaunchHandler = finishLaunchHandler; + this.stopLaunchHandler = stopLaunchHandler; + this.deleteLaunchMessageHandler = deleteLaunchMessageHandler; + this.getLaunchMessageHandler = getLaunchMessageHandler; + this.updateLaunchHandler = updateLaunchHandler; + this.mergeLaunchesHandler = mergeLaunchesHandler; + this.importLaunchHandler = importLaunchHandler; + this.getJasperHandler = getJasperHandler; + } + + /* Report client API */ + + @PostMapping + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(CREATED) + @ApiOperation("Starts launch for specified project") + public StartLaunchRS startLaunch(@PathVariable String projectName, + @ApiParam(value = "Start launch request body", required = true) @RequestBody @Validated @Valid StartLaunchRQ startLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return startLaunchHandler.startLaunch(user, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), startLaunchRQ); + } + + @PutMapping(value = "/{launchId}/finish") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Finish launch for specified project") + public FinishLaunchRS finishLaunch(@PathVariable String projectName, + @PathVariable String launchId, + @RequestBody @Validated FinishExecutionRQ finishLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user, + HttpServletRequest request) { + return finishLaunchHandler.finishLaunch(launchId, + finishLaunchRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), + user, + composeBaseUrl(request) + ); + } + + /* Frontend API */ + + @Transactional + @PutMapping("/{launchId}/stop") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Force finish launch for specified project") + public OperationCompletionRS forceFinishLaunch(@PathVariable String projectName, + @PathVariable Long launchId, + @RequestBody @Validated FinishExecutionRQ finishExecutionRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return stopLaunchHandler.stopLaunch(launchId, finishExecutionRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @Transactional + @PutMapping("/stop") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Force finish launch") + public List<OperationCompletionRS> bulkForceFinish(@PathVariable String projectName, + @RequestBody @Validated BulkRQ<Long, FinishExecutionRQ> rq, + @AuthenticationPrincipal ReportPortalUser user) { + return stopLaunchHandler.stopLaunch(rq, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @Transactional + @PutMapping("/{launchId}/update") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Updates launch for specified project") + public OperationCompletionRS updateLaunch(@PathVariable String projectName, + @PathVariable Long launchId, + @RequestBody @Validated UpdateLaunchRQ updateLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateLaunchHandler.updateLaunch(launchId, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, + updateLaunchRQ); + } + + @Transactional + @PutMapping("/update") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Updates launches for specified project") + public List<OperationCompletionRS> updateLaunches(@PathVariable String projectName, + @RequestBody @Validated BulkRQ<Long, UpdateLaunchRQ> rq, + @AuthenticationPrincipal ReportPortalUser user) { + return updateLaunchHandler.updateLaunch(rq, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @Transactional + @DeleteMapping("/{launchId}") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Delete specified launch by ID") + public OperationCompletionRS deleteLaunch(@PathVariable String projectName, + @PathVariable Long launchId, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteLaunchMessageHandler.deleteLaunch(launchId, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @Transactional(readOnly = true) + @GetMapping("/{launchId}") + @ResponseStatus(OK) + @ApiOperation("Get specified launch by ID") + public LaunchResource getLaunch(@PathVariable String projectName, @PathVariable String launchId, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getLaunch(launchId, + projectExtractor.extractProjectDetails(user, normalizeId(projectName))); + } + + @Transactional(readOnly = true) + @GetMapping("/uuid/{launchId}") + @ResponseStatus(OK) + @ApiOperation("Get specified launch by UUID") + public LaunchResource getLaunchByUuid(@PathVariable String projectName, + @PathVariable String launchId, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getLaunch(launchId, + projectExtractor.extractProjectDetails(user, normalizeId(projectName))); + } + + @Transactional(readOnly = true) + @GetMapping + @ResponseStatus(OK) + @ApiOperation("Get list of project launches by filter") + public Iterable<LaunchResource> getProjectLaunches(@PathVariable String projectName, + @FilterFor(Launch.class) Filter filter, + @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getProjectLaunches( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), + filter, + pageable, + user.getUsername() + ); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/latest") + @ResponseStatus(OK) + @ApiOperation("Get list of latest project launches by filter") + public Iterable<LaunchResource> getLatestLaunches(@PathVariable String projectName, + @FilterFor(Launch.class) Filter filter, + @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getLatestLaunches( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), filter, pageable); + } + + @GetMapping(value = "/mode") + @ResponseBody + @ResponseStatus(OK) + @ApiOperation("Get launches of specified project from DEBUG mode") + public Iterable<LaunchResource> getDebugLaunches(@PathVariable String projectName, + @FilterFor(Launch.class) Filter filter, + @SortFor(Launch.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getDebugLaunches( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), filter, pageable); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/attribute/keys") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute keys of project launches") + public List<String> getAttributeKeys(@PathVariable String projectName, + @RequestParam(value = "filter." + "cnt." + "attributeKey") String value, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getAttributeKeys( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/attribute/values") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute values of project launches") + public List<String> getAttributeValues(@PathVariable String projectName, + @RequestParam(value = "filter." + "eq." + "attributeKey", required = false) String key, + @RequestParam(value = "filter." + "cnt." + "attributeValue") String value, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getAttributeValues( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), key, value); + } + + @GetMapping(value = "/cluster/{launchId}") + @ResponseStatus(OK) + @ApiOperation("Get all index clusters of the launch") + public Iterable<ClusterInfoResource> getClusters(@PathVariable String projectName, + @PathVariable String launchId, Pageable pageable, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getClusters(launchId, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), + pageable + ); + } + + @Transactional + @PutMapping(value = "/info") + @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) + @ResponseStatus(OK) + @ApiOperation("Bulk update attributes and description") + public OperationCompletionRS bulkUpdate(@PathVariable String projectName, + @RequestBody @Validated BulkInfoUpdateRQ bulkInfoUpdateRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateLaunchHandler.bulkInfoUpdate(bulkInfoUpdateRQ, + projectExtractor.extractProjectDetails(user, projectName)); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/owners") + @ResponseStatus(OK) + @ApiOperation("Get all unique owners of project launches") + public List<String> getAllOwners(@PathVariable String projectName, + @RequestParam(value = "filter." + "cnt." + "user") String value, + @RequestParam(value = "mode", required = false, defaultValue = "DEFAULT") String mode, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getOwners( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value, mode); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/names") + @ResponseStatus(OK) + @ApiOperation("Get launch names of project") + public List<String> getAllLaunchNames(@PathVariable String projectName, + @RequestParam(value = "filter." + "cnt." + + "name", required = false, defaultValue = "") String value, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getLaunchNames( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), value); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/compare") + @ResponseStatus(OK) + @ApiOperation("Compare launches") + public Map<String, List<ChartStatisticsContent>> compareLaunches(@PathVariable String projectName, + @RequestParam(value = "ids") Long[] ids, @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getLaunchesComparisonInfo( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), ids); + } + + @Transactional + @PostMapping("/merge") + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Merge set of specified launches in common one") + public LaunchResource mergeLaunches(@PathVariable String projectName, + @ApiParam(value = "Merge launches request body", required = true) @RequestBody @Validated MergeLaunchesRQ mergeLaunchesRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return mergeLaunchesHandler.mergeLaunches( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, + mergeLaunchesRQ); + } + + @Transactional + @PostMapping(value = "/analyze") + @ResponseStatus(OK) + @ApiOperation("Start launch auto-analyzer on demand") + public OperationCompletionRS startLaunchAnalyzer(@PathVariable String projectName, + @RequestBody @Validated AnalyzeLaunchRQ analyzeLaunchRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateLaunchHandler.startLaunchAnalyzer(analyzeLaunchRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @PostMapping(value = "/cluster") + @ResponseStatus(OK) + @ApiOperation("Create launch clusters") + public OperationCompletionRS createClusters(@PathVariable String projectName, + @RequestBody @Validated CreateClustersRQ createClustersRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateLaunchHandler.createClusters(createClustersRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/status") + @ResponseStatus(OK) + + public Map<String, String> getStatuses(@PathVariable String projectName, + @RequestParam(value = "ids") Long[] ids, + @AuthenticationPrincipal ReportPortalUser user) { + return getLaunchMessageHandler.getStatuses( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), ids); + } + + @Transactional(readOnly = true) + @GetMapping(value = "/{launchId}/report") + @ResponseStatus(OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation(value = "Export specified launch", notes = "Only following formats are supported: pdf (by default), xls, html.") + public void getLaunchReport(@PathVariable String projectName, @PathVariable Long launchId, + @ApiParam(allowableValues = "pdf, xls, html") @RequestParam(value = "view", required = false, defaultValue = "pdf") String view, + @AuthenticationPrincipal ReportPortalUser user, HttpServletResponse response) { + + ReportFormat format = getJasperHandler.getReportFormat(view); + response.setContentType(format.getContentType()); + + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, + String.format("attachment; filename=\"RP_LAUNCH_%s_Report.%s\"", format.name(), + format.getValue()) + ); + + try (OutputStream outputStream = response.getOutputStream()) { + getLaunchMessageHandler.exportLaunch(launchId, format, outputStream, user); + } catch (IOException e) { + throw new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + "Unable to write data to the response."); + } + } + + @Transactional + @DeleteMapping + @PreAuthorize(ALLOWED_TO_REPORT) + @ResponseStatus(OK) + @ApiOperation("Delete specified launches by ids") + public DeleteBulkRS deleteLaunches(@PathVariable String projectName, + @RequestBody @Valid DeleteBulkRQ deleteBulkRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteLaunchMessageHandler.deleteLaunches(deleteBulkRQ, + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user); + } + + @ApiImplicitParams( + @ApiImplicitParam(name = "launchImportRq", dataType = "LaunchImportRQ", paramType = "body") + ) + @PostMapping(value = "/import", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) @ResponseStatus(OK) @ApiOperation(value = "Import junit xml report", notes = "Only following formats are supported: zip and xml.") - public OperationCompletionRS importLaunch(@PathVariable String projectName, @RequestParam("file") MultipartFile file, + public OperationCompletionRS importLaunch(@PathVariable String projectName, + @RequestParam("file") MultipartFile file, @AuthenticationPrincipal ReportPortalUser user, HttpServletRequest request, - @ApiParam(required = false) @RequestParam Map<String, String> params) { - return importLaunchHandler.importLaunch(projectExtractor.extractProjectDetails(user, normalizeId(projectName)), + @RequestPart(required = false) @Valid LaunchImportRQ launchImportRq) { + return importLaunchHandler.importLaunch( + projectExtractor.extractProjectDetails(user, normalizeId(projectName)), user, "XUNIT", file, composeBaseUrl(request), - params + launchImportRq ); } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/LogAsyncController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/LogAsyncController.java index a63bdd1cf7..980ac468fa 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/LogAsyncController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/LogAsyncController.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.util.ControllerUtils.findByFileName; +import static com.epam.ta.reportportal.util.ControllerUtils.getUploadedFiles; +import static com.epam.ta.reportportal.util.ControllerUtils.validateSaveRQ; +import static org.springframework.http.HttpStatus.CREATED; + import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.BusinessRule; @@ -23,9 +30,16 @@ import com.epam.ta.reportportal.core.log.CreateLogHandler; import com.epam.ta.reportportal.core.logging.HttpLogging; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.model.*; +import com.epam.ta.reportportal.ws.model.BatchElementCreatedRS; +import com.epam.ta.reportportal.ws.model.BatchSaveOperatingRS; +import com.epam.ta.reportportal.ws.model.Constants; +import com.epam.ta.reportportal.ws.model.EntryCreatedAsyncRS; +import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import io.swagger.annotations.ApiOperation; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Validator; +import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -34,19 +48,16 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import springfox.documentation.annotations.ApiIgnore; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Validator; -import java.util.Map; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; -import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; -import static com.epam.ta.reportportal.util.ControllerUtils.*; -import static org.springframework.http.HttpStatus.CREATED; - /** * @author Konstantin Antipin */ @@ -55,94 +66,104 @@ @PreAuthorize(ASSIGNED_TO_PROJECT) public class LogAsyncController { - private final ProjectExtractor projectExtractor; - private final CreateLogHandler createLogHandler; - private final Validator validator; + private final ProjectExtractor projectExtractor; + private final CreateLogHandler createLogHandler; + private final Validator validator; - @Autowired - public LogAsyncController(ProjectExtractor projectExtractor, @Qualifier("asyncCreateLogHandler") CreateLogHandler createLogHandler, Validator validator) { - this.projectExtractor = projectExtractor; - this.createLogHandler = createLogHandler; - this.validator = validator; - } + @Autowired + public LogAsyncController(ProjectExtractor projectExtractor, + @Qualifier("asyncCreateLogHandler") CreateLogHandler createLogHandler, Validator validator) { + this.projectExtractor = projectExtractor; + this.createLogHandler = createLogHandler; + this.validator = validator; + } - /** - * @deprecated in favour of {@link LogAsyncController#createLogEntry(String, SaveLogRQ, ReportPortalUser)} because of mapping collisions - */ - /* Report client API */ - @Deprecated - @HttpLogging - @PostMapping(consumes = { MediaType.APPLICATION_JSON_VALUE }) - @ResponseStatus(CREATED) - @ApiIgnore - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS createLog(@PathVariable String projectName, @RequestBody SaveLogRQ createLogRQ, - @AuthenticationPrincipal ReportPortalUser user) { - validateSaveRQ(validator, createLogRQ); - return createLogHandler.createLog(createLogRQ, null, projectExtractor.extractProjectDetails(user, projectName)); - } + /** + * @deprecated in favour of + * {@link LogAsyncController#createLogEntry(String, SaveLogRQ, ReportPortalUser)} because of + * mapping collisions + */ + /* Report client API */ + @Deprecated + @HttpLogging + @PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(CREATED) + @ApiIgnore + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS createLog(@PathVariable String projectName, + @RequestBody SaveLogRQ createLogRQ, + @AuthenticationPrincipal ReportPortalUser user) { + validateSaveRQ(validator, createLogRQ); + return createLogHandler.createLog(createLogRQ, null, + projectExtractor.extractProjectDetails(user, projectName)); + } - @HttpLogging - @PostMapping(value = "/entry", consumes = { MediaType.APPLICATION_JSON_VALUE }) - @ResponseStatus(CREATED) - @ApiOperation("Create log") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS createLogEntry(@PathVariable String projectName, @RequestBody SaveLogRQ createLogRQ, - @AuthenticationPrincipal ReportPortalUser user) { - validateSaveRQ(validator, createLogRQ); - return createLogHandler.createLog(createLogRQ, null, projectExtractor.extractProjectDetails(user, projectName)); - } + @HttpLogging + @PostMapping(value = "/entry", consumes = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(CREATED) + @ApiOperation("Create log") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS createLogEntry(@PathVariable String projectName, + @RequestBody SaveLogRQ createLogRQ, + @AuthenticationPrincipal ReportPortalUser user) { + validateSaveRQ(validator, createLogRQ); + return createLogHandler.createLog(createLogRQ, null, + projectExtractor.extractProjectDetails(user, projectName)); + } - @HttpLogging - @PostMapping(consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) - @ApiOperation("Create log (batching operation)") - // Specific handler should be added for springfox in case of similar POST - // request mappings - // @Async - @PreAuthorize(ALLOWED_TO_REPORT) - public ResponseEntity<BatchSaveOperatingRS> createLog(@PathVariable String projectName, - @RequestPart(value = Constants.LOG_REQUEST_JSON_PART) SaveLogRQ[] createLogRQs, HttpServletRequest request, - @AuthenticationPrincipal ReportPortalUser user) { + @HttpLogging + @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @ApiOperation("Create log (batching operation)") + // Specific handler should be added for springfox in case of similar POST + // request mappings + // @Async + @PreAuthorize(ALLOWED_TO_REPORT) + public ResponseEntity<BatchSaveOperatingRS> createLog(@PathVariable String projectName, + @RequestPart(value = Constants.LOG_REQUEST_JSON_PART) SaveLogRQ[] createLogRQs, + HttpServletRequest request, + @AuthenticationPrincipal ReportPortalUser user) { - /* - * Since this is multipart request we can retrieve list of uploaded - * attachments - */ - Map<String, MultipartFile> uploadedFiles = getUploadedFiles(request); - BatchSaveOperatingRS response = new BatchSaveOperatingRS(); - EntryCreatedAsyncRS responseItem; - /* Go through all provided save log request items */ - for (SaveLogRQ createLogRq : createLogRQs) { - try { - validateSaveRQ(validator, createLogRq); - String filename = createLogRq.getFile() == null ? null : createLogRq.getFile().getName(); - if (StringUtils.isEmpty(filename)) { - /* - * There is no filename in request. Use simple save - * method - */ - responseItem = createLog(projectName, createLogRq, user); + /* + * Since this is multipart request we can retrieve list of uploaded + * attachments + */ + MultiValuedMap<String, MultipartFile> uploadedFiles = getUploadedFiles(request); + BatchSaveOperatingRS response = new BatchSaveOperatingRS(); + EntryCreatedAsyncRS responseItem; + /* Go through all provided save log request items */ + for (SaveLogRQ createLogRq : createLogRQs) { + try { + validateSaveRQ(validator, createLogRq); + String filename = createLogRq.getFile() == null ? null : createLogRq.getFile().getName(); + if (StringUtils.isEmpty(filename)) { + /* + * There is no filename in request. Use simple save + * method + */ + responseItem = createLog(projectName, createLogRq, user); - } else { - /* Find by request part */ - MultipartFile data = findByFileName(filename, uploadedFiles); - BusinessRule.expect(data, Predicates.notNull()).verify( - ErrorType.BINARY_DATA_CANNOT_BE_SAVED, - Suppliers.formattedSupplier("There is no request part or file with name {}", filename) - ); - /* - * If provided content type is null or this is octet - * stream, try to detect real content type of binary - * data - */ - //noinspection ConstantConditions - responseItem = createLogHandler.createLog(createLogRq, data, projectExtractor.extractProjectDetails(user, projectName)); - } - response.addResponse(new BatchElementCreatedRS(responseItem.getId())); - } catch (Exception e) { - response.addResponse(new BatchElementCreatedRS(ExceptionUtils.getStackTrace(e), ExceptionUtils.getMessage(e))); - } - } - return new ResponseEntity<>(response, CREATED); - } + } else { + /* Find by request part */ + MultipartFile data = findByFileName(filename, uploadedFiles); + BusinessRule.expect(data, Predicates.notNull()).verify( + ErrorType.BINARY_DATA_CANNOT_BE_SAVED, + Suppliers.formattedSupplier("There is no request part or file with name {}", filename) + ); + /* + * If provided content type is null or this is octet + * stream, try to detect real content type of binary + * data + */ + //noinspection ConstantConditions + responseItem = createLogHandler.createLog(createLogRq, data, + projectExtractor.extractProjectDetails(user, projectName)); + } + response.addResponse(new BatchElementCreatedRS(responseItem.getId())); + } catch (Exception e) { + response.addResponse(new BatchElementCreatedRS(ExceptionUtils.getStackTrace(e), + ExceptionUtils.getMessage(e))); + } + } + return new ResponseEntity<>(response, CREATED); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/LogController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/LogController.java index 425c3aaa71..c55898dc0d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/LogController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/LogController.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.commons.querygen.Condition.UNDR; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; +import static com.epam.ta.reportportal.util.ControllerUtils.findByFileName; +import static com.epam.ta.reportportal.util.ControllerUtils.getUploadedFiles; +import static com.epam.ta.reportportal.util.ControllerUtils.validateSaveRQ; +import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; @@ -28,13 +39,28 @@ import com.epam.ta.reportportal.core.log.impl.PagedLogResource; import com.epam.ta.reportportal.entity.log.Log; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.model.*; -import com.epam.ta.reportportal.ws.model.log.*; +import com.epam.ta.reportportal.ws.model.BatchElementCreatedRS; +import com.epam.ta.reportportal.ws.model.BatchSaveOperatingRS; +import com.epam.ta.reportportal.ws.model.Constants; +import com.epam.ta.reportportal.ws.model.EntryCreatedAsyncRS; +import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.log.GetLogsUnderRq; +import com.epam.ta.reportportal.ws.model.log.LogResource; +import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import com.epam.ta.reportportal.ws.model.log.SearchLogRq; +import com.epam.ta.reportportal.ws.model.log.SearchLogRs; import com.epam.ta.reportportal.ws.resolver.FilterFor; import com.epam.ta.reportportal.ws.resolver.SortFor; import com.google.common.collect.ImmutableMap; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Validator; +import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -45,25 +71,19 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import springfox.documentation.annotations.ApiIgnore; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Validator; -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; -import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; -import static com.epam.ta.reportportal.commons.querygen.Condition.UNDR; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; -import static com.epam.ta.reportportal.util.ControllerUtils.*; -import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; - /** * @author Pavel Bortnik */ @@ -72,179 +92,214 @@ @PreAuthorize(ASSIGNED_TO_PROJECT) public class LogController { - private final ProjectExtractor projectExtractor; - private final CreateLogHandler createLogHandler; - private final DeleteLogHandler deleteLogHandler; - private final GetLogHandler getLogHandler; - private final SearchLogService searchLogService; - private final Validator validator; - - @Autowired - public LogController(ProjectExtractor projectExtractor, @Autowired CreateLogHandler createLogHandler, DeleteLogHandler deleteLogHandler, GetLogHandler getLogHandler, - SearchLogService searchLogService, Validator validator) { - this.projectExtractor = projectExtractor; - this.createLogHandler = createLogHandler; - this.deleteLogHandler = deleteLogHandler; - this.getLogHandler = getLogHandler; - this.searchLogService = searchLogService; - this.validator = validator; - } - - /** - * @deprecated in favour of {@link LogController#createLogEntry(String, SaveLogRQ, ReportPortalUser)} because of mapping collisions - */ - /* Report client API */ - @Deprecated - @PostMapping(consumes = { MediaType.APPLICATION_JSON_VALUE }) - @ResponseStatus(CREATED) - @ApiIgnore - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS createLog(@PathVariable String projectName, @RequestBody SaveLogRQ createLogRQ, - @AuthenticationPrincipal ReportPortalUser user) { - validateSaveRQ(validator, createLogRQ); - return createLogHandler.createLog(createLogRQ, null, projectExtractor.extractProjectDetails(user, projectName)); - } - - /* Report client API */ - @PostMapping(value = "/entry", consumes = { MediaType.APPLICATION_JSON_VALUE }) - @ResponseStatus(CREATED) - @ApiOperation("Create log") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS createLogEntry(@PathVariable String projectName, @RequestBody SaveLogRQ createLogRQ, - @AuthenticationPrincipal ReportPortalUser user) { - validateSaveRQ(validator, createLogRQ); - return createLogHandler.createLog(createLogRQ, null, projectExtractor.extractProjectDetails(user, projectName)); - } - - @PostMapping(consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) - @ApiOperation("Create log (batching operation)") - // Specific handler should be added for springfox in case of similar POST - // request mappings - // @Async - @PreAuthorize(ALLOWED_TO_REPORT) - public ResponseEntity<BatchSaveOperatingRS> createLog(@PathVariable String projectName, - @RequestPart(value = Constants.LOG_REQUEST_JSON_PART) SaveLogRQ[] createLogRQs, HttpServletRequest request, - @AuthenticationPrincipal ReportPortalUser user) { - - /* - * Since this is multipart request we can retrieve list of uploaded - * attachments - */ - Map<String, MultipartFile> uploadedFiles = getUploadedFiles(request); - BatchSaveOperatingRS response = new BatchSaveOperatingRS(); - EntryCreatedAsyncRS responseItem; - /* Go through all provided save log request items */ - for (SaveLogRQ createLogRq : createLogRQs) { - try { - validateSaveRQ(validator, createLogRq); - String filename = createLogRq.getFile() == null ? null : createLogRq.getFile().getName(); - if (StringUtils.isEmpty(filename)) { - /* - * There is no filename in request. Use simple save - * method - */ - responseItem = createLog(projectName, createLogRq, user); - - } else { - /* Find by request part */ - MultipartFile data = findByFileName(filename, uploadedFiles); - BusinessRule.expect(data, Predicates.notNull()).verify(ErrorType.BINARY_DATA_CANNOT_BE_SAVED, - Suppliers.formattedSupplier("There is no request part or file with name {}", filename) - ); - /* - * If provided content type is null or this is octet - * stream, try to detect real content type of binary - * data - */ - //noinspection ConstantConditions - responseItem = createLogHandler.createLog(createLogRq, data, projectExtractor.extractProjectDetails(user, projectName)); - } - response.addResponse(new BatchElementCreatedRS(responseItem.getId())); - } catch (Exception e) { - response.addResponse(new BatchElementCreatedRS(ExceptionUtils.getStackTrace(e), ExceptionUtils.getMessage(e))); - } - } - return new ResponseEntity<>(response, CREATED); - } - - - /* Frontend API */ - - @RequestMapping(value = "/{logId}", method = RequestMethod.DELETE) - @ApiOperation("Delete log") - @Transactional - public OperationCompletionRS deleteLog(@PathVariable String projectName, @PathVariable Long logId, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteLogHandler.deleteLog(logId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @RequestMapping(method = RequestMethod.GET) - @ApiOperation("Get logs by filter") - @Transactional(readOnly = true) - public Iterable<LogResource> getLogs(@PathVariable String projectName, - @RequestParam(value = DEFAULT_FILTER_PREFIX + UNDR + CRITERIA_PATH, required = false) String underPath, - @FilterFor(Log.class) Filter filter, - @SortDefault({ "logTime" }) @SortFor(Log.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getLogs(underPath, projectExtractor.extractProjectDetails(user, projectName), filter, pageable); - } - - @PostMapping(value = "/under") - @ApiOperation("Get logs under items") - @Transactional(readOnly = true) - public Map<Long, List<LogResource>> getLogsUnder(@PathVariable String projectName, - @RequestBody GetLogsUnderRq logsUnderRq, @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getLogs(logsUnderRq, projectExtractor.extractProjectDetails(user, projectName)); - } - - @GetMapping(value = "/{logId}/page") - @ApiOperation("Get logs by filter") - @Transactional(readOnly = true) - public Map<String, Serializable> getPageNumber(@PathVariable String projectName, @PathVariable Long logId, - @FilterFor(Log.class) Filter filter, @SortFor(Log.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return ImmutableMap.<String, Serializable>builder().put("number", - getLogHandler.getPageNumber(logId, projectExtractor.extractProjectDetails(user, projectName), filter, pageable) - ).build(); - } - - @GetMapping(value = "/{logId}") - @ApiOperation("Get log by ID") - @Transactional(readOnly = true) - public LogResource getLog(@PathVariable String projectName, @PathVariable String logId, - @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getLog(logId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @GetMapping(value = "/uuid/{logId}") - @ApiOperation("Get log by UUID") - @Transactional(readOnly = true) - public LogResource getLogByUuid(@PathVariable String projectName, @PathVariable String logId, - @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getLog(logId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @GetMapping(value = "/nested/{parentId}") - @ApiOperation("Get nested steps with logs for the parent Test Item") - @Transactional(readOnly = true) - public Iterable<?> getNestedItems(@PathVariable String projectName, @PathVariable Long parentId, - @ApiParam(required = false) @RequestParam Map<String, String> params, @FilterFor(Log.class) Filter filter, - @SortFor(Log.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getNestedItems(parentId, projectExtractor.extractProjectDetails(user, projectName), params, filter, pageable); - } - - @GetMapping(value = "/locations/{parentId}") - @ApiOperation("Get next or previous log in test item") - @Transactional(readOnly = true) - public List<PagedLogResource> getErrorPage(@PathVariable String projectName, @PathVariable Long parentId, @RequestParam Map<String, String> params, - @FilterFor(Log.class) Filter filter, @SortFor(Log.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getLogHandler.getLogsWithLocation(parentId, projectExtractor.extractProjectDetails(user, projectName), params, filter, pageable); - } - - @PostMapping("search/{itemId}") - @ResponseStatus(OK) - @ApiOperation("Search test items with similar error logs") - public Iterable<SearchLogRs> searchLogs(@PathVariable String projectName, @RequestBody SearchLogRq request, @PathVariable Long itemId, - @AuthenticationPrincipal ReportPortalUser user) { - return searchLogService.search(itemId, request, projectExtractor.extractProjectDetails(user, projectName)); - } + private final ProjectExtractor projectExtractor; + private final CreateLogHandler createLogHandler; + private final DeleteLogHandler deleteLogHandler; + private final GetLogHandler getLogHandler; + private final SearchLogService searchLogService; + private final Validator validator; + + @Autowired + public LogController(ProjectExtractor projectExtractor, + @Autowired CreateLogHandler createLogHandler, DeleteLogHandler deleteLogHandler, + GetLogHandler getLogHandler, + SearchLogService searchLogService, Validator validator) { + this.projectExtractor = projectExtractor; + this.createLogHandler = createLogHandler; + this.deleteLogHandler = deleteLogHandler; + this.getLogHandler = getLogHandler; + this.searchLogService = searchLogService; + this.validator = validator; + } + + /** + * @deprecated in favour of + * {@link LogController#createLogEntry(String, SaveLogRQ, ReportPortalUser)} because of mapping + * collisions + */ + /* Report client API */ + @Deprecated + @PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(CREATED) + @ApiIgnore + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS createLog(@PathVariable String projectName, + @RequestBody SaveLogRQ createLogRQ, + @AuthenticationPrincipal ReportPortalUser user) { + validateSaveRQ(validator, createLogRQ); + return createLogHandler.createLog(createLogRQ, null, + projectExtractor.extractProjectDetails(user, projectName)); + } + + /* Report client API */ + @PostMapping(value = "/entry", consumes = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(CREATED) + @ApiOperation("Create log") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS createLogEntry(@PathVariable String projectName, + @RequestBody SaveLogRQ createLogRQ, + @AuthenticationPrincipal ReportPortalUser user) { + validateSaveRQ(validator, createLogRQ); + return createLogHandler.createLog(createLogRQ, null, + projectExtractor.extractProjectDetails(user, projectName)); + } + + @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @ApiOperation("Create log (batching operation)") + // Specific handler should be added for springfox in case of similar POST + // request mappings + // @Async + @PreAuthorize(ALLOWED_TO_REPORT) + public ResponseEntity<BatchSaveOperatingRS> createLog(@PathVariable String projectName, + @RequestPart(value = Constants.LOG_REQUEST_JSON_PART) SaveLogRQ[] createLogRQs, + HttpServletRequest request, + @AuthenticationPrincipal ReportPortalUser user) { + + /* + * Since this is multipart request we can retrieve list of uploaded + * attachments + */ + MultiValuedMap<String, MultipartFile> uploadedFiles = getUploadedFiles(request); + BatchSaveOperatingRS response = new BatchSaveOperatingRS(); + EntryCreatedAsyncRS responseItem; + /* Go through all provided save log request items */ + for (SaveLogRQ createLogRq : createLogRQs) { + try { + validateSaveRQ(validator, createLogRq); + String filename = createLogRq.getFile() == null ? null : createLogRq.getFile().getName(); + if (StringUtils.isEmpty(filename)) { + /* + * There is no filename in request. Use simple save + * method + */ + responseItem = createLog(projectName, createLogRq, user); + + } else { + /* Find by request part */ + MultipartFile data = findByFileName(filename, uploadedFiles); + BusinessRule.expect(data, Predicates.notNull()) + .verify(ErrorType.BINARY_DATA_CANNOT_BE_SAVED, + Suppliers.formattedSupplier("There is no request part or file with name {}", + filename) + ); + /* + * If provided content type is null or this is octet + * stream, try to detect real content type of binary + * data + */ + //noinspection ConstantConditions + responseItem = createLogHandler.createLog(createLogRq, data, + projectExtractor.extractProjectDetails(user, projectName)); + } + response.addResponse(new BatchElementCreatedRS(responseItem.getId())); + } catch (Exception e) { + response.addResponse(new BatchElementCreatedRS(ExceptionUtils.getStackTrace(e), + ExceptionUtils.getMessage(e))); + } + } + return new ResponseEntity<>(response, CREATED); + } + + + /* Frontend API */ + + @RequestMapping(value = "/{logId}", method = RequestMethod.DELETE) + @ApiOperation("Delete log") + @Transactional + public OperationCompletionRS deleteLog(@PathVariable String projectName, @PathVariable Long logId, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteLogHandler.deleteLog(logId, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @RequestMapping(method = RequestMethod.GET) + @ApiOperation("Get logs by filter") + @Transactional(readOnly = true) + public Iterable<LogResource> getLogs(@PathVariable String projectName, + @RequestParam(value = DEFAULT_FILTER_PREFIX + UNDR + + CRITERIA_PATH, required = false) String underPath, + @FilterFor(Log.class) Filter filter, + @SortDefault({"logTime"}) @SortFor(Log.class) Pageable pageable, + @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getLogs(underPath, + projectExtractor.extractProjectDetails(user, projectName), filter, pageable); + } + + @PostMapping(value = "/under") + @ApiOperation("Get logs under items") + @Transactional(readOnly = true) + public Map<Long, List<LogResource>> getLogsUnder(@PathVariable String projectName, + @RequestBody GetLogsUnderRq logsUnderRq, @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getLogs(logsUnderRq, + projectExtractor.extractProjectDetails(user, projectName)); + } + + @GetMapping(value = "/{logId}/page") + @ApiOperation("Get logs by filter") + @Transactional(readOnly = true) + public Map<String, Serializable> getPageNumber(@PathVariable String projectName, + @PathVariable Long logId, + @FilterFor(Log.class) Filter filter, @SortFor(Log.class) Pageable pageable, + @AuthenticationPrincipal ReportPortalUser user) { + return ImmutableMap.<String, Serializable>builder().put("number", + getLogHandler.getPageNumber(logId, + projectExtractor.extractProjectDetails(user, projectName), filter, pageable) + ).build(); + } + + @GetMapping(value = "/{logId}") + @ApiOperation("Get log by ID") + @Transactional(readOnly = true) + public LogResource getLog(@PathVariable String projectName, @PathVariable String logId, + @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getLog(logId, projectExtractor.extractProjectDetails(user, projectName), + user); + } + + /** + * @deprecated Need to remove in version 6.0. This API significantly impacts database performance + * - high IO operations on getting log record by UUID from production-like database amount. + */ + @Deprecated(since = "5.8", forRemoval = true) + @GetMapping(value = "/uuid/{logId}") + @ApiOperation("Get log by UUID (Will be removed in version 6.0)") + @Transactional(readOnly = true) + public LogResource getLogByUuid(@PathVariable String projectName, @PathVariable String logId, + @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getLog(logId, projectExtractor.extractProjectDetails(user, projectName), + user); + } + + @GetMapping(value = "/nested/{parentId}") + @ApiOperation("Get nested steps with logs for the parent Test Item") + @Transactional(readOnly = true) + public Iterable<?> getNestedItems(@PathVariable String projectName, @PathVariable Long parentId, + @ApiParam(required = false) @RequestParam Map<String, String> params, + @FilterFor(Log.class) Filter filter, + @SortFor(Log.class) Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getNestedItems(parentId, + projectExtractor.extractProjectDetails(user, projectName), params, filter, pageable); + } + + @GetMapping(value = "/locations/{parentId}") + @ApiOperation("Get next or previous log in test item") + @Transactional(readOnly = true) + public List<PagedLogResource> getErrorPage(@PathVariable String projectName, + @PathVariable Long parentId, @RequestParam Map<String, String> params, + @FilterFor(Log.class) Filter filter, @SortFor(Log.class) Pageable pageable, + @AuthenticationPrincipal ReportPortalUser user) { + return getLogHandler.getLogsWithLocation(parentId, + projectExtractor.extractProjectDetails(user, projectName), params, filter, pageable); + } + + @PostMapping("search/{itemId}") + @ResponseStatus(OK) + @ApiOperation("Search test items with similar error logs") + public Iterable<SearchLogRs> searchLogs(@PathVariable String projectName, + @RequestBody SearchLogRq request, @PathVariable Long itemId, + @AuthenticationPrincipal ReportPortalUser user) { + return searchLogService.search(itemId, request, + projectExtractor.extractProjectDetails(user, projectName)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/OnboardingController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/OnboardingController.java index e30680e4a1..92aebdda3a 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/OnboardingController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/OnboardingController.java @@ -29,15 +29,16 @@ @RequestMapping("/v1/onboarding") public class OnboardingController { - private final OnboardingService onboardingService; + private final OnboardingService onboardingService; - public OnboardingController(OnboardingService onboardingService) { - this.onboardingService = onboardingService; - } + public OnboardingController(OnboardingService onboardingService) { + this.onboardingService = onboardingService; + } - /** - * Provide unstructured onboarding information. Possible json or string(html, js, etc), or something else. - */ + /** + * Provide unstructured onboarding information. Possible json or string(html, js, etc), or + * something else. + */ @GetMapping(value = { "" }) @ApiOperation("Return onboarding information for page if available, -1 otherwise") public Object onBoarding(@RequestParam(value = "page", defaultValue = "GENERAL") String page) { diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/PluginPublicController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/PluginPublicController.java new file mode 100644 index 0000000000..b616ce2210 --- /dev/null +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/PluginPublicController.java @@ -0,0 +1,85 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.ws.controller; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import com.epam.ta.reportportal.core.integration.ExecuteIntegrationHandler; +import com.epam.ta.reportportal.core.integration.plugin.GetPluginHandler; +import com.epam.ta.reportportal.core.integration.plugin.binary.PluginFilesProvider; +import com.epam.ta.reportportal.entity.attachment.BinaryData; +import com.epam.ta.reportportal.util.BinaryDataResponseWriter; +import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; +import io.swagger.annotations.ApiOperation; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +@RestController +@RequestMapping(value = "/v1/plugin/public") +public class PluginPublicController { + + private final PluginFilesProvider pluginPublicFilesProvider; + private final BinaryDataResponseWriter binaryDataResponseWriter; + private final ExecuteIntegrationHandler executeIntegrationHandler; + private final GetPluginHandler getPluginHandler; + + public PluginPublicController(PluginFilesProvider pluginPublicFilesProvider, + BinaryDataResponseWriter binaryDataResponseWriter, + ExecuteIntegrationHandler executeIntegrationHandler, GetPluginHandler getPluginHandler) { + this.pluginPublicFilesProvider = pluginPublicFilesProvider; + this.binaryDataResponseWriter = binaryDataResponseWriter; + this.executeIntegrationHandler = executeIntegrationHandler; + this.getPluginHandler = getPluginHandler; + } + + @GetMapping(value = "/{pluginName}/file/{name}") + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get public plugin file without authentication") + public void getPublicFile(@PathVariable(value = "pluginName") String pluginName, + @PathVariable(value = "name") String fileName, + HttpServletResponse response) { + final BinaryData binaryData = pluginPublicFilesProvider.load(pluginName, fileName); + binaryDataResponseWriter.write(binaryData, response); + } + + @PutMapping(value = "/{pluginName}/{command}", consumes = {APPLICATION_JSON_VALUE}) + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Execute public command without authentication") + public Object executePublicPluginCommand(@PathVariable("pluginName") String pluginName, + @PathVariable("command") String command, @RequestBody Map<String, Object> executionParams) { + return executeIntegrationHandler.executePublicCommand(pluginName, command, executionParams); + } + + @GetMapping + @ResponseStatus(HttpStatus.OK) + @ApiOperation("Get all available public plugins") + public List<IntegrationTypeResource> getPlugins() { + return getPluginHandler.getPublicPlugins(); + } +} diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsController.java index 491ea0b9a7..f4cc134fbf 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsController.java @@ -16,11 +16,23 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER_OR_ADMIN; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.project.GetProjectHandler; import com.epam.ta.reportportal.core.project.settings.CreateProjectSettingsHandler; import com.epam.ta.reportportal.core.project.settings.DeleteProjectSettingsHandler; import com.epam.ta.reportportal.core.project.settings.GetProjectSettingsHandler; import com.epam.ta.reportportal.core.project.settings.UpdateProjectSettingsHandler; +import com.epam.ta.reportportal.core.project.settings.notification.CreateProjectNotificationHandler; +import com.epam.ta.reportportal.core.project.settings.notification.DeleteProjectNotificationHandler; +import com.epam.ta.reportportal.core.project.settings.notification.GetProjectNotificationsHandler; +import com.epam.ta.reportportal.core.project.settings.notification.UpdateProjectNotificationHandler; import com.epam.ta.reportportal.ws.model.EntryCreatedRS; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; @@ -29,22 +41,27 @@ import com.epam.ta.reportportal.ws.model.project.config.UpdateIssueSubTypeRQ; import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; import com.epam.ta.reportportal.ws.model.project.config.pattern.UpdatePatternTemplateRQ; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; import io.swagger.annotations.ApiOperation; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; -import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** - * Projects settings controller. - * Provides resources for manipulation of various project settings items. + * Projects settings controller. Provides resources for manipulation of various project settings + * items. * * @author Andrei_Ramanchuk */ @@ -53,82 +70,165 @@ @PreAuthorize(ASSIGNED_TO_PROJECT) public class ProjectSettingsController { - private final CreateProjectSettingsHandler createHandler; - - private final UpdateProjectSettingsHandler updateHandler; - - private final DeleteProjectSettingsHandler deleteHandler; - - private final GetProjectSettingsHandler getHandler; - - @Autowired - public ProjectSettingsController(CreateProjectSettingsHandler createHandler, UpdateProjectSettingsHandler updateHandler, - DeleteProjectSettingsHandler deleteHandler, GetProjectSettingsHandler getHandler) { - this.createHandler = createHandler; - this.updateHandler = updateHandler; - this.deleteHandler = deleteHandler; - this.getHandler = getHandler; - } - - @PostMapping("/sub-type") - @ResponseStatus(CREATED) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Creation of custom project specific issue sub-type") - public IssueSubTypeCreatedRS createProjectIssueSubType(@PathVariable String projectName, - @RequestBody @Validated CreateIssueSubTypeRQ request, @AuthenticationPrincipal ReportPortalUser user) { - return createHandler.createProjectIssueSubType(normalizeId(projectName), user, request); - } - - @PutMapping("/sub-type") - @ResponseStatus(OK) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Update of custom project specific issue sub-type") - public OperationCompletionRS updateProjectIssueSubType(@PathVariable String projectName, - @RequestBody @Validated UpdateIssueSubTypeRQ request, @AuthenticationPrincipal ReportPortalUser user) { - return updateHandler.updateProjectIssueSubType(normalizeId(projectName), user, request); - } - - @DeleteMapping("/sub-type/{id}") - @ResponseStatus(OK) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Delete custom project specific issue sub-type") - public OperationCompletionRS deleteProjectIssueSubType(@PathVariable String projectName, @PathVariable Long id, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteHandler.deleteProjectIssueSubType(normalizeId(projectName), user, id); - } - - @GetMapping - @ResponseStatus(OK) - @PreAuthorize(ASSIGNED_TO_PROJECT) - @ApiOperation(value = "Get project specific issue sub-types", notes = "Only for users that are assigned to the project") - public ProjectSettingsResource getProjectSettings(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user) { - return getHandler.getProjectSettings(normalizeId(projectName)); - } - - @PostMapping("/pattern") - @ResponseStatus(CREATED) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Create pattern template for items' log messages pattern analysis") - public EntryCreatedRS createPatternTemplate(@PathVariable String projectName, - @RequestBody @Validated CreatePatternTemplateRQ createPatternTemplateRQ, @AuthenticationPrincipal ReportPortalUser user) { - return createHandler.createPatternTemplate(normalizeId(projectName), createPatternTemplateRQ, user); - } - - @PutMapping("/pattern/{id}") - @ResponseStatus(OK) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Update pattern template for items' log messages pattern analysis") - public OperationCompletionRS updatePatternTemplate(@PathVariable String projectName, @PathVariable Long id, - @RequestBody @Validated UpdatePatternTemplateRQ updatePatternTemplateRQ, @AuthenticationPrincipal ReportPortalUser user) { - return updateHandler.updatePatternTemplate(id, normalizeId(projectName), updatePatternTemplateRQ, user); - } - - @DeleteMapping("/pattern/{id}") - @ResponseStatus(OK) - @PreAuthorize(PROJECT_MANAGER) - @ApiOperation("Delete pattern template for items' log messages pattern analysis") - public OperationCompletionRS deletePatternTemplate(@PathVariable String projectName, @PathVariable Long id, - @AuthenticationPrincipal ReportPortalUser user) { - return deleteHandler.deletePatternTemplate(normalizeId(projectName), user, id); - } + private final CreateProjectSettingsHandler createHandler; + + private final UpdateProjectSettingsHandler updateHandler; + + private final DeleteProjectSettingsHandler deleteHandler; + + private final GetProjectSettingsHandler getHandler; + + private final GetProjectHandler getProjectHandler; + + private final GetProjectNotificationsHandler getProjectNotificationsHandler; + + private final CreateProjectNotificationHandler createProjectNotificationHandler; + + private final UpdateProjectNotificationHandler updateProjectNotificationHandler; + + private final DeleteProjectNotificationHandler deleteNotificationHandler; + + @Autowired + public ProjectSettingsController(CreateProjectSettingsHandler createHandler, + UpdateProjectSettingsHandler updateHandler, + DeleteProjectSettingsHandler deleteHandler, GetProjectSettingsHandler getHandler, + GetProjectHandler getProjectHandler, + GetProjectNotificationsHandler getProjectNotificationsHandler, + CreateProjectNotificationHandler createProjectNotificationHandler, + UpdateProjectNotificationHandler updateProjectNotificationHandler, + DeleteProjectNotificationHandler deleteNotificationHandler) { + this.createHandler = createHandler; + this.updateHandler = updateHandler; + this.deleteHandler = deleteHandler; + this.getHandler = getHandler; + this.getProjectHandler = getProjectHandler; + this.getProjectNotificationsHandler = getProjectNotificationsHandler; + this.createProjectNotificationHandler = createProjectNotificationHandler; + this.updateProjectNotificationHandler = updateProjectNotificationHandler; + this.deleteNotificationHandler = deleteNotificationHandler; + } + + @PostMapping("/sub-type") + @ResponseStatus(CREATED) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Creation of custom project specific issue sub-type") + public IssueSubTypeCreatedRS createProjectIssueSubType(@PathVariable String projectName, + @RequestBody @Validated CreateIssueSubTypeRQ request, + @AuthenticationPrincipal ReportPortalUser user) { + return createHandler.createProjectIssueSubType(normalizeId(projectName), user, request); + } + + @PutMapping("/sub-type") + @ResponseStatus(OK) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Update of custom project specific issue sub-type") + public OperationCompletionRS updateProjectIssueSubType(@PathVariable String projectName, + @RequestBody @Validated UpdateIssueSubTypeRQ request, + @AuthenticationPrincipal ReportPortalUser user) { + return updateHandler.updateProjectIssueSubType(normalizeId(projectName), user, request); + } + + @DeleteMapping("/sub-type/{id}") + @ResponseStatus(OK) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Delete custom project specific issue sub-type") + public OperationCompletionRS deleteProjectIssueSubType(@PathVariable String projectName, + @PathVariable Long id, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteHandler.deleteProjectIssueSubType(normalizeId(projectName), user, id); + } + + @GetMapping + @ResponseStatus(OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation(value = "Get project specific issue sub-types", notes = "Only for users that are assigned to the project") + public ProjectSettingsResource getProjectSettings(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user) { + return getHandler.getProjectSettings(normalizeId(projectName)); + } + + @PostMapping("/pattern") + @ResponseStatus(CREATED) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Create pattern template for items' log messages pattern analysis") + public EntryCreatedRS createPatternTemplate(@PathVariable String projectName, + @RequestBody @Validated CreatePatternTemplateRQ createPatternTemplateRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return createHandler.createPatternTemplate(normalizeId(projectName), createPatternTemplateRQ, + user); + } + + @PutMapping("/pattern/{id}") + @ResponseStatus(OK) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Update pattern template for items' log messages pattern analysis") + public OperationCompletionRS updatePatternTemplate(@PathVariable String projectName, + @PathVariable Long id, + @RequestBody @Validated UpdatePatternTemplateRQ updatePatternTemplateRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateHandler.updatePatternTemplate(id, normalizeId(projectName), + updatePatternTemplateRQ, user); + } + + @DeleteMapping("/pattern/{id}") + @ResponseStatus(OK) + @PreAuthorize(PROJECT_MANAGER) + @ApiOperation("Delete pattern template for items' log messages pattern analysis") + public OperationCompletionRS deletePatternTemplate(@PathVariable String projectName, + @PathVariable Long id, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteHandler.deletePatternTemplate(normalizeId(projectName), user, id); + } + + @Transactional(readOnly = true) + @GetMapping("/notification") + @ResponseStatus(OK) + @PreAuthorize(ASSIGNED_TO_PROJECT) + @ApiOperation(value = "Returns notifications config of specified project", notes = "Only for users assigned to specified project") + public List<SenderCaseDTO> getNotifications(@PathVariable String projectName) { + return getProjectNotificationsHandler.getProjectNotifications( + getProjectHandler.get(normalizeId(projectName)).getId()); + } + + @Transactional + @PostMapping("/notification") + @ResponseStatus(CREATED) + @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) + @ApiOperation(value = "Creates notification for specified project", notes = "Only for users with PROJECT_MANAGER or ADMIN roles") + public EntryCreatedRS createNotification(@PathVariable String projectName, + @RequestBody @Validated SenderCaseDTO createNotificationRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return createProjectNotificationHandler.createNotification( + getProjectHandler.get(normalizeId(projectName)), + createNotificationRQ, + user + ); + } + + @Transactional + @PutMapping("/notification") + @ResponseStatus(CREATED) + @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) + @ApiOperation(value = "Updates notification for specified project", notes = "Only for users with PROJECT_MANAGER or ADMIN roles") + public OperationCompletionRS updateNotification(@PathVariable String projectName, + @RequestBody @Validated SenderCaseDTO updateNotificationRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateProjectNotificationHandler.updateNotification( + getProjectHandler.get(normalizeId(projectName)), + updateNotificationRQ, + user + ); + } + + @Transactional + @DeleteMapping("/notification/{notificationId:\\d+}") + @ResponseStatus(OK) + @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) + @ApiOperation(value = "Deletes notification for specified project", notes = "Only for users with PROJECT_MANAGER or ADMIN roles") + public OperationCompletionRS deleteNotification(@PathVariable String projectName, + @PathVariable Long notificationId, + @AuthenticationPrincipal ReportPortalUser user) { + return deleteNotificationHandler.deleteNotification( + getProjectHandler.get(normalizeId(projectName)), notificationId, user); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/SettingsController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/SettingsController.java index fd5149a070..f9726ff2df 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/SettingsController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/SettingsController.java @@ -16,22 +16,26 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.admin.ServerAdminHandler; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.settings.AnalyticsResource; import io.swagger.annotations.ApiOperation; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ADMIN_ONLY; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** * @author Andrei_Ramanchuk @@ -42,27 +46,28 @@ @PreAuthorize(ADMIN_ONLY) public class SettingsController { - private final ServerAdminHandler serverHandler; + private final ServerAdminHandler serverHandler; - @Autowired - public SettingsController(ServerAdminHandler serverHandler) { - this.serverHandler = serverHandler; - } + @Autowired + public SettingsController(ServerAdminHandler serverHandler) { + this.serverHandler = serverHandler; + } - @Transactional - @RequestMapping(value = "/analytics", method = { RequestMethod.PUT, RequestMethod.POST }) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Update analytics settings") - public OperationCompletionRS saveAnalyticsSettings(@RequestBody @Validated AnalyticsResource request, - @AuthenticationPrincipal ReportPortalUser user) { - return serverHandler.saveAnalyticsSettings(request); - } + @Transactional + @RequestMapping(value = "/analytics", method = {RequestMethod.PUT, RequestMethod.POST}) + @ResponseStatus(HttpStatus.OK) + @ApiOperation(value = "Update analytics settings") + public OperationCompletionRS saveAnalyticsSettings( + @RequestBody @Validated AnalyticsResource request, + @AuthenticationPrincipal ReportPortalUser user) { + return serverHandler.saveAnalyticsSettings(request); + } - @Transactional(readOnly = true) - @GetMapping - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "Get server settings") - public Map<String, String> getServerSettings(@AuthenticationPrincipal ReportPortalUser user) { - return serverHandler.getServerSettings(); - } + @Transactional(readOnly = true) + @GetMapping + @ResponseStatus(HttpStatus.OK) + @ApiOperation(value = "Get server settings") + public Map<String, String> getServerSettings(@AuthenticationPrincipal ReportPortalUser user) { + return serverHandler.getServerSettings(); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncController.java index 67a59c59ce..0b234f8aa5 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncController.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; import com.epam.ta.reportportal.core.item.StartTestItemHandler; @@ -31,12 +36,13 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; -import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** * Controller implementation for async reporting client API for @@ -50,46 +56,53 @@ @PreAuthorize(ASSIGNED_TO_PROJECT) public class TestItemAsyncController { - private final ProjectExtractor projectExtractor; - private final StartTestItemHandler startTestItemHandler; - private final FinishTestItemHandler finishTestItemHandler; + private final ProjectExtractor projectExtractor; + private final StartTestItemHandler startTestItemHandler; + private final FinishTestItemHandler finishTestItemHandler; - @Autowired - public TestItemAsyncController(ProjectExtractor projectExtractor, @Qualifier("startTestItemHandlerAsync") StartTestItemHandler startTestItemHandler, - @Qualifier("finishTestItemHandlerAsync") FinishTestItemHandler finishTestItemHandler) { - this.projectExtractor = projectExtractor; - this.startTestItemHandler = startTestItemHandler; - this.finishTestItemHandler = finishTestItemHandler; - } + @Autowired + public TestItemAsyncController(ProjectExtractor projectExtractor, + @Qualifier("startTestItemHandlerAsync") StartTestItemHandler startTestItemHandler, + @Qualifier("finishTestItemHandlerAsync") FinishTestItemHandler finishTestItemHandler) { + this.projectExtractor = projectExtractor; + this.startTestItemHandler = startTestItemHandler; + this.finishTestItemHandler = finishTestItemHandler; + } - @HttpLogging - @PostMapping - @ResponseStatus(CREATED) - @ApiOperation("Start a root test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS startRootItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestBody @Validated StartTestItemRQ startTestItemRQ) { - return startTestItemHandler.startRootItem(user, projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ); - } + @HttpLogging + @PostMapping + @ResponseStatus(CREATED) + @ApiOperation("Start a root test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS startRootItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated StartTestItemRQ startTestItemRQ) { + return startTestItemHandler.startRootItem(user, + projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ); + } - @HttpLogging - @PostMapping("/{parentItem}") - @ResponseStatus(CREATED) - @ApiOperation("Start a child test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS startChildItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String parentItem, @RequestBody @Validated StartTestItemRQ startTestItemRQ) { - return startTestItemHandler.startChildItem(user, projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ, parentItem); - } + @HttpLogging + @PostMapping("/{parentItem}") + @ResponseStatus(CREATED) + @ApiOperation("Start a child test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS startChildItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String parentItem, @RequestBody @Validated StartTestItemRQ startTestItemRQ) { + return startTestItemHandler.startChildItem(user, + projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ, parentItem); + } - @HttpLogging - @PutMapping("/{testItemId}") - @ResponseStatus(OK) - @ApiOperation("Finish test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public OperationCompletionRS finishTestItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String testItemId, @RequestBody @Validated FinishTestItemRQ finishExecutionRQ) { - return finishTestItemHandler.finishTestItem(user, projectExtractor.extractProjectDetails(user, projectName), testItemId, finishExecutionRQ); - } + @HttpLogging + @PutMapping("/{testItemId}") + @ResponseStatus(OK) + @ApiOperation("Finish test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public OperationCompletionRS finishTestItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String testItemId, @RequestBody @Validated FinishTestItemRQ finishExecutionRQ) { + return finishTestItemHandler.finishTestItem(user, + projectExtractor.extractProjectDetails(user, projectName), testItemId, finishExecutionRQ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemController.java index 9a8854cba7..ae6cf080ab 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/TestItemController.java @@ -16,6 +16,21 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ALLOWED_TO_REPORT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.ASSIGNED_TO_PROJECT; +import static com.epam.ta.reportportal.auth.permissions.Permissions.PROJECT_MANAGER_OR_ADMIN; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_NAME; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_ITEM_ATTRIBUTE_KEY; +import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_ITEM_ATTRIBUTE_VALUE; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PARENT_ID; +import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; +import static java.util.Optional.ofNullable; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.CompositeFilter; import com.epam.ta.reportportal.commons.querygen.Condition; @@ -24,12 +39,22 @@ import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; import com.epam.ta.reportportal.core.analyzer.auto.impl.SuggestItemService; import com.epam.ta.reportportal.core.analyzer.auto.impl.SuggestedItem; -import com.epam.ta.reportportal.core.item.*; +import com.epam.ta.reportportal.core.item.DeleteTestItemHandler; +import com.epam.ta.reportportal.core.item.FinishTestItemHandler; +import com.epam.ta.reportportal.core.item.GetTestItemHandler; +import com.epam.ta.reportportal.core.item.StartTestItemHandler; +import com.epam.ta.reportportal.core.item.UpdateTestItemHandler; import com.epam.ta.reportportal.core.item.history.TestItemsHistoryHandler; import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.model.*; +import com.epam.ta.reportportal.ws.model.BulkInfoUpdateRQ; +import com.epam.ta.reportportal.ws.model.EntryCreatedAsyncRS; +import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import com.epam.ta.reportportal.ws.model.TestItemHistoryElement; +import com.epam.ta.reportportal.ws.model.TestItemResource; import com.epam.ta.reportportal.ws.model.issue.DefineIssueRQ; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.item.LinkExternalIssueRQ; @@ -39,6 +64,11 @@ import com.epam.ta.reportportal.ws.resolver.FilterFor; import com.epam.ta.reportportal.ws.resolver.SortFor; import io.swagger.annotations.ApiOperation; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; @@ -47,377 +77,437 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Nullable; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.epam.ta.reportportal.auth.permissions.Permissions.*; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.*; -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_ITEM_ATTRIBUTE_KEY; -import static com.epam.ta.reportportal.commons.querygen.constant.ItemAttributeConstant.CRITERIA_ITEM_ATTRIBUTE_VALUE; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PARENT_ID; -import static com.epam.ta.reportportal.ws.resolver.FilterCriteriaResolver.DEFAULT_FILTER_PREFIX; -import static java.util.Optional.ofNullable; -import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.OK; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; /** - * Controller implementation for - * {@link com.epam.ta.reportportal.entity.item.TestItem} entity - * <p> + * Controller implementation for {@link com.epam.ta.reportportal.entity.item.TestItem} entity */ @RestController @RequestMapping("/v1/{projectName}/item") @PreAuthorize(ASSIGNED_TO_PROJECT) public class TestItemController { - public static final String HISTORY_TYPE_PARAM = "type"; - public static final String FILTER_ID_REQUEST_PARAM = "filterId"; - public static final String IS_LATEST_LAUNCHES_REQUEST_PARAM = "isLatest"; - public static final String LAUNCHES_LIMIT_REQUEST_PARAM = "launchesLimit"; - private static final String HISTORY_DEPTH_PARAM = "historyDepth"; - private static final String HISTORY_DEPTH_DEFAULT_VALUE = "5"; - private static final String LAUNCHES_LIMIT_DEFAULT_VALUE = "0"; - - private final ProjectExtractor projectExtractor; - private final StartTestItemHandler startTestItemHandler; - private final DeleteTestItemHandler deleteTestItemHandler; - private final FinishTestItemHandler finishTestItemHandler; - private final UpdateTestItemHandler updateTestItemHandler; - private final GetTestItemHandler getTestItemHandler; - private final TestItemsHistoryHandler testItemsHistoryHandler; - private final SuggestItemService suggestItemService; - - @Autowired - public TestItemController(ProjectExtractor projectExtractor, StartTestItemHandler startTestItemHandler, DeleteTestItemHandler deleteTestItemHandler, - FinishTestItemHandler finishTestItemHandler, UpdateTestItemHandler updateTestItemHandler, GetTestItemHandler getTestItemHandler, - TestItemsHistoryHandler testItemsHistoryHandler, SuggestItemService suggestItemService) { - this.projectExtractor = projectExtractor; - this.startTestItemHandler = startTestItemHandler; - this.deleteTestItemHandler = deleteTestItemHandler; - this.finishTestItemHandler = finishTestItemHandler; - this.updateTestItemHandler = updateTestItemHandler; - this.getTestItemHandler = getTestItemHandler; - this.testItemsHistoryHandler = testItemsHistoryHandler; - this.suggestItemService = suggestItemService; - } - - /* Report client API */ - - @PostMapping - @ResponseStatus(CREATED) - @ApiOperation("Start a root test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS startRootItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestBody @Validated StartTestItemRQ startTestItemRQ) { - return startTestItemHandler.startRootItem(user, projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ); - } - - @PostMapping("/{parentItem}") - @ResponseStatus(CREATED) - @ApiOperation("Start a child test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public EntryCreatedAsyncRS startChildItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String parentItem, @RequestBody @Validated StartTestItemRQ startTestItemRQ) { - return startTestItemHandler.startChildItem(user, projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ, parentItem); - } - - @PutMapping("/{testItemId}") - @ResponseStatus(OK) - @ApiOperation("Finish test item") - @PreAuthorize(ALLOWED_TO_REPORT) - public OperationCompletionRS finishTestItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String testItemId, @RequestBody @Validated FinishTestItemRQ finishExecutionRQ) { - return finishTestItemHandler.finishTestItem(user, projectExtractor.extractProjectDetails(user, projectName), testItemId, finishExecutionRQ); - } - - - /* Frontend API */ - - @Transactional(readOnly = true) - @GetMapping("/{itemId}") - @ResponseStatus(OK) - @ApiOperation("Find test item by ID") - public TestItemResource getTestItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String itemId) { - return getTestItemHandler.getTestItem(itemId, projectExtractor.extractProjectDetails(user, projectName), user); - - } - - @Transactional(readOnly = true) - @GetMapping("/uuid/{itemId}") - @ResponseStatus(OK) - @ApiOperation("Find test item by UUID") - public TestItemResource getTestItemByUuid(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable String itemId) { - return getTestItemHandler.getTestItem(itemId, projectExtractor.extractProjectDetails(user, projectName), user); - - } - - @Transactional(readOnly = true) - @GetMapping("/suggest/{itemId}") - @ResponseStatus(OK) - @ApiOperation("Search suggested items in analyzer for provided one") - public List<SuggestedItem> getSuggestedItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable Long itemId) { - return suggestItemService.suggestItems(itemId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @GetMapping("/suggest/cluster/{clusterId}") - @ResponseStatus(OK) - @ApiOperation("Search suggested items in analyzer for provided one") - public List<SuggestedItem> getSuggestedClusterItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable Long clusterId) { - return suggestItemService.suggestClusterItems(clusterId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @Transactional - @PutMapping("/suggest/choice") - @ResponseStatus(OK) - @ApiOperation("Handle user choice from suggested items") - public OperationCompletionRS handleSuggestChoose(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestBody @Validated List<SuggestInfo> request) { - projectExtractor.extractProjectDetails(user, projectName); - return suggestItemService.handleSuggestChoice(request); - } - - //TODO check pre-defined filter - @Transactional(readOnly = true) - @GetMapping - @ResponseStatus(OK) - @ApiOperation("Find test items by specified filter") - public Iterable<TestItemResource> getTestItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_LAUNCH_ID, required = false) Long launchId, - @Nullable @RequestParam(value = FILTER_ID_REQUEST_PARAM, required = false) Long filterId, - @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, - @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0", required = false) int launchesLimit, - @FilterFor(TestItem.class) Filter filter, @FilterFor(TestItem.class) Queryable predefinedFilter, - @SortFor(TestItem.class) Pageable pageable) { - return getTestItemHandler.getTestItems(new CompositeFilter(Operator.AND, filter, predefinedFilter), - pageable, - projectExtractor.extractProjectDetails(user, projectName), - user, - launchId, - filterId, - isLatest, - launchesLimit - ); - } - - @Transactional(readOnly = true) - @GetMapping("/v2") - @ResponseStatus(OK) - @ApiOperation("Find test items by specified filter") - public Iterable<TestItemResource> getTestItemsV2(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam Map<String, String> params, @FilterFor(TestItem.class) Filter filter, - @FilterFor(TestItem.class) Queryable predefinedFilter, @SortFor(TestItem.class) Pageable pageable) { - // tmp return null for project, to fix perf issue - if ("libg-140".equalsIgnoreCase(projectName)) return null; - return getTestItemHandler.getTestItemsByProvider(new CompositeFilter(Operator.AND, filter, predefinedFilter), - pageable, - projectExtractor.extractProjectDetails(user, projectName), - user, - params - ); - } - - @Transactional(readOnly = true) - @GetMapping("/statistics") - @ResponseStatus(OK) - @ApiOperation("Find accumulated statistics of items by specified filter") - public StatisticsResource getTestItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @FilterFor(TestItem.class) Filter filter, @FilterFor(TestItem.class) Queryable predefinedFilter, - @RequestParam Map<String, String> params) { - return getTestItemHandler.getStatisticsByProvider(new CompositeFilter(Operator.AND, filter, predefinedFilter), - projectExtractor.extractProjectDetails(user, projectName), - user, - params - ); - } - - @Transactional - @DeleteMapping("/{itemId}") - @ResponseStatus(OK) - @ApiOperation("Delete test item") - public OperationCompletionRS deleteTestItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable Long itemId) { - return deleteTestItemHandler.deleteTestItem(itemId, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @Transactional - @DeleteMapping - @ResponseStatus(OK) - @ApiOperation("Delete test items by specified ids") - public List<OperationCompletionRS> deleteTestItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = "ids") Set<Long> ids) { - return deleteTestItemHandler.deleteTestItems(ids, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @Transactional - @PutMapping - @ResponseStatus(OK) - @ApiOperation("Update issues of specified test items") - public List<Issue> defineTestItemIssueType(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestBody @Validated DefineIssueRQ request) { - return updateTestItemHandler.defineTestItemsIssues(projectExtractor.extractProjectDetails(user, projectName), request, user); - } - - @Transactional(readOnly = true) - @GetMapping("/history") - @ResponseStatus(OK) - @ApiOperation("Load history of test items") - public Iterable<TestItemHistoryElement> getItemsHistory(@PathVariable String projectName, - @AuthenticationPrincipal ReportPortalUser user, @FilterFor(TestItem.class) Filter filter, - @FilterFor(TestItem.class) Queryable predefinedFilter, @SortFor(TestItem.class) Pageable pageable, - @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_PARENT_ID, required = false) Long parentId, - @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_ID, required = false) Long itemId, - @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_LAUNCH_ID, required = false) Long launchId, - @Nullable @RequestParam(value = HISTORY_TYPE_PARAM, required = false) String type, - @Nullable @RequestParam(value = FILTER_ID_REQUEST_PARAM, required = false) Long filterId, - @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, - @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0", required = false) int launchesLimit, - @RequestParam(value = HISTORY_DEPTH_PARAM, required = false, defaultValue = HISTORY_DEPTH_DEFAULT_VALUE) int historyDepth) { - - return testItemsHistoryHandler.getItemsHistory(projectExtractor.extractProjectDetails(user, projectName), - new CompositeFilter(Operator.AND, filter, predefinedFilter), - pageable, - HistoryRequestParams.of(historyDepth, parentId, itemId, launchId, type, filterId, launchesLimit, isLatest), - user - ); - } - - @Transactional(readOnly = true) - @GetMapping("/ticket/ids") - @ResponseStatus(OK) - @ApiOperation("Get tickets that contains a term as a part inside for specified launch") - public List<String> getTicketIds(@AuthenticationPrincipal ReportPortalUser user, @PathVariable String projectName, - @RequestParam(value = "launch") Long id, @RequestParam(value = "term") String term) { - return getTestItemHandler.getTicketIds(id, normalizeId(term)); - } - - @Transactional(readOnly = true) - @GetMapping("/ticket/ids/all") - @ResponseStatus(OK) - @ApiOperation("Get tickets that contains a term as a part inside for specified launch") - public List<String> getTicketIdsForProject(@AuthenticationPrincipal ReportPortalUser user, @PathVariable String projectName, - @RequestParam(value = "term") String term) { - return getTestItemHandler.getTicketIds(projectExtractor.extractProjectDetails(user, projectName), normalizeId(term)); - } - - //TODO EPMRPP-59414 - @Transactional(readOnly = true) - @GetMapping("/attribute/keys") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute keys of specified launch") - public List<String> getAttributeKeys(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = "launch") Long id, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + CRITERIA_ITEM_ATTRIBUTE_KEY) String value) { - return getTestItemHandler.getAttributeKeys(id, value); - } - - //TODO EPMRPP-59414 - @Transactional(readOnly = true) - @GetMapping("/attribute/keys/all") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute keys of specified launch") - public List<String> getAttributeKeysForProject(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + CRITERIA_ITEM_ATTRIBUTE_KEY) String value, - @RequestParam(value = FILTER_ID_REQUEST_PARAM) Long launchFilterId, - @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, - @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0") int launchesLimit) { - return getTestItemHandler.getAttributeKeys(launchFilterId, - isLatest, - launchesLimit, - projectExtractor.extractProjectDetails(user, projectName), - value - ); - } - - //TODO EPMRPP-59414 - @Transactional(readOnly = true) - @GetMapping("/attribute/values") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute values of specified launch") - public List<String> getAttributeValues(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = "launch") Long id, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_ITEM_ATTRIBUTE_KEY, required = false) String key, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + CRITERIA_ITEM_ATTRIBUTE_VALUE) String value) { - return getTestItemHandler.getAttributeValues(id, key, value); - } - - @Transactional(readOnly = true) - @GetMapping("/step/attribute/keys") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute keys of step items under specified project") - public List<String> getAttributeKeys(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_NAME, required = false) String launchName, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + CRITERIA_ITEM_ATTRIBUTE_KEY) String value) { - return ofNullable(launchName).filter(StringUtils::isNotBlank) - .map(name -> getTestItemHandler.getAttributeKeys(projectExtractor.extractProjectDetails(user, projectName), name, value)) - .orElseGet(Collections::emptyList); - } - - @Transactional(readOnly = true) - @GetMapping("/step/attribute/values") - @ResponseStatus(OK) - @ApiOperation("Get all unique attribute values of step items under specified project") - public List<String> getAttributeValues(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_NAME, required = false) String launchName, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + CRITERIA_ITEM_ATTRIBUTE_KEY, required = false) String key, - @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + CRITERIA_ITEM_ATTRIBUTE_VALUE) String value) { - return ofNullable(launchName).filter(StringUtils::isNotBlank) - .map(name -> getTestItemHandler.getAttributeValues(projectExtractor.extractProjectDetails(user, projectName), name, key, value)) - .orElseGet(Collections::emptyList); - } - - @Transactional - @PutMapping(value = "/info") - @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) - @ResponseStatus(OK) - @ApiOperation("Bulk update attributes and description") - public OperationCompletionRS bulkUpdate(@PathVariable String projectName, @RequestBody @Validated BulkInfoUpdateRQ bulkInfoUpdateRQ, - @AuthenticationPrincipal ReportPortalUser user) { - return updateTestItemHandler.bulkInfoUpdate(bulkInfoUpdateRQ, projectExtractor.extractProjectDetails(user, projectName)); - } - - @Transactional - @PutMapping("/{itemId}/update") - @ResponseStatus(OK) - @ApiOperation("Update test item") - public OperationCompletionRS updateTestItem(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @PathVariable Long itemId, @RequestBody @Validated UpdateTestItemRQ rq) { - return updateTestItemHandler.updateTestItem(projectExtractor.extractProjectDetails(user, projectName), itemId, rq, user); - } - - @Transactional - @PutMapping("/issue/link") - @ResponseStatus(OK) - @ApiOperation("Attach external issue for specified test items") - public List<OperationCompletionRS> linkExternalIssues(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestBody @Validated LinkExternalIssueRQ rq) { - return updateTestItemHandler.processExternalIssues(rq, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @Transactional - @PutMapping("/issue/unlink") - @ResponseStatus(OK) - @ApiOperation("Unlink external issue for specified test items") - public List<OperationCompletionRS> unlinkExternalIssues(@PathVariable String projectName, - @AuthenticationPrincipal ReportPortalUser user, @RequestBody @Validated UnlinkExternalIssueRQ rq) { - return updateTestItemHandler.processExternalIssues(rq, projectExtractor.extractProjectDetails(user, projectName), user); - } - - @Transactional(readOnly = true) - @GetMapping("/items") - @ResponseStatus(OK) - @ApiOperation("Get test items by specified ids") - public List<TestItemResource> getTestItems(@PathVariable String projectName, @AuthenticationPrincipal ReportPortalUser user, - @RequestParam(value = "ids") Long[] ids) { - return getTestItemHandler.getTestItems(ids, projectExtractor.extractProjectDetails(user, projectName), user); - } + public static final String HISTORY_TYPE_PARAM = "type"; + public static final String FILTER_ID_REQUEST_PARAM = "filterId"; + public static final String IS_LATEST_LAUNCHES_REQUEST_PARAM = "isLatest"; + public static final String LAUNCHES_LIMIT_REQUEST_PARAM = "launchesLimit"; + private static final String HISTORY_DEPTH_PARAM = "historyDepth"; + private static final String HISTORY_DEPTH_DEFAULT_VALUE = "5"; + private static final String LAUNCHES_LIMIT_DEFAULT_VALUE = "0"; + + private final ProjectExtractor projectExtractor; + private final StartTestItemHandler startTestItemHandler; + private final DeleteTestItemHandler deleteTestItemHandler; + private final FinishTestItemHandler finishTestItemHandler; + private final UpdateTestItemHandler updateTestItemHandler; + private final GetTestItemHandler getTestItemHandler; + private final TestItemsHistoryHandler testItemsHistoryHandler; + private final SuggestItemService suggestItemService; + + @Autowired + public TestItemController(ProjectExtractor projectExtractor, + StartTestItemHandler startTestItemHandler, DeleteTestItemHandler deleteTestItemHandler, + FinishTestItemHandler finishTestItemHandler, UpdateTestItemHandler updateTestItemHandler, + GetTestItemHandler getTestItemHandler, + TestItemsHistoryHandler testItemsHistoryHandler, SuggestItemService suggestItemService) { + this.projectExtractor = projectExtractor; + this.startTestItemHandler = startTestItemHandler; + this.deleteTestItemHandler = deleteTestItemHandler; + this.finishTestItemHandler = finishTestItemHandler; + this.updateTestItemHandler = updateTestItemHandler; + this.getTestItemHandler = getTestItemHandler; + this.testItemsHistoryHandler = testItemsHistoryHandler; + this.suggestItemService = suggestItemService; + } + + /* Report client API */ + + @PostMapping + @ResponseStatus(CREATED) + @ApiOperation("Start a root test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS startRootItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated StartTestItemRQ startTestItemRQ) { + return startTestItemHandler.startRootItem(user, + projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ); + } + + @PostMapping("/{parentItem}") + @ResponseStatus(CREATED) + @ApiOperation("Start a child test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public EntryCreatedAsyncRS startChildItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String parentItem, @RequestBody @Validated StartTestItemRQ startTestItemRQ) { + return startTestItemHandler.startChildItem(user, + projectExtractor.extractProjectDetails(user, projectName), startTestItemRQ, parentItem); + } + + @PutMapping("/{testItemId}") + @ResponseStatus(OK) + @ApiOperation("Finish test item") + @PreAuthorize(ALLOWED_TO_REPORT) + public OperationCompletionRS finishTestItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String testItemId, @RequestBody @Validated FinishTestItemRQ finishExecutionRQ) { + return finishTestItemHandler.finishTestItem(user, + projectExtractor.extractProjectDetails(user, projectName), testItemId, finishExecutionRQ); + } + + + /* Frontend API */ + + @Transactional(readOnly = true) + @GetMapping("/{itemId}") + @ResponseStatus(OK) + @ApiOperation("Find test item by ID") + public TestItemResource getTestItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String itemId) { + return getTestItemHandler.getTestItem(itemId, + projectExtractor.extractProjectDetails(user, projectName), user); + + } + + @Transactional(readOnly = true) + @GetMapping("/uuid/{itemId}") + @ResponseStatus(OK) + @ApiOperation("Find test item by UUID") + public TestItemResource getTestItemByUuid(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable String itemId) { + return getTestItemHandler.getTestItem(itemId, + projectExtractor.extractProjectDetails(user, projectName), user); + + } + + @Transactional(readOnly = true) + @GetMapping("/suggest/{itemId}") + @ResponseStatus(OK) + @ApiOperation("Search suggested items in analyzer for provided one") + public List<SuggestedItem> getSuggestedItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable Long itemId) { + return suggestItemService.suggestItems(itemId, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @GetMapping("/suggest/cluster/{clusterId}") + @ResponseStatus(OK) + @ApiOperation("Search suggested items in analyzer for provided one") + public List<SuggestedItem> getSuggestedClusterItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable Long clusterId) { + return suggestItemService.suggestClusterItems(clusterId, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @Transactional + @PutMapping("/suggest/choice") + @ResponseStatus(OK) + @ApiOperation("Handle user choice from suggested items") + public OperationCompletionRS handleSuggestChoose(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated List<SuggestInfo> request) { + projectExtractor.extractProjectDetails(user, projectName); + return suggestItemService.handleSuggestChoice(request); + } + + //TODO check pre-defined filter + @Transactional(readOnly = true) + @GetMapping + @ResponseStatus(OK) + @ApiOperation("Find test items by specified filter") + public Iterable<TestItemResource> getTestItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_LAUNCH_ID, required = false) Long launchId, + @Nullable @RequestParam(value = FILTER_ID_REQUEST_PARAM, required = false) Long filterId, + @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, + @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0", required = false) int launchesLimit, + @FilterFor(TestItem.class) Filter filter, + @FilterFor(TestItem.class) Queryable predefinedFilter, + @SortFor(TestItem.class) Pageable pageable) { + return getTestItemHandler.getTestItems( + new CompositeFilter(Operator.AND, filter, predefinedFilter), + pageable, + projectExtractor.extractProjectDetails(user, projectName), + user, + launchId, + filterId, + isLatest, + launchesLimit + ); + } + + @Transactional(readOnly = true) + @GetMapping("/v2") + @ResponseStatus(OK) + @ApiOperation("Find test items by specified filter") + public Iterable<TestItemResource> getTestItemsV2(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam Map<String, String> params, @FilterFor(TestItem.class) Filter filter, + @FilterFor(TestItem.class) Queryable predefinedFilter, + @SortFor(TestItem.class) Pageable pageable) { + // tmp return null for project, to fix perf issue + if ("libg-140".equalsIgnoreCase(projectName)) { + return null; + } + return getTestItemHandler.getTestItemsByProvider( + new CompositeFilter(Operator.AND, filter, predefinedFilter), + pageable, + projectExtractor.extractProjectDetails(user, projectName), + user, + params + ); + } + + @Transactional(readOnly = true) + @GetMapping("/statistics") + @ResponseStatus(OK) + @ApiOperation("Find accumulated statistics of items by specified filter") + public StatisticsResource getTestItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @FilterFor(TestItem.class) Filter filter, + @FilterFor(TestItem.class) Queryable predefinedFilter, + @RequestParam Map<String, String> params) { + return getTestItemHandler.getStatisticsByProvider( + new CompositeFilter(Operator.AND, filter, predefinedFilter), + projectExtractor.extractProjectDetails(user, projectName), + user, + params + ); + } + + @Transactional + @DeleteMapping("/{itemId}") + @ResponseStatus(OK) + @ApiOperation("Delete test item") + public OperationCompletionRS deleteTestItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable Long itemId) { + return deleteTestItemHandler.deleteTestItem(itemId, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @Transactional + @DeleteMapping + @ResponseStatus(OK) + @ApiOperation("Delete test items by specified ids") + public List<OperationCompletionRS> deleteTestItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = "ids") Set<Long> ids) { + return deleteTestItemHandler.deleteTestItems(ids, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @Transactional + @PutMapping + @ResponseStatus(OK) + @ApiOperation("Update issues of specified test items") + public List<Issue> defineTestItemIssueType(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated DefineIssueRQ request) { + return updateTestItemHandler.defineTestItemsIssues( + projectExtractor.extractProjectDetails(user, projectName), request, user); + } + + @Transactional(readOnly = true) + @GetMapping("/history") + @ResponseStatus(OK) + @ApiOperation("Load history of test items") + public Iterable<TestItemHistoryElement> getItemsHistory(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, @FilterFor(TestItem.class) Filter filter, + @FilterFor(TestItem.class) Queryable predefinedFilter, + @SortFor(TestItem.class) Pageable pageable, + @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_PARENT_ID, required = false) Long parentId, + @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_ID, required = false) Long itemId, + @Nullable @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_LAUNCH_ID, required = false) Long launchId, + @Nullable @RequestParam(value = HISTORY_TYPE_PARAM, required = false) String type, + @Nullable @RequestParam(value = FILTER_ID_REQUEST_PARAM, required = false) Long filterId, + @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, + @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0", required = false) int launchesLimit, + @RequestParam(value = HISTORY_DEPTH_PARAM, required = false, defaultValue = HISTORY_DEPTH_DEFAULT_VALUE) int historyDepth) { + + return testItemsHistoryHandler.getItemsHistory( + projectExtractor.extractProjectDetails(user, projectName), + new CompositeFilter(Operator.AND, filter, predefinedFilter), + pageable, + HistoryRequestParams.of(historyDepth, parentId, itemId, launchId, type, filterId, + launchesLimit, isLatest), + user + ); + } + + @Transactional(readOnly = true) + @GetMapping("/ticket/ids") + @ResponseStatus(OK) + @ApiOperation("Get tickets that contains a term as a part inside for specified launch") + public List<String> getTicketIds(@AuthenticationPrincipal ReportPortalUser user, + @PathVariable String projectName, + @RequestParam(value = "launch") Long id, @RequestParam(value = "term") String term) { + return getTestItemHandler.getTicketIds(id, normalizeId(term)); + } + + @Transactional(readOnly = true) + @GetMapping("/ticket/ids/all") + @ResponseStatus(OK) + @ApiOperation("Get tickets that contains a term as a part inside for specified launch") + public List<String> getTicketIdsForProject(@AuthenticationPrincipal ReportPortalUser user, + @PathVariable String projectName, + @RequestParam(value = "term") String term) { + return getTestItemHandler.getTicketIds( + projectExtractor.extractProjectDetails(user, projectName), normalizeId(term)); + } + + //TODO EPMRPP-59414 + @Transactional(readOnly = true) + @GetMapping("/attribute/keys") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute keys of specified launch") + public List<String> getAttributeKeys(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = "launch") Long id, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + + CRITERIA_ITEM_ATTRIBUTE_KEY) String value) { + return getTestItemHandler.getAttributeKeys(id, value); + } + + //TODO EPMRPP-59414 + @Transactional(readOnly = true) + @GetMapping("/attribute/keys/all") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute keys of specified launch") + public List<String> getAttributeKeysForProject(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + + CRITERIA_ITEM_ATTRIBUTE_KEY) String value, + @RequestParam(value = FILTER_ID_REQUEST_PARAM) Long launchFilterId, + @RequestParam(value = IS_LATEST_LAUNCHES_REQUEST_PARAM, defaultValue = "false", required = false) boolean isLatest, + @RequestParam(value = LAUNCHES_LIMIT_REQUEST_PARAM, defaultValue = "0") int launchesLimit) { + return getTestItemHandler.getAttributeKeys(launchFilterId, + isLatest, + launchesLimit, + projectExtractor.extractProjectDetails(user, projectName), + value + ); + } + + //TODO EPMRPP-59414 + @Transactional(readOnly = true) + @GetMapping("/attribute/values") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute values of specified launch") + public List<String> getAttributeValues(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = "launch") Long id, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_ITEM_ATTRIBUTE_KEY, required = false) String key, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + + CRITERIA_ITEM_ATTRIBUTE_VALUE) String value) { + return getTestItemHandler.getAttributeValues(id, key, value); + } + + @Transactional(readOnly = true) + @GetMapping("/step/attribute/keys") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute keys of step items under specified project") + public List<String> getAttributeKeys(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_NAME, required = false) String launchName, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + + CRITERIA_ITEM_ATTRIBUTE_KEY) String value) { + return ofNullable(launchName).filter(StringUtils::isNotBlank) + .map(name -> getTestItemHandler.getAttributeKeys( + projectExtractor.extractProjectDetails(user, projectName), name, value)) + .orElseGet(Collections::emptyList); + } + + @Transactional(readOnly = true) + @GetMapping("/step/attribute/values") + @ResponseStatus(OK) + @ApiOperation("Get all unique attribute values of step items under specified project") + public List<String> getAttributeValues(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_NAME, required = false) String launchName, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.EQ + + CRITERIA_ITEM_ATTRIBUTE_KEY, required = false) String key, + @RequestParam(value = DEFAULT_FILTER_PREFIX + Condition.CNT + + CRITERIA_ITEM_ATTRIBUTE_VALUE) String value) { + return ofNullable(launchName).filter(StringUtils::isNotBlank) + .map(name -> getTestItemHandler.getAttributeValues( + projectExtractor.extractProjectDetails(user, projectName), name, key, value)) + .orElseGet(Collections::emptyList); + } + + @Transactional + @PutMapping(value = "/info") + @PreAuthorize(PROJECT_MANAGER_OR_ADMIN) + @ResponseStatus(OK) + @ApiOperation("Bulk update attributes and description") + public OperationCompletionRS bulkUpdate(@PathVariable String projectName, + @RequestBody @Validated BulkInfoUpdateRQ bulkInfoUpdateRQ, + @AuthenticationPrincipal ReportPortalUser user) { + return updateTestItemHandler.bulkInfoUpdate(bulkInfoUpdateRQ, + projectExtractor.extractProjectDetails(user, projectName)); + } + + @Transactional + @PutMapping("/{itemId}/update") + @ResponseStatus(OK) + @ApiOperation("Update test item") + public OperationCompletionRS updateTestItem(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @PathVariable Long itemId, @RequestBody @Validated UpdateTestItemRQ rq) { + return updateTestItemHandler.updateTestItem( + projectExtractor.extractProjectDetails(user, projectName), itemId, rq, user); + } + + @Transactional + @PutMapping("/issue/link") + @ResponseStatus(OK) + @ApiOperation("Attach external issue for specified test items") + public List<OperationCompletionRS> linkExternalIssues(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated LinkExternalIssueRQ rq) { + return updateTestItemHandler.processExternalIssues(rq, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @Transactional + @PutMapping("/issue/unlink") + @ResponseStatus(OK) + @ApiOperation("Unlink external issue for specified test items") + public List<OperationCompletionRS> unlinkExternalIssues(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestBody @Validated UnlinkExternalIssueRQ rq) { + return updateTestItemHandler.processExternalIssues(rq, + projectExtractor.extractProjectDetails(user, projectName), user); + } + + @Transactional(readOnly = true) + @GetMapping("/items") + @ResponseStatus(OK) + @ApiOperation("Get test items by specified ids") + public List<TestItemResource> getTestItems(@PathVariable String projectName, + @AuthenticationPrincipal ReportPortalUser user, + @RequestParam(value = "ids") Long[] ids) { + return getTestItemHandler.getTestItems(ids, + projectExtractor.extractProjectDetails(user, projectName), user); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java index 4252f9033d..d2ccfd71c3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/UserController.java @@ -89,7 +89,7 @@ import org.springframework.web.bind.annotation.RestController; @RestController -@RequestMapping("/v1/user") +@RequestMapping("/users") public class UserController { private final CreateUserHandler createUserMessageHandler; diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/LogResourceAssembler.java b/src/main/java/com/epam/ta/reportportal/ws/converter/LogResourceAssembler.java index a76fa30d37..79910bbbe5 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/LogResourceAssembler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/LogResourceAssembler.java @@ -16,7 +16,7 @@ package com.epam.ta.reportportal.ws.converter; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.converter.converters.LogConverter; import com.epam.ta.reportportal.ws.model.log.LogResource; import org.springframework.stereotype.Service; @@ -27,10 +27,10 @@ * @author Andrei Varabyeu */ @Service -public class LogResourceAssembler extends PagedResourcesAssembler<Log, LogResource> { +public class LogResourceAssembler extends PagedResourcesAssembler<LogFull, LogResource> { - @Override - public LogResource toResource(Log log) { - return LogConverter.TO_RESOURCE.apply(log); - } + @Override + public LogResource toResource(LogFull log) { + return LogConverter.TO_RESOURCE.apply(log); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/ResourceAssembler.java b/src/main/java/com/epam/ta/reportportal/ws/converter/ResourceAssembler.java index 0569f859cc..1d3a44ed54 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/ResourceAssembler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/ResourceAssembler.java @@ -16,7 +16,6 @@ package com.epam.ta.reportportal.ws.converter; import com.google.common.base.Preconditions; - import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -26,36 +25,36 @@ */ public abstract class ResourceAssembler<T, R> implements Function<T, R> { - /** - * Converts all given entities into resources. - * - * @param entities must not be {@literal null}. - * @return - * @see #toResource(Object) - */ - public List<R> toResources(Iterable<? extends T> entities) { - - Preconditions.checkNotNull(entities); - List<R> result = new ArrayList<>(); - - for (T entity : entities) { - result.add(toResource(entity)); - } - - return result; - } - - @Override - public R apply(T t) { - return toResource(t); - } - - /** - * Converts the given entity into an another one - * - * @param entity Entity to convert - * @return Converted entity - */ - abstract R toResource(T entity); + /** + * Converts all given entities into resources. + * + * @param entities must not be {@literal null}. + * @return List of resources + * @see #toResource(Object) + */ + public List<R> toResources(Iterable<? extends T> entities) { + + Preconditions.checkNotNull(entities); + List<R> result = new ArrayList<>(); + + for (T entity : entities) { + result.add(toResource(entity)); + } + + return result; + } + + @Override + public R apply(T t) { + return toResource(t); + } + + /** + * Converts the given entity into an another one + * + * @param entity Entity to convert + * @return Converted entity + */ + abstract R toResource(T entity); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/TestItemResourceAssembler.java b/src/main/java/com/epam/ta/reportportal/ws/converter/TestItemResourceAssembler.java index aee42a2be8..cf5ac71417 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/TestItemResourceAssembler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/TestItemResourceAssembler.java @@ -16,15 +16,14 @@ package com.epam.ta.reportportal.ws.converter; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.item.PathName; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.converter.converters.TestItemConverter; import com.epam.ta.reportportal.ws.model.TestItemResource; -import org.springframework.stereotype.Component; - import javax.annotation.Nullable; - -import static java.util.Optional.ofNullable; +import org.springframework.stereotype.Component; /** * @author Pavel Bortnik @@ -32,14 +31,15 @@ @Component public class TestItemResourceAssembler extends PagedResourcesAssembler<TestItem, TestItemResource> { - @Override - public TestItemResource toResource(TestItem entity) { - return TestItemConverter.TO_RESOURCE.apply(entity); - } + @Override + public TestItemResource toResource(TestItem entity) { + return TestItemConverter.TO_RESOURCE.apply(entity); + } - public TestItemResource toResource(TestItem entity, @Nullable PathName pathName) { - TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(entity); - ofNullable(pathName).ifPresent(pn -> resource.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE.apply(pn))); - return resource; - } + public TestItemResource toResource(TestItem entity, @Nullable PathName pathName) { + TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(entity); + ofNullable(pathName).ifPresent( + pn -> resource.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE.apply(pn))); + return resource; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/AttachmentBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/AttachmentBuilder.java index 2280f86df6..cf8c7027d1 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/AttachmentBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/AttachmentBuilder.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.commons.BinaryDataMetaInfo; import com.epam.ta.reportportal.entity.attachment.Attachment; - import java.util.function.Supplier; /** @@ -26,48 +25,49 @@ */ public class AttachmentBuilder implements Supplier<Attachment> { - private final Attachment attachment; + private final Attachment attachment; - public AttachmentBuilder() { - this.attachment = new Attachment(); - } + public AttachmentBuilder() { + this.attachment = new Attachment(); + } - public AttachmentBuilder withFileId(String fileId) { - attachment.setFileId(fileId); - return this; - } + public AttachmentBuilder withFileId(String fileId) { + attachment.setFileId(fileId); + return this; + } - public AttachmentBuilder withThumbnailId(String thumbnailId) { - attachment.setThumbnailId(thumbnailId); - return this; - } + public AttachmentBuilder withThumbnailId(String thumbnailId) { + attachment.setThumbnailId(thumbnailId); + return this; + } - public AttachmentBuilder withContentType(String contentType) { - attachment.setContentType(contentType); - return this; - } + public AttachmentBuilder withContentType(String contentType) { + attachment.setContentType(contentType); + return this; + } - public AttachmentBuilder withProjectId(Long projectId) { - attachment.setProjectId(projectId); - return this; - } + public AttachmentBuilder withProjectId(Long projectId) { + attachment.setProjectId(projectId); + return this; + } - public AttachmentBuilder withLaunchId(Long launchId) { - attachment.setLaunchId(launchId); - return this; - } + public AttachmentBuilder withLaunchId(Long launchId) { + attachment.setLaunchId(launchId); + return this; + } - public AttachmentBuilder withItemId(Long itemId) { - attachment.setItemId(itemId); - return this; - } + public AttachmentBuilder withItemId(Long itemId) { + attachment.setItemId(itemId); + return this; + } - public AttachmentBuilder withMetaInfo(BinaryDataMetaInfo metaInfo) { - return withFileId(metaInfo.getFileId()).withThumbnailId(metaInfo.getThumbnailFileId()).withContentType(metaInfo.getContentType()); - } + public AttachmentBuilder withMetaInfo(BinaryDataMetaInfo metaInfo) { + return withFileId(metaInfo.getFileId()).withThumbnailId(metaInfo.getThumbnailFileId()) + .withContentType(metaInfo.getContentType()); + } - @Override - public Attachment get() { - return attachment; - } + @Override + public Attachment get() { + return attachment; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilder.java index d8eebdb2bf..64e946ff33 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilder.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.integration.IntegrationParams; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.entity.project.Project; - import java.time.LocalDateTime; import java.util.function.Supplier; @@ -29,53 +28,53 @@ */ public class IntegrationBuilder implements Supplier<Integration> { - private Integration integration; + private Integration integration; - public IntegrationBuilder() { - integration = new Integration(); - } + public IntegrationBuilder() { + integration = new Integration(); + } - public IntegrationBuilder(Integration integration) { - this.integration = integration; - } + public IntegrationBuilder(Integration integration) { + this.integration = integration; + } - public IntegrationBuilder withCreationDate(LocalDateTime date) { - this.integration.setCreationDate(date); - return this; - } + public IntegrationBuilder withCreationDate(LocalDateTime date) { + this.integration.setCreationDate(date); + return this; + } - public IntegrationBuilder withCreator(String creator) { - this.integration.setCreator(creator); - return this; - } + public IntegrationBuilder withCreator(String creator) { + this.integration.setCreator(creator); + return this; + } - public IntegrationBuilder withEnabled(boolean enabled) { - this.integration.setEnabled(enabled); - return this; - } + public IntegrationBuilder withEnabled(boolean enabled) { + this.integration.setEnabled(enabled); + return this; + } - public IntegrationBuilder withName(String name) { - this.integration.setName(name); - return this; - } + public IntegrationBuilder withName(String name) { + this.integration.setName(name); + return this; + } - public IntegrationBuilder withType(IntegrationType type) { - this.integration.setType(type); - return this; - } + public IntegrationBuilder withType(IntegrationType type) { + this.integration.setType(type); + return this; + } - public IntegrationBuilder withProject(Project project) { - this.integration.setProject(project); - return this; - } + public IntegrationBuilder withProject(Project project) { + this.integration.setProject(project); + return this; + } - public IntegrationBuilder withParams(IntegrationParams params) { - this.integration.setParams(params); - return this; - } + public IntegrationBuilder withParams(IntegrationParams params) { + this.integration.setParams(params); + return this; + } - @Override - public Integration get() { - return integration; - } + @Override + public Integration get() { + return integration; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationTypeBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationTypeBuilder.java index d65861350b..11300f0e9a 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationTypeBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationTypeBuilder.java @@ -20,60 +20,59 @@ import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; import com.google.common.collect.Maps; - -import javax.validation.constraints.NotNull; import java.time.LocalDateTime; import java.util.function.Supplier; +import javax.validation.constraints.NotNull; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class IntegrationTypeBuilder implements Supplier<IntegrationType> { - private final IntegrationType integrationType; + private final IntegrationType integrationType; - public IntegrationTypeBuilder() { - this.integrationType = new IntegrationType(); - this.integrationType.setCreationDate(LocalDateTime.now()); - integrationType.setDetails(createIntegrationTypeDetails()); - } + public IntegrationTypeBuilder() { + this.integrationType = new IntegrationType(); + this.integrationType.setCreationDate(LocalDateTime.now()); + integrationType.setDetails(createIntegrationTypeDetails()); + } - public IntegrationTypeBuilder(final IntegrationType integrationType) { - this.integrationType = integrationType; - if (this.integrationType.getDetails() == null) { - this.integrationType.setDetails(createIntegrationTypeDetails()); - } - } + public IntegrationTypeBuilder(final IntegrationType integrationType) { + this.integrationType = integrationType; + if (this.integrationType.getDetails() == null) { + this.integrationType.setDetails(createIntegrationTypeDetails()); + } + } - public static IntegrationTypeDetails createIntegrationTypeDetails() { - IntegrationTypeDetails integrationTypeDetails = new IntegrationTypeDetails(); - integrationTypeDetails.setDetails(Maps.newHashMap()); - return integrationTypeDetails; - } + public static IntegrationTypeDetails createIntegrationTypeDetails() { + IntegrationTypeDetails integrationTypeDetails = new IntegrationTypeDetails(); + integrationTypeDetails.setDetails(Maps.newHashMap()); + return integrationTypeDetails; + } - public IntegrationTypeBuilder setName(String name) { - integrationType.setName(name); - return this; - } + public IntegrationTypeBuilder setName(String name) { + integrationType.setName(name); + return this; + } - public IntegrationTypeBuilder setIntegrationGroup(IntegrationGroupEnum integrationGroup) { - integrationType.setIntegrationGroup(integrationGroup); - return this; - } + public IntegrationTypeBuilder setIntegrationGroup(IntegrationGroupEnum integrationGroup) { + integrationType.setIntegrationGroup(integrationGroup); + return this; + } - public IntegrationTypeBuilder setDetails(IntegrationTypeDetails typeDetails) { - integrationType.setDetails(typeDetails); - return this; - } + public IntegrationTypeBuilder setDetails(IntegrationTypeDetails typeDetails) { + integrationType.setDetails(typeDetails); + return this; + } - public IntegrationTypeBuilder setEnabled(boolean enabled) { - integrationType.setEnabled(enabled); - return this; - } + public IntegrationTypeBuilder setEnabled(boolean enabled) { + integrationType.setEnabled(enabled); + return this; + } - @NotNull - @Override - public IntegrationType get() { - return integrationType; - } + @NotNull + @Override + public IntegrationType get() { + return integrationType; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilder.java index 1d88c45933..1944e65a2d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilder.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.google.common.base.Preconditions; - import java.util.function.Supplier; /** @@ -27,42 +26,42 @@ */ public class IssueEntityBuilder implements Supplier<IssueEntity> { - private IssueEntity issueEntity; + private IssueEntity issueEntity; - public IssueEntityBuilder() { - this.issueEntity = new IssueEntity(); - } + public IssueEntityBuilder() { + this.issueEntity = new IssueEntity(); + } - public IssueEntityBuilder(IssueEntity issueEntity) { - this.issueEntity = issueEntity; - } + public IssueEntityBuilder(IssueEntity issueEntity) { + this.issueEntity = issueEntity; + } - public IssueEntityBuilder addIssueType(IssueType issueType) { - Preconditions.checkNotNull(issueType); - issueEntity.setIssueType(issueType); - return this; - } + public IssueEntityBuilder addIssueType(IssueType issueType) { + Preconditions.checkNotNull(issueType); + issueEntity.setIssueType(issueType); + return this; + } - public IssueEntityBuilder addDescription(String comment) { - if (null != comment) { - issueEntity.setIssueDescription(comment.trim()); - } - return this; - } + public IssueEntityBuilder addDescription(String comment) { + if (null != comment) { + issueEntity.setIssueDescription(comment.trim()); + } + return this; + } - public IssueEntityBuilder addIgnoreFlag(boolean ignoreAnalyzer) { - issueEntity.setIgnoreAnalyzer(ignoreAnalyzer); - return this; - } + public IssueEntityBuilder addIgnoreFlag(boolean ignoreAnalyzer) { + issueEntity.setIgnoreAnalyzer(ignoreAnalyzer); + return this; + } - public IssueEntityBuilder addAutoAnalyzedFlag(boolean autoAnalyzed) { - issueEntity.setAutoAnalyzed(autoAnalyzed); - return this; - } + public IssueEntityBuilder addAutoAnalyzedFlag(boolean autoAnalyzed) { + issueEntity.setAutoAnalyzed(autoAnalyzed); + return this; + } - @Override - public IssueEntity get() { - return this.issueEntity; - } + @Override + public IssueEntity get() { + return this.issueEntity; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilder.java index 60069092e8..39c4ca1ce7 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilder.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.entity.project.Project; - import java.util.function.Supplier; /** @@ -27,53 +26,53 @@ */ public class IssueTypeBuilder implements Supplier<IssueType> { - private IssueType issueType; + private IssueType issueType; - public IssueTypeBuilder() { - this.issueType = new IssueType(); - } + public IssueTypeBuilder() { + this.issueType = new IssueType(); + } - public IssueTypeBuilder(IssueType issueType) { - this.issueType = issueType; - } + public IssueTypeBuilder(IssueType issueType) { + this.issueType = issueType; + } - public IssueTypeBuilder addLocator(String locator) { - issueType.setLocator(locator); - return this; - } + public IssueTypeBuilder addLocator(String locator) { + issueType.setLocator(locator); + return this; + } - public IssueTypeBuilder addIssueGroup(IssueGroup issueGroup) { - issueType.setIssueGroup(issueGroup); - return this; - } + public IssueTypeBuilder addIssueGroup(IssueGroup issueGroup) { + issueType.setIssueGroup(issueGroup); + return this; + } - public IssueTypeBuilder addLongName(String longName) { - issueType.setLongName(longName); - return this; - } + public IssueTypeBuilder addLongName(String longName) { + issueType.setLongName(longName); + return this; + } - public IssueTypeBuilder addShortName(String shortName) { - issueType.setShortName(shortName.toUpperCase()); - return this; - } + public IssueTypeBuilder addShortName(String shortName) { + issueType.setShortName(shortName.toUpperCase()); + return this; + } - public IssueTypeBuilder addHexColor(String color) { - issueType.setHexColor(color); - return this; - } + public IssueTypeBuilder addHexColor(String color) { + issueType.setHexColor(color); + return this; + } - public IssueTypeBuilder addProject(Project project) { - // issueType.getProjects().add(project); - return this; - } + public IssueTypeBuilder addProject(Project project) { + // issueType.getProjects().add(project); + return this; + } - // public IssueTypeBuilder addProjectList(List<Project> projects) { - // issueType.getProjects().addAll(projects); - // return this; - // } + // public IssueTypeBuilder addProjectList(List<Project> projects) { + // issueType.getProjects().addAll(projects); + // return this; + // } - @Override - public IssueType get() { - return issueType; - } + @Override + public IssueType get() { + return issueType; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilder.java index 649c542896..de875316f3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilder.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; @@ -28,112 +31,110 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.base.Preconditions; -import org.apache.commons.lang3.StringUtils; - import java.util.Date; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.StringUtils; public class LaunchBuilder implements Supplier<Launch> { - private static final int LAUNCH_DESCRIPTION_LENGTH_LIMIT = 2048; - private static final int DESCRIPTION_START_SYMBOL_INDEX = 0; - - private Launch launch; - - public LaunchBuilder() { - this.launch = new Launch(); - } - - public LaunchBuilder(Launch launch) { - this.launch = launch; - } - - public LaunchBuilder addStartRQ(StartLaunchRQ request) { - Preconditions.checkNotNull(request, ErrorType.BAD_REQUEST_ERROR); - launch.setStartTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(request.getStartTime())); - launch.setName(request.getName().trim()); - launch.setStatus(StatusEnum.IN_PROGRESS); - launch.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); - addDescription(request.getDescription()); - LaunchModeEnum.findByName(ofNullable(request.getMode()).map(Enum::name).orElse(LaunchModeEnum.DEFAULT.name())) - .ifPresent(it -> launch.setMode(it)); - return this; - } - - public LaunchBuilder addDescription(String description) { - ofNullable(description).ifPresent(it -> launch.setDescription(StringUtils.substring(it.trim(), - DESCRIPTION_START_SYMBOL_INDEX, - LAUNCH_DESCRIPTION_LENGTH_LIMIT - ))); - return this; - } - - public LaunchBuilder addUserId(Long userId) { - launch.setUserId(userId); - return this; - } - - public LaunchBuilder addProject(Long projectId) { - launch.setProjectId(projectId); - return this; - } - - public LaunchBuilder addAttribute(ItemAttributeResource attributeResource) { - ItemAttribute itemAttribute = FROM_RESOURCE.apply(attributeResource); - itemAttribute.setLaunch(launch); - launch.getAttributes().add(itemAttribute); - return this; - } - - public LaunchBuilder addAttributes(Set<ItemAttributesRQ> attributes) { - ofNullable(attributes).ifPresent(it -> launch.getAttributes().addAll(it.stream().map(val -> { - ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); - itemAttribute.setLaunch(launch); - return itemAttribute; - }).collect(Collectors.toSet()))); - return this; - } - - public LaunchBuilder overwriteAttributes(Set<ItemAttributeResource> attributes) { - if (attributes != null) { - final Set<ItemAttribute> overwrittenAttributes = launch.getAttributes() - .stream() - .filter(ItemAttribute::isSystem) - .collect(Collectors.toSet()); - attributes.stream().map(val -> { - ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); - itemAttribute.setLaunch(launch); - return itemAttribute; - }).forEach(overwrittenAttributes::add); - launch.setAttributes(overwrittenAttributes); - } - return this; - } - - public LaunchBuilder addMode(Mode mode) { - ofNullable(mode).ifPresent(it -> launch.setMode(LaunchModeEnum.valueOf(it.name()))); - return this; - } - - public LaunchBuilder addStatus(String status) { - launch.setStatus(StatusEnum.fromValue(status).orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FINISH_STATUS))); - return this; - } - - public LaunchBuilder addEndTime(Date date) { - launch.setEndTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(date)); - return this; - } - - @Override - public Launch get() { - return launch; - } + private static final int LAUNCH_DESCRIPTION_LENGTH_LIMIT = 2048; + private static final int DESCRIPTION_START_SYMBOL_INDEX = 0; + + private Launch launch; + + public LaunchBuilder() { + this.launch = new Launch(); + } + + public LaunchBuilder(Launch launch) { + this.launch = launch; + } + + public LaunchBuilder addStartRQ(StartLaunchRQ request) { + Preconditions.checkNotNull(request, ErrorType.BAD_REQUEST_ERROR); + launch.setStartTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(request.getStartTime())); + launch.setName(request.getName().trim()); + launch.setStatus(StatusEnum.IN_PROGRESS); + launch.setUuid(Optional.ofNullable(request.getUuid()).orElse(UUID.randomUUID().toString())); + addDescription(request.getDescription()); + LaunchModeEnum.findByName( + ofNullable(request.getMode()).map(Enum::name).orElse(LaunchModeEnum.DEFAULT.name())) + .ifPresent(it -> launch.setMode(it)); + return this; + } + + public LaunchBuilder addDescription(String description) { + ofNullable(description).ifPresent(it -> launch.setDescription(StringUtils.substring(it.trim(), + DESCRIPTION_START_SYMBOL_INDEX, + LAUNCH_DESCRIPTION_LENGTH_LIMIT + ))); + return this; + } + + public LaunchBuilder addUserId(Long userId) { + launch.setUserId(userId); + return this; + } + + public LaunchBuilder addProject(Long projectId) { + launch.setProjectId(projectId); + return this; + } + + public LaunchBuilder addAttribute(ItemAttributeResource attributeResource) { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(attributeResource); + itemAttribute.setLaunch(launch); + launch.getAttributes().add(itemAttribute); + return this; + } + + public LaunchBuilder addAttributes(Set<ItemAttributesRQ> attributes) { + ofNullable(attributes).ifPresent(it -> launch.getAttributes().addAll(it.stream().map(val -> { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); + itemAttribute.setLaunch(launch); + return itemAttribute; + }).collect(Collectors.toSet()))); + return this; + } + + public LaunchBuilder overwriteAttributes(Set<ItemAttributeResource> attributes) { + if (attributes != null) { + final Set<ItemAttribute> overwrittenAttributes = launch.getAttributes() + .stream() + .filter(ItemAttribute::isSystem) + .collect(Collectors.toSet()); + attributes.stream().map(val -> { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); + itemAttribute.setLaunch(launch); + return itemAttribute; + }).forEach(overwrittenAttributes::add); + launch.setAttributes(overwrittenAttributes); + } + return this; + } + + public LaunchBuilder addMode(Mode mode) { + ofNullable(mode).ifPresent(it -> launch.setMode(LaunchModeEnum.valueOf(it.name()))); + return this; + } + + public LaunchBuilder addStatus(String status) { + launch.setStatus(StatusEnum.fromValue(status) + .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FINISH_STATUS))); + return this; + } + + public LaunchBuilder addEndTime(Date date) { + launch.setEndTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(date)); + return this; + } + + @Override + public Launch get() { + return launch; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilder.java similarity index 51% rename from src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilder.java rename to src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilder.java index 8fd4622cdc..9f679b4dce 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilder.java @@ -16,55 +16,54 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; - import java.util.UUID; import java.util.function.Supplier; -import static java.util.Optional.ofNullable; - /** * @author Pavel Bortnik */ -public class LogBuilder implements Supplier<Log> { +public class LogFullBuilder implements Supplier<LogFull> { - private final Log log; + private final LogFull logFull; - public LogBuilder() { - log = new Log(); - } + public LogFullBuilder() { + logFull = new LogFull(); + } - public LogBuilder addSaveLogRq(SaveLogRQ createLogRQ) { - log.setLogLevel(LogLevel.toCustomLogLevel(createLogRQ.getLevel())); - log.setLogMessage(ofNullable(createLogRQ.getMessage()).orElse("NULL")); - log.setLogTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(createLogRQ.getLogTime())); - log.setUuid(ofNullable(createLogRQ.getUuid()).orElse(UUID.randomUUID().toString())); - return this; - } + public LogFullBuilder addSaveLogRq(SaveLogRQ createLogRQ) { + logFull.setLogLevel(LogLevel.toCustomLogLevel(createLogRQ.getLevel())); + logFull.setLogMessage(ofNullable(createLogRQ.getMessage()).orElse("NULL")); + logFull.setLogTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(createLogRQ.getLogTime())); + logFull.setUuid(ofNullable(createLogRQ.getUuid()).orElse(UUID.randomUUID().toString())); + return this; + } - public LogBuilder addTestItem(TestItem testItem) { - log.setTestItem(testItem); - return this; - } + public LogFullBuilder addTestItem(TestItem testItem) { + logFull.setTestItem(testItem); + return this; + } - public LogBuilder addLaunch(Launch launch) { - log.setLaunch(launch); - return this; - } + public LogFullBuilder addLaunch(Launch launch) { + logFull.setLaunch(launch); + return this; + } - public LogBuilder addProjectId(Long projectId) { - log.setProjectId(projectId); - return this; - } + public LogFullBuilder addProjectId(Long projectId) { + logFull.setProjectId(projectId); + return this; + } - @Override - public Log get() { - return log; - } + @Override + public LogFull get() { + return logFull; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilder.java index 18f009392f..f60ef03f0c 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilder.java @@ -22,59 +22,60 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; -import org.apache.commons.lang3.StringUtils; - import java.util.function.Supplier; +import org.apache.commons.lang3.StringUtils; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class PatternTemplateBuilder implements Supplier<PatternTemplate> { - private PatternTemplate patternTemplate; + private PatternTemplate patternTemplate; - public PatternTemplateBuilder() { - patternTemplate = new PatternTemplate(); - } + public PatternTemplateBuilder() { + patternTemplate = new PatternTemplate(); + } - public PatternTemplateBuilder withCreateRequest(CreatePatternTemplateRQ createRequest) { - patternTemplate.setTemplateType(PatternTemplateType.fromString(createRequest.getType()).orElseThrow(() -> new ReportPortalException( - ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Unknown pattern template type - '{}'", createRequest.getType()).get() - ))); - patternTemplate.setName(StringUtils.trim(createRequest.getName())); - patternTemplate.setValue(createRequest.getValue()); - patternTemplate.setEnabled(createRequest.getEnabled()); - return this; - } + public PatternTemplateBuilder withCreateRequest(CreatePatternTemplateRQ createRequest) { + patternTemplate.setTemplateType(PatternTemplateType.fromString(createRequest.getType()) + .orElseThrow(() -> new ReportPortalException( + ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Unknown pattern template type - '{}'", + createRequest.getType()).get() + ))); + patternTemplate.setName(StringUtils.trim(createRequest.getName())); + patternTemplate.setValue(createRequest.getValue()); + patternTemplate.setEnabled(createRequest.getEnabled()); + return this; + } - public PatternTemplateBuilder withName(String name) { - patternTemplate.setName(StringUtils.trim(name)); - return this; - } + public PatternTemplateBuilder withName(String name) { + patternTemplate.setName(StringUtils.trim(name)); + return this; + } - public PatternTemplateBuilder withValue(String value) { - patternTemplate.setValue(value); - return this; - } + public PatternTemplateBuilder withValue(String value) { + patternTemplate.setValue(value); + return this; + } - public PatternTemplateBuilder withType(PatternTemplateType type) { - patternTemplate.setTemplateType(type); - return this; - } + public PatternTemplateBuilder withType(PatternTemplateType type) { + patternTemplate.setTemplateType(type); + return this; + } - public PatternTemplateBuilder withEnabled(boolean isEnabled) { - patternTemplate.setEnabled(isEnabled); - return this; - } + public PatternTemplateBuilder withEnabled(boolean isEnabled) { + patternTemplate.setEnabled(isEnabled); + return this; + } - public PatternTemplateBuilder withProjectId(Long projectId) { - patternTemplate.setProjectId(projectId); - return this; - } + public PatternTemplateBuilder withProjectId(Long projectId) { + patternTemplate.setProjectId(projectId); + return this; + } - @Override - public PatternTemplate get() { - return patternTemplate; - } + @Override + public PatternTemplate get() { + return patternTemplate; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestCaseIdEntry.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestCaseIdEntry.java index d0c8d82df4..5a39771e01 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestCaseIdEntry.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestCaseIdEntry.java @@ -23,37 +23,37 @@ */ public class TestCaseIdEntry { - private String id; + private String id; - private int hash; + private int hash; - public String getId() { - return id; - } + public String getId() { + return id; + } - public int getHash() { - return hash; - } + public int getHash() { + return hash; + } - TestCaseIdEntry(String id, int hash) { - this.id = isCropNeeded(id) ? cropTestCaseId(id) : id; - this.hash = hash; - } + TestCaseIdEntry(String id, int hash) { + this.id = isCropNeeded(id) ? cropTestCaseId(id) : id; + this.hash = hash; + } - TestCaseIdEntry(int hash) { - this.hash = hash; - } + TestCaseIdEntry(int hash) { + this.hash = hash; + } - public static TestCaseIdEntry empty() { - return new TestCaseIdEntry(0); - } + public static TestCaseIdEntry empty() { + return new TestCaseIdEntry(0); + } - private static boolean isCropNeeded(String testCaseId) { - return Objects.nonNull(testCaseId) && testCaseId.length() > 1024; - } + private static boolean isCropNeeded(String testCaseId) { + return Objects.nonNull(testCaseId) && testCaseId.length() > 1024; + } - private static String cropTestCaseId(String testCaseId) { - return testCaseId.substring(0, 1011) + "[" + testCaseId.substring(1011).hashCode() + "]"; - } + private static String cropTestCaseId(String testCaseId) { + return testCaseId.substring(0, 1011) + "[" + testCaseId.substring(1011).hashCode() + "]"; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilder.java index 2a2eab4111..504b9885b0 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilder.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.StatusEnum; @@ -29,175 +33,197 @@ import com.epam.ta.reportportal.ws.model.StartTestItemRQ; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -import javax.annotation.Nullable; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import java.util.*; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.function.Supplier; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.ws.converter.converters.ItemAttributeConverter.FROM_RESOURCE; -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Optional.ofNullable; +import javax.annotation.Nullable; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; public class TestItemBuilder implements Supplier<TestItem> { - private static final int TEST_ITEM_DESCRIPTION_LENGTH_LIMIT = 2048; - private static final int DESCRIPTION_START_SYMBOL_INDEX = 0; - public static final String PARAMETER_NULL_VALUE = "NULL"; - - private TestItem testItem; - - public TestItemBuilder() { - testItem = new TestItem(); - } - - public TestItemBuilder(TestItem testItem) { - this.testItem = testItem; - } - - public TestItemBuilder addStartItemRequest(StartTestItemRQ rq) { - - testItem.setStartTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(rq.getStartTime())); - testItem.setName(rq.getName().trim()); - testItem.setUniqueId(rq.getUniqueId()); - testItem.setUuid(Optional.ofNullable(rq.getUuid()).orElse(UUID.randomUUID().toString())); - testItem.setHasStats(rq.isHasStats()); - - TestCaseIdEntry testCaseIdEntry = processTestCaseId(rq); - testItem.setTestCaseId(testCaseIdEntry.getId()); - testItem.setTestCaseHash(testCaseIdEntry.getHash()); - - testItem.setCodeRef(rq.getCodeRef()); - - TestItemResults testItemResults = new TestItemResults(); - testItemResults.setStatus(StatusEnum.IN_PROGRESS); - - testItemResults.setTestItem(testItem); - testItem.setItemResults(testItemResults); - - addDescription(rq.getDescription()); - addParameters(rq.getParameters()); - addType(rq.getType()); - return this; - } - - public TestItemBuilder addLaunchId(Long launchId) { - testItem.setLaunchId(launchId); - return this; - } - - public TestItemBuilder addParentId(Long parentId) { - testItem.setParentId(parentId); - return this; - } - - public TestItemBuilder addType(String typeValue) { - TestItemTypeEnum type = TestItemTypeEnum.fromValue(typeValue) - .orElseThrow(() -> new ReportPortalException(ErrorType.UNSUPPORTED_TEST_ITEM_TYPE, typeValue)); - testItem.setType(type); - return this; - } - - public TestItemBuilder addDescription(String description) { - ofNullable(description).ifPresent(it -> testItem.setDescription(StringUtils.substring(it.trim(), - DESCRIPTION_START_SYMBOL_INDEX, - TEST_ITEM_DESCRIPTION_LENGTH_LIMIT - ))); - return this; - } - - public TestItemBuilder addStatus(StatusEnum statusEnum) { - testItem.getItemResults().setStatus(statusEnum); - return this; - } - - public TestItemBuilder addTestCaseId(@Nullable String testCaseId) { - ofNullable(testCaseId).map(caseId -> new TestCaseIdEntry(testCaseId, testCaseId.hashCode())).ifPresent(entry -> { - testItem.setTestCaseId(entry.getId()); - testItem.setTestCaseHash(entry.getHash()); - }); - return this; - } - - public TestItemBuilder addAttributes(Set<ItemAttributesRQ> attributes) { - ofNullable(attributes).ifPresent(it -> testItem.getAttributes().addAll(it.stream().map(val -> { - ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); - itemAttribute.setTestItem(testItem); - return itemAttribute; - }).collect(Collectors.toSet()))); - return this; - } - - public TestItemBuilder overwriteAttributes(Set<? extends ItemAttributeResource> attributes) { - if (attributes != null) { - final Set<ItemAttribute> overwrittenAttributes = testItem.getAttributes() - .stream() - .filter(ItemAttribute::isSystem) - .collect(Collectors.toSet()); - attributes.stream().map(val -> { - ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); - itemAttribute.setTestItem(testItem); - return itemAttribute; - }).forEach(overwrittenAttributes::add); - testItem.setAttributes(overwrittenAttributes); - } - return this; - } - - public TestItemBuilder addTestItemResults(TestItemResults testItemResults) { - checkNotNull(testItemResults, "Provided value shouldn't be null"); - testItem.setItemResults(testItemResults); - addDuration(testItemResults.getEndTime()); - return this; - } - - public TestItemBuilder addDuration(LocalDateTime endTime) { - checkNotNull(endTime, "Provided value shouldn't be null"); - checkNotNull(testItem.getItemResults(), "Test item results shouldn't be null"); - - //converts to seconds - testItem.getItemResults().setDuration(ChronoUnit.MILLIS.between(testItem.getStartTime(), endTime) / 1000d); - return this; - } - - public TestItemBuilder addParameters(List<ParameterResource> parameters) { - if (!CollectionUtils.isEmpty(parameters)) { - testItem.setParameters(parameters.stream().map(it -> { - Parameter parameter = new Parameter(); - parameter.setKey(it.getKey()); - parameter.setValue(ofNullable(it.getValue()).orElse(PARAMETER_NULL_VALUE)); - return parameter; - }).collect(Collectors.toSet())); - } - return this; - } - - public static TestCaseIdEntry processTestCaseId(StartTestItemRQ startTestItemRQ) { - final String testCaseId = startTestItemRQ.getTestCaseId(); - if (Objects.nonNull(testCaseId)) { - return new TestCaseIdEntry(testCaseId, testCaseId.hashCode()); - } else { - final String codeRef = startTestItemRQ.getCodeRef(); - if (Objects.nonNull(codeRef)) { - String id = compose(codeRef, startTestItemRQ.getParameters()); - return new TestCaseIdEntry(id, id.hashCode()); - } - } - return TestCaseIdEntry.empty(); - } - - private static String compose(String codeRef, List<ParameterResource> parameters) { - return CollectionUtils.isEmpty(parameters) ? - codeRef : - codeRef + "[" + parameters.stream().map(ParameterResource::getValue).collect(Collectors.joining(",")) + "]"; - } - - @Override - public TestItem get() { - return this.testItem; - } + private static final int TEST_ITEM_DESCRIPTION_LENGTH_LIMIT = 2048; + private static final int DESCRIPTION_START_SYMBOL_INDEX = 0; + public static final String PARAMETER_NULL_VALUE = "NULL"; + + private TestItem testItem; + + public TestItemBuilder() { + testItem = new TestItem(); + } + + public TestItemBuilder(TestItem testItem) { + this.testItem = testItem; + } + + public TestItemBuilder addStartItemRequest(StartTestItemRQ rq) { + + testItem.setStartTime(EntityUtils.TO_LOCAL_DATE_TIME.apply(rq.getStartTime())); + testItem.setName(rq.getName().trim()); + testItem.setUniqueId(rq.getUniqueId()); + testItem.setUuid(Optional.ofNullable(rq.getUuid()).orElse(UUID.randomUUID().toString())); + testItem.setHasStats(rq.isHasStats()); + + TestCaseIdEntry testCaseIdEntry = processTestCaseId(rq); + testItem.setTestCaseId(testCaseIdEntry.getId()); + testItem.setTestCaseHash(testCaseIdEntry.getHash()); + + testItem.setCodeRef(rq.getCodeRef()); + + TestItemResults testItemResults = new TestItemResults(); + testItemResults.setStatus(StatusEnum.IN_PROGRESS); + + testItemResults.setTestItem(testItem); + testItem.setItemResults(testItemResults); + + addDescription(rq.getDescription()); + addParameters(rq.getParameters()); + addType(rq.getType()); + return this; + } + + public TestItemBuilder addLaunchId(Long launchId) { + testItem.setLaunchId(launchId); + return this; + } + + public TestItemBuilder addParentId(Long parentId) { + testItem.setParentId(parentId); + return this; + } + + public TestItemBuilder addType(String typeValue) { + TestItemTypeEnum type = TestItemTypeEnum.fromValue(typeValue) + .orElseThrow( + () -> new ReportPortalException(ErrorType.UNSUPPORTED_TEST_ITEM_TYPE, typeValue)); + testItem.setType(type); + return this; + } + + public TestItemBuilder addDescription(String description) { + ofNullable(description).ifPresent(it -> testItem.setDescription(StringUtils.substring(it.trim(), + DESCRIPTION_START_SYMBOL_INDEX, + TEST_ITEM_DESCRIPTION_LENGTH_LIMIT + ))); + return this; + } + + public TestItemBuilder addStatus(StatusEnum statusEnum) { + testItem.getItemResults().setStatus(statusEnum); + return this; + } + + public TestItemBuilder addTestCaseId(@Nullable String testCaseId) { + ofNullable(testCaseId).map(caseId -> new TestCaseIdEntry(testCaseId, testCaseId.hashCode())) + .ifPresent(entry -> { + testItem.setTestCaseId(entry.getId()); + testItem.setTestCaseHash(entry.getHash()); + }); + return this; + } + + public TestItemBuilder addAttributes(Set<ItemAttributesRQ> attributes) { + ofNullable(attributes).ifPresent(it -> testItem.getAttributes().addAll(it.stream().map(val -> { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); + itemAttribute.setTestItem(testItem); + return itemAttribute; + }).collect(Collectors.toSet()))); + return this; + } + + public TestItemBuilder overwriteAttributesValues(Set<? extends ItemAttributeResource> attributes) { + if (attributes != null) { + attributes.forEach(val -> { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); + itemAttribute.setTestItem(testItem); + Optional<ItemAttribute> existingAttr = testItem.getAttributes().stream() + .filter(attr -> Objects.nonNull(attr.getKey()) && attr.getKey() + .equals(itemAttribute.getKey())) + .findFirst(); + if (existingAttr.isPresent()) { + existingAttr.get().setValue(itemAttribute.getValue()); + } else { + testItem.getAttributes().add(itemAttribute); + } + }); + } + return this; + } + + public TestItemBuilder overwriteAttributes(Set<? extends ItemAttributeResource> attributes) { + if (attributes != null) { + final Set<ItemAttribute> overwrittenAttributes = testItem.getAttributes() + .stream() + .filter(ItemAttribute::isSystem) + .collect(Collectors.toSet()); + attributes.stream().map(val -> { + ItemAttribute itemAttribute = FROM_RESOURCE.apply(val); + itemAttribute.setTestItem(testItem); + return itemAttribute; + }).forEach(overwrittenAttributes::add); + testItem.setAttributes(overwrittenAttributes); + } + return this; + } + + public TestItemBuilder addTestItemResults(TestItemResults testItemResults) { + checkNotNull(testItemResults, "Provided value shouldn't be null"); + testItem.setItemResults(testItemResults); + addDuration(testItemResults.getEndTime()); + return this; + } + + public TestItemBuilder addDuration(LocalDateTime endTime) { + checkNotNull(endTime, "Provided value shouldn't be null"); + checkNotNull(testItem.getItemResults(), "Test item results shouldn't be null"); + + //converts to seconds + testItem.getItemResults() + .setDuration(ChronoUnit.MILLIS.between(testItem.getStartTime(), endTime) / 1000d); + return this; + } + + public TestItemBuilder addParameters(List<ParameterResource> parameters) { + if (!CollectionUtils.isEmpty(parameters)) { + testItem.setParameters(parameters.stream().map(it -> { + Parameter parameter = new Parameter(); + parameter.setKey(it.getKey()); + parameter.setValue(ofNullable(it.getValue()).orElse(PARAMETER_NULL_VALUE)); + return parameter; + }).collect(Collectors.toSet())); + } + return this; + } + + public static TestCaseIdEntry processTestCaseId(StartTestItemRQ startTestItemRQ) { + final String testCaseId = startTestItemRQ.getTestCaseId(); + if (Objects.nonNull(testCaseId)) { + return new TestCaseIdEntry(testCaseId, testCaseId.hashCode()); + } else { + final String codeRef = startTestItemRQ.getCodeRef(); + if (Objects.nonNull(codeRef)) { + String id = compose(codeRef, startTestItemRQ.getParameters()); + return new TestCaseIdEntry(id, id.hashCode()); + } + } + return TestCaseIdEntry.empty(); + } + + private static String compose(String codeRef, List<ParameterResource> parameters) { + return CollectionUtils.isEmpty(parameters) ? + codeRef : + codeRef + "[" + parameters.stream().map(ParameterResource::getValue) + .collect(Collectors.joining(",")) + "]"; + } + + @Override + public TestItem get() { + return this.testItem; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilder.java index 97272a07cb..1586fc65f1 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilder.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.Metadata; import com.epam.ta.reportportal.entity.user.User; @@ -23,65 +25,62 @@ import com.epam.ta.reportportal.entity.user.UserType; import com.epam.ta.reportportal.ws.model.user.CreateUserRQConfirm; import com.epam.ta.reportportal.ws.model.user.CreateUserRQFull; - import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class UserBuilder implements Supplier<User> { - public static final String USER_LAST_LOGIN = "last_login"; - private User user; + public static final String USER_LAST_LOGIN = "last_login"; + private User user; - public UserBuilder() { - user = new User(); - } + public UserBuilder() { + user = new User(); + } - public UserBuilder(User user) { - this.user = user; - } + public UserBuilder(User user) { + this.user = user; + } - public UserBuilder addCreateUserRQ(CreateUserRQConfirm request) { - ofNullable(request).ifPresent(r -> fillUser(r.getLogin(), r.getEmail(), r.getFullName())); - return this; - } + public UserBuilder addCreateUserRQ(CreateUserRQConfirm request) { + ofNullable(request).ifPresent(r -> fillUser(r.getLogin(), r.getEmail(), r.getFullName())); + return this; + } - public UserBuilder addCreateUserFullRQ(CreateUserRQFull request) { - ofNullable(request).ifPresent(it -> fillUser(it.getLogin(), it.getEmail(), it.getFullName())); - return this; - } + public UserBuilder addCreateUserFullRQ(CreateUserRQFull request) { + ofNullable(request).ifPresent(it -> fillUser(it.getLogin(), it.getEmail(), it.getFullName())); + return this; + } - public UserBuilder addPassword(String password) { - user.setPassword(password); - return this; - } + public UserBuilder addPassword(String password) { + user.setPassword(password); + return this; + } - public UserBuilder addUserRole(UserRole userRole) { - user.setRole(userRole); - return this; - } + public UserBuilder addUserRole(UserRole userRole) { + user.setRole(userRole); + return this; + } - @Override - public User get() { + @Override + public User get() { - //TODO check for existing of the default project etc. - return user; - } + //TODO check for existing of the default project etc. + return user; + } - private void fillUser(String login, String email, String fullName) { - user.setLogin(EntityUtils.normalizeId(login)); - ofNullable(email).map(String::trim).map(EntityUtils::normalizeId).ifPresent(user::setEmail); - user.setFullName(fullName); - user.setUserType(UserType.INTERNAL); - user.setExpired(false); - Map<String, Object> meta = new HashMap<>(); - meta.put(USER_LAST_LOGIN, new Date()); - user.setMetadata(new Metadata(meta)); - } + private void fillUser(String login, String email, String fullName) { + user.setLogin(EntityUtils.normalizeId(login)); + ofNullable(email).map(String::trim).map(EntityUtils::normalizeId).ifPresent(user::setEmail); + user.setFullName(fullName); + user.setUserType(UserType.INTERNAL); + user.setExpired(false); + Map<String, Object> meta = new HashMap<>(); + meta.put(USER_LAST_LOGIN, new Date()); + user.setMetadata(new Metadata(meta)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilder.java b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilder.java index 6da3de8ede..6780a78d1b 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilder.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilder.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.preference.UserPreference; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.user.User; - import java.util.function.Supplier; /** @@ -28,33 +27,33 @@ */ public class UserPreferenceBuilder implements Supplier<UserPreference> { - private UserPreference userPreference; - - public UserPreferenceBuilder() { - userPreference = new UserPreference(); - } - - public UserPreferenceBuilder withProject(Long id) { - Project project = new Project(); - project.setId(id); - userPreference.setProject(project); - return this; - } - - public UserPreferenceBuilder withUser(Long id) { - User user = new User(); - user.setId(id); - userPreference.setUser(user); - return this; - } - - public UserPreferenceBuilder withFilter(UserFilter filter) { - userPreference.setFilter(filter); - return this; - } - - @Override - public UserPreference get() { - return userPreference; - } + private UserPreference userPreference; + + public UserPreferenceBuilder() { + userPreference = new UserPreference(); + } + + public UserPreferenceBuilder withProject(Long id) { + Project project = new Project(); + project.setId(id); + userPreference.setProject(project); + return this; + } + + public UserPreferenceBuilder withUser(Long id) { + User user = new User(); + user.setId(id); + userPreference.setUser(user); + return this; + } + + public UserPreferenceBuilder withFilter(UserFilter filter) { + userPreference.setFilter(filter); + return this; + } + + @Override + public UserPreference get() { + return userPreference; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ActivityEventConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ActivityEventConverter.java index e88c449149..3889e3bab4 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ActivityEventConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ActivityEventConverter.java @@ -19,6 +19,7 @@ import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.activity.Activity; import com.epam.ta.reportportal.ws.model.ActivityEventResource; +import java.util.Objects; import java.util.function.Function; /** @@ -43,6 +44,7 @@ private ActivityEventConverter() { .projectName(activity.getProjectName()) .subjectName(activity.getSubjectName()) .subjectType(activity.getSubjectType().getValue()) + .subjectId(Objects.toString(activity.getSubjectId(), null)) .details(activity.getDetails()) .build(); diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/BaseEntityConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/BaseEntityConverter.java index 04fc3153d3..96f6c2086b 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/BaseEntityConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/BaseEntityConverter.java @@ -26,14 +26,14 @@ */ public final class BaseEntityConverter { - private BaseEntityConverter() { - //static only - } + private BaseEntityConverter() { + //static only + } - public static final Function<? super OwnedEntity, OwnedEntityResource> TO_OWNED_ENTITY = shareable -> { - OwnedEntityResource ownedEntity = new OwnedEntityResource(); - ownedEntity.setId(String.valueOf(shareable.getId())); - ownedEntity.setOwner(shareable.getOwner()); - return ownedEntity; - }; + public static final Function<? super OwnedEntity, OwnedEntityResource> TO_OWNED_ENTITY = shareable -> { + OwnedEntityResource ownedEntity = new OwnedEntityResource(); + ownedEntity.setId(String.valueOf(shareable.getId())); + ownedEntity.setOwner(shareable.getOwner()); + return ownedEntity; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ClusterConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ClusterConverter.java index 6db9ef203e..4b08a0ae6f 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ClusterConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ClusterConverter.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterInfoRs; import com.epam.ta.reportportal.entity.cluster.Cluster; import com.epam.ta.reportportal.ws.model.launch.cluster.ClusterInfoResource; - import java.util.function.Function; /** @@ -27,23 +26,23 @@ */ public class ClusterConverter { - private ClusterConverter() { - //static only - } + private ClusterConverter() { + //static only + } - public static final Function<ClusterInfoRs, Cluster> TO_CLUSTER = rs -> { - final Cluster cluster = new Cluster(); - cluster.setIndexId(rs.getClusterId()); - cluster.setMessage(rs.getClusterMessage()); - return cluster; - }; + public static final Function<ClusterInfoRs, Cluster> TO_CLUSTER = rs -> { + final Cluster cluster = new Cluster(); + cluster.setIndexId(rs.getClusterId()); + cluster.setMessage(rs.getClusterMessage()); + return cluster; + }; - public static final Function<Cluster, ClusterInfoResource> TO_CLUSTER_INFO = c -> { - final ClusterInfoResource resource = new ClusterInfoResource(); - resource.setId(c.getId()); - resource.setIndex(c.getIndexId()); - resource.setLaunchId(c.getLaunchId()); - resource.setMessage(c.getMessage()); - return resource; - }; + public static final Function<Cluster, ClusterInfoResource> TO_CLUSTER_INFO = c -> { + final ClusterInfoResource resource = new ClusterInfoResource(); + resource.setId(c.getId()); + resource.setIndex(c.getIndexId()); + resource.setLaunchId(c.getLaunchId()); + resource.setMessage(c.getMessage()); + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ExceptionConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ExceptionConverter.java index 3f821ce5af..5bda88f895 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ExceptionConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ExceptionConverter.java @@ -2,19 +2,18 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorRS; - import java.util.function.Function; public class ExceptionConverter { - private ExceptionConverter() { - //static only - } + private ExceptionConverter() { + //static only + } - public static final Function<ReportPortalException, ErrorRS> TO_ERROR_RS = ex -> { - ErrorRS errorResponse = new ErrorRS(); - errorResponse.setErrorType(ex.getErrorType()); - errorResponse.setMessage(ex.getMessage()); - return errorResponse; - }; + public static final Function<ReportPortalException, ErrorRS> TO_ERROR_RS = ex -> { + ErrorRS errorResponse = new ErrorRS(); + errorResponse.setErrorType(ex.getErrorType()); + errorResponse.setMessage(ex.getMessage()); + return errorResponse; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverter.java index 62a9fe8833..0200049578 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverter.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.core.integration.util.property.AuthProperties; import com.epam.ta.reportportal.core.integration.util.property.BtsProperties; @@ -27,7 +29,6 @@ import com.epam.ta.reportportal.ws.model.integration.AuthFlowEnum; import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,67 +36,70 @@ import java.util.function.Function; import java.util.function.Predicate; -import static java.util.Optional.ofNullable; - /** * @author Pavel Bortnik */ public final class IntegrationConverter { - private static final List<String> IGNORE_FIELDS = List.of(EmailSettingsEnum.PASSWORD.getAttribute(), - SauceLabsProperties.ACCESS_TOKEN.getName(), - BtsProperties.OAUTH_ACCESS_KEY.getName(), - BtsProperties.API_TOKEN.getName(), - AuthProperties.MANAGER_PASSWORD.getName() - ); + private static final List<String> IGNORE_FIELDS = List.of( + EmailSettingsEnum.PASSWORD.getAttribute(), + SauceLabsProperties.ACCESS_TOKEN.getName(), + BtsProperties.OAUTH_ACCESS_KEY.getName(), + BtsProperties.API_TOKEN.getName(), + AuthProperties.MANAGER_PASSWORD.getName() + ); - private static final Predicate<Map.Entry<String, Object>> IGNORE_FIELDS_CONDITION = entry -> IGNORE_FIELDS.stream() - .noneMatch(field -> field.equalsIgnoreCase(entry.getKey())); + private static final Predicate<Map.Entry<String, Object>> IGNORE_FIELDS_CONDITION = entry -> IGNORE_FIELDS.stream() + .noneMatch(field -> field.equalsIgnoreCase(entry.getKey())); - public static final Function<Integration, IntegrationResource> TO_INTEGRATION_RESOURCE = integration -> { - IntegrationResource resource = new IntegrationResource(); - resource.setId(integration.getId()); - resource.setName(integration.getName()); - resource.setCreator(integration.getCreator()); - resource.setCreationDate(EntityUtils.TO_DATE.apply(integration.getCreationDate())); - resource.setEnabled(integration.isEnabled()); - ofNullable(integration.getProject()).ifPresent(p -> resource.setProjectId(p.getId())); - ofNullable(integration.getParams()).flatMap(IntegrationConverter::convertToResourceParams) - .ifPresent(resource::setIntegrationParams); - IntegrationTypeResource type = new IntegrationTypeResource(); - type.setId(integration.getType().getId()); - type.setName(integration.getType().getName()); - type.setEnabled(integration.getType().isEnabled()); - type.setCreationDate(EntityUtils.TO_DATE.apply(integration.getType().getCreationDate())); - type.setGroupType(integration.getType().getIntegrationGroup().name()); - ofNullable(integration.getType().getDetails()).ifPresent(it -> type.setDetails(it.getDetails())); - ofNullable(integration.getType().getAuthFlow()).ifPresent(it -> type.setAuthFlow(AuthFlowEnum.valueOf(it.name()))); - resource.setIntegrationType(type); + public static final Function<Integration, IntegrationResource> TO_INTEGRATION_RESOURCE = integration -> { + IntegrationResource resource = new IntegrationResource(); + resource.setId(integration.getId()); + resource.setName(integration.getName()); + resource.setCreator(integration.getCreator()); + resource.setCreationDate(EntityUtils.TO_DATE.apply(integration.getCreationDate())); + resource.setEnabled(integration.isEnabled()); + ofNullable(integration.getProject()).ifPresent(p -> resource.setProjectId(p.getId())); + ofNullable(integration.getParams()).flatMap(IntegrationConverter::convertToResourceParams) + .ifPresent(resource::setIntegrationParams); + IntegrationTypeResource type = new IntegrationTypeResource(); + type.setId(integration.getType().getId()); + type.setName(integration.getType().getName()); + type.setEnabled(integration.getType().isEnabled()); + type.setCreationDate(EntityUtils.TO_DATE.apply(integration.getType().getCreationDate())); + type.setGroupType(integration.getType().getIntegrationGroup().name()); + ofNullable(integration.getType().getDetails()).ifPresent( + it -> type.setDetails(it.getDetails())); + ofNullable(integration.getType().getAuthFlow()).ifPresent( + it -> type.setAuthFlow(AuthFlowEnum.valueOf(it.name()))); + resource.setIntegrationType(type); - return resource; - }; + return resource; + }; - private static Optional<Map<String, Object>> convertToResourceParams(IntegrationParams it) { - return ofNullable(it.getParams()).map(p -> p.entrySet() - .stream() - .filter(IGNORE_FIELDS_CONDITION) - .collect(HashMap::new, (resourceParams, entry) -> resourceParams.put(entry.getKey(), entry.getValue()), Map::putAll)); - } + private static Optional<Map<String, Object>> convertToResourceParams(IntegrationParams it) { + return ofNullable(it.getParams()).map(p -> p.entrySet() + .stream() + .filter(IGNORE_FIELDS_CONDITION) + .collect(HashMap::new, + (resourceParams, entry) -> resourceParams.put(entry.getKey(), entry.getValue()), + Map::putAll)); + } - public static final Function<Integration, IntegrationActivityResource> TO_ACTIVITY_RESOURCE = integration -> { - IntegrationActivityResource resource = new IntegrationActivityResource(); - resource.setId(integration.getId()); - resource.setName(integration.getName()); - ofNullable(integration.getProject()).ifPresent(p -> { - resource.setProjectId(p.getId()); - resource.setProjectName(p.getName()); - }); - resource.setTypeName(integration.getType().getName()); - return resource; - }; + public static final Function<Integration, IntegrationActivityResource> TO_ACTIVITY_RESOURCE = integration -> { + IntegrationActivityResource resource = new IntegrationActivityResource(); + resource.setId(integration.getId()); + resource.setName(integration.getName()); + ofNullable(integration.getProject()).ifPresent(p -> { + resource.setProjectId(p.getId()); + resource.setProjectName(p.getName()); + }); + resource.setTypeName(integration.getType().getName()); + return resource; + }; - private IntegrationConverter() { - //static only - } + private IntegrationConverter() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverter.java index 9dba5e0a6d..08b28e97da 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverter.java @@ -16,71 +16,69 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.bts.DefectFieldAllowedValue; import com.epam.ta.reportportal.entity.bts.DefectFormField; import com.epam.ta.reportportal.ws.model.externalsystem.AllowedValue; import com.epam.ta.reportportal.ws.model.externalsystem.PostFormField; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; -import org.apache.commons.collections.CollectionUtils; - import java.util.ArrayList; import java.util.HashSet; import java.util.function.Function; import java.util.stream.Collectors; - -import static java.util.Optional.ofNullable; +import org.apache.commons.collections.CollectionUtils; /** * @author Pavel Bortnik */ public final class IntegrationFieldsConverter { - private IntegrationFieldsConverter() { - //static only - } - - public static final Function<PostFormField, DefectFormField> FIELD_TO_DB = field -> { - Preconditions.checkNotNull(field); - DefectFormField defectFormField = new DefectFormField(); - defectFormField.setFieldId(field.getId()); - defectFormField.setType(field.getFieldType()); - defectFormField.setRequired(field.getIsRequired()); - if (!CollectionUtils.isEmpty(field.getValue())) { - defectFormField.setValues(new HashSet<>(field.getValue())); - } - - defectFormField.setDefectFieldAllowedValues(ofNullable(field.getDefinedValues()).map(dvs -> dvs.stream() - .map(IntegrationFieldsConverter.VALUE_TO_DB) - .collect(Collectors.toSet())).orElseGet(Sets::newHashSet)); - return defectFormField; - }; - - public static final Function<DefectFormField, PostFormField> FIELD_TO_MODEL = defectFormField -> { - Preconditions.checkNotNull(defectFormField); - PostFormField postFormField = new PostFormField(); - postFormField.setId(defectFormField.getFieldId()); - postFormField.setFieldType(defectFormField.getType()); - postFormField.setIsRequired(defectFormField.isRequired()); - postFormField.setDefinedValues(defectFormField.getDefectFieldAllowedValues().stream().map(IntegrationFieldsConverter.VALUE_TO_MODEL) - .collect(Collectors.toList())); - postFormField.setValue(new ArrayList<>(defectFormField.getValues())); - return postFormField; - }; + public static final Function<AllowedValue, DefectFieldAllowedValue> VALUE_TO_DB = value -> { + Preconditions.checkNotNull(value); + DefectFieldAllowedValue allowedValue = new DefectFieldAllowedValue(); + allowedValue.setValueId(value.getValueId()); + allowedValue.setValueName(value.getValueName()); + return allowedValue; + }; + public static final Function<PostFormField, DefectFormField> FIELD_TO_DB = field -> { + Preconditions.checkNotNull(field); + DefectFormField defectFormField = new DefectFormField(); + defectFormField.setFieldId(field.getId()); + defectFormField.setType(field.getFieldType()); + defectFormField.setRequired(field.getIsRequired()); + if (!CollectionUtils.isEmpty(field.getValue())) { + defectFormField.setValues(new HashSet<>(field.getValue())); + } - public static final Function<AllowedValue, DefectFieldAllowedValue> VALUE_TO_DB = value -> { - Preconditions.checkNotNull(value); - DefectFieldAllowedValue allowedValue = new DefectFieldAllowedValue(); - allowedValue.setValueId(value.getValueId()); - allowedValue.setValueName(value.getValueName()); - return allowedValue; - }; + defectFormField.setDefectFieldAllowedValues( + ofNullable(field.getDefinedValues()).map(dvs -> dvs.stream() + .map(IntegrationFieldsConverter.VALUE_TO_DB) + .collect(Collectors.toSet())).orElseGet(Sets::newHashSet)); + return defectFormField; + }; + public static final Function<DefectFieldAllowedValue, AllowedValue> VALUE_TO_MODEL = defectFieldAllowedValue -> { + Preconditions.checkNotNull(defectFieldAllowedValue); + AllowedValue allowedValue = new AllowedValue(); + allowedValue.setValueId(defectFieldAllowedValue.getValueId()); + allowedValue.setValueName(defectFieldAllowedValue.getValueName()); + return allowedValue; + }; + public static final Function<DefectFormField, PostFormField> FIELD_TO_MODEL = defectFormField -> { + Preconditions.checkNotNull(defectFormField); + PostFormField postFormField = new PostFormField(); + postFormField.setId(defectFormField.getFieldId()); + postFormField.setFieldType(defectFormField.getType()); + postFormField.setIsRequired(defectFormField.isRequired()); + postFormField.setDefinedValues(defectFormField.getDefectFieldAllowedValues().stream() + .map(IntegrationFieldsConverter.VALUE_TO_MODEL) + .collect(Collectors.toList())); + postFormField.setValue(new ArrayList<>(defectFormField.getValues())); + return postFormField; + }; - public static final Function<DefectFieldAllowedValue, AllowedValue> VALUE_TO_MODEL = defectFieldAllowedValue -> { - Preconditions.checkNotNull(defectFieldAllowedValue); - AllowedValue allowedValue = new AllowedValue(); - allowedValue.setValueId(defectFieldAllowedValue.getValueId()); - allowedValue.setValueName(defectFieldAllowedValue.getValueName()); - return allowedValue; - }; + private IntegrationFieldsConverter() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationTypeConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationTypeConverter.java index 6cc2c0f62e..ee68f161e9 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationTypeConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationTypeConverter.java @@ -16,31 +16,31 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; - import java.util.function.Function; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public final class IntegrationTypeConverter { - public static final Function<IntegrationType, IntegrationTypeResource> TO_RESOURCE = integrationType -> { - IntegrationTypeResource resource = new IntegrationTypeResource(); - resource.setId(integrationType.getId()); - resource.setName(integrationType.getName()); - resource.setEnabled(integrationType.isEnabled()); - resource.setCreationDate(EntityUtils.TO_DATE.apply(integrationType.getCreationDate())); - resource.setGroupType(integrationType.getIntegrationGroup().name()); - ofNullable(integrationType.getDetails()).ifPresent(it -> resource.setDetails(integrationType.getDetails().getDetails())); - return resource; - }; + public static final Function<IntegrationType, IntegrationTypeResource> TO_RESOURCE = integrationType -> { + IntegrationTypeResource resource = new IntegrationTypeResource(); + resource.setId(integrationType.getId()); + resource.setName(integrationType.getName()); + resource.setEnabled(integrationType.isEnabled()); + resource.setCreationDate(EntityUtils.TO_DATE.apply(integrationType.getCreationDate())); + resource.setGroupType(integrationType.getIntegrationGroup().name()); + ofNullable(integrationType.getDetails()).ifPresent( + it -> resource.setDetails(integrationType.getDetails().getDetails())); + return resource; + }; - private IntegrationTypeConverter() { - //static only - } + private IntegrationTypeConverter() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverter.java index 869018255f..10bc73c11d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverter.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.google.common.base.Preconditions; - import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -30,44 +29,45 @@ */ public final class IssueConverter { - private IssueConverter() { - //static only - } + private IssueConverter() { + //static only + } - public static final Function<Issue, IssueEntity> TO_ISSUE = from -> { - IssueEntity issue = new IssueEntity(); - issue.setAutoAnalyzed(from.getAutoAnalyzed()); - issue.setIgnoreAnalyzer(from.getIgnoreAnalyzer()); - issue.setIssueDescription(from.getComment()); - return issue; - }; + public static final Function<Issue, IssueEntity> TO_ISSUE = from -> { + IssueEntity issue = new IssueEntity(); + issue.setAutoAnalyzed(from.getAutoAnalyzed()); + issue.setIgnoreAnalyzer(from.getIgnoreAnalyzer()); + issue.setIssueDescription(from.getComment()); + return issue; + }; - /** - * Converts external system from db to model - */ - public static final Function<Ticket, Issue.ExternalSystemIssue> TO_MODEL_EXTERNAL = externalSystemIssue -> { - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setTicketId(externalSystemIssue.getTicketId()); - ticket.setBtsUrl(externalSystemIssue.getBtsUrl()); - ticket.setUrl(externalSystemIssue.getUrl()); - ticket.setBtsProject(externalSystemIssue.getBtsProject()); - ticket.setPluginName(externalSystemIssue.getPluginName()); - return ticket; - }; - /** - * Converts issue from db to model - */ - public static final Function<IssueEntity, Issue> TO_MODEL = issueEntity -> { - Preconditions.checkNotNull(issueEntity); - Issue issue = new Issue(); - issue.setIssueType(issueEntity.getIssueType().getLocator()); - issue.setAutoAnalyzed(issueEntity.getAutoAnalyzed()); - issue.setIgnoreAnalyzer(issueEntity.getIgnoreAnalyzer()); - issue.setComment(issueEntity.getIssueDescription()); + /** + * Converts external system from db to model + */ + public static final Function<Ticket, Issue.ExternalSystemIssue> TO_MODEL_EXTERNAL = externalSystemIssue -> { + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setTicketId(externalSystemIssue.getTicketId()); + ticket.setBtsUrl(externalSystemIssue.getBtsUrl()); + ticket.setUrl(externalSystemIssue.getUrl()); + ticket.setBtsProject(externalSystemIssue.getBtsProject()); + ticket.setPluginName(externalSystemIssue.getPluginName()); + return ticket; + }; + /** + * Converts issue from db to model + */ + public static final Function<IssueEntity, Issue> TO_MODEL = issueEntity -> { + Preconditions.checkNotNull(issueEntity); + Issue issue = new Issue(); + issue.setIssueType(issueEntity.getIssueType().getLocator()); + issue.setAutoAnalyzed(issueEntity.getAutoAnalyzed()); + issue.setIgnoreAnalyzer(issueEntity.getIgnoreAnalyzer()); + issue.setComment(issueEntity.getIssueDescription()); - Optional.ofNullable(issueEntity.getTickets()).ifPresent(tickets -> { - issue.setExternalSystemIssues(tickets.stream().map(IssueConverter.TO_MODEL_EXTERNAL).collect(Collectors.toSet())); - }); - return issue; - }; + Optional.ofNullable(issueEntity.getTickets()).ifPresent(tickets -> { + issue.setExternalSystemIssues( + tickets.stream().map(IssueConverter.TO_MODEL_EXTERNAL).collect(Collectors.toSet())); + }); + return issue; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueTypeConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueTypeConverter.java index 73605a8287..98e0423176 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueTypeConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/IssueTypeConverter.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.ws.model.activity.IssueTypeActivityResource; - import java.util.function.Function; /** @@ -26,14 +25,14 @@ */ public class IssueTypeConverter { - private IssueTypeConverter() { - //static only - } + private IssueTypeConverter() { + //static only + } - public static final Function<IssueType, IssueTypeActivityResource> TO_ACTIVITY_RESOURCE = issueType -> { - IssueTypeActivityResource resource = new IssueTypeActivityResource(); - resource.setId(issueType.getId()); - resource.setLongName(issueType.getLongName()); - return resource; - }; + public static final Function<IssueType, IssueTypeActivityResource> TO_ACTIVITY_RESOURCE = issueType -> { + IssueTypeActivityResource resource = new IssueTypeActivityResource(); + resource.setId(issueType.getId()); + resource.setLongName(issueType.getLongName()); + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LaunchConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LaunchConverter.java index 1cbd1ed0dd..eeceb6ae92 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LaunchConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LaunchConverter.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; import com.epam.ta.reportportal.dao.UserRepository; @@ -28,17 +32,12 @@ import com.epam.ta.reportportal.ws.model.launch.LaunchResource; import com.epam.ta.reportportal.ws.model.launch.Mode; import com.google.common.base.Preconditions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.function.Function; - -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.toSet; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author Pavel Bortnik @@ -46,57 +45,63 @@ @Service public class LaunchConverter { - @Autowired - private AnalyzerStatusCache analyzerStatusCache; + @Autowired + private AnalyzerStatusCache analyzerStatusCache; - @Autowired - private UserRepository userRepository; + @Autowired + private UserRepository userRepository; - @Autowired - private ItemAttributeTypeResolver itemAttributeTypeResolver; + @Autowired + private ItemAttributeTypeResolver itemAttributeTypeResolver; - @Autowired - private Map<ItemAttributeType, ResourceAttributeHandler<LaunchResource>> resourceAttributeUpdaterMapping; + @Autowired + private Map<ItemAttributeType, ResourceAttributeHandler<LaunchResource>> resourceAttributeUpdaterMapping; - public static final Function<Launch, LaunchActivityResource> TO_ACTIVITY_RESOURCE = launch -> { - LaunchActivityResource resource = new LaunchActivityResource(); - resource.setId(launch.getId()); - resource.setProjectId(launch.getProjectId()); - resource.setName(launch.getName() + " #" + launch.getNumber()); - return resource; - }; + public static final Function<Launch, LaunchActivityResource> TO_ACTIVITY_RESOURCE = launch -> { + LaunchActivityResource resource = new LaunchActivityResource(); + resource.setId(launch.getId()); + resource.setProjectId(launch.getProjectId()); + resource.setName(launch.getName() + " #" + launch.getNumber()); + return resource; + }; - public Function<Launch, LaunchResource> TO_RESOURCE = db -> { + public Function<Launch, LaunchResource> TO_RESOURCE = db -> { - Preconditions.checkNotNull(db); + Preconditions.checkNotNull(db); - LaunchResource resource = new LaunchResource(); - resource.setLaunchId(db.getId()); - resource.setUuid(db.getUuid()); - resource.setName(db.getName()); - resource.setNumber(db.getNumber()); - resource.setDescription(db.getDescription()); - resource.setStatus(db.getStatus() == null ? null : db.getStatus().toString()); - resource.setStartTime(db.getStartTime() == null ? null : EntityUtils.TO_DATE.apply(db.getStartTime())); - resource.setEndTime(db.getEndTime() == null ? null : EntityUtils.TO_DATE.apply(db.getEndTime())); - ofNullable(db.getLastModified()).map(EntityUtils.TO_DATE).ifPresent(resource::setLastModified); - ofNullable(db.getAttributes()).ifPresent(attributes -> updateAttributes(resource, attributes)); - ofNullable(resource.getAttributes()).ifPresentOrElse(a -> { - }, () -> resource.setAttributes(Collections.emptySet())); - resource.setMode(db.getMode() == null ? null : Mode.valueOf(db.getMode().name())); - resource.setAnalyzers(analyzerStatusCache.getStartedAnalyzers(db.getId())); - resource.setStatisticsResource(StatisticsConverter.TO_RESOURCE.apply(db.getStatistics())); - resource.setApproximateDuration(db.getApproximateDuration()); - resource.setHasRetries(db.isHasRetries()); - //TODO replace with single select on higher level to prevent selection for each launch - ofNullable(db.getUserId()).flatMap(id -> userRepository.findLoginById(id)).ifPresent(resource::setOwner); - resource.setRerun(db.isRerun()); - return resource; - }; + LaunchResource resource = new LaunchResource(); + resource.setLaunchId(db.getId()); + resource.setUuid(db.getUuid()); + resource.setName(db.getName()); + resource.setNumber(db.getNumber()); + resource.setDescription(db.getDescription()); + resource.setStatus(db.getStatus() == null ? null : db.getStatus().toString()); + resource.setStartTime( + db.getStartTime() == null ? null : EntityUtils.TO_DATE.apply(db.getStartTime())); + resource.setEndTime( + db.getEndTime() == null ? null : EntityUtils.TO_DATE.apply(db.getEndTime())); + ofNullable(db.getLastModified()).map(EntityUtils.TO_DATE).ifPresent(resource::setLastModified); + ofNullable(db.getAttributes()).ifPresent(attributes -> updateAttributes(resource, attributes)); + ofNullable(resource.getAttributes()).ifPresentOrElse(a -> { + }, () -> resource.setAttributes(Collections.emptySet())); + resource.setMode(db.getMode() == null ? null : Mode.valueOf(db.getMode().name())); + resource.setAnalyzers(analyzerStatusCache.getStartedAnalyzers(db.getId())); + resource.setStatisticsResource(StatisticsConverter.TO_RESOURCE.apply(db.getStatistics())); + resource.setApproximateDuration(db.getApproximateDuration()); + resource.setHasRetries(db.isHasRetries()); + //TODO replace with single select on higher level to prevent selection for each launch + ofNullable(db.getUserId()).flatMap(id -> userRepository.findLoginById(id)) + .ifPresent(resource::setOwner); + resource.setRerun(db.isRerun()); + return resource; + }; - private void updateAttributes(LaunchResource resource, Set<ItemAttribute> attributes) { - final Map<ItemAttributeType, Set<ItemAttribute>> attributeMapping = attributes.stream() - .collect(groupingBy(attr -> itemAttributeTypeResolver.resolve(attr).orElse(ItemAttributeType.UNRESOLVED), toSet())); - attributeMapping.forEach((type, attr) -> resourceAttributeUpdaterMapping.get(type).handle(resource, attr)); - } + private void updateAttributes(LaunchResource resource, Set<ItemAttribute> attributes) { + final Map<ItemAttributeType, Set<ItemAttribute>> attributeMapping = attributes.stream() + .collect(groupingBy( + attr -> itemAttributeTypeResolver.resolve(attr).orElse(ItemAttributeType.UNRESOLVED), + toSet())); + attributeMapping.forEach( + (type, attr) -> resourceAttributeUpdaterMapping.get(type).handle(resource, attr)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LogConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LogConverter.java index 548fcbd6d6..05a4ca0801 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LogConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/LogConverter.java @@ -16,20 +16,20 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.core.log.impl.PagedLogResource; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.model.log.LogResource; import com.epam.ta.reportportal.ws.model.log.SearchLogRs; import com.google.common.base.Preconditions; - import java.util.function.BiFunction; import java.util.function.Function; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.isNotEmpty; - /** * Converts internal DB model to DTO * @@ -37,53 +37,89 @@ */ public final class LogConverter { - private LogConverter() { - //static only - } - - public static final Function<Log, LogResource> TO_RESOURCE = model -> { - Preconditions.checkNotNull(model); - LogResource resource = new LogResource(); - fillWithLogContent(model, resource); - return resource; - }; - - private static void fillWithLogContent(Log model, LogResource resource) { - resource.setId(model.getId()); - resource.setUuid(model.getUuid()); - resource.setMessage(ofNullable(model.getLogMessage()).orElse("NULL")); - resource.setLogTime(EntityUtils.TO_DATE.apply(model.getLogTime())); - - if (isBinaryDataExists(model)) { - - LogResource.BinaryContent binaryContent = new LogResource.BinaryContent(); - - binaryContent.setBinaryDataId(String.valueOf(model.getAttachment().getId())); - binaryContent.setContentType(model.getAttachment().getContentType()); - binaryContent.setThumbnailId(model.getAttachment().getThumbnailId()); - resource.setBinaryContent(binaryContent); - } - - ofNullable(model.getTestItem()).ifPresent(testItem -> resource.setItemId(testItem.getItemId())); - ofNullable(model.getLaunch()).ifPresent(launch -> resource.setLaunchId(launch.getId())); - ofNullable(model.getLogLevel()).ifPresent(level -> resource.setLevel(LogLevel.toLevel(level).toString())); - } - - public static final BiFunction<Log, PagedLogResource, PagedLogResource> FILL_WITH_LOG_CONTENT = (model, pagedLog) -> { - fillWithLogContent(model, pagedLog); - return pagedLog; - }; - - public static final Function<Log, SearchLogRs.LogEntry> TO_LOG_ENTRY = log -> { - SearchLogRs.LogEntry logEntry = new SearchLogRs.LogEntry(); - logEntry.setMessage(log.getLogMessage()); - logEntry.setLevel(LogLevel.toLevel(log.getLogLevel()).name()); - return logEntry; - }; - - private static boolean isBinaryDataExists(Log log) { - return ofNullable(log.getAttachment()).map(a -> isNotEmpty(a.getContentType()) || isNotEmpty(a.getThumbnailId()) - || isNotEmpty(a.getFileId())).orElse(false); - } + private LogConverter() { + //static only + } + + public static final Function<LogFull, LogResource> TO_RESOURCE = model -> { + Preconditions.checkNotNull(model); + LogResource resource = new LogResource(); + fillWithLogContent(model, resource); + return resource; + }; + + private static void fillWithLogContent(LogFull model, LogResource resource) { + resource.setId(model.getId()); + resource.setUuid(model.getUuid()); + resource.setMessage(ofNullable(model.getLogMessage()).orElse("NULL")); + resource.setLogTime(EntityUtils.TO_DATE.apply(model.getLogTime())); + + if (isBinaryDataExists(model)) { + + LogResource.BinaryContent binaryContent = new LogResource.BinaryContent(); + + binaryContent.setBinaryDataId(String.valueOf(model.getAttachment().getId())); + binaryContent.setContentType(model.getAttachment().getContentType()); + binaryContent.setThumbnailId(model.getAttachment().getThumbnailId()); + resource.setBinaryContent(binaryContent); + } + + ofNullable(model.getTestItem()).ifPresent(testItem -> resource.setItemId(testItem.getItemId())); + ofNullable(model.getLaunch()).ifPresent(launch -> resource.setLaunchId(launch.getId())); + ofNullable(model.getLogLevel()).ifPresent( + level -> resource.setLevel(LogLevel.toLevel(level).toString())); + } + + public static final BiFunction<LogFull, PagedLogResource, PagedLogResource> FILL_WITH_LOG_CONTENT = (model, pagedLog) -> { + fillWithLogContent(model, pagedLog); + return pagedLog; + }; + + public static final Function<LogFull, SearchLogRs.LogEntry> TO_LOG_ENTRY = log -> { + SearchLogRs.LogEntry logEntry = new SearchLogRs.LogEntry(); + logEntry.setMessage(log.getLogMessage()); + logEntry.setLevel(LogLevel.toLevel(log.getLogLevel()).name()); + return logEntry; + }; + + public static final Function<LogFull, Log> LOG_FULL_TO_LOG = logFull -> { + Log log = new Log(); + log.setAttachment(logFull.getAttachment()); + log.setClusterId(logFull.getClusterId()); + log.setId(logFull.getId()); + log.setLastModified(logFull.getLastModified()); + log.setLaunch(logFull.getLaunch()); + log.setLogLevel(logFull.getLogLevel()); + log.setLogMessage(logFull.getLogMessage()); + log.setLogTime(logFull.getLogTime()); + log.setProjectId(logFull.getProjectId()); + log.setTestItem(logFull.getTestItem()); + log.setUuid(logFull.getUuid()); + + return log; + }; + + public static final Function<Log, LogFull> LOG_TO_LOG_FULL = log -> { + LogFull logFull = new LogFull(); + logFull.setAttachment(log.getAttachment()); + logFull.setClusterId(log.getClusterId()); + logFull.setId(log.getId()); + logFull.setLastModified(log.getLastModified()); + logFull.setLaunch(log.getLaunch()); + logFull.setLogLevel(log.getLogLevel()); + logFull.setLogMessage(log.getLogMessage()); + logFull.setLogTime(log.getLogTime()); + logFull.setProjectId(log.getProjectId()); + logFull.setTestItem(log.getTestItem()); + logFull.setUuid(log.getUuid()); + + return logFull; + }; + + private static boolean isBinaryDataExists(LogFull log) { + return ofNullable(log.getAttachment()).map( + a -> isNotEmpty(a.getContentType()) || isNotEmpty(a.getThumbnailId()) + || isNotEmpty(a.getFileId())).orElse(false); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/NotificationConfigConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/NotificationConfigConverter.java index 3efafa9ea4..f2a6feb6e3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/NotificationConfigConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/NotificationConfigConverter.java @@ -22,6 +22,7 @@ import com.epam.ta.reportportal.entity.project.email.SenderCase; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.ValidationConstraints; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; import com.google.common.base.Preconditions; @@ -66,16 +67,30 @@ private NotificationConfigConverter() { resource.setRecipients(Lists.newArrayList(model.getRecipients())); resource.setEnabled(model.isEnabled()); resource.setAttributesOperator(model.getAttributesOperator().getOperator()); + resource.setRuleName(model.getRuleName()); + resource.setId(model.getId()); return resource; }; public static final Function<ItemAttributeResource, LaunchAttributeRule> TO_ATTRIBUTE_RULE_MODEL = resource -> { LaunchAttributeRule launchAttributeRule = new LaunchAttributeRule(); + cutAttributeToMaxLength(resource); launchAttributeRule.setKey(resource.getKey()); launchAttributeRule.setValue(resource.getValue()); return launchAttributeRule; }; + private static void cutAttributeToMaxLength(ItemAttributeResource entity) { + String key = entity.getKey(); + String value = entity.getValue(); + if (key != null && key.length() > ValidationConstraints.MAX_ATTRIBUTE_LENGTH) { + entity.setKey(key.trim().substring(0, ValidationConstraints.MAX_ATTRIBUTE_LENGTH)); + } + if (value != null && value.length() > ValidationConstraints.MAX_ATTRIBUTE_LENGTH) { + entity.setValue(value.trim().substring(0, ValidationConstraints.MAX_ATTRIBUTE_LENGTH)); + } + } + public final static Function<SenderCaseDTO, SenderCase> TO_CASE_MODEL = resource -> { SenderCase senderCase = new SenderCase(); ofNullable(resource.getAttributes()).ifPresent(attributes -> senderCase.setLaunchAttributeRules(attributes.stream() @@ -93,6 +108,8 @@ private NotificationConfigConverter() { ))); senderCase.setEnabled(resource.isEnabled()); senderCase.setAttributesOperator(LogicalOperator.valueOf(resource.getAttributesOperator())); + senderCase.setRuleName(resource.getRuleName()); + senderCase.setId(resource.getId()); return senderCase; }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/OAuthDetailsConverters.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/OAuthDetailsConverters.java index 85d0188d0a..12ca1baf80 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/OAuthDetailsConverters.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/OAuthDetailsConverters.java @@ -23,39 +23,39 @@ */ public final class OAuthDetailsConverters { - private OAuthDetailsConverters() { - //static only - } + private OAuthDetailsConverters() { + //static only + } - // public final static Function<OAuthDetailsResource, OAuth2LoginDetails> FROM_RESOURCE = resource -> { - // Preconditions.checkNotNull(resource); - // OAuth2LoginDetails db = new OAuth2LoginDetails(); - // db.setClientAuthenticationScheme(resource.getClientAuthenticationScheme()); - // db.setUserAuthorizationUri(resource.getUserAuthorizationUri()); - // db.setAccessTokenUri(resource.getAccessTokenUri()); - // db.setClientId(resource.getClientId()); - // db.setClientSecret(resource.getClientSecret()); - // db.setGrantType(resource.getGrantType()); - // db.setScope(resource.getScope()); - // db.setRestrictions(resource.getRestrictions()); - // db.setAuthenticationScheme(resource.getAuthenticationScheme()); - // db.setTokenName(resource.getTokenName()); - // return db; - // }; - // - // public final static Function<OAuth2LoginDetails, OAuthDetailsResource> TO_RESOURCE = db -> { - // Preconditions.checkNotNull(db); - // OAuthDetailsResource resource = new OAuthDetailsResource(); - // resource.setClientAuthenticationScheme(db.getClientAuthenticationScheme()); - // resource.setUserAuthorizationUri(db.getUserAuthorizationUri()); - // resource.setAccessTokenUri(db.getAccessTokenUri()); - // resource.setClientId(db.getClientId()); - // resource.setClientSecret(db.getClientSecret()); - // resource.setGrantType(db.getGrantType()); - // resource.setScope(db.getScope()); - // resource.setRestrictions(db.getRestrictions()); - // resource.setAuthenticationScheme(db.getAuthenticationScheme()); - // resource.setTokenName(db.getTokenName()); - // return resource; - // }; + // public final static Function<OAuthDetailsResource, OAuth2LoginDetails> FROM_RESOURCE = resource -> { + // Preconditions.checkNotNull(resource); + // OAuth2LoginDetails db = new OAuth2LoginDetails(); + // db.setClientAuthenticationScheme(resource.getClientAuthenticationScheme()); + // db.setUserAuthorizationUri(resource.getUserAuthorizationUri()); + // db.setAccessTokenUri(resource.getAccessTokenUri()); + // db.setClientId(resource.getClientId()); + // db.setClientSecret(resource.getClientSecret()); + // db.setGrantType(resource.getGrantType()); + // db.setScope(resource.getScope()); + // db.setRestrictions(resource.getRestrictions()); + // db.setAuthenticationScheme(resource.getAuthenticationScheme()); + // db.setTokenName(resource.getTokenName()); + // return db; + // }; + // + // public final static Function<OAuth2LoginDetails, OAuthDetailsResource> TO_RESOURCE = db -> { + // Preconditions.checkNotNull(db); + // OAuthDetailsResource resource = new OAuthDetailsResource(); + // resource.setClientAuthenticationScheme(db.getClientAuthenticationScheme()); + // resource.setUserAuthorizationUri(db.getUserAuthorizationUri()); + // resource.setAccessTokenUri(db.getAccessTokenUri()); + // resource.setClientId(db.getClientId()); + // resource.setClientSecret(db.getClientSecret()); + // resource.setGrantType(db.getGrantType()); + // resource.setScope(db.getScope()); + // resource.setRestrictions(db.getRestrictions()); + // resource.setAuthenticationScheme(db.getAuthenticationScheme()); + // resource.setTokenName(db.getTokenName()); + // return resource; + // }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverter.java index e590384d7e..b1a829e943 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverter.java @@ -17,7 +17,6 @@ import com.epam.ta.reportportal.entity.item.Parameter; import com.epam.ta.reportportal.ws.model.ParameterResource; - import java.util.function.Function; /** @@ -27,22 +26,22 @@ */ public final class ParametersConverter { - private ParametersConverter() { - //static only - } + private ParametersConverter() { + //static only + } - public static final Function<ParameterResource, Parameter> TO_MODEL = resource -> { - Parameter parameters = new Parameter(); - parameters.setKey(resource.getKey()); - parameters.setValue(resource.getValue()); - return parameters; - }; + public static final Function<ParameterResource, Parameter> TO_MODEL = resource -> { + Parameter parameters = new Parameter(); + parameters.setKey(resource.getKey()); + parameters.setValue(resource.getValue()); + return parameters; + }; - public static final Function<Parameter, ParameterResource> TO_RESOURCE = model -> { - ParameterResource parameter = new ParameterResource(); - parameter.setKey(model.getKey()); - parameter.setValue(model.getValue()); - return parameter; - }; + public static final Function<Parameter, ParameterResource> TO_RESOURCE = model -> { + ParameterResource parameter = new ParameterResource(); + parameter.setKey(model.getKey()); + parameter.setValue(model.getValue()); + return parameter; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverter.java index ff5691fb95..9c5214db63 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverter.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.pattern.PatternTemplate; import com.epam.ta.reportportal.ws.model.activity.PatternTemplateActivityResource; import com.epam.ta.reportportal.ws.model.project.config.pattern.PatternTemplateResource; - import java.util.function.Function; /** @@ -27,27 +26,27 @@ */ public class PatternTemplateConverter { - private PatternTemplateConverter() { - //static only - } - - public static final Function<PatternTemplate, PatternTemplateResource> TO_RESOURCE = patternTemplate -> { - PatternTemplateResource resource = new PatternTemplateResource(); - resource.setId(patternTemplate.getId()); - resource.setType(patternTemplate.getTemplateType().name()); - resource.setName(patternTemplate.getName()); - resource.setValue(patternTemplate.getValue()); - resource.setEnabled(patternTemplate.isEnabled()); - - return resource; - }; - - public static final Function<PatternTemplate, PatternTemplateActivityResource> TO_ACTIVITY_RESOURCE = patternTemplate -> { - PatternTemplateActivityResource resource = new PatternTemplateActivityResource(); - resource.setId(patternTemplate.getId()); - resource.setName(patternTemplate.getName()); - resource.setEnabled(patternTemplate.isEnabled()); - resource.setProjectId(patternTemplate.getProjectId()); - return resource; - }; + private PatternTemplateConverter() { + //static only + } + + public static final Function<PatternTemplate, PatternTemplateResource> TO_RESOURCE = patternTemplate -> { + PatternTemplateResource resource = new PatternTemplateResource(); + resource.setId(patternTemplate.getId()); + resource.setType(patternTemplate.getTemplateType().name()); + resource.setName(patternTemplate.getName()); + resource.setValue(patternTemplate.getValue()); + resource.setEnabled(patternTemplate.isEnabled()); + + return resource; + }; + + public static final Function<PatternTemplate, PatternTemplateActivityResource> TO_ACTIVITY_RESOURCE = patternTemplate -> { + PatternTemplateActivityResource resource = new PatternTemplateActivityResource(); + resource.setId(patternTemplate.getId()); + resource.setName(patternTemplate.getName()); + resource.setEnabled(patternTemplate.isEnabled()); + resource.setProjectId(patternTemplate.getProjectId()); + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverter.java index ff99f823e3..6bdb4d288c 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverter.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectUtils; import com.epam.ta.reportportal.ws.model.activity.ProjectAttributesActivityResource; - import java.util.function.Function; /** @@ -27,16 +26,16 @@ */ public final class ProjectActivityConverter { - private ProjectActivityConverter() { - //static only - } + private ProjectActivityConverter() { + //static only + } - public static final Function<Project, ProjectAttributesActivityResource> TO_ACTIVITY_RESOURCE = project -> { - ProjectAttributesActivityResource resource = new ProjectAttributesActivityResource(); - resource.setProjectId(project.getId()); - resource.setProjectName(project.getName()); - resource.setConfig(ProjectUtils.getConfigParameters(project.getProjectAttributes())); - return resource; - }; + public static final Function<Project, ProjectAttributesActivityResource> TO_ACTIVITY_RESOURCE = project -> { + ProjectAttributesActivityResource resource = new ProjectAttributesActivityResource(); + resource.setProjectId(project.getId()); + resource.setProjectName(project.getName()); + resource.setConfig(ProjectUtils.getConfigParameters(project.getProjectAttributes())); + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectSettingsConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectSettingsConverter.java index b7dd91f275..66deb60f28 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectSettingsConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ProjectSettingsConverter.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.entity.project.Project; @@ -25,63 +27,60 @@ import com.epam.ta.reportportal.ws.model.project.config.IssueSubTypeResource; import com.epam.ta.reportportal.ws.model.project.config.ProjectSettingsResource; import com.google.common.base.Preconditions; - import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public final class ProjectSettingsConverter { - private ProjectSettingsConverter() { - //static only - } + private ProjectSettingsConverter() { + //static only + } - public static final Function<ProjectInfo, ProjectInfoResource> TO_PROJECT_INFO_RESOURCE = project -> { - Preconditions.checkNotNull(project); - ProjectInfoResource resource = new ProjectInfoResource(); - resource.setUsersQuantity(project.getUsersQuantity()); - resource.setLaunchesQuantity(project.getLaunchesQuantity()); - resource.setProjectId(project.getId()); - resource.setProjectName(project.getName()); - resource.setCreationDate(EntityUtils.TO_DATE.apply(project.getCreationDate())); - resource.setLastRun(ofNullable(project.getLastRun()).map(EntityUtils.TO_DATE).orElse(null)); - resource.setEntryType(project.getProjectType()); - resource.setOrganization(project.getOrganization()); - return resource; - }; + public static final Function<ProjectInfo, ProjectInfoResource> TO_PROJECT_INFO_RESOURCE = project -> { + Preconditions.checkNotNull(project); + ProjectInfoResource resource = new ProjectInfoResource(); + resource.setUsersQuantity(project.getUsersQuantity()); + resource.setLaunchesQuantity(project.getLaunchesQuantity()); + resource.setProjectId(project.getId()); + resource.setProjectName(project.getName()); + resource.setCreationDate(EntityUtils.TO_DATE.apply(project.getCreationDate())); + resource.setLastRun(ofNullable(project.getLastRun()).map(EntityUtils.TO_DATE).orElse(null)); + resource.setEntryType(project.getProjectType()); + resource.setOrganization(project.getOrganization()); + return resource; + }; - public static final Function<IssueType, IssueSubTypeResource> TO_SUBTYPE_RESOURCE = issueType -> { - IssueSubTypeResource issueSubTypeResource = new IssueSubTypeResource(); - issueSubTypeResource.setId(issueType.getId()); - issueSubTypeResource.setLocator(issueType.getLocator()); - issueSubTypeResource.setColor(issueType.getHexColor()); - issueSubTypeResource.setLongName(issueType.getLongName()); - issueSubTypeResource.setShortName(issueType.getShortName()); - issueSubTypeResource.setTypeRef(issueType.getIssueGroup().getTestItemIssueGroup().getValue()); - return issueSubTypeResource; - }; + public static final Function<IssueType, IssueSubTypeResource> TO_SUBTYPE_RESOURCE = issueType -> { + IssueSubTypeResource issueSubTypeResource = new IssueSubTypeResource(); + issueSubTypeResource.setId(issueType.getId()); + issueSubTypeResource.setLocator(issueType.getLocator()); + issueSubTypeResource.setColor(issueType.getHexColor()); + issueSubTypeResource.setLongName(issueType.getLongName()); + issueSubTypeResource.setShortName(issueType.getShortName()); + issueSubTypeResource.setTypeRef(issueType.getIssueGroup().getTestItemIssueGroup().getValue()); + return issueSubTypeResource; + }; - public static final Function<List<IssueType>, Map<String, List<IssueSubTypeResource>>> TO_PROJECT_SUB_TYPES_RESOURCE = issueTypes -> issueTypes - .stream() - .collect(Collectors.groupingBy( - it -> it.getIssueGroup().getTestItemIssueGroup().getValue(), - Collectors.mapping(TO_SUBTYPE_RESOURCE, Collectors.toList()) - )); + public static final Function<List<IssueType>, Map<String, List<IssueSubTypeResource>>> TO_PROJECT_SUB_TYPES_RESOURCE = issueTypes -> issueTypes + .stream() + .collect(Collectors.groupingBy( + it -> it.getIssueGroup().getTestItemIssueGroup().getValue(), + Collectors.mapping(TO_SUBTYPE_RESOURCE, Collectors.toList()) + )); - public static final Function<Project, ProjectSettingsResource> TO_PROJECT_SETTINGS_RESOURCE = project -> { - ProjectSettingsResource resource = new ProjectSettingsResource(); - resource.setProjectId(project.getId()); - resource.setSubTypes(TO_PROJECT_SUB_TYPES_RESOURCE.apply(project.getProjectIssueTypes() - .stream() - .map(ProjectIssueType::getIssueType) - .collect(Collectors.toList()))); - return resource; - }; + public static final Function<Project, ProjectSettingsResource> TO_PROJECT_SETTINGS_RESOURCE = project -> { + ProjectSettingsResource resource = new ProjectSettingsResource(); + resource.setProjectId(project.getId()); + resource.setSubTypes(TO_PROJECT_SUB_TYPES_RESOURCE.apply(project.getProjectIssueTypes() + .stream() + .map(ProjectIssueType::getIssueType) + .collect(Collectors.toList()))); + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverter.java index d7f7108482..ab08b88c3e 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverter.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.user.RestorePasswordBid; import com.epam.ta.reportportal.ws.model.user.RestorePasswordRQ; import com.google.common.base.Preconditions; - import java.util.UUID; import java.util.function.Function; @@ -30,15 +29,15 @@ */ public final class RestorePasswordBidConverter { - private RestorePasswordBidConverter() { - //static only - } + private RestorePasswordBidConverter() { + //static only + } - public static final Function<RestorePasswordRQ, RestorePasswordBid> TO_BID = request -> { - Preconditions.checkNotNull(request); - RestorePasswordBid bid = new RestorePasswordBid(); - bid.setEmail(request.getEmail()); - bid.setUuid(UUID.randomUUID().toString()); - return bid; - }; + public static final Function<RestorePasswordRQ, RestorePasswordBid> TO_BID = request -> { + Preconditions.checkNotNull(request); + RestorePasswordBid bid = new RestorePasswordBid(); + bid.setEmail(request.getEmail()); + bid.setUuid(UUID.randomUUID().toString()); + return bid; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ServerSettingsConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ServerSettingsConverter.java index 4a3fe0382c..78ecd5b7e5 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ServerSettingsConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/ServerSettingsConverter.java @@ -16,16 +16,15 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; + import com.epam.ta.reportportal.entity.ServerSettings; import com.epam.ta.reportportal.ws.model.ErrorType; -import org.apache.commons.collections4.CollectionUtils; - import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.validation.BusinessRule.expect; +import org.apache.commons.collections4.CollectionUtils; /** * Converts internal DB model to DTO @@ -34,13 +33,15 @@ */ public final class ServerSettingsConverter { - private ServerSettingsConverter() { - //static only - } + private ServerSettingsConverter() { + //static only + } - public static final Function<List<ServerSettings>, Map<String, String>> TO_RESOURCE = serverSettings -> { - expect(serverSettings, CollectionUtils::isNotEmpty).verify(ErrorType.SERVER_SETTINGS_NOT_FOUND, "default"); - return serverSettings.stream().collect(Collectors.toMap(ServerSettings::getKey, ServerSettings::getValue)); - }; + public static final Function<List<ServerSettings>, Map<String, String>> TO_RESOURCE = serverSettings -> { + expect(serverSettings, CollectionUtils::isNotEmpty).verify(ErrorType.SERVER_SETTINGS_NOT_FOUND, + "default"); + return serverSettings.stream() + .collect(Collectors.toMap(ServerSettings::getKey, ServerSettings::getValue)); + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/StatisticsConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/StatisticsConverter.java index 5505a003c9..f736e464ca 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/StatisticsConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/StatisticsConverter.java @@ -16,44 +16,47 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_KEY; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_KEY; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.ws.model.statistics.StatisticsResource; -import org.apache.commons.lang3.StringUtils; - import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_KEY; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_KEY; -import static java.util.Optional.ofNullable; +import org.apache.commons.lang3.StringUtils; /** * @author Pavel Bortnik */ public final class StatisticsConverter { - private StatisticsConverter() { - //static only - } - - public static final Function<Set<Statistics>, StatisticsResource> TO_RESOURCE = statistics -> { - StatisticsResource statisticsResource = new StatisticsResource(); - statisticsResource.setDefects(statistics.stream() - .filter(it -> ofNullable(it.getStatisticsField()).isPresent() && StringUtils.isNotEmpty(it.getStatisticsField().getName())) - .filter(it -> it.getCounter() > 0 && it.getStatisticsField().getName().contains(DEFECTS_KEY)) - .collect(Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[2], - Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[3], - Collectors.summingInt(Statistics::getCounter) - ) - ))); - statisticsResource.setExecutions(statistics.stream() - .filter(it -> ofNullable(it.getStatisticsField()).isPresent() && StringUtils.isNotEmpty(it.getStatisticsField().getName())) - .filter(it -> it.getCounter() > 0 && it.getStatisticsField().getName().contains(EXECUTIONS_KEY)) - .collect(Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[2], - Collectors.summingInt(Statistics::getCounter) - ))); - return statisticsResource; - - }; + private StatisticsConverter() { + //static only + } + + public static final Function<Set<Statistics>, StatisticsResource> TO_RESOURCE = statistics -> { + StatisticsResource statisticsResource = new StatisticsResource(); + statisticsResource.setDefects(statistics.stream() + .filter(it -> ofNullable(it.getStatisticsField()).isPresent() && StringUtils.isNotEmpty( + it.getStatisticsField().getName())) + .filter( + it -> it.getCounter() > 0 && it.getStatisticsField().getName().contains(DEFECTS_KEY)) + .collect(Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[2], + Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[3], + Collectors.summingInt(Statistics::getCounter) + ) + ))); + statisticsResource.setExecutions(statistics.stream() + .filter(it -> ofNullable(it.getStatisticsField()).isPresent() && StringUtils.isNotEmpty( + it.getStatisticsField().getName())) + .filter( + it -> it.getCounter() > 0 && it.getStatisticsField().getName().contains(EXECUTIONS_KEY)) + .collect(Collectors.groupingBy(it -> it.getStatisticsField().getName().split("\\$")[2], + Collectors.summingInt(Statistics::getCounter) + ))); + return statisticsResource; + + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverter.java index 611b001118..19ec0aaabf 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverter.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.commons.EntityUtils; import com.epam.ta.reportportal.entity.item.NestedStep; import com.epam.ta.reportportal.entity.item.PathName; @@ -28,15 +31,11 @@ import com.epam.ta.reportportal.ws.model.item.ItemPathName; import com.epam.ta.reportportal.ws.model.item.LaunchPathName; import com.epam.ta.reportportal.ws.model.item.PathNameResource; -import org.apache.commons.collections.CollectionUtils; - import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; - -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toSet; +import org.apache.commons.collections.CollectionUtils; /** * Converts internal DB model to DTO @@ -45,101 +44,106 @@ */ public final class TestItemConverter { - private TestItemConverter() { - //static only - } + private TestItemConverter() { + //static only + } - public static final Function<TestItem, TestItemResource> TO_RESOURCE = item -> { - TestItemResource resource = new TestItemResource(); - resource.setDescription(item.getDescription()); - resource.setUniqueId(item.getUniqueId()); - resource.setTestCaseId(item.getTestCaseId()); - resource.setTestCaseHash(item.getTestCaseHash()); - resource.setUuid(item.getUuid()); - resource.setAttributes(item.getAttributes() - .stream() - .filter(it -> !it.isSystem()) - .map(it -> new ItemAttributeResource(it.getKey(), it.getValue())) - .collect(toSet())); - resource.setEndTime(EntityUtils.TO_DATE.apply(item.getItemResults().getEndTime())); - resource.setItemId(item.getItemId()); - if (null != item.getParameters()) { - resource.setParameters(item.getParameters().stream().map(ParametersConverter.TO_RESOURCE).collect(Collectors.toList())); - } - ofNullable(item.getItemResults().getIssue()).ifPresent(i -> { - if (!Objects.isNull(i.getIssueId())) { - resource.setIssue(IssueConverter.TO_MODEL.apply(i)); - } - }); - resource.setName(item.getName()); - resource.setStartTime(EntityUtils.TO_DATE.apply(item.getStartTime())); - resource.setStatus(item.getItemResults().getStatus() != null ? item.getItemResults().getStatus().toString() : null); - resource.setType(item.getType() != null ? item.getType().name() : null); - resource.setHasChildren(item.isHasChildren()); - resource.setHasStats(item.isHasStats()); - resource.setCodeRef(item.getCodeRef()); + public static final Function<TestItem, TestItemResource> TO_RESOURCE = item -> { + TestItemResource resource = new TestItemResource(); + resource.setDescription(item.getDescription()); + resource.setUniqueId(item.getUniqueId()); + resource.setTestCaseId(item.getTestCaseId()); + resource.setTestCaseHash(item.getTestCaseHash()); + resource.setUuid(item.getUuid()); + resource.setAttributes(item.getAttributes() + .stream() + .filter(it -> !it.isSystem()) + .map(it -> new ItemAttributeResource(it.getKey(), it.getValue())) + .collect(toSet())); + resource.setEndTime(EntityUtils.TO_DATE.apply(item.getItemResults().getEndTime())); + resource.setItemId(item.getItemId()); + if (null != item.getParameters()) { + resource.setParameters(item.getParameters().stream().map(ParametersConverter.TO_RESOURCE) + .collect(Collectors.toList())); + } + ofNullable(item.getItemResults().getIssue()).ifPresent(i -> { + if (!Objects.isNull(i.getIssueId())) { + resource.setIssue(IssueConverter.TO_MODEL.apply(i)); + } + }); + resource.setName(item.getName()); + resource.setStartTime(EntityUtils.TO_DATE.apply(item.getStartTime())); + resource.setStatus( + item.getItemResults().getStatus() != null ? item.getItemResults().getStatus().toString() + : null); + resource.setType(item.getType() != null ? item.getType().name() : null); + resource.setHasChildren(item.isHasChildren()); + resource.setHasStats(item.isHasStats()); + resource.setCodeRef(item.getCodeRef()); - ofNullable(item.getParentId()).ifPresent(resource::setParent); - ofNullable(item.getLaunchId()).ifPresent(resource::setLaunchId); - resource.setPatternTemplates(item.getPatternTemplateTestItems() - .stream() - .map(patternTemplateTestItem -> patternTemplateTestItem.getPatternTemplate().getName()) - .collect(toSet())); - resource.setPath(item.getPath()); - resource.setStatisticsResource(StatisticsConverter.TO_RESOURCE.apply(item.getItemResults().getStatistics())); - return resource; - }; + ofNullable(item.getParentId()).ifPresent(resource::setParent); + ofNullable(item.getLaunchId()).ifPresent(resource::setLaunchId); + resource.setPatternTemplates(item.getPatternTemplateTestItems() + .stream() + .map(patternTemplateTestItem -> patternTemplateTestItem.getPatternTemplate().getName()) + .collect(toSet())); + resource.setPath(item.getPath()); + resource.setStatisticsResource( + StatisticsConverter.TO_RESOURCE.apply(item.getItemResults().getStatistics())); + return resource; + }; - public static final Function<PathName, PathNameResource> PATH_NAME_TO_RESOURCE = pathName -> { + public static final Function<PathName, PathNameResource> PATH_NAME_TO_RESOURCE = pathName -> { - PathNameResource pathNameResource = new PathNameResource(); - ofNullable(pathName.getLaunchPathName()).ifPresent(lpn -> pathNameResource.setLaunchPathName(new LaunchPathName(lpn.getName(), - lpn.getNumber() - ))); - ofNullable(pathName.getItemPaths()).ifPresent(itemPaths -> { - if (CollectionUtils.isNotEmpty(itemPaths)) { - pathNameResource.setItemPaths(itemPaths.stream() - .map(path -> new ItemPathName(path.getId(), path.getName())) - .collect(Collectors.toList())); - } - }); + PathNameResource pathNameResource = new PathNameResource(); + ofNullable(pathName.getLaunchPathName()).ifPresent( + lpn -> pathNameResource.setLaunchPathName(new LaunchPathName(lpn.getName(), + lpn.getNumber() + ))); + ofNullable(pathName.getItemPaths()).ifPresent(itemPaths -> { + if (CollectionUtils.isNotEmpty(itemPaths)) { + pathNameResource.setItemPaths(itemPaths.stream() + .map(path -> new ItemPathName(path.getId(), path.getName())) + .collect(Collectors.toList())); + } + }); - return pathNameResource; + return pathNameResource; - }; + }; - public static final Function<NestedStep, NestedStepResource> TO_NESTED_STEP_RESOURCE = item -> { - NestedStepResource resource = new NestedStepResource(); - resource.setId(item.getId()); - resource.setName(item.getName()); - resource.setUuid(item.getUuid()); - resource.setStartTime(EntityUtils.TO_DATE.apply(item.getStartTime())); - resource.setEndTime(EntityUtils.TO_DATE.apply(item.getEndTime())); - resource.setStatus(item.getStatus() != null ? item.getStatus().toString() : null); - resource.setType(item.getType() != null ? item.getType().name() : null); - resource.setHasContent(item.isHasContent()); - resource.setAttachmentsCount(item.getAttachmentsCount()); - resource.setDuration(item.getDuration()); + public static final Function<NestedStep, NestedStepResource> TO_NESTED_STEP_RESOURCE = item -> { + NestedStepResource resource = new NestedStepResource(); + resource.setId(item.getId()); + resource.setName(item.getName()); + resource.setUuid(item.getUuid()); + resource.setStartTime(EntityUtils.TO_DATE.apply(item.getStartTime())); + resource.setEndTime(EntityUtils.TO_DATE.apply(item.getEndTime())); + resource.setStatus(item.getStatus() != null ? item.getStatus().toString() : null); + resource.setType(item.getType() != null ? item.getType().name() : null); + resource.setHasContent(item.isHasContent()); + resource.setAttachmentsCount(item.getAttachmentsCount()); + resource.setDuration(item.getDuration()); - return resource; - }; + return resource; + }; - public static final BiFunction<TestItem, Long, TestItemActivityResource> TO_ACTIVITY_RESOURCE = (testItem, projectId) -> { - TestItemActivityResource resource = new TestItemActivityResource(); - resource.setId(testItem.getItemId()); - resource.setName(testItem.getName()); - resource.setStatus(testItem.getItemResults().getStatus().name()); - resource.setProjectId(projectId); - IssueEntity issue = testItem.getItemResults().getIssue(); - if (issue != null) { - resource.setAutoAnalyzed(issue.getAutoAnalyzed()); - resource.setIgnoreAnalyzer(issue.getIgnoreAnalyzer()); - resource.setIssueDescription(issue.getIssueDescription()); - resource.setIssueTypeLongName(issue.getIssueType().getLongName()); - ofNullable(issue.getTickets()).ifPresent(it -> resource.setTickets(it.stream() - .map(ticket -> ticket.getTicketId().concat(":").concat(ticket.getUrl())) - .collect(Collectors.joining(", ")))); - } - return resource; - }; + public static final BiFunction<TestItem, Long, TestItemActivityResource> TO_ACTIVITY_RESOURCE = (testItem, projectId) -> { + TestItemActivityResource resource = new TestItemActivityResource(); + resource.setId(testItem.getItemId()); + resource.setName(testItem.getName()); + resource.setStatus(testItem.getItemResults().getStatus().name()); + resource.setProjectId(projectId); + IssueEntity issue = testItem.getItemResults().getIssue(); + if (issue != null) { + resource.setAutoAnalyzed(issue.getAutoAnalyzed()); + resource.setIgnoreAnalyzer(issue.getIgnoreAnalyzer()); + resource.setIssueDescription(issue.getIssueDescription()); + resource.setIssueTypeLongName(issue.getIssueType().getLongName()); + ofNullable(issue.getTickets()).ifPresent(it -> resource.setTickets(it.stream() + .map(ticket -> ticket.getTicketId().concat(":").concat(ticket.getUrl())) + .collect(Collectors.joining(", ")))); + } + return resource; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverter.java index 8d81ef5fc5..73052d8db0 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverter.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.bts.Ticket; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.google.common.base.Preconditions; - import java.util.function.Function; /** @@ -27,18 +26,18 @@ */ public final class TicketConverter { - private TicketConverter() { - //static only - } + private TicketConverter() { + //static only + } - public static final Function<Issue.ExternalSystemIssue, Ticket> TO_TICKET = issue -> { - Preconditions.checkNotNull(issue); - Ticket ticket = new Ticket(); - ticket.setBtsUrl(issue.getBtsUrl()); - ticket.setBtsProject(issue.getBtsProject()); - ticket.setTicketId(issue.getTicketId()); - ticket.setUrl(issue.getUrl()); - ticket.setPluginName(issue.getPluginName()); - return ticket; - }; + public static final Function<Issue.ExternalSystemIssue, Ticket> TO_TICKET = issue -> { + Preconditions.checkNotNull(issue); + Ticket ticket = new Ticket(); + ticket.setBtsUrl(issue.getBtsUrl()); + ticket.setBtsProject(issue.getBtsProject()); + ticket.setTicketId(issue.getTicketId()); + ticket.setUrl(issue.getUrl()); + ticket.setPluginName(issue.getPluginName()); + return ticket; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverter.java index 1819d62263..137353c8a4 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverter.java @@ -21,7 +21,6 @@ import com.epam.ta.reportportal.entity.user.UserCreationBid; import com.epam.ta.reportportal.ws.model.user.CreateUserRQ; import com.google.common.base.Preconditions; - import java.util.UUID; import java.util.function.BiFunction; @@ -32,17 +31,17 @@ */ public final class UserCreationBidConverter { - private UserCreationBidConverter() { - //static only - } + private UserCreationBidConverter() { + //static only + } - public static final BiFunction<CreateUserRQ, Project, UserCreationBid> TO_USER = (request, project) -> { - Preconditions.checkNotNull(request); - UserCreationBid user = new UserCreationBid(); - user.setUuid(UUID.randomUUID().toString()); - user.setEmail(EntityUtils.normalizeId(request.getEmail().trim())); - user.setDefaultProject(project); - user.setRole(request.getRole()); - return user; - }; + public static final BiFunction<CreateUserRQ, Project, UserCreationBid> TO_USER = (request, project) -> { + Preconditions.checkNotNull(request); + UserCreationBid user = new UserCreationBid(); + user.setUuid(UUID.randomUUID().toString()); + user.setEmail(EntityUtils.normalizeId(request.getEmail().trim())); + user.setProjectName(project.getName()); + user.setRole(request.getRole()); + return user; + }; } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/WidgetConverter.java b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/WidgetConverter.java index 1f59e20fcc..87b95395e9 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/converters/WidgetConverter.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/converters/WidgetConverter.java @@ -38,75 +38,76 @@ */ public class WidgetConverter { - public static final Function<DashboardWidget, DashboardResource.WidgetObjectModel> TO_OBJECT_MODEL = dashboardWidget -> { - DashboardResource.WidgetObjectModel objectModel = new DashboardResource.WidgetObjectModel(); - objectModel.setName(dashboardWidget.getWidgetName()); - objectModel.setWidgetType(dashboardWidget.getWidgetType()); - objectModel.setWidgetId(dashboardWidget.getId().getWidgetId()); - objectModel.setWidgetPosition(new Position(dashboardWidget.getPositionX(), dashboardWidget.getPositionY())); - objectModel.setWidgetSize(new Size(dashboardWidget.getWidth(), dashboardWidget.getHeight())); - ofNullable(dashboardWidget.getWidget().getWidgetOptions()).ifPresent(wo -> objectModel.setWidgetOptions(wo.getOptions())); - return objectModel; - }; + public static final Function<DashboardWidget, DashboardResource.WidgetObjectModel> TO_OBJECT_MODEL = dashboardWidget -> { + DashboardResource.WidgetObjectModel objectModel = new DashboardResource.WidgetObjectModel(); + objectModel.setName(dashboardWidget.getWidgetName()); + objectModel.setWidgetType(dashboardWidget.getWidgetType()); + objectModel.setWidgetId(dashboardWidget.getId().getWidgetId()); + objectModel.setWidgetPosition(new Position(dashboardWidget.getPositionX(), dashboardWidget.getPositionY())); + objectModel.setWidgetSize(new Size(dashboardWidget.getWidth(), dashboardWidget.getHeight())); + ofNullable(dashboardWidget.getWidget().getWidgetOptions()).ifPresent(wo -> objectModel.setWidgetOptions(wo.getOptions())); + return objectModel; + }; - public static final Function<Widget, WidgetResource> TO_WIDGET_RESOURCE = widget -> { - WidgetResource widgetResource = new WidgetResource(); - widgetResource.setWidgetId(widget.getId()); - widgetResource.setName(widget.getName()); - widgetResource.setWidgetType(widget.getWidgetType()); - widgetResource.setDescription(widget.getDescription()); - widgetResource.setOwner(widget.getOwner()); - ofNullable(widget.getFilters()).ifPresent(filter -> widgetResource.setAppliedFilters(UserFilterConverter.FILTER_SET_TO_FILTER_RESOURCE - .apply(filter))); - ContentParameters contentParameters = new ContentParameters(); - contentParameters.setItemsCount(widget.getItemsCount()); - ofNullable(widget.getWidgetOptions()).ifPresent(wo -> contentParameters.setWidgetOptions(wo.getOptions())); - contentParameters.setContentFields(Lists.newArrayList(widget.getContentFields())); - widgetResource.setContentParameters(contentParameters); - return widgetResource; - }; + public static final Function<Widget, WidgetResource> TO_WIDGET_RESOURCE = widget -> { + WidgetResource widgetResource = new WidgetResource(); + widgetResource.setWidgetId(widget.getId()); + widgetResource.setName(widget.getName()); + widgetResource.setWidgetType(widget.getWidgetType()); + widgetResource.setDescription(widget.getDescription()); + widgetResource.setOwner(widget.getOwner()); + ofNullable(widget.getFilters()).ifPresent(filter -> widgetResource.setAppliedFilters(UserFilterConverter.FILTER_SET_TO_FILTER_RESOURCE + .apply(filter))); + ContentParameters contentParameters = new ContentParameters(); + contentParameters.setItemsCount(widget.getItemsCount()); + ofNullable(widget.getWidgetOptions()).ifPresent(wo -> contentParameters.setWidgetOptions(wo.getOptions())); + contentParameters.setContentFields(Lists.newArrayList(widget.getContentFields())); + widgetResource.setContentParameters(contentParameters); + return widgetResource; + }; - public static final Function<Widget, WidgetActivityResource> TO_ACTIVITY_RESOURCE = widget -> { - WidgetActivityResource resource = new WidgetActivityResource(); - resource.setId(widget.getId()); - resource.setProjectId(widget.getProject().getId()); - resource.setName(widget.getName()); - resource.setDescription(widget.getDescription()); - resource.setItemsCount(widget.getItemsCount()); - resource.setContentFields(Sets.newHashSet(widget.getContentFields())); - ofNullable(widget.getWidgetOptions()).ifPresent(wo -> resource.setWidgetOptions(wo.getOptions())); - return resource; - }; + public static final Function<Widget, WidgetActivityResource> TO_ACTIVITY_RESOURCE = widget -> { + WidgetActivityResource resource = new WidgetActivityResource(); + resource.setId(widget.getId()); + resource.setProjectId(widget.getProject().getId()); + resource.setName(widget.getName()); + resource.setDescription(widget.getDescription()); + resource.setItemsCount(widget.getItemsCount()); + resource.setContentFields(Sets.newHashSet(widget.getContentFields())); + ofNullable(widget.getWidgetOptions()).ifPresent(wo -> resource.setWidgetOptions(wo.getOptions())); + return resource; + }; - /** - * Creates many-to-many object representation of dashboards and widgets - * - * @param model Widget model object - * @param dashboard Dashboard - * @param widget Widget - * @return many-to-many object representation - */ - public static DashboardWidget toDashboardWidget(DashboardResource.WidgetObjectModel model, Dashboard dashboard, Widget widget, - boolean isCreatedOn) { + /** + * Creates many-to-many object representation of dashboards and widgets + * + * @param model Widget model object + * @param dashboard Dashboard + * @param widget Widget + * @param isCreatedOn true if widget was created + * @return many-to-many object representation + */ + public static DashboardWidget toDashboardWidget(DashboardResource.WidgetObjectModel model, Dashboard dashboard, Widget widget, + boolean isCreatedOn) { - DashboardWidgetId id = new DashboardWidgetId(); - id.setDashboardId(dashboard.getId()); - id.setWidgetId(model.getWidgetId()); + DashboardWidgetId id = new DashboardWidgetId(); + id.setDashboardId(dashboard.getId()); + id.setWidgetId(model.getWidgetId()); - DashboardWidget dashboardWidget = new DashboardWidget(); - dashboardWidget.setId(id); - dashboardWidget.setWidgetType(widget.getWidgetType()); - dashboardWidget.setWidgetName(widget.getName()); - dashboardWidget.setPositionX(model.getWidgetPosition().getX()); - dashboardWidget.setPositionY(model.getWidgetPosition().getY()); - dashboardWidget.setWidth(model.getWidgetSize().getWidth()); - dashboardWidget.setHeight(model.getWidgetSize().getHeight()); - dashboardWidget.setDashboard(dashboard); - dashboardWidget.setWidget(widget); - dashboardWidget.setCreatedOn(isCreatedOn); - dashboardWidget.setWidgetOwner(widget.getOwner()); + DashboardWidget dashboardWidget = new DashboardWidget(); + dashboardWidget.setId(id); + dashboardWidget.setWidgetType(widget.getWidgetType()); + dashboardWidget.setWidgetName(widget.getName()); + dashboardWidget.setPositionX(model.getWidgetPosition().getX()); + dashboardWidget.setPositionY(model.getWidgetPosition().getY()); + dashboardWidget.setWidth(model.getWidgetSize().getWidth()); + dashboardWidget.setHeight(model.getWidgetSize().getHeight()); + dashboardWidget.setDashboard(dashboard); + dashboardWidget.setWidget(widget); + dashboardWidget.setCreatedOn(isCreatedOn); + dashboardWidget.setWidgetOwner(widget.getOwner()); - return dashboardWidget; - } + return dashboardWidget; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ItemAttributeType.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ItemAttributeType.java index 294566c256..7fa3c7ab1d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ItemAttributeType.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ItemAttributeType.java @@ -20,7 +20,7 @@ * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public enum ItemAttributeType { - PUBLIC, - SYSTEM, - UNRESOLVED + PUBLIC, + SYSTEM, + UNRESOLVED } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ResourceAttributeHandler.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ResourceAttributeHandler.java index 150c0445ec..81680ba8bd 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ResourceAttributeHandler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/ResourceAttributeHandler.java @@ -17,7 +17,6 @@ package com.epam.ta.reportportal.ws.converter.resource.handler.attribute; import com.epam.ta.reportportal.entity.ItemAttribute; - import java.util.Collection; /** @@ -25,6 +24,6 @@ */ public interface ResourceAttributeHandler<T> { - void handle(T resource, Collection<ItemAttribute> attributes); + void handle(T resource, Collection<ItemAttribute> attributes); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeLogger.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeLogger.java index c157b1ea33..226ebc48e9 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeLogger.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeLogger.java @@ -19,28 +19,28 @@ import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ResourceAttributeHandler; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; +import java.util.Collection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collection; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class LaunchResourceAttributeLogger implements ResourceAttributeHandler<LaunchResource> { - private static final Logger LOGGER = LoggerFactory.getLogger(LaunchResourceAttributeLogger.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LaunchResourceAttributeLogger.class); - private final String baseMessage; + private final String baseMessage; - public LaunchResourceAttributeLogger(String baseMessage) { - this.baseMessage = baseMessage; - } + public LaunchResourceAttributeLogger(String baseMessage) { + this.baseMessage = baseMessage; + } - @Override - public void handle(LaunchResource resource, Collection<ItemAttribute> attributes) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(baseMessage + " Launch - {}, attributes - {}", resource.getLaunchId(), attributes); - } - } + @Override + public void handle(LaunchResource resource, Collection<ItemAttribute> attributes) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(baseMessage + " Launch - {}, attributes - {}", resource.getLaunchId(), + attributes); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdater.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdater.java index b427400704..1ff7947d06 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdater.java @@ -16,22 +16,23 @@ package com.epam.ta.reportportal.ws.converter.resource.handler.attribute.launch; +import static java.util.stream.Collectors.toSet; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ResourceAttributeHandler; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; - import java.util.Collection; -import static java.util.stream.Collectors.toSet; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class LaunchResourceAttributeUpdater implements ResourceAttributeHandler<LaunchResource> { - @Override - public void handle(LaunchResource resource, Collection<ItemAttribute> attributes) { - resource.setAttributes(attributes.stream().map(it -> new ItemAttributeResource(it.getKey(), it.getValue())).collect(toSet())); - } + @Override + public void handle(LaunchResource resource, Collection<ItemAttribute> attributes) { + resource.setAttributes( + attributes.stream().map(it -> new ItemAttributeResource(it.getKey(), it.getValue())) + .collect(toSet())); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/ItemAttributeTypeMatcher.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/ItemAttributeTypeMatcher.java index dbb199ba72..a2822a28f6 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/ItemAttributeTypeMatcher.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/ItemAttributeTypeMatcher.java @@ -24,7 +24,7 @@ */ public interface ItemAttributeTypeMatcher { - boolean matches(ItemAttribute attribute); + boolean matches(ItemAttribute attribute); - ItemAttributeType getType(); + ItemAttributeType getType(); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcher.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcher.java index 08f49bfae2..bb5997a517 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcher.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcher.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ItemAttributeType; - import java.util.function.Predicate; /** @@ -26,21 +25,22 @@ */ public class PredicateItemAttributeTypeMatcher implements ItemAttributeTypeMatcher { - private final Predicate<ItemAttribute> predicate; - private final ItemAttributeType type; + private final Predicate<ItemAttribute> predicate; + private final ItemAttributeType type; - public PredicateItemAttributeTypeMatcher(Predicate<ItemAttribute> predicate, ItemAttributeType type) { - this.predicate = predicate; - this.type = type; - } + public PredicateItemAttributeTypeMatcher(Predicate<ItemAttribute> predicate, + ItemAttributeType type) { + this.predicate = predicate; + this.type = type; + } - @Override - public boolean matches(ItemAttribute attribute) { - return predicate.test(attribute); - } + @Override + public boolean matches(ItemAttribute attribute) { + return predicate.test(attribute); + } - @Override - public ItemAttributeType getType() { - return type; - } + @Override + public ItemAttributeType getType() { + return type; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolver.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolver.java index a41429c69f..afd4758407 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolver.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ItemAttributeType; - import java.util.Optional; /** @@ -26,6 +25,6 @@ */ public interface ItemAttributeTypeResolver { - Optional<ItemAttributeType> resolve(ItemAttribute attribute); + Optional<ItemAttributeType> resolve(ItemAttribute attribute); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolverDelegate.java b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolverDelegate.java index 22ad04177f..7de9450e90 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolverDelegate.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/resolver/ItemAttributeTypeResolverDelegate.java @@ -19,7 +19,6 @@ import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.ItemAttributeType; import com.epam.ta.reportportal.ws.converter.resource.handler.attribute.matcher.ItemAttributeTypeMatcher; - import java.util.List; import java.util.Optional; @@ -28,14 +27,15 @@ */ public class ItemAttributeTypeResolverDelegate implements ItemAttributeTypeResolver { - private final List<ItemAttributeTypeMatcher> matchers; + private final List<ItemAttributeTypeMatcher> matchers; - public ItemAttributeTypeResolverDelegate(List<ItemAttributeTypeMatcher> matchers) { - this.matchers = matchers; - } + public ItemAttributeTypeResolverDelegate(List<ItemAttributeTypeMatcher> matchers) { + this.matchers = matchers; + } - @Override - public Optional<ItemAttributeType> resolve(ItemAttribute attribute) { - return matchers.stream().filter(m -> m.matches(attribute)).findFirst().map(ItemAttributeTypeMatcher::getType); - } + @Override + public Optional<ItemAttributeType> resolve(ItemAttribute attribute) { + return matchers.stream().filter(m -> m.matches(attribute)).findFirst() + .map(ItemAttributeTypeMatcher::getType); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdater.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdater.java index a069fbfc91..794e4d1b33 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdater.java @@ -21,5 +21,5 @@ */ public interface ResourceUpdater<R> { - void updateResource(R resource); + void updateResource(R resource); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdaterProvider.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdaterProvider.java index b3e7db48d7..47254f3810 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdaterProvider.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/ResourceUpdaterProvider.java @@ -21,5 +21,5 @@ */ public interface ResourceUpdaterProvider<C extends ResourceUpdaterContent, R> { - ResourceUpdater<R> retrieve(C updaterContent); + ResourceUpdater<R> retrieve(C updaterContent); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/content/TestItemUpdaterContent.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/content/TestItemUpdaterContent.java index ffaa22fcc0..155d717b34 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/content/TestItemUpdaterContent.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/content/TestItemUpdaterContent.java @@ -18,7 +18,6 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdaterContent; - import java.util.List; /** @@ -26,23 +25,23 @@ */ public final class TestItemUpdaterContent implements ResourceUpdaterContent { - private final Long projectId; - private final List<TestItem> testItems; + private final Long projectId; + private final List<TestItem> testItems; - private TestItemUpdaterContent(Long projectId, List<TestItem> testItems) { - this.projectId = projectId; - this.testItems = testItems; - } + private TestItemUpdaterContent(Long projectId, List<TestItem> testItems) { + this.projectId = projectId; + this.testItems = testItems; + } - public Long getProjectId() { - return projectId; - } + public Long getProjectId() { + return projectId; + } - public List<TestItem> getTestItems() { - return testItems; - } + public List<TestItem> getTestItems() { + return testItems; + } - public static TestItemUpdaterContent of(Long projectId, List<TestItem> testItems) { - return new TestItemUpdaterContent(projectId, testItems); - } + public static TestItemUpdaterContent of(Long projectId, List<TestItem> testItems) { + return new TestItemUpdaterContent(projectId, testItems); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/PathNameUpdaterProvider.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/PathNameUpdaterProvider.java index 5b42f070bf..ed707962aa 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/PathNameUpdaterProvider.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/PathNameUpdaterProvider.java @@ -23,28 +23,29 @@ import com.epam.ta.reportportal.ws.converter.utils.item.content.TestItemUpdaterContent; import com.epam.ta.reportportal.ws.converter.utils.item.updater.PathNameUpdater; import com.epam.ta.reportportal.ws.model.TestItemResource; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Map; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class PathNameUpdaterProvider implements ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource> { +public class PathNameUpdaterProvider implements + ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource> { - private final TestItemRepository testItemRepository; + private final TestItemRepository testItemRepository; - @Autowired - public PathNameUpdaterProvider(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } + @Autowired + public PathNameUpdaterProvider(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } - @Override - public ResourceUpdater<TestItemResource> retrieve(TestItemUpdaterContent updaterContent) { - Map<Long, PathName> pathNamesMapping = testItemRepository.selectPathNames(updaterContent.getTestItems()); + @Override + public ResourceUpdater<TestItemResource> retrieve(TestItemUpdaterContent updaterContent) { + Map<Long, PathName> pathNamesMapping = testItemRepository.selectPathNames( + updaterContent.getTestItems()); - return PathNameUpdater.of(pathNamesMapping); - } + return PathNameUpdater.of(pathNamesMapping); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/RetriesUpdaterProvider.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/RetriesUpdaterProvider.java index 762b29bab2..46b8d3e11e 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/RetriesUpdaterProvider.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/provider/RetriesUpdaterProvider.java @@ -16,42 +16,43 @@ package com.epam.ta.reportportal.ws.converter.utils.item.provider; +import static java.util.stream.Collectors.groupingBy; + import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdaterProvider; import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdater; +import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdaterProvider; import com.epam.ta.reportportal.ws.converter.utils.item.content.TestItemUpdaterContent; import com.epam.ta.reportportal.ws.converter.utils.item.updater.RetriesUpdater; import com.epam.ta.reportportal.ws.model.TestItemResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; - -import static java.util.stream.Collectors.groupingBy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Service -public class RetriesUpdaterProvider implements ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource> { - - private final TestItemRepository testItemRepository; - - @Autowired - public RetriesUpdaterProvider(TestItemRepository testItemRepository) { - this.testItemRepository = testItemRepository; - } - - @Override - public ResourceUpdater<TestItemResource> retrieve(TestItemUpdaterContent updaterContent) { - Map<Long, List<TestItem>> retriesMapping = testItemRepository.selectRetries(updaterContent.getTestItems() - .stream() - .filter(TestItem::isHasRetries) - .map(TestItem::getItemId) - .collect(Collectors.toList())).stream().collect(groupingBy(TestItem::getRetryOf)); - return RetriesUpdater.of(retriesMapping); - } +public class RetriesUpdaterProvider implements + ResourceUpdaterProvider<TestItemUpdaterContent, TestItemResource> { + + private final TestItemRepository testItemRepository; + + @Autowired + public RetriesUpdaterProvider(TestItemRepository testItemRepository) { + this.testItemRepository = testItemRepository; + } + + @Override + public ResourceUpdater<TestItemResource> retrieve(TestItemUpdaterContent updaterContent) { + Map<Long, List<TestItem>> retriesMapping = testItemRepository.selectRetries( + updaterContent.getTestItems() + .stream() + .filter(TestItem::isHasRetries) + .map(TestItem::getItemId) + .collect(Collectors.toList())).stream().collect(groupingBy(TestItem::getRetryOf)); + return RetriesUpdater.of(retriesMapping); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/PathNameUpdater.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/PathNameUpdater.java index 9452520a8a..5521cbb97c 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/PathNameUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/PathNameUpdater.java @@ -16,33 +16,33 @@ package com.epam.ta.reportportal.ws.converter.utils.item.updater; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.item.PathName; import com.epam.ta.reportportal.ws.converter.converters.TestItemConverter; import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdater; import com.epam.ta.reportportal.ws.model.TestItemResource; - import java.util.Map; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class PathNameUpdater implements ResourceUpdater<TestItemResource> { - private final Map<Long, PathName> pathNamesMapping; + private final Map<Long, PathName> pathNamesMapping; - private PathNameUpdater(Map<Long, PathName> pathNamesMapping) { - this.pathNamesMapping = pathNamesMapping; - } + private PathNameUpdater(Map<Long, PathName> pathNamesMapping) { + this.pathNamesMapping = pathNamesMapping; + } - @Override - public void updateResource(TestItemResource resource) { - ofNullable(pathNamesMapping.get(resource.getItemId())).ifPresent(pathName -> resource.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE - .apply(pathName))); - } + @Override + public void updateResource(TestItemResource resource) { + ofNullable(pathNamesMapping.get(resource.getItemId())).ifPresent( + pathName -> resource.setPathNames(TestItemConverter.PATH_NAME_TO_RESOURCE + .apply(pathName))); + } - public static PathNameUpdater of(Map<Long, PathName> pathNameMapping) { - return new PathNameUpdater(pathNameMapping); - } + public static PathNameUpdater of(Map<Long, PathName> pathNameMapping) { + return new PathNameUpdater(pathNameMapping); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/RetriesUpdater.java b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/RetriesUpdater.java index 42a76ba47c..5b2d2bc442 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/RetriesUpdater.java +++ b/src/main/java/com/epam/ta/reportportal/ws/converter/utils/item/updater/RetriesUpdater.java @@ -16,36 +16,36 @@ package com.epam.ta.reportportal.ws.converter.utils.item.updater; +import static java.util.Optional.ofNullable; + import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.ws.converter.converters.TestItemConverter; import com.epam.ta.reportportal.ws.converter.utils.ResourceUpdater; import com.epam.ta.reportportal.ws.model.TestItemResource; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static java.util.Optional.ofNullable; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class RetriesUpdater implements ResourceUpdater<TestItemResource> { - private final Map<Long, List<TestItem>> retriesMapping; + private final Map<Long, List<TestItem>> retriesMapping; - private RetriesUpdater(Map<Long, List<TestItem>> retriesMapping) { - this.retriesMapping = retriesMapping; - } + private RetriesUpdater(Map<Long, List<TestItem>> retriesMapping) { + this.retriesMapping = retriesMapping; + } - @Override - public void updateResource(TestItemResource resource) { - ofNullable(retriesMapping.get(resource.getItemId())).ifPresent(retries -> resource.setRetries(retries.stream() - .map(TestItemConverter.TO_RESOURCE) - .collect(Collectors.toList()))); - } + @Override + public void updateResource(TestItemResource resource) { + ofNullable(retriesMapping.get(resource.getItemId())).ifPresent( + retries -> resource.setRetries(retries.stream() + .map(TestItemConverter.TO_RESOURCE) + .collect(Collectors.toList()))); + } - public static RetriesUpdater of(Map<Long, List<TestItem>> retriesMapping) { - return new RetriesUpdater(retriesMapping); - } + public static RetriesUpdater of(Map<Long, List<TestItem>> retriesMapping) { + return new RetriesUpdater(retriesMapping); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/handler/QueryHandler.java b/src/main/java/com/epam/ta/reportportal/ws/handler/QueryHandler.java index 9807f17b78..3dde7d4ed3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/handler/QueryHandler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/handler/QueryHandler.java @@ -23,5 +23,5 @@ */ public interface QueryHandler { - Object find(QueryRQ queryRQ); + Object find(QueryRQ queryRQ); } diff --git a/src/main/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImpl.java index 0cff6786ad..54ed9e187a 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImpl.java @@ -16,7 +16,11 @@ package com.epam.ta.reportportal.ws.handler.impl; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.FilterableRepository; +import com.epam.ta.reportportal.dao.IntegrationRepository; +import com.epam.ta.reportportal.dao.LogRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.log.Log; @@ -25,10 +29,9 @@ import com.epam.ta.reportportal.ws.handler.QueryHandler; import com.epam.ta.reportportal.ws.rabbit.QueryRQ; import com.google.common.collect.ImmutableMap; -import org.springframework.stereotype.Service; - import java.util.Map; import java.util.Optional; +import org.springframework.stereotype.Service; /** * @author Yauheni_Martynau @@ -36,34 +39,35 @@ @Service public class QueryHandlerImpl implements QueryHandler { - private final ProjectRepository projectRepository; - private final IntegrationRepository integrationRepository; - private final TestItemRepository testItemRepository; - private final LogRepository logRepository; + private final ProjectRepository projectRepository; + private final IntegrationRepository integrationRepository; + private final TestItemRepository testItemRepository; + private final LogRepository logRepository; - private Map<String, FilterableRepository> repositories; + private Map<String, FilterableRepository> repositories; - public QueryHandlerImpl(ProjectRepository projectRepository, IntegrationRepository integrationRepository, - TestItemRepository testItemRepository, LogRepository logRepository) { + public QueryHandlerImpl(ProjectRepository projectRepository, + IntegrationRepository integrationRepository, + TestItemRepository testItemRepository, LogRepository logRepository) { - this.projectRepository = projectRepository; - this.integrationRepository = integrationRepository; - this.testItemRepository = testItemRepository; - this.logRepository = logRepository; + this.projectRepository = projectRepository; + this.integrationRepository = integrationRepository; + this.testItemRepository = testItemRepository; + this.logRepository = logRepository; - repositories = ImmutableMap.<String, FilterableRepository>builder() - .put(Project.class.getSimpleName(), projectRepository) - .put(Integration.class.getSimpleName(), integrationRepository) - .put(TestItem.class.getSimpleName(), testItemRepository) - .put(Log.class.getSimpleName(), logRepository) - .build(); - } + repositories = ImmutableMap.<String, FilterableRepository>builder() + .put(Project.class.getSimpleName(), projectRepository) + .put(Integration.class.getSimpleName(), integrationRepository) + .put(TestItem.class.getSimpleName(), testItemRepository) + .put(Log.class.getSimpleName(), logRepository) + .build(); + } - @Override - public Object find(QueryRQ queryRQ) { + @Override + public Object find(QueryRQ queryRQ) { - return Optional.ofNullable(repositories.get(queryRQ.getEntity())) - .map(repository -> repository.findByFilter(queryRQ.getFilter())) - .orElseThrow(() -> new ReportPortalException("Repository not found")); - } + return Optional.ofNullable(repositories.get(queryRQ.getEntity())) + .map(repository -> repository.findByFilter(queryRQ.getFilter())) + .orElseThrow(() -> new ReportPortalException("Repository not found")); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java index 574610eeef..54e9a9bfe3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.ws.rabbit; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.DEAD_LETTER_MAX_RETRY; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.EXCHANGE_REPORTING_RETRY; +import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.QUEUE_DLQ; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_FULL_TO_LOG; + import com.epam.ta.reportportal.auth.basic.DatabaseUserDetailsService; import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; import com.epam.ta.reportportal.commons.BinaryDataMetaInfo; @@ -35,9 +41,10 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.converter.builders.LogBuilder; +import com.epam.ta.reportportal.ws.converter.builders.LogFullBuilder; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; @@ -45,6 +52,12 @@ import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.google.common.base.Strings; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,288 +71,294 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.core.ParameterizedTypeReference; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; -import static com.epam.ta.reportportal.core.configs.rabbit.ReportingConfiguration.*; - /** * @author Konstantin Antipin */ public class AsyncReportingListener implements MessageListener { - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncReportingListener.class); - - @Autowired - private MessageConverter messageConverter; - - @Autowired - @Qualifier("rabbitTemplate") - private AmqpTemplate amqpTemplate; - - @Autowired - private StartLaunchHandler startLaunchHandler; - - @Autowired - private FinishLaunchHandler finishLaunchHandler; - - @Autowired - private StartTestItemHandler startTestItemHandler; - - @Autowired - private FinishTestItemHandler finishTestItemHandler; - - @Autowired - private DatabaseUserDetailsService userDetailsService; - - @Autowired - private LogRepository logRepository; - - @Autowired - private LaunchRepository launchRepository; - - @Autowired - private TestItemRepository testItemRepository; - - @Autowired - private TestItemService testItemService; - - @Autowired - private AttachmentBinaryDataService attachmentBinaryDataService; - - @Autowired - private ProjectExtractor projectExtractor; - - @Autowired - private LogService logService; - - @Override - @RabbitMessageLogging - public void onMessage(Message message) { - - try { - if (breakRetrying(message)) { - return; - } - - RequestType requestType = getRequestType(message); - Map<String, Object> headers = message.getMessageProperties().getHeaders(); - - switch (requestType) { - case START_LAUNCH: - onStartLaunch((StartLaunchRQ) messageConverter.fromMessage(message), - (String) headers.get(MessageHeaders.USERNAME), - (String) headers.get(MessageHeaders.PROJECT_NAME) - ); - break; - case FINISH_LAUNCH: - onFinishLaunch((FinishExecutionRQ) messageConverter.fromMessage(message), - (String) headers.get(MessageHeaders.USERNAME), - (String) headers.get(MessageHeaders.PROJECT_NAME), - (String) headers.get(MessageHeaders.LAUNCH_ID), - (String) headers.get(MessageHeaders.BASE_URL) - ); - break; - case START_TEST: - onStartItem((StartTestItemRQ) messageConverter.fromMessage(message), - (String) headers.get(MessageHeaders.USERNAME), - (String) headers.get(MessageHeaders.PROJECT_NAME), - (String) headers.get(MessageHeaders.PARENT_ITEM_ID) - ); - break; - case FINISH_TEST: - onFinishItem((FinishTestItemRQ) messageConverter.fromMessage(message), - (String) headers.get(MessageHeaders.USERNAME), - (String) headers.get(MessageHeaders.PROJECT_NAME), - (String) headers.get(MessageHeaders.ITEM_ID) - ); - break; - case LOG: - Jackson2JsonMessageConverter converter = (Jackson2JsonMessageConverter) messageConverter; - onLogCreate((DeserializablePair) converter.fromMessage(message, - new ParameterizedTypeReference<DeserializablePair<SaveLogRQ, BinaryDataMetaInfo>>() { - } - ), (Long) headers.get(MessageHeaders.PROJECT_ID)); - break; - default: - LOGGER.error("Unknown message type"); - break; - } - } catch (Throwable e) { - if (e instanceof ReportPortalException && e.getMessage().startsWith("Test Item ")) { - LOGGER.debug("exception : {}, message : {}, cause : {}", - e.getClass().getName(), - e.getMessage(), - e.getCause() != null ? e.getCause().getMessage() : "" - ); - } else { - LOGGER.error("exception : {}, message : {}, cause : {}", - e.getClass().getName(), - e.getMessage(), - e.getCause() != null ? e.getCause().getMessage() : "" - ); - } - throw new AmqpRejectAndDontRequeueException(e); - } - } - - public void onStartLaunch(StartLaunchRQ rq, String username, String projectName) { - ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); - startLaunchHandler.startLaunch(user, extractProjectDetails(user, projectName), rq); - } - - public void onFinishLaunch(FinishExecutionRQ rq, String username, String projectName, String launchId, String baseUrl) { - ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); - finishLaunchHandler.finishLaunch(launchId, rq, extractProjectDetails(user, projectName), user, baseUrl); - } + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncReportingListener.class); + + @Autowired + private MessageConverter messageConverter; + + @Autowired + @Qualifier("rabbitTemplate") + private AmqpTemplate amqpTemplate; + + @Autowired + private StartLaunchHandler startLaunchHandler; + + @Autowired + private FinishLaunchHandler finishLaunchHandler; + + @Autowired + private StartTestItemHandler startTestItemHandler; + + @Autowired + private FinishTestItemHandler finishTestItemHandler; + + @Autowired + private DatabaseUserDetailsService userDetailsService; + + @Autowired + private LogRepository logRepository; + + @Autowired + private LaunchRepository launchRepository; + + @Autowired + private TestItemRepository testItemRepository; + + @Autowired + private TestItemService testItemService; + + @Autowired + private AttachmentBinaryDataService attachmentBinaryDataService; + + @Autowired + private ProjectExtractor projectExtractor; + + @Autowired + private LogService logService; + + @Override + @RabbitMessageLogging + public void onMessage(Message message) { + + try { + if (breakRetrying(message)) { + return; + } + + RequestType requestType = getRequestType(message); + Map<String, Object> headers = message.getMessageProperties().getHeaders(); + + switch (requestType) { + case START_LAUNCH: + onStartLaunch((StartLaunchRQ) messageConverter.fromMessage(message), + (String) headers.get(MessageHeaders.USERNAME), + (String) headers.get(MessageHeaders.PROJECT_NAME) + ); + break; + case FINISH_LAUNCH: + onFinishLaunch((FinishExecutionRQ) messageConverter.fromMessage(message), + (String) headers.get(MessageHeaders.USERNAME), + (String) headers.get(MessageHeaders.PROJECT_NAME), + (String) headers.get(MessageHeaders.LAUNCH_ID), + (String) headers.get(MessageHeaders.BASE_URL) + ); + break; + case START_TEST: + onStartItem((StartTestItemRQ) messageConverter.fromMessage(message), + (String) headers.get(MessageHeaders.USERNAME), + (String) headers.get(MessageHeaders.PROJECT_NAME), + (String) headers.get(MessageHeaders.PARENT_ITEM_ID) + ); + break; + case FINISH_TEST: + onFinishItem((FinishTestItemRQ) messageConverter.fromMessage(message), + (String) headers.get(MessageHeaders.USERNAME), + (String) headers.get(MessageHeaders.PROJECT_NAME), + (String) headers.get(MessageHeaders.ITEM_ID) + ); + break; + case LOG: + Jackson2JsonMessageConverter converter = (Jackson2JsonMessageConverter) messageConverter; + onLogCreate((DeserializablePair) converter.fromMessage(message, + new ParameterizedTypeReference<DeserializablePair<SaveLogRQ, BinaryDataMetaInfo>>() { + } + ), (Long) headers.get(MessageHeaders.PROJECT_ID)); + break; + default: + LOGGER.error("Unknown message type"); + break; + } + } catch (Throwable e) { + if (e instanceof ReportPortalException && e.getMessage().startsWith("Test Item ")) { + LOGGER.debug("exception : {}, message : {}, cause : {}", + e.getClass().getName(), + e.getMessage(), + e.getCause() != null ? e.getCause().getMessage() : "" + ); + } else { + LOGGER.error("exception : {}, message : {}, cause : {}", + e.getClass().getName(), + e.getMessage(), + e.getCause() != null ? e.getCause().getMessage() : "" + ); + } + throw new AmqpRejectAndDontRequeueException(e); + } - public void onStartItem(StartTestItemRQ rq, String username, String projectName, String parentId) { - ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); - ReportPortalUser.ProjectDetails projectDetails = extractProjectDetails(user, normalizeId(projectName)); - if (!Strings.isNullOrEmpty(parentId)) { - startTestItemHandler.startChildItem(user, projectDetails, rq, parentId); - } else { - startTestItemHandler.startRootItem(user, projectDetails, rq); - } - } + } + + public void onStartLaunch(StartLaunchRQ rq, String username, String projectName) { + ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); + startLaunchHandler.startLaunch(user, extractProjectDetails(user, projectName), rq); + } + + public void onFinishLaunch(FinishExecutionRQ rq, String username, String projectName, + String launchId, String baseUrl) { + ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); + finishLaunchHandler.finishLaunch(launchId, rq, extractProjectDetails(user, projectName), user, + baseUrl); + } + + public void onStartItem(StartTestItemRQ rq, String username, String projectName, + String parentId) { + ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); + ReportPortalUser.ProjectDetails projectDetails = extractProjectDetails(user, + normalizeId(projectName)); + if (!Strings.isNullOrEmpty(parentId)) { + startTestItemHandler.startChildItem(user, projectDetails, rq, parentId); + } else { + startTestItemHandler.startRootItem(user, projectDetails, rq); + } + } - public void onFinishItem(FinishTestItemRQ rq, String username, String projectName, String itemId) { - ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); - finishTestItemHandler.finishTestItem(user, extractProjectDetails(user, normalizeId(projectName)), itemId, rq); - } + public void onFinishItem(FinishTestItemRQ rq, String username, String projectName, + String itemId) { + ReportPortalUser user = (ReportPortalUser) userDetailsService.loadUserByUsername(username); + finishTestItemHandler.finishTestItem(user, + extractProjectDetails(user, normalizeId(projectName)), itemId, rq); + } private ReportPortalUser.ProjectDetails extractProjectDetails(ReportPortalUser user, String projectName) { return projectExtractor.extractProjectDetails(user, projectName); } - public void onLogCreate(DeserializablePair<SaveLogRQ, BinaryDataMetaInfo> payload, Long projectId) { - SaveLogRQ request = payload.getLeft(); - BinaryDataMetaInfo metaInfo = payload.getRight(); + public void onLogCreate(DeserializablePair<SaveLogRQ, BinaryDataMetaInfo> payload, + Long projectId) { + SaveLogRQ request = payload.getLeft(); + BinaryDataMetaInfo metaInfo = payload.getRight(); - Optional<TestItem> itemOptional = testItemRepository.findByUuid(request.getItemUuid()); - - if (StringUtils.isNotEmpty(payload.getLeft().getItemUuid()) && !itemOptional.isPresent()) { - throw new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, payload.getLeft().getItemUuid()); - } - - if (itemOptional.isPresent()) { - createItemLog(request, itemOptional.get(), metaInfo, projectId); - } else { - Launch launch = launchRepository.findByUuid(request.getLaunchUuid()) - .orElseThrow(() -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, request.getLaunchUuid())); - createLaunchLog(request, launch, metaInfo, projectId); - } - } + Optional<TestItem> itemOptional = testItemRepository.findByUuid(request.getItemUuid()); - /** - * Process xdHeader of the message, breaking processing if maximum retry limit reached - * - * @param message - * @return - - */ - private boolean breakRetrying(Message message) { - List<Map<String, ?>> xdHeader = (List<Map<String, ?>>) message.getMessageProperties().getHeaders().get(MessageHeaders.XD_HEADER); - - if (xdHeader != null) { - long count = (Long) xdHeader.get(0).get("count"); - if (count > DEAD_LETTER_MAX_RETRY) { - LOGGER.error("Dropping on maximum retry limit request of type = {}, for target id = {} ", - getRequestType(message), - getTargetId(message) - ); - - // log request : don't cleanup to not loose binary content of dropped DLQ message - // cleanup(payload); - - amqpTemplate.send(EXCHANGE_REPORTING_RETRY, QUEUE_DLQ, message); - return true; - } - } - return false; - } - - private String getTargetId(Message message) { - try { - switch (getRequestType(message)) { - case START_LAUNCH: - return ((StartLaunchRQ) messageConverter.fromMessage(message)).getUuid(); - case FINISH_LAUNCH: - return (String) message.getMessageProperties().getHeaders().get(MessageHeaders.LAUNCH_ID); - case START_TEST: - return ((StartTestItemRQ) messageConverter.fromMessage(message)).getUuid(); - case FINISH_TEST: - return (String) message.getMessageProperties().getHeaders().get(MessageHeaders.ITEM_ID); - case LOG: - Jackson2JsonMessageConverter converter = (Jackson2JsonMessageConverter) messageConverter; - return ((SaveLogRQ) ((DeserializablePair) converter.fromMessage(message, - new ParameterizedTypeReference<DeserializablePair<SaveLogRQ, BinaryDataMetaInfo>>() { - } - )).getLeft()).getUuid(); - default: - return ""; - } - } catch (Throwable e) { - return ""; - } - } - - private void createItemLog(SaveLogRQ request, TestItem item, BinaryDataMetaInfo metaInfo, - Long projectId) { - Log log = new LogBuilder().addSaveLogRq(request).addTestItem(item).addProjectId(projectId) - .get(); - logRepository.save(log); - Launch effectiveLaunch = testItemService.getEffectiveLaunch(item); - logService.saveLogMessageToElasticSearch(log, effectiveLaunch.getId()); - - if (Objects.nonNull(request.getFile())) { - saveAttachment(request.getFile().getName(), metaInfo, - log.getId(), - projectId, - effectiveLaunch.getId(), - item.getItemId(), - effectiveLaunch.getUuid(), - log.getUuid() - ); + if (StringUtils.isNotEmpty(payload.getLeft().getItemUuid()) && !itemOptional.isPresent()) { + throw new ReportPortalException(ErrorType.TEST_ITEM_NOT_FOUND, + payload.getLeft().getItemUuid()); } - } - - private void createLaunchLog(SaveLogRQ request, Launch launch, BinaryDataMetaInfo metaInfo, - Long projectId) { - Log log = new LogBuilder().addSaveLogRq(request).addLaunch(launch).addProjectId(projectId) - .get(); - logRepository.save(log); - logService.saveLogMessageToElasticSearch(log, launch.getId()); - - saveAttachment(request.getFile().getName(), metaInfo, log.getId(), projectId, launch.getId(), - null, launch.getUuid(), log.getUuid()); - } - private void saveAttachment(String fileName, BinaryDataMetaInfo metaInfo, Long logId, - Long projectId, Long launchId, Long itemId, String launchUuid, - String logUuid) { - if (!Objects.isNull(metaInfo)) { - attachmentBinaryDataService.attachToLog(metaInfo, - AttachmentMetaInfo.builder() - .withProjectId(projectId) - .withLaunchId(launchId) - .withItemId(itemId) - .withLogId(logId) - .withLaunchUuid(launchUuid) - .withLogUuid(logUuid) + if (itemOptional.isPresent()) { + createItemLog(request, itemOptional.get(), metaInfo, projectId); + } else { + Launch launch = launchRepository.findByUuid(request.getLaunchUuid()) + .orElseThrow( + () -> new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND, request.getLaunchUuid())); + createLaunchLog(request, launch, metaInfo, projectId); + } + } + + /** + * Process xdHeader of the message, breaking processing if maximum retry limit reached + * + * @param message + * @return - + */ + private boolean breakRetrying(Message message) { + List<Map<String, ?>> xdHeader = (List<Map<String, ?>>) message.getMessageProperties() + .getHeaders().get(MessageHeaders.XD_HEADER); + + if (xdHeader != null) { + long count = (Long) xdHeader.get(0).get("count"); + if (count > DEAD_LETTER_MAX_RETRY) { + LOGGER.error("Dropping on maximum retry limit request of type = {}, for target id = {} ", + getRequestType(message), + getTargetId(message) + ); + + // log request : don't cleanup to not loose binary content of dropped DLQ message + // cleanup(payload); + + amqpTemplate.send(EXCHANGE_REPORTING_RETRY, QUEUE_DLQ, message); + return true; + } + } + return false; + } + + private String getTargetId(Message message) { + try { + switch (getRequestType(message)) { + case START_LAUNCH: + return ((StartLaunchRQ) messageConverter.fromMessage(message)).getUuid(); + case FINISH_LAUNCH: + return (String) message.getMessageProperties().getHeaders().get(MessageHeaders.LAUNCH_ID); + case START_TEST: + return ((StartTestItemRQ) messageConverter.fromMessage(message)).getUuid(); + case FINISH_TEST: + return (String) message.getMessageProperties().getHeaders().get(MessageHeaders.ITEM_ID); + case LOG: + Jackson2JsonMessageConverter converter = (Jackson2JsonMessageConverter) messageConverter; + return ((SaveLogRQ) ((DeserializablePair) converter.fromMessage(message, + new ParameterizedTypeReference<DeserializablePair<SaveLogRQ, BinaryDataMetaInfo>>() { + } + )).getLeft()).getUuid(); + default: + return ""; + } + } catch (Throwable e) { + return ""; + } + } + + private void createItemLog(SaveLogRQ request, TestItem item, BinaryDataMetaInfo metaInfo, + Long projectId) { + LogFull logFull = new LogFullBuilder().addSaveLogRq(request).addTestItem(item) + .addProjectId(projectId).get(); + Log log = LOG_FULL_TO_LOG.apply(logFull); + logRepository.save(log); + logFull.setId(log.getId()); + Launch effectiveLaunch = testItemService.getEffectiveLaunch(item); + logService.saveLogMessage(logFull, effectiveLaunch.getId()); + + if (Objects.nonNull(request.getFile())) {saveAttachment(request.getFile().getName(), metaInfo, + logFull.getId(), + projectId, + effectiveLaunch.getId(), + item.getItemId(), + effectiveLaunch.getUuid(), + logFull.getUuid() + ); + }} + + private void createLaunchLog(SaveLogRQ request, Launch launch, BinaryDataMetaInfo metaInfo, + Long projectId) { + LogFull logFull = new LogFullBuilder().addSaveLogRq(request).addLaunch(launch) + .addProjectId(projectId).get(); + Log log = LOG_FULL_TO_LOG.apply(logFull); + logRepository.save(log); + logFull.setId(log.getId()); + logService.saveLogMessage(logFull, launch.getId()); + + saveAttachment(request.getFile().getName(), metaInfo, logFull.getId(), projectId, launch.getId(), + null, launch.getUuid(), + logFull.getUuid()); + } + + private void saveAttachment(String fileName, BinaryDataMetaInfo metaInfo, Long logId, + Long projectId, + Long launchId, Long itemId, String launchUuid, + String logUuid) { + if (!Objects.isNull(metaInfo)) { + attachmentBinaryDataService.attachToLog(metaInfo, + AttachmentMetaInfo.builder() + .withProjectId(projectId) + .withLaunchId(launchId) + .withItemId(itemId) + .withLogId(logId) + .withLaunchUuid(launchUuid) + .withLogUuid(logUuid) .withFileName(fileName) - .withCreationDate(LocalDateTime.now(ZoneOffset.UTC)) - .build() - ); - } - } + .withCreationDate(LocalDateTime.now(ZoneOffset.UTC)) + .build() + ); + } + } - private RequestType getRequestType(Message message) { - return RequestType.valueOf((String) message.getMessageProperties().getHeaders().get(MessageHeaders.REQUEST_TYPE)); - } + private RequestType getRequestType(Message message) { + return RequestType.valueOf( + (String) message.getMessageProperties().getHeaders().get(MessageHeaders.REQUEST_TYPE)); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/ConsumerEventListener.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/ConsumerEventListener.java index bd39012010..f0c802b9fd 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/ConsumerEventListener.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/ConsumerEventListener.java @@ -20,6 +20,9 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.ShutdownSignalException; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Queue; @@ -32,53 +35,50 @@ import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.TimeoutException; - /** - * Finds a queue that doesn't have any connected consumers and set's it - * to consumer that should be restarted, so it can be registered - * with a different queue. + * Finds a queue that doesn't have any connected consumers and set's it to consumer that should be + * restarted, so it can be registered with a different queue. * * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @Component @Conditional(Conditions.NotTestCondition.class) -public class ConsumerEventListener implements ApplicationListener<ListenerContainerConsumerFailedEvent> { +public class ConsumerEventListener implements + ApplicationListener<ListenerContainerConsumerFailedEvent> { - private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerEventListener.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerEventListener.class); - @Autowired - @Qualifier("queues") - private List<Queue> queues; + @Autowired + @Qualifier("queues") + private List<Queue> queues; - @Autowired - private ConnectionFactory connectionFactory; + @Autowired + private ConnectionFactory connectionFactory; - @Override - public void onApplicationEvent(ListenerContainerConsumerFailedEvent event) { - Object source = event.getSource(); - if (source instanceof AbstractMessageListenerContainer) { - AbstractMessageListenerContainer listenerContainer = (AbstractMessageListenerContainer) source; - Throwable throwable = event.getThrowable(); - if (throwable.getCause() instanceof IOException && throwable.getCause().getCause() instanceof ShutdownSignalException - && throwable.getCause().getCause().getMessage().contains("in exclusive use")) { - for (Queue q : queues) { - if (getQueueConsumerCount(q) == 0) { - listenerContainer.setQueues(q); - LOGGER.info("Restarting consumer with a queue {}", q.getName()); - } - } - } - } - } + @Override + public void onApplicationEvent(ListenerContainerConsumerFailedEvent event) { + Object source = event.getSource(); + if (source instanceof AbstractMessageListenerContainer) { + AbstractMessageListenerContainer listenerContainer = (AbstractMessageListenerContainer) source; + Throwable throwable = event.getThrowable(); + if (throwable.getCause() instanceof IOException && throwable.getCause() + .getCause() instanceof ShutdownSignalException + && throwable.getCause().getCause().getMessage().contains("in exclusive use")) { + for (Queue q : queues) { + if (getQueueConsumerCount(q) == 0) { + listenerContainer.setQueues(q); + LOGGER.info("Restarting consumer with a queue {}", q.getName()); + } + } + } + } + } - private int getQueueConsumerCount(Queue queue) { - try (Channel channel = connectionFactory.createConnection().createChannel(false)) { - return channel.queueDeclarePassive(queue.getName()).getConsumerCount(); - } catch (IOException | TimeoutException e) { - throw new ReportPortalException(e.getMessage()); - } - } + private int getQueueConsumerCount(Queue queue) { + try (Channel channel = connectionFactory.createConnection().createChannel(false)) { + return channel.queueDeclarePassive(queue.getName()).getConsumerCount(); + } catch (IOException | TimeoutException e) { + throw new ReportPortalException(e.getMessage()); + } + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/MessageHeaders.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/MessageHeaders.java index a78e1e82c4..452885116d 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/MessageHeaders.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/MessageHeaders.java @@ -21,22 +21,22 @@ */ public final class MessageHeaders { - public static final String REQUEST_TYPE = "requestType"; - public static final String USERNAME = "username"; - public static final String PROJECT_NAME = "projectName"; - public static final String PROJECT_ID = "projectId"; - public static final String LAUNCH_ID = "launchId"; - public static final String ITEM_ID = "itemId"; - public static final String PARENT_ITEM_ID = "parentItemId"; - public static final String XD_HEADER = "x-death"; - public static final String BASE_URL = "baseUrl"; + public static final String REQUEST_TYPE = "requestType"; + public static final String USERNAME = "username"; + public static final String PROJECT_NAME = "projectName"; + public static final String PROJECT_ID = "projectId"; + public static final String LAUNCH_ID = "launchId"; + public static final String ITEM_ID = "itemId"; + public static final String PARENT_ITEM_ID = "parentItemId"; + public static final String XD_HEADER = "x-death"; + public static final String BASE_URL = "baseUrl"; - public static final String ITEM_REF = "itemRef"; - public static final String LIMIT = "limit"; - public static final String IS_LOAD_BINARY_DATA = "isLoadBinaryData"; + public static final String ITEM_REF = "itemRef"; + public static final String LIMIT = "limit"; + public static final String IS_LOAD_BINARY_DATA = "isLoadBinaryData"; - private MessageHeaders() { - //static only - } + private MessageHeaders() { + //static only + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumer.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumer.java index af72c95088..da45a89fe7 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumer.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumer.java @@ -16,23 +16,23 @@ package com.epam.ta.reportportal.ws.rabbit; +import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.QUEUE_QUERY_RQ; + import com.epam.ta.reportportal.ws.handler.QueryHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Component; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.QUEUE_QUERY_RQ; - @Component public class QueryConsumer { - @Autowired - private QueryHandler queryHandler; + @Autowired + private QueryHandler queryHandler; - @RabbitListener(queues = QUEUE_QUERY_RQ) - public Object find(@Payload QueryRQ queryRQ) { + @RabbitListener(queues = QUEUE_QUERY_RQ) + public Object find(@Payload QueryRQ queryRQ) { - return queryHandler.find(queryRQ); - } + return queryHandler.find(queryRQ); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryRQ.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryRQ.java index 611d9575a3..93ea5d025c 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryRQ.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/QueryRQ.java @@ -23,23 +23,23 @@ */ public class QueryRQ { - private String entity; + private String entity; - private Filter filter; + private Filter filter; - public String getEntity() { - return entity; - } + public String getEntity() { + return entity; + } - public void setEntity(String entity) { - this.entity = entity; - } + public void setEntity(String entity) { + this.entity = entity; + } - public Filter getFilter() { - return filter; - } + public Filter getFilter() { + return filter; + } - public void setFilter(Filter filter) { - this.filter = filter; - } + public void setFilter(Filter filter) { + this.filter = filter; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/ReportingStartupService.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/ReportingStartupService.java index 6798120239..23b459231c 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/ReportingStartupService.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/ReportingStartupService.java @@ -17,16 +17,14 @@ package com.epam.ta.reportportal.ws.rabbit; import com.epam.ta.reportportal.core.configs.Conditions; +import java.util.List; +import javax.annotation.PostConstruct; import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Conditional; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; - -import java.util.List; - /** * @author Konstantin Antipin */ @@ -34,15 +32,15 @@ @Conditional(Conditions.NotTestCondition.class) public class ReportingStartupService { - @Autowired - @Qualifier("reportingListenerContainers") - private List<AbstractMessageListenerContainer> listenerContainers; + @Autowired + @Qualifier("reportingListenerContainers") + private List<AbstractMessageListenerContainer> listenerContainers; - @PostConstruct - public void init() { - for (AbstractMessageListenerContainer listenerContainer : listenerContainers) { - listenerContainer.start(); - } + @PostConstruct + public void init() { + for (AbstractMessageListenerContainer listenerContainer : listenerContainers) { + listenerContainer.start(); } + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/RequestType.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/RequestType.java index 82f80386bf..3749c7d0a5 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/RequestType.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/RequestType.java @@ -20,5 +20,5 @@ * @author Konstantin Antipin */ public enum RequestType { - START_LAUNCH, FINISH_LAUNCH, START_TEST, FINISH_TEST, LOG + START_LAUNCH, FINISH_LAUNCH, START_TEST, FINISH_TEST, LOG } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveRole.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveRole.java index f4d1e5251a..9dca62e094 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveRole.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveRole.java @@ -16,11 +16,15 @@ package com.epam.ta.reportportal.ws.resolver; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** - * Annotation should be used as parameter in controllers to show that UserRole - * should be resolved by Spring's resolvers + * Annotation should be used as parameter in controllers to show that UserRole should be resolved by + * Spring's resolvers * * @author Andrei Varabyeu */ @@ -28,4 +32,5 @@ @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ActiveRole { + } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveUserWebArgumentResolver.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveUserWebArgumentResolver.java index 966bafc9e3..0770d76537 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveUserWebArgumentResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/ActiveUserWebArgumentResolver.java @@ -17,6 +17,7 @@ package com.epam.ta.reportportal.ws.resolver; import com.epam.ta.reportportal.entity.user.UserRole; +import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.security.core.Authentication; import org.springframework.web.bind.support.WebArgumentResolver; @@ -25,47 +26,47 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import java.util.Optional; - /** - * {@link org.springframework.web.bind.support.WebArgumentResolver} for - * ReportPortal User Roles. Will resolve {@link UserRole} in case if method - * parameter annotated by {@link ActiveRole} annotation + * {@link org.springframework.web.bind.support.WebArgumentResolver} for ReportPortal User Roles. + * Will resolve {@link UserRole} in case if method parameter annotated by {@link ActiveRole} + * annotation * * @author Andrei Varabyeu */ public class ActiveUserWebArgumentResolver implements HandlerMethodArgumentResolver { - /** - * Returns TRUE if method argument is {@link UserRole} and annotated by - * {@link ActiveRole} annotation - */ - @Override - public boolean supportsParameter(MethodParameter methodParameter) { - return methodParameter.getParameterType().equals(UserRole.class) && null != methodParameter.getParameterAnnotation( - ActiveRole.class); - } + /** + * Returns TRUE if method argument is {@link UserRole} and annotated by {@link ActiveRole} + * annotation + */ + @Override + public boolean supportsParameter(MethodParameter methodParameter) { + return methodParameter.getParameterType().equals(UserRole.class) + && null != methodParameter.getParameterAnnotation( + ActiveRole.class); + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.web.method.support.HandlerMethodArgumentResolver# - * resolveArgument(org.springframework.core.MethodParameter, - * org.springframework.web.method.support.ModelAndViewContainer, - * org.springframework.web.context.request.NativeWebRequest, - * org.springframework.web.bind.support.WebDataBinderFactory) - */ - @Override - public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer paramModelAndViewContainer, - NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { - Authentication authentication = (Authentication) webRequest.getUserPrincipal(); - if (!authentication.getAuthorities().isEmpty()) { - Optional<UserRole> userRole = UserRole.findByAuthority( - authentication.getAuthorities().iterator().next().getAuthority()); - return userRole.isPresent() ? userRole.get() : WebArgumentResolver.UNRESOLVED; - } - return WebArgumentResolver.UNRESOLVED; - } + /* + * (non-Javadoc) + * + * @see + * org.springframework.web.method.support.HandlerMethodArgumentResolver# + * resolveArgument(org.springframework.core.MethodParameter, + * org.springframework.web.method.support.ModelAndViewContainer, + * org.springframework.web.context.request.NativeWebRequest, + * org.springframework.web.bind.support.WebDataBinderFactory) + */ + @Override + public Object resolveArgument(MethodParameter methodParameter, + ModelAndViewContainer paramModelAndViewContainer, + NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { + Authentication authentication = (Authentication) webRequest.getUserPrincipal(); + if (!authentication.getAuthorities().isEmpty()) { + Optional<UserRole> userRole = UserRole.findByAuthority( + authentication.getAuthorities().iterator().next().getAuthority()); + return userRole.isPresent() ? userRole.get() : WebArgumentResolver.UNRESOLVED; + } + return WebArgumentResolver.UNRESOLVED; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterCriteriaResolver.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterCriteriaResolver.java index 6391654ef6..ae8a5a5107 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterCriteriaResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterCriteriaResolver.java @@ -25,6 +25,8 @@ import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.List; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -32,90 +34,87 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import java.util.List; -import java.util.stream.Collectors; - /** * Resolves filter parameters in GET requests. All Parameters should start with * <b>'filter.'</b> prefix. For example, if you would like to filter some - * parameter with name 'age' you have to put in request the following: - * '?filter.age=20'. Resolves parameter only in case argument marked with - * annotation {@link FilterFor}. <br> - * By FilterFor value resolves criterias/parameters to the given domain class - * and resolves them if possible. If there are no criteria/parameter defined for - * specified class than will throw exception + * parameter with name 'age' you have to put in request the following: '?filter.age=20'. Resolves + * parameter only in case argument marked with annotation {@link FilterFor}. <br> By FilterFor value + * resolves criterias/parameters to the given domain class and resolves them if possible. If there + * are no criteria/parameter defined for specified class than will throw exception * * @author Andrei Varabyeu */ public class FilterCriteriaResolver implements HandlerMethodArgumentResolver { - /** - * Default prefix for filter conditions. Since Request contains a lot of - * parameters (some of them may not be related to filtering), we have to - * introduce this - */ - public static final String DEFAULT_FILTER_PREFIX = "filter."; + /** + * Default prefix for filter conditions. Since Request contains a lot of parameters (some of them + * may not be related to filtering), we have to introduce this + */ + public static final String DEFAULT_FILTER_PREFIX = "filter."; - /** - * Prefix before condition type. 'NOT' filter condition may be marked with - * this prefix - */ - public static final String NOT_FILTER_MARKER = "!"; + /** + * Prefix before condition type. 'NOT' filter condition may be marked with this prefix + */ + public static final String NOT_FILTER_MARKER = "!"; - /** - * Returns TRUE only for {@link java.util.List} marked with {@link FilterFor} - * annotations - */ - @Override - public boolean supportsParameter(MethodParameter methodParameter) { - return methodParameter.getParameterType().equals(Filter.class) && null != methodParameter.getParameterAnnotation(FilterFor.class); - } + /** + * Returns TRUE only for {@link java.util.List} marked with {@link FilterFor} annotations + */ + @Override + public boolean supportsParameter(MethodParameter methodParameter) { + return methodParameter.getParameterType().equals(Filter.class) + && null != methodParameter.getParameterAnnotation(FilterFor.class); + } - @Override - public Filter resolveArgument(MethodParameter methodParameter, ModelAndViewContainer paramModelAndViewContainer, - NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { - return resolveAsList(methodParameter, webRequest); - } + @Override + public Filter resolveArgument(MethodParameter methodParameter, + ModelAndViewContainer paramModelAndViewContainer, + NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { + return resolveAsList(methodParameter, webRequest); + } - @SuppressWarnings("unchecked") - private <T> Filter resolveAsList(MethodParameter methodParameter, NativeWebRequest webRequest) { - Class<T> domainModelType = (Class<T>) methodParameter.getParameterAnnotation(FilterFor.class).value(); + @SuppressWarnings("unchecked") + private <T> Filter resolveAsList(MethodParameter methodParameter, NativeWebRequest webRequest) { + Class<T> domainModelType = (Class<T>) methodParameter.getParameterAnnotation(FilterFor.class) + .value(); - List<ConvertibleCondition> filterConditions = webRequest.getParameterMap() - .entrySet() - .stream() - .filter(parameter -> parameter.getKey().startsWith(DEFAULT_FILTER_PREFIX) && parameter.getValue().length > 0) - .map(parameter -> { - final String[] tokens = parameter.getKey().split("\\."); - checkTokens(tokens); - String stringCondition = tokens[1]; - boolean isNegative = stringCondition.startsWith(NOT_FILTER_MARKER); + List<ConvertibleCondition> filterConditions = webRequest.getParameterMap() + .entrySet() + .stream() + .filter(parameter -> parameter.getKey().startsWith(DEFAULT_FILTER_PREFIX) + && parameter.getValue().length > 0) + .map(parameter -> { + final String[] tokens = parameter.getKey().split("\\."); + checkTokens(tokens); + String stringCondition = tokens[1]; + boolean isNegative = stringCondition.startsWith(NOT_FILTER_MARKER); - Condition condition = getCondition(isNegative ? - StringUtils.substringAfter(stringCondition, NOT_FILTER_MARKER) : - stringCondition); - String criteria = tokens[2]; - BusinessRule.expect(parameter.getValue()[0], StringUtils::isNotBlank) - .verify(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Filter criteria - '{}' value should be not empty", parameter.getKey()) - .get() - ); - return new FilterCondition(condition, isNegative, parameter.getValue()[0], criteria); + Condition condition = getCondition(isNegative ? + StringUtils.substringAfter(stringCondition, NOT_FILTER_MARKER) : + stringCondition); + String criteria = tokens[2]; + BusinessRule.expect(parameter.getValue()[0], StringUtils::isNotBlank) + .verify(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier("Filter criteria - '{}' value should be not empty", + parameter.getKey()) + .get() + ); + return new FilterCondition(condition, isNegative, parameter.getValue()[0], criteria); - }) - .collect(Collectors.toList()); - return new Filter(domainModelType, filterConditions); - } + }) + .collect(Collectors.toList()); + return new Filter(domainModelType, filterConditions); + } - private void checkTokens(String[] tokens) { - BusinessRule.expect(tokens.length, Predicates.equalTo(3)) - .verify(ErrorType.INCORRECT_FILTER_PARAMETERS, "Incorrect format of filtering parameters"); - } + private void checkTokens(String[] tokens) { + BusinessRule.expect(tokens.length, Predicates.equalTo(3)) + .verify(ErrorType.INCORRECT_FILTER_PARAMETERS, "Incorrect format of filtering parameters"); + } - private Condition getCondition(String marker) { - return Condition.findByMarker(marker) - .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, - "Unable to find condition with marker '" + marker + "'" - )); - } + private Condition getCondition(String marker) { + return Condition.findByMarker(marker) + .orElseThrow(() -> new ReportPortalException(ErrorType.INCORRECT_FILTER_PARAMETERS, + "Unable to find condition with marker '" + marker + "'" + )); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterFor.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterFor.java index 31aa7bf2ad..2954b3c891 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterFor.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/FilterFor.java @@ -16,11 +16,15 @@ package com.epam.ta.reportportal.ws.resolver; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** - * Annotation to show that method parameter should be resolved as map of - * parameters for specified class. Should be used in controllers + * Annotation to show that method parameter should be resolved as map of parameters for specified + * class. Should be used in controllers * * @author Andrei Varabyeu */ @@ -29,10 +33,10 @@ @Documented public @interface FilterFor { - /** - * Domain Object class queries and parameters will be applied to - * - * @return - */ - Class<?> value(); + /** + * Domain Object class queries and parameters will be applied to + * + * @return class of filter + */ + Class<?> value(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAware.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAware.java index b8086181ef..550dcf1255 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAware.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAware.java @@ -23,27 +23,27 @@ */ public class JacksonViewAware { - /* - * Java bean to be wrapped - */ - private final Object pojo; - - /* - * Jackson's JSON View - */ - private final Class<?> view; - - public JacksonViewAware(Object pojo, Class<?> view) { - this.pojo = pojo; - this.view = view; - } - - public Object getPojo() { - return pojo; - } - - public Class<?> getView() { - return view; - } + /* + * Java bean to be wrapped + */ + private final Object pojo; + + /* + * Jackson's JSON View + */ + private final Class<?> view; + + public JacksonViewAware(Object pojo, Class<?> view) { + this.pojo = pojo; + this.view = view; + } + + public Object getPojo() { + return pojo; + } + + public Class<?> getView() { + return view; + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAwareModule.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAwareModule.java index 048f877cf7..0c1eac419b 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAwareModule.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewAwareModule.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer; - import java.io.IOException; /** @@ -31,39 +30,38 @@ */ public class JacksonViewAwareModule extends SimpleModule { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /** - * @param objectMapper - We need to provide ObjectMapper here since it's impossible - * to serialize using JSON Views without mapper. It's little bit - * unusual from Jackson point of view, but this is only one way - * to avoid 'instaceOf' and classcast on http message converters - * level - * @see <a - * href="http://wiki.fasterxml.com/JacksonHowToCustomSerializers">Jackson - * - HowTo - CustomSerializers</a> - */ - public JacksonViewAwareModule(ObjectMapper objectMapper) { - addSerializer(JacksonViewAware.class, new JacksonViewAwareSerializer(objectMapper)); - } + /** + * @param objectMapper - We need to provide ObjectMapper here since it's impossible to serialize + * using JSON Views without mapper. It's little bit unusual from Jackson point + * of view, but this is only one way to avoid 'instaceOf' and classcast on + * http message converters level + * @see <a href="http://wiki.fasterxml.com/JacksonHowToCustomSerializers">Jackson - HowTo - + * CustomSerializers</a> + */ + public JacksonViewAwareModule(ObjectMapper objectMapper) { + addSerializer(JacksonViewAware.class, new JacksonViewAwareSerializer(objectMapper)); + } - public static class JacksonViewAwareSerializer extends StdScalarSerializer<JacksonViewAware> { + public static class JacksonViewAwareSerializer extends StdScalarSerializer<JacksonViewAware> { - private ObjectMapper objectMapper; + private ObjectMapper objectMapper; - protected JacksonViewAwareSerializer(ObjectMapper objectMapper) { - super(JacksonViewAware.class); - this.objectMapper = objectMapper; - } + protected JacksonViewAwareSerializer(ObjectMapper objectMapper) { + super(JacksonViewAware.class); + this.objectMapper = objectMapper; + } - @Override - public void serialize(JacksonViewAware value, JsonGenerator jgen, SerializerProvider provider) throws IOException { - /* - * Writes bean with specified view - */ - objectMapper.writerWithView(value.getView()).writeValue(jgen, value.getPojo()); - } + @Override + public void serialize(JacksonViewAware value, JsonGenerator jgen, SerializerProvider provider) + throws IOException { + /* + * Writes bean with specified view + */ + objectMapper.writerWithView(value.getView()).writeValue(jgen, value.getPojo()); + } - } + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewReturnValueHandler.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewReturnValueHandler.java index da45ba2686..b7c269faa3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewReturnValueHandler.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/JacksonViewReturnValueHandler.java @@ -22,62 +22,62 @@ import org.springframework.web.method.support.ModelAndViewContainer; /** - * Wraps {@link HandlerMethodReturnValueHandler}. Checks if {@link ResponseView} - * annotation present, and if yes wraps bean to be serialized with view mapped - * to it on controller's level class + * Wraps {@link HandlerMethodReturnValueHandler}. Checks if {@link ResponseView} annotation present, + * and if yes wraps bean to be serialized with view mapped to it on controller's level class * * @author Andrei Varabyeu */ class JacksonViewReturnValueHandler implements HandlerMethodReturnValueHandler { - private final HandlerMethodReturnValueHandler delegate; + private final HandlerMethodReturnValueHandler delegate; - public JacksonViewReturnValueHandler(HandlerMethodReturnValueHandler delegate) { - this.delegate = delegate; - } + public JacksonViewReturnValueHandler(HandlerMethodReturnValueHandler delegate) { + this.delegate = delegate; + } - @Override - public boolean supportsReturnType(MethodParameter returnType) { - return delegate.supportsReturnType(returnType); - } + @Override + public boolean supportsReturnType(MethodParameter returnType) { + return delegate.supportsReturnType(returnType); + } - @Override - public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest) throws Exception { + @Override + public void handleReturnValue(Object returnValue, MethodParameter returnType, + ModelAndViewContainer mavContainer, + NativeWebRequest webRequest) throws Exception { - /* - * Wraps bean to be serialized if there is some view assigned to it on - * controller level - */ - Class<?> viewClass = getDeclaredViewClass(returnType); - if (viewClass != null) { - returnValue = wrapResult(returnValue, viewClass); - } + /* + * Wraps bean to be serialized if there is some view assigned to it on + * controller level + */ + Class<?> viewClass = getDeclaredViewClass(returnType); + if (viewClass != null) { + returnValue = wrapResult(returnValue, viewClass); + } - delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest); + delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest); - } + } - /** - * Returns assigned view or null - * - * @param returnType - * @return - */ - private Class<?> getDeclaredViewClass(MethodParameter returnType) { - ResponseView annotation = returnType.getMethodAnnotation(ResponseView.class); - if (annotation != null) { - return annotation.value(); - } else { - return null; - } - } + /** + * Returns assigned view or null + * + * @param returnType + * @return + */ + private Class<?> getDeclaredViewClass(MethodParameter returnType) { + ResponseView annotation = returnType.getMethodAnnotation(ResponseView.class); + if (annotation != null) { + return annotation.value(); + } else { + return null; + } + } - /** - * Wraps bean and view into one object - */ - private Object wrapResult(Object result, Class<?> viewClass) { - return new JacksonViewAware(result, viewClass); - } + /** + * Wraps bean and view into one object + */ + private Object wrapResult(Object result, Class<?> viewClass) { + return new JacksonViewAware(result, viewClass); + } } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/JsonViewSupportFactoryBean.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/JsonViewSupportFactoryBean.java index 9c69db4a62..6b7ee82be6 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/JsonViewSupportFactoryBean.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/JsonViewSupportFactoryBean.java @@ -16,47 +16,46 @@ package com.epam.ta.reportportal.ws.resolver; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** - * Initializing bean for wrapping {@link HandlerMethodReturnValueHandler} with - * JSON view decorators + * Initializing bean for wrapping {@link HandlerMethodReturnValueHandler} with JSON view decorators * * @author Andrei Varabyeu */ public class JsonViewSupportFactoryBean implements InitializingBean { - @Autowired - private RequestMappingHandlerAdapter adapter; - - @Override - public void afterPropertiesSet() { - List<HandlerMethodReturnValueHandler> handlers = adapter.getReturnValueHandlers(); - adapter.setReturnValueHandlers(decorateHandlers(handlers)); - } - - private List<HandlerMethodReturnValueHandler> decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) { - - /* - * We have to create new collection here, because initial list is - * unmodifiable - */ - List<HandlerMethodReturnValueHandler> updatedHandlers = new ArrayList<>(handlers.size()); - for (HandlerMethodReturnValueHandler handler : handlers) { - if (handler instanceof RequestResponseBodyMethodProcessor) { - updatedHandlers.add(new JacksonViewReturnValueHandler(handler)); - } else { - updatedHandlers.add(handler); - } - } - return Collections.unmodifiableList(updatedHandlers); - } + @Autowired + private RequestMappingHandlerAdapter adapter; + + @Override + public void afterPropertiesSet() { + List<HandlerMethodReturnValueHandler> handlers = adapter.getReturnValueHandlers(); + adapter.setReturnValueHandlers(decorateHandlers(handlers)); + } + + private List<HandlerMethodReturnValueHandler> decorateHandlers( + List<HandlerMethodReturnValueHandler> handlers) { + + /* + * We have to create new collection here, because initial list is + * unmodifiable + */ + List<HandlerMethodReturnValueHandler> updatedHandlers = new ArrayList<>(handlers.size()); + for (HandlerMethodReturnValueHandler handler : handlers) { + if (handler instanceof RequestResponseBodyMethodProcessor) { + updatedHandlers.add(new JacksonViewReturnValueHandler(handler)); + } else { + updatedHandlers.add(handler); + } + } + return Collections.unmodifiableList(updatedHandlers); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/PagingHandlerMethodArgumentResolver.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/PagingHandlerMethodArgumentResolver.java index 0dd27bb586..93589e1b69 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/PagingHandlerMethodArgumentResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/PagingHandlerMethodArgumentResolver.java @@ -16,6 +16,7 @@ package com.epam.ta.reportportal.ws.resolver; +import javax.annotation.Nonnull; import org.springframework.core.MethodParameter; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -25,45 +26,48 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; -import javax.annotation.Nonnull; - /** - * Added to avoid issue with page size == 0 (in this case repository layer tries - * to retrieve all results from database) and page size greater than 300. + * Added to avoid issue with page size == 0 (in this case repository layer tries to retrieve all + * results from database) and page size greater than 300. * * @author Andrei Varabyeu */ -public class PagingHandlerMethodArgumentResolver extends org.springframework.data.web.PageableHandlerMethodArgumentResolver { +public class PagingHandlerMethodArgumentResolver extends + org.springframework.data.web.PageableHandlerMethodArgumentResolver { - public PagingHandlerMethodArgumentResolver() { - super(); - } + public PagingHandlerMethodArgumentResolver() { + super(); + } - public PagingHandlerMethodArgumentResolver(SortHandlerMethodArgumentResolver sortResolver) { - super(sortResolver); - } + public PagingHandlerMethodArgumentResolver(SortHandlerMethodArgumentResolver sortResolver) { + super(sortResolver); + } - public static final int DEFAULT_PAGE_SIZE = 50; - public static final int MAX_PAGE_SIZE = 300000; + public static final int DEFAULT_PAGE_SIZE = 50; + public static final int MAX_PAGE_SIZE = 300000; - @Override - @Nonnull - public Pageable resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) { - Pageable pageable = super.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory); + @Override + @Nonnull + public Pageable resolveArgument(MethodParameter methodParameter, + @Nullable ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) { + Pageable pageable = super.resolveArgument(methodParameter, mavContainer, webRequest, + binderFactory); - //overriding spring base limit for page size - String pageSize = webRequest.getParameter(getParameterNameToUse(getSizeParameterName(), methodParameter)); - if (pageSize != null) { - pageable = PageRequest.of(pageable.getPageNumber(), Integer.parseInt(pageSize), pageable.getSort()); - } + //overriding spring base limit for page size + String pageSize = webRequest.getParameter( + getParameterNameToUse(getSizeParameterName(), methodParameter)); + if (pageSize != null) { + pageable = PageRequest.of(pageable.getPageNumber(), Integer.parseInt(pageSize), + pageable.getSort()); + } - if (0 == pageable.getPageSize()) { - return PageRequest.of(pageable.getPageNumber(), DEFAULT_PAGE_SIZE, pageable.getSort()); - } else if (MAX_PAGE_SIZE < pageable.getPageSize()) { - return PageRequest.of(pageable.getPageNumber(), MAX_PAGE_SIZE, pageable.getSort()); - } - return pageable; - } + if (0 == pageable.getPageSize()) { + return PageRequest.of(pageable.getPageNumber(), DEFAULT_PAGE_SIZE, pageable.getSort()); + } else if (MAX_PAGE_SIZE < pageable.getPageSize()) { + return PageRequest.of(pageable.getPageNumber(), MAX_PAGE_SIZE, pageable.getSort()); + } + return pageable; + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/PredefinedFilterCriteriaResolver.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/PredefinedFilterCriteriaResolver.java index cb7af96822..479f56227e 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/PredefinedFilterCriteriaResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/PredefinedFilterCriteriaResolver.java @@ -23,6 +23,11 @@ import com.epam.ta.reportportal.core.filter.predefined.PredefinedFilterType; import com.epam.ta.reportportal.core.filter.predefined.PredefinedFilters; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.jooq.Operator; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -30,76 +35,74 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.function.Predicate; -import java.util.stream.Collectors; - /** * Resolves filter parameters in GET requests. All Parameters should start with * <b>'filter.'</b> prefix. For example, if you would like to filter some - * parameter with name 'age' you have to put in request the following: - * '?filter.age=20'. Resolves parameter only in case argument marked with - * annotation {@link FilterFor}. <br> - * By FilterFor value resolves criterias/parameters to the given domain class - * and resolves them if possible. If there are no criteria/parameter defined for - * specified class than will throw exception + * parameter with name 'age' you have to put in request the following: '?filter.age=20'. Resolves + * parameter only in case argument marked with annotation {@link FilterFor}. <br> By FilterFor value + * resolves criterias/parameters to the given domain class and resolves them if possible. If there + * are no criteria/parameter defined for specified class than will throw exception * * @author Andrei Varabyeu */ public class PredefinedFilterCriteriaResolver implements HandlerMethodArgumentResolver { - /** - * Default prefix for filter conditions. Since Request contains a lot of - * parameters (some of them may not be related to filtering), we have to - * introduce this - */ - public static final String PREDEFINED_FILTER_PREFIX = "predefinedFilter."; + /** + * Default prefix for filter conditions. Since Request contains a lot of parameters (some of them + * may not be related to filtering), we have to introduce this + */ + public static final String PREDEFINED_FILTER_PREFIX = "predefinedFilter."; - /** - * Returns TRUE only for {@link List} marked with {@link FilterFor} - * annotations - */ - @Override - public boolean supportsParameter(MethodParameter methodParameter) { - return Queryable.class.isAssignableFrom(methodParameter.getParameterType()) && null != methodParameter.getParameterAnnotation( - FilterFor.class); - } + /** + * Returns TRUE only for {@link List} marked with {@link FilterFor} annotations + */ + @Override + public boolean supportsParameter(MethodParameter methodParameter) { + return Queryable.class.isAssignableFrom(methodParameter.getParameterType()) + && null != methodParameter.getParameterAnnotation( + FilterFor.class); + } - @Override - public Queryable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer paramModelAndViewContainer, - NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { - Class<?> domainModelType = methodParameter.getParameterAnnotation(FilterFor.class).value(); + @Override + public Queryable resolveArgument(MethodParameter methodParameter, + ModelAndViewContainer paramModelAndViewContainer, + NativeWebRequest webRequest, WebDataBinderFactory paramWebDataBinderFactory) { + Class<?> domainModelType = methodParameter.getParameterAnnotation(FilterFor.class).value(); - List<Queryable> filterConditions = webRequest.getParameterMap() - .entrySet().stream().filter(parameter -> parameter.getKey().startsWith(PREDEFINED_FILTER_PREFIX)) - .map(parameter -> { - BusinessRule.expect(parameter.getValue(), v -> null != v && v.length == 1) - .verify(ErrorType.INCORRECT_REQUEST, "Incorrect filter value"); + List<Queryable> filterConditions = webRequest.getParameterMap() + .entrySet().stream() + .filter(parameter -> parameter.getKey().startsWith(PREDEFINED_FILTER_PREFIX)) + .map(parameter -> { + BusinessRule.expect(parameter.getValue(), v -> null != v && v.length == 1) + .verify(ErrorType.INCORRECT_REQUEST, "Incorrect filter value"); - String filterName = parameter.getKey().split("\\.")[1]; - String[] filterParameters = parameter.getValue()[0].split(","); + String filterName = parameter.getKey().split("\\.")[1]; + String[] filterParameters = parameter.getValue()[0].split(","); - Optional<PredefinedFilterType> predefinedFilterType = PredefinedFilterType.fromString(filterName); - BusinessRule.expect(predefinedFilterType, Optional::isPresent) - .verify(ErrorType.BAD_REQUEST_ERROR, "Incorrect predefined filter type " + filterName); + Optional<PredefinedFilterType> predefinedFilterType = PredefinedFilterType.fromString( + filterName); + BusinessRule.expect(predefinedFilterType, Optional::isPresent) + .verify(ErrorType.BAD_REQUEST_ERROR, + "Incorrect predefined filter type " + filterName); - BusinessRule.expect(PredefinedFilters.hasFilter(predefinedFilterType.get()), Predicate.isEqual(true)) - .verify(ErrorType.INCORRECT_REQUEST, "Unknown filter '" + filterName + "'"); + BusinessRule.expect(PredefinedFilters.hasFilter(predefinedFilterType.get()), + Predicate.isEqual(true)) + .verify(ErrorType.INCORRECT_REQUEST, "Unknown filter '" + filterName + "'"); - final Queryable queryable = PredefinedFilters.buildFilter(predefinedFilterType.get(), filterParameters); - BusinessRule.expect(queryable.getTarget().getClazz(), Predicate.isEqual(domainModelType)) - .verify(ErrorType.INCORRECT_REQUEST, "Incorrect filter target class type"); + final Queryable queryable = PredefinedFilters.buildFilter(predefinedFilterType.get(), + filterParameters); + BusinessRule.expect(queryable.getTarget().getClazz(), Predicate.isEqual(domainModelType)) + .verify(ErrorType.INCORRECT_REQUEST, "Incorrect filter target class type"); - return queryable; + return queryable; - }) - .collect(Collectors.toList()); - return filterConditions.isEmpty() ? nop(domainModelType) : new CompositeFilter(Operator.AND, filterConditions); - } + }) + .collect(Collectors.toList()); + return filterConditions.isEmpty() ? nop(domainModelType) + : new CompositeFilter(Operator.AND, filterConditions); + } - private Queryable nop(Class<?> type) { - return new Filter(type, Collections.emptyList()); - } + private Queryable nop(Class<?> type) { + return new Filter(type, Collections.emptyList()); + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/ResponseView.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/ResponseView.java index a1ba321674..1af8f3e2cd 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/ResponseView.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/ResponseView.java @@ -31,8 +31,9 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ResponseView { - /** - * View class - */ - Class<?> value(); + + /** + * View class + */ + Class<?> value(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/SortArgumentResolver.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/SortArgumentResolver.java index b9e762c4a4..5841d34f05 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/SortArgumentResolver.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/SortArgumentResolver.java @@ -16,11 +16,16 @@ package com.epam.ta.reportportal.ws.resolver; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static java.util.stream.Collectors.toList; + import com.epam.ta.reportportal.commons.Preconditions; import com.epam.ta.reportportal.commons.querygen.CriteriaHolder; import com.epam.ta.reportportal.commons.querygen.FilterTarget; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.ws.model.ErrorType; +import java.util.Optional; +import java.util.stream.StreamSupport; import org.springframework.core.MethodParameter; import org.springframework.data.domain.Sort; import org.springframework.data.web.SortHandlerMethodArgumentResolver; @@ -28,56 +33,52 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; -import java.util.Optional; -import java.util.stream.StreamSupport; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static java.util.stream.Collectors.toList; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ public class SortArgumentResolver extends SortHandlerMethodArgumentResolver { - @Override - public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, - WebDataBinderFactory binderFactory) { + @Override + public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) { - /* - * Resolve sort argument in default way - */ - Sort defaultSort = super.resolveArgument(parameter, mavContainer, webRequest, binderFactory); + /* + * Resolve sort argument in default way + */ + Sort defaultSort = super.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - /* - * Try to find parameter to be sorted in internal-external mapping - */ - if (null != parameter.getParameterAnnotation(SortFor.class)) { + /* + * Try to find parameter to be sorted in internal-external mapping + */ + if (null != parameter.getParameterAnnotation(SortFor.class)) { - Class<?> domainModelType = parameter.getParameterAnnotation(SortFor.class).value(); - FilterTarget filterTarget = FilterTarget.findByClass(domainModelType); + Class<?> domainModelType = parameter.getParameterAnnotation(SortFor.class).value(); + FilterTarget filterTarget = FilterTarget.findByClass(domainModelType); - /* - * Hack. Adds sort by id to each query to avoid problems with - * lost data while paging - */ - defaultSort = defaultSort.and(Sort.by(CRITERIA_ID)); + /* + * Hack. Adds sort by id to each query to avoid problems with + * lost data while paging + */ + defaultSort = defaultSort.and(Sort.by(CRITERIA_ID)); - /* - * Build Sort with search criteria from internal domain model - */ - return Sort.by(StreamSupport.stream(defaultSort.spliterator(), false).map(order -> { - Optional<CriteriaHolder> criteriaHolder = filterTarget.getCriteriaByFilter(order.getProperty()); - BusinessRule.expect(criteriaHolder, Preconditions.IS_PRESENT) - .verify(ErrorType.INCORRECT_SORTING_PARAMETERS, order.getProperty()); - return new Sort.Order(order.getDirection(), order.getProperty()); - }).collect(toList())); - } else { - /* - * Return default sort in case there are no SortFor annotation - */ - return defaultSort; - } + /* + * Build Sort with search criteria from internal domain model + */ + return Sort.by(StreamSupport.stream(defaultSort.spliterator(), false).map(order -> { + Optional<CriteriaHolder> criteriaHolder = filterTarget.getCriteriaByFilter( + order.getProperty()); + BusinessRule.expect(criteriaHolder, Preconditions.IS_PRESENT) + .verify(ErrorType.INCORRECT_SORTING_PARAMETERS, order.getProperty()); + return new Sort.Order(order.getDirection(), order.getProperty()); + }).collect(toList())); + } else { + /* + * Return default sort in case there are no SortFor annotation + */ + return defaultSort; + } - } + } } diff --git a/src/main/java/com/epam/ta/reportportal/ws/resolver/SortFor.java b/src/main/java/com/epam/ta/reportportal/ws/resolver/SortFor.java index 9664c0aae1..e63de831b1 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/resolver/SortFor.java +++ b/src/main/java/com/epam/ta/reportportal/ws/resolver/SortFor.java @@ -15,7 +15,11 @@ */ package com.epam.ta.reportportal.ws.resolver; -import java.lang.annotation.*; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** * Remaps WS domain model to internal domain model in sorting request parameters @@ -27,10 +31,10 @@ @Documented public @interface SortFor { - /** - * Domain Object class sorting parameters will be applied to - * - * @return Class - */ - Class<?> value(); + /** + * Domain Object class sorting parameters will be applied to + * + * @return Class + */ + Class<?> value(); } \ No newline at end of file diff --git a/src/main/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidator.java b/src/main/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidator.java index f487237949..7c39324df3 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidator.java +++ b/src/main/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidator.java @@ -20,6 +20,10 @@ import com.epam.ta.reportportal.commons.accessible.Accessible; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.AnnotationUtils; @@ -27,53 +31,51 @@ import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - public class JaskonRequiredPropertiesValidator implements Validator { - private static final Logger LOGGER = LoggerFactory.getLogger(JaskonRequiredPropertiesValidator.class); - @Override - public boolean supports(Class<?> clazz) { - return AnnotationUtils.isAnnotationDeclaredLocally(JsonInclude.class, clazz); - } + private static final Logger LOGGER = LoggerFactory.getLogger( + JaskonRequiredPropertiesValidator.class); + + @Override + public boolean supports(Class<?> clazz) { + return AnnotationUtils.isAnnotationDeclaredLocally(JsonInclude.class, clazz); + } - @Override - public void validate(Object object, Errors errors) { - for (Field field : collectFields(object.getClass())) { - if (AnnotationUtils.isAnnotationDeclaredLocally(JsonInclude.class, field.getType())) { - try { - Object innerObject = Accessible.on(object).field(field).getValue(); - if (null != innerObject) { - errors.pushNestedPath(field.getName()); - validate(innerObject, errors); - } - } catch (Exception e) { - LOGGER.error("JaskonRequiredPropertiesValidator error: " + e.getMessage(), e); - // do nothing - } + @Override + public void validate(Object object, Errors errors) { + for (Field field : collectFields(object.getClass())) { + if (AnnotationUtils.isAnnotationDeclaredLocally(JsonInclude.class, field.getType())) { + try { + Object innerObject = Accessible.on(object).field(field).getValue(); + if (null != innerObject) { + errors.pushNestedPath(field.getName()); + validate(innerObject, errors); + } + } catch (Exception e) { + LOGGER.error("JaskonRequiredPropertiesValidator error: " + e.getMessage(), e); + // do nothing + } - } - if (field.isAnnotationPresent(JsonProperty.class) && field.getAnnotation(JsonProperty.class).required()) { - String errorCode = "NotNull." + field.getName(); - ValidationUtils.rejectIfEmpty(errors, field.getName(), errorCode, new Object[] { errorCode }); - } - } - if (errors.getNestedPath() != null && errors.getNestedPath().length() != 0) { - errors.popNestedPath(); - } - } + } + if (field.isAnnotationPresent(JsonProperty.class) && field.getAnnotation(JsonProperty.class) + .required()) { + String errorCode = "NotNull." + field.getName(); + ValidationUtils.rejectIfEmpty(errors, field.getName(), errorCode, new Object[]{errorCode}); + } + } + if (errors.getNestedPath() != null && errors.getNestedPath().length() != 0) { + errors.popNestedPath(); + } + } - private List<Field> collectFields(Class<?> clazz) { - List<Field> fields = null; - if (!Object.class.equals(clazz.getSuperclass())) { - fields = collectFields(clazz.getSuperclass()); - } + private List<Field> collectFields(Class<?> clazz) { + List<Field> fields = null; + if (!Object.class.equals(clazz.getSuperclass())) { + fields = collectFields(clazz.getSuperclass()); + } - fields = (fields == null) ? new ArrayList<>() : fields; - fields.addAll(Arrays.asList(clazz.getDeclaredFields())); - return fields; - } + fields = (fields == null) ? new ArrayList<>() : fields; + fields.addAll(Arrays.asList(clazz.getDeclaredFields())); + return fields; + } } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4056f615ae..7ff12905eb 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,26 +14,23 @@ # limitations under the License. # spring.main.allow-bean-definition-overriding=true -spring.batch.initialize-schema=always - +spring.batch.jdbc.initialize-schema=always info.build.name=API Service info.build.description=ReportPortal API Service info.build.version=${version}${buildNumber} info.build.branch=${branch} info.build.repo=${repo} - management.endpoints.web.base-path=/ +management.endpoint.health.show-details=always #security.sessions=never #security.basic.enabled=false -management.server.servlet.context-path=/admin - +management.server.base-path=/admin ## Supported period format details ## https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence- -com.ta.reportportal.job.load.plugins.cron=PT1M -com.ta.reportportal.job.clean.outdated.plugins.cron=PT1M +com.ta.reportportal.job.load.plugins.cron=PT10S +com.ta.reportportal.job.clean.outdated.plugins.cron=PT10S com.ta.reportportal.job.interrupt.broken.launches.cron=PT1H com.ta.reportportal.job.clean.bids.cron=PT1H - spring.jooq.sql-dialect=POSTGRES @@ -57,4 +54,4 @@ com.ta.reportportal.rp.flushing.time.cron=\${rp.environment.variable.flushing.ti ## Profiles list spring.profiles.active=\${rp.profiles:default} -rp.feature.flags= \ No newline at end of file +rp.feature.flags= diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 641973021c..6cbd6f282e 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -2,7 +2,7 @@ spring: application: name: api quartz: -# org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX + # org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate org.quartz.jobStore.dataSource: dataSource org.quartz.jobStore.tablePrefix: quartz.scheduler_ @@ -70,6 +70,11 @@ rp: batch-size: 20 pattern-analysis: batch-size: 100 + consumers-count: 2 + prefetch-count: 0 + single-item: true + elements-counter: + batch-size: 50 history: old: false demo: @@ -94,10 +99,6 @@ rp: core: 10 max: 30 queue: 500 - pattern-analyze: - core: 20 - max: 30 - queue: 500 demo-data: core: 10 max: 20 @@ -110,6 +111,10 @@ rp: core: 10 max: 20 queue: 1000 + user-email: + core: 5 + max: 20 + queue: 500 amqp: addresses: amqp://${rp.amqp.user}:${rp.amqp.pass}@${rp.amqp.host}:${rp.amqp.port} @@ -136,6 +141,10 @@ rp: jwt: signing-key: + + jobs: + baseUrl: http://jobs:8686 + datasource: type: com.zaxxer.hikari.HikariDataSource driverClassName: org.postgresql.Driver @@ -162,6 +171,7 @@ rp: path: ${rp.plugins.rootDir}/resolved resources: path: ${rp.plugins.rootDir}/resources + public: public temp: path: ${rp.plugins.rootDir}/temp binarystore: diff --git a/src/main/resources/bug_template.ftl b/src/main/resources/bug_template.ftl index aff122189c..6f973628d8 100644 --- a/src/main/resources/bug_template.ftl +++ b/src/main/resources/bug_template.ftl @@ -3,53 +3,55 @@ ${description} </#if> -<#--if RP contains some comments for test item--> + <#--if RP contains some comments for test item--> <#if comments??> - <h3>Test Item comments:</h3> + <h3>Test Item comments:</h3> ${comments} </#if> -<#--## if backlinks are present--> + <#--## if backlinks are present--> <#if backLinks??> - <h3>Back link to Report Portal:</h3> - <ul type="square"> - <#list backLinks as key,value> + <h3>Back link to Report Portal:</h3> + <ul type="square"> + <#list backLinks as key,value> <li><a href="${value}" rel="nofollow" title="Follow link">Link to defect</a></li> - </#list> - </ul> - <br> + </#list> + </ul> + <br> </#if> -<#--Complex block with logic in velocity. Consider to move all logic in JAVA code.--> - <#if logs?? && logs?size != 0> - <div class="panel"> - <div class="panelHeader" - style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: #ccc;background-color: #6DB33F;color: #34302D;"> - <b>Test execution log</b> - </div> - <div class="panelContent"> - <#list logs as logEntry> - <#if logEntry.message??> - <div style="border-width: 1px;"> - <pre style="white-space: pre-wrap; display: block;font-family: monospace;max-height: 30em;text-align: left;">${logEntry.message}</pre> - </div> - </#if> - <#--## if URL provided to screen source--> - <#if logEntry.decodedFileName??> - <#if (logEntry.image)!false> - <p><img src="${logEntry.decodedFileName}" align="absmiddle" border="0" height="366"><br class="atl-forced-newline"> - </p> - <#else> - <p> - <a href="${logEntry.decodedFileName}"> - "${logEntry.decodedFileName}" - </a> - <br class="atl-forced-newline"> - </p> - </#if> + <#--Complex block with logic in velocity. Consider to move all logic in JAVA code.--> + <#if logs?? && logs?size != 0> + <div class="panel"> + <div class="panelHeader" + style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: #ccc;background-color: #6DB33F;color: #34302D;"> + <b>Test execution log</b> + </div> + <div class="panelContent"> + <#list logs as logEntry> + <#if logEntry.message??> + <div style="border-width: 1px;"> + <pre + style="white-space: pre-wrap; display: block;font-family: monospace;max-height: 30em;text-align: left;">${logEntry.message}</pre> + </div> + </#if> + <#--## if URL provided to screen source--> + <#if logEntry.decodedFileName??> + <#if (logEntry.image)!false> + <p><img src="${logEntry.decodedFileName}" align="absmiddle" border="0" + height="366"><br class="atl-forced-newline"> + </p> + <#else> + <p> + <a href="${logEntry.decodedFileName}"> + "${logEntry.decodedFileName}" + </a> + <br class="atl-forced-newline"> + </p> </#if> - </#list> - </div> + </#if> + </#list> </div> - </#if> + </div> + </#if> </div> diff --git a/src/main/resources/demo/attachments/css.css b/src/main/resources/demo/attachments/css.css index fce80e34c3..67f6d90a09 100644 --- a/src/main/resources/demo/attachments/css.css +++ b/src/main/resources/demo/attachments/css.css @@ -1,31 +1,31 @@ p { - font-family: arial, helvetica, sans-serif; + font-family: arial, helvetica, sans-serif; } h2 { - font-size: 20pt; - color: red; - background: white; + font-size: 20pt; + color: red; + background: white; } .note { - color: red; - background-color: yellow; - font-weight: bold; + color: red; + background-color: yellow; + font-weight: bold; } p#paragraph1 { - padding-left: 10px; + padding-left: 10px; } a:hover { - text-decoration: none; + text-decoration: none; } #news p { - color: blue; + color: blue; } [type="button"] { - background-color: green; + background-color: green; } \ No newline at end of file diff --git a/src/main/resources/demo/attachments/html.html b/src/main/resources/demo/attachments/html.html index fca8088680..a2e5c1dde6 100644 --- a/src/main/resources/demo/attachments/html.html +++ b/src/main/resources/demo/attachments/html.html @@ -1,16 +1,16 @@ <!DOCTYPE html> <html> <head> - <title>Sample "Hello, World" Application</title> + <title>Sample "Hello, World" Application</title> </head> <body bgcolor=white> <table border="0" cellpadding="10"> - <tr> - <td> - <h1>Sample "Hello, World" Application</h1> - </td> - </tr> + <tr> + <td> + <h1>Sample "Hello, World" Application</h1> + </td> + </tr> </table> </body> </html> \ No newline at end of file diff --git a/src/main/resources/demo/attachments/javascript.js b/src/main/resources/demo/attachments/javascript.js index de5361602b..e3e51f1831 100644 --- a/src/main/resources/demo/attachments/javascript.js +++ b/src/main/resources/demo/attachments/javascript.js @@ -1,62 +1,62 @@ var APP = APP || {}; APP.Views.People = Backbone.View.extend({ - template: APP.getTemplate('people-list-template'), - initialize: function () { - this.render(); - var peopleControls = new APP.Views.PeopleControls({ - el: '#controls' - }); - var peopleInfo = new APP.Views.PeopleInfo({ - el: '#summary' - }); - this.showPeopleCount(); - this.listenTo(this.collection, 'reset', this.renderPeopleList); - this.listenTo(this.collection, 'all', this.showPeopleCount); - }, - events: { - 'click .toJSON': 'convertToJSON', - 'click .deleteAll': 'deleteAll', - 'click .addPerson': 'addPerson' - }, - convertToJSON: function () { - this.$('#JSON-output').html(JSON.stringify(this.collection.toJSON())); - }, - renderPerson: function (person) { - var personView = new APP.Views.Person({ - model: person, - //el: '#peopleList' затирает el при каждом вызове - }); - this.$el.find('#peopleList').append(personView.render().el); - }, - deleteAll: function () { - if (confirm('Delete all data?')) { - this.collection.reset(); - } - }, - addPerson: function () { - var personModel = new APP.Models.Person({ - 'name': this.$el.find('#name').val().trim(), - 'age': +this.$el.find('#age').val().trim(), - 'profession': this.$el.find('#profession > option:selected').text(), - }, { - validate: true - }); - if (!personModel.validationError) { - this.collection.add(personModel); - this.renderPerson(personModel); - } else { - alert(personModel.validationError); - } - }, - renderPeopleList: function () { - this.$el.find('#peopleList').html(''); - this.collection.each(this.renderCollection, this); - }, - showPeopleCount: function () { - this.$el.find('#peopleCount').html(this.collection.length); - }, - render: function () { - this.$el.html(this.template); - this.collection.each(this.renderPerson, this); + template: APP.getTemplate('people-list-template'), + initialize: function () { + this.render(); + var peopleControls = new APP.Views.PeopleControls({ + el: '#controls' + }); + var peopleInfo = new APP.Views.PeopleInfo({ + el: '#summary' + }); + this.showPeopleCount(); + this.listenTo(this.collection, 'reset', this.renderPeopleList); + this.listenTo(this.collection, 'all', this.showPeopleCount); + }, + events: { + 'click .toJSON': 'convertToJSON', + 'click .deleteAll': 'deleteAll', + 'click .addPerson': 'addPerson' + }, + convertToJSON: function () { + this.$('#JSON-output').html(JSON.stringify(this.collection.toJSON())); + }, + renderPerson: function (person) { + var personView = new APP.Views.Person({ + model: person, + //el: '#peopleList' затирает el при каждом вызове + }); + this.$el.find('#peopleList').append(personView.render().el); + }, + deleteAll: function () { + if (confirm('Delete all data?')) { + this.collection.reset(); } + }, + addPerson: function () { + var personModel = new APP.Models.Person({ + 'name': this.$el.find('#name').val().trim(), + 'age': +this.$el.find('#age').val().trim(), + 'profession': this.$el.find('#profession > option:selected').text(), + }, { + validate: true + }); + if (!personModel.validationError) { + this.collection.add(personModel); + this.renderPerson(personModel); + } else { + alert(personModel.validationError); + } + }, + renderPeopleList: function () { + this.$el.find('#peopleList').html(''); + this.collection.each(this.renderCollection, this); + }, + showPeopleCount: function () { + this.$el.find('#peopleCount').html(this.collection.length); + }, + render: function () { + this.$el.html(this.template); + this.collection.each(this.renderPerson, this); + } }); diff --git a/src/main/resources/demo/attachments/xml.xml b/src/main/resources/demo/attachments/xml.xml index e727599fea..7ba28131c4 100644 --- a/src/main/resources/demo/attachments/xml.xml +++ b/src/main/resources/demo/attachments/xml.xml @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <configuration> - <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> - <layout class="ch.qos.logback.classic.PatternLayout"> - <Pattern> - %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n - </Pattern> - </layout> - </appender> - <logger name="com.mkyong.web" level="debug" - additivity="false"> - <appender-ref ref="STDOUT"/> - </logger> - <root level="error"> - <appender-ref ref="STDOUT"/> - </root> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <layout class="ch.qos.logback.classic.PatternLayout"> + <Pattern> + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + </Pattern> + </layout> + </appender> + <logger name="com.mkyong.web" level="debug" + additivity="false"> + <appender-ref ref="STDOUT"/> + </logger> + <root level="error"> + <appender-ref ref="STDOUT"/> + </root> </configuration> diff --git a/src/main/resources/demo/launch/002_launch.json b/src/main/resources/demo/launch/002_launch.json index 2566579c44..0fa5122fc3 100644 --- a/src/main/resources/demo/launch/002_launch.json +++ b/src/main/resources/demo/launch/002_launch.json @@ -1,175 +1,175 @@ - { - "suites": [ - { - "type": "RETRY", - "name": "Suite with retries", - "status": "FAILED", - "tests": [ - { - "name": "First test case", - "status": "FAILED", - "steps": [ - { - "name": "first test", - "status": "FAILED", - "issue": "SYSTEM_ISSUE" - } - ] - } - ] - }, - { - "type": "NESTED", - "name": "Suite with nested steps", - "status": "FAILED", - "tests": [ - { - "name": "History table. Extended functionality. Permissions. Edit defect", - "status": "FAILED", - "issue": "AUTOMATION_BUG", - "steps": [ - { - "name": "Launch was executed 11 times", - "status": "PASSED" - }, - { - "name": "**Step 1:** Login to https://localhost:8080/ with password *** <br />**Expected Result:** User is in RP", - "status": "PASSED" - }, - { - "name": "**Step 2:** Open 'All launches' <br />**Expected Result:** All launches page is presented", - "status": "PASSED" - }, - { - "name": "**Step 3:** Click on Total statistics <br />**Expected Result:** Launch list view is displayed, refines contains criteria **Method type: Test**; **Status: Passed, Failed, Skipped, Interrupted**", - "status": "PASSED" - }, - { - "name": "**Step 4:** Click on 'History view' icon <br />**Expected Result:** 10 latest executions for the first 20 items (from the latest executions to the eldest) displayed by default**", - "status": "PASSED" - }, - { - "name": "**Step 5:** Check several items **(own and not own)** <br />**Expected Result:** Items are added to the header", - "status": "PASSED" - }, - { - "name": "**Step 6:** Click 'Actions'> 'Edit Defects' <br />**Expected Result:** Edit modal for bulk operation is opened", - "status": "PASSED" - }, - { - "name": "**Step 7:** Update defect type <br />**Expected Result:** Value(s) are in the fields", - "status": "PASSED" - }, - { - "name": "**Step 8:** Click 'Save'<br />**Expected Result:** Updates are saved for the last launch and all chosen items", - "status": "FAILED" - } - ] - } - ] - }, - { - "type": "DEFAULT", - "name": "Filtering Launch Tests", - "status": "FAILED", - "hasBefore": true, - "tests": [ - { - "name": "FilteringLaunchGtePassedTest", - "status": "PASSED", - "hasBefore": true, - "steps": [ - { - "name": "testFilterLaunchGreaterThanEqualsNegativeValue", - "status": "PASSED", - "hasBefore": true - }, - { - "name": "testFilterLaunchGreaterThanEqualsNotNumber", - "status": "PASSED", - "hasAfter": true - }, - { - "name": "testFilterLaunchGreaterThanEqualsPositive", - "status": "PASSED" - }, - { - "name": "testFilterLaunchGreaterThanEqualsZero", - "status": "PASSED" - }, - { - "name": "testFilterLaunchLowerThanEqualsNegativeValue", - "status": "PASSED" - } - ] - }, - { - "name": "FilteringLaunchInTagsTest", - "status": "FAILED", - "hasAfter": true, - "steps": [ - { - "name": "testFilterPositive", - "status": "FAILED", - "hasBefore": true, - "issue": "SYSTEM_ISSUE" - }, - { - "name": "testFilterNegative", - "status": "FAILED", - "hasAfter": true, - "issue": "SYSTEM_ISSUE" - }, - { - "name": "testFilterSpecialSymbols", - "status": "FAILED", - "issue": "SYSTEM_ISSUE" - } - ] - } - ] - }, - { - "type": "DEFAULT", - "name": "Launch Tests", - "status": "FAILED", - "hasBefore": true, - "tests": [ - { - "name": "LaunchStatusTest", - "status": "FAILED", - "hasBefore": true, - "steps": [ - { - "name": "launchMixedItemsStatusText", - "status": "SKIPPED", - "issue": "PRODUCT_BUG", - "hasBefore": true - }, - { - "name": "launchStatusTest", - "status": "FAILED", - "hasAfter": true, - "issue": "AUTOMATION_BUG" - }, - { - "name": "testLaunchStatusAfterDeletingTest", - "status": "FAILED", - "issue": "AUTOMATION_BUG" - }, - { - "name": "testMixedItemsStatusAfterDeletingStep", - "status": "FAILED", - "issue": "AUTOMATION_BUG" - }, - { - "name": "mixedItemStatus", - "status": "FAILED", - "issue": "AUTOMATION_BUG" - } - ] - } - ] - } - ] - } \ No newline at end of file +{ + "suites": [ + { + "type": "RETRY", + "name": "Suite with retries", + "status": "FAILED", + "tests": [ + { + "name": "First test case", + "status": "FAILED", + "steps": [ + { + "name": "first test", + "status": "FAILED", + "issue": "SYSTEM_ISSUE" + } + ] + } + ] + }, + { + "type": "NESTED", + "name": "Suite with nested steps", + "status": "FAILED", + "tests": [ + { + "name": "History table. Extended functionality. Permissions. Edit defect", + "status": "FAILED", + "issue": "AUTOMATION_BUG", + "steps": [ + { + "name": "Launch was executed 11 times", + "status": "PASSED" + }, + { + "name": "**Step 1:** Login to https://localhost:8080/ with password *** <br />**Expected Result:** User is in RP", + "status": "PASSED" + }, + { + "name": "**Step 2:** Open 'All launches' <br />**Expected Result:** All launches page is presented", + "status": "PASSED" + }, + { + "name": "**Step 3:** Click on Total statistics <br />**Expected Result:** Launch list view is displayed, refines contains criteria **Method type: Test**; **Status: Passed, Failed, Skipped, Interrupted**", + "status": "PASSED" + }, + { + "name": "**Step 4:** Click on 'History view' icon <br />**Expected Result:** 10 latest executions for the first 20 items (from the latest executions to the eldest) displayed by default**", + "status": "PASSED" + }, + { + "name": "**Step 5:** Check several items **(own and not own)** <br />**Expected Result:** Items are added to the header", + "status": "PASSED" + }, + { + "name": "**Step 6:** Click 'Actions'> 'Edit Defects' <br />**Expected Result:** Edit modal for bulk operation is opened", + "status": "PASSED" + }, + { + "name": "**Step 7:** Update defect type <br />**Expected Result:** Value(s) are in the fields", + "status": "PASSED" + }, + { + "name": "**Step 8:** Click 'Save'<br />**Expected Result:** Updates are saved for the last launch and all chosen items", + "status": "FAILED" + } + ] + } + ] + }, + { + "type": "DEFAULT", + "name": "Filtering Launch Tests", + "status": "FAILED", + "hasBefore": true, + "tests": [ + { + "name": "FilteringLaunchGtePassedTest", + "status": "PASSED", + "hasBefore": true, + "steps": [ + { + "name": "testFilterLaunchGreaterThanEqualsNegativeValue", + "status": "PASSED", + "hasBefore": true + }, + { + "name": "testFilterLaunchGreaterThanEqualsNotNumber", + "status": "PASSED", + "hasAfter": true + }, + { + "name": "testFilterLaunchGreaterThanEqualsPositive", + "status": "PASSED" + }, + { + "name": "testFilterLaunchGreaterThanEqualsZero", + "status": "PASSED" + }, + { + "name": "testFilterLaunchLowerThanEqualsNegativeValue", + "status": "PASSED" + } + ] + }, + { + "name": "FilteringLaunchInTagsTest", + "status": "FAILED", + "hasAfter": true, + "steps": [ + { + "name": "testFilterPositive", + "status": "FAILED", + "hasBefore": true, + "issue": "SYSTEM_ISSUE" + }, + { + "name": "testFilterNegative", + "status": "FAILED", + "hasAfter": true, + "issue": "SYSTEM_ISSUE" + }, + { + "name": "testFilterSpecialSymbols", + "status": "FAILED", + "issue": "SYSTEM_ISSUE" + } + ] + } + ] + }, + { + "type": "DEFAULT", + "name": "Launch Tests", + "status": "FAILED", + "hasBefore": true, + "tests": [ + { + "name": "LaunchStatusTest", + "status": "FAILED", + "hasBefore": true, + "steps": [ + { + "name": "launchMixedItemsStatusText", + "status": "SKIPPED", + "issue": "PRODUCT_BUG", + "hasBefore": true + }, + { + "name": "launchStatusTest", + "status": "FAILED", + "hasAfter": true, + "issue": "AUTOMATION_BUG" + }, + { + "name": "testLaunchStatusAfterDeletingTest", + "status": "FAILED", + "issue": "AUTOMATION_BUG" + }, + { + "name": "testMixedItemsStatusAfterDeletingStep", + "status": "FAILED", + "issue": "AUTOMATION_BUG" + }, + { + "name": "mixedItemStatus", + "status": "FAILED", + "issue": "AUTOMATION_BUG" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/templates/email/change-password-template.ftl b/src/main/resources/templates/email/change-password-template.ftl index 84d95445df..a0140181e8 100644 --- a/src/main/resources/templates/email/change-password-template.ftl +++ b/src/main/resources/templates/email/change-password-template.ftl @@ -1,146 +1,171 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } + .rplogo { + margin-left: 15px; + } - table[class="mainimgwrapper"] { - height: 130px; - background-image: url("illustration.png"); - background-size: cover; - background-position: center; - } + table[class="mainimgwrapper"] { + height: 130px; + background-image: url("images/illustration.png"); + background-size: cover; + background-position: center; + } - .mainimg { - display: none; - } - } - </style> + .mainimg { + display: none; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" vlink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> + <tbody> + <tr> + <td height="130"> + <img class="mainimg" src="cid:illustration.png" border="0" width="540" height="130" + alt="Your password has been changed"> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <h2 align="center" style="font-size: 20px; color: #777777;">Your password has been + changed</h2> + <p style="font-size: 14px; color: #777777">The password for user + <b>${user_name}</b> has been successfully changed.</p> + <p style="font-size: 14px; color: #777777">If you didn’t change your password, + please <a href="mailto:support@reportportal.io?subject=A change password issue">Contact + us</a>.</p> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td> + <a href="https://slack.epmrpp.reportportal.io" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> - <tbody> - <tr> - <td height="130"> - <img class="mainimg" src="cid:illustration.png" border="0" width="540" height="130" - alt="Your password has been changed"> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <h2 align="center" style="font-size: 20px; color: #777777;">Your password has been changed</h2> - <p style="font-size: 14px; color: #777777">The password for user - <b>${user_name}</b> has been successfully changed.</p> - <p style="font-size: 14px; color: #777777">If you didn’t change your password, - please <a href="mailto:support@reportportal.io?subject=A change password issue">Contact us</a>.</p> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" border="0" - width="20" height="21" alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img src="cid:ic-twitter.png" border="0" - width="20" height="16" alt="twitter"></a> - </td> - <td><a href="https://www.youtube.com/c/ReportPortal" target="_blank"><img src="cid:ic-youtube.png" - border="0" width="20" - height="15" alt="youtube"></a> - </td> - <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a></td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="52" class="footercontent"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"><b>ReportPortal Notification Center</b><br> - This notification was created automatically. Please don't reply to this e-mail.</p> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="52" class="footercontent"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"><b>ReportPortal + Notification Center</b><br> + This notification was created automatically. Please don't reply to this e-mail.</p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/email/create-user-template.ftl b/src/main/resources/templates/email/create-user-template.ftl index 62d3356e4e..36e7199fd8 100644 --- a/src/main/resources/templates/email/create-user-template.ftl +++ b/src/main/resources/templates/email/create-user-template.ftl @@ -1,167 +1,195 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } + .rplogo { + margin-left: 15px; + } - table[class="mainimgwrapper"] { - height: 130px; - background-image: url("create-user.png"); - background-size: cover; - background-position: center; - } + table[class="mainimgwrapper"] { + height: 130px; + background-image: url("images/create-user.png"); + background-size: cover; + background-position: center; + } - .mainimg { - display: none; - } - } - </style> + .mainimg { + display: none; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" vlink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> + <tbody> + <tr> + <td height="130"> + <img class="mainimg" src="cid:create-user.png" border="0" width="540" height="130" + alt="You have been successfully registered on ReportPortal"> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <h2 style="font-size: 20px; color: #777777;" align="center">Welcome to + ReportPortal!</h2> + <p style="font-size: 14px; color: #777777;">You have been successfully registered on + ReportPortal.</p> + <p style="font-size: 14px; line-height: 1.7; color: #777777">Please, use the following + information to login:<br> + Login: <b>${login}</b><br> + Password: <b>${password}</b></p> + <table border="0" cellspacing="8" cellpadding="0" align="center"> + <tbody> + <tr> + <td width="130" height="35" align="center" bgcolor="#a3c644"> + <a href="${url}" + style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 100px;"> + Login + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> - <tbody> - <tr> - <td height="130"> - <img class="mainimg" src="cid:create-user.png" border="0" width="540" height="130" - alt="You have been successfully registered on ReportPortal"> - </td> - </tr> - </tbody> + <p style="font-size: 14px; color: #777777;">New to ReportPortal? Check out the <a + href="https://reportportal.io/docs/reportportal-tutorial/?utm_source=trigger&utm_medium=email&utm_campaign=tutorial&utm_content=invitation" + target="_blank">ReportPortal Tutorial</a>.</p> + <br> + <p style="font-size: 14px; line-height: 1.7; color: #777777;">Thanks,<br> + ReportPortal.io Team</p> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td> + <a href="https://slack.epmrpp.reportportal.io" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <h2 style="font-size: 20px; color: #777777;" align="center">Welcome to ReportPortal!</h2> - <p style="font-size: 14px; color: #777777;">You have been successfully registered on ReportPortal.</p> - <p style="font-size: 14px; line-height: 1.7; color: #777777">Please, use the following information to login:<br> - Login: <b>${login}</b><br> - Password: <b>${password}</b></p> - <table border="0" cellspacing="8" cellpadding="0" align="center"> - <tbody> - <tr> - <td width="130" height="35" align="center" bgcolor="#a3c644"> - <a href="${url}" - style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 100px;"> - Login - </a> - </td> - </tr> - </tbody> - </table> - <p style="font-size: 14px; color: #777777;">New to ReportPortal? Check out the <a - href="https://reportportal.io/docs/reportportal-tutorial/?utm_source=trigger&utm_medium=email&utm_campaign=tutorial&utm_content=invitation" target="_blank">ReportPortal Tutorial</a>.</p> - <br> - <p style="font-size: 14px; line-height: 1.7; color: #777777;">Thanks,<br> - ReportPortal.io Team</p> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" border="0" - width="20" height="21" alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img src="cid:ic-twitter.png" border="0" - width="20" height="16" alt="twitter"></a> - </td> - <td><a href="https://www.youtube.com/c/ReportPortal" target="_blank"><img src="cid:ic-youtube.png" - border="0" width="20" - height="15" alt="youtube"></a> - </td> - <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a></td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="85" class="footercontent" style="padding: 4px;"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> - <b>ReportPortal Notification Center</b><br> - This is an automatically generated notification - please do not reply to this message. You are receiving this - email to complete the registration initiated on the ReportPortal application; if you are not waiting - for the ReportPortal's invitation then just ignore this message. - </p> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="85" class="footercontent" style="padding: 4px;"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> + <b>ReportPortal Notification Center</b><br> + This is an automatically generated notification - please do not reply to this message. + You are receiving this + email to complete the registration initiated on the ReportPortal application; if you + are not waiting + for the ReportPortal's invitation then just ignore this message. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/email/delete-account-notification-template.ftl b/src/main/resources/templates/email/delete-account-notification-template.ftl index 1f6f33f36d..a156437854 100644 --- a/src/main/resources/templates/email/delete-account-notification-template.ftl +++ b/src/main/resources/templates/email/delete-account-notification-template.ftl @@ -1,75 +1,81 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <!-- [if mso ]> - <xml - ><o:OfficeDocumentSettings - ><o:PixelsPerInch>96</o:PixelsPerInch - ><o:AllowPNG /></o:OfficeDocumentSettings - ></xml> - <![endif] --> - <link +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <!-- [if mso ]> + <xml + > + <o:OfficeDocumentSettings + > + <o:PixelsPerInch>96 + </o:PixelsPerInch + > + <o:AllowPNG/> + </o:OfficeDocumentSettings + > + </xml> + <![endif] --> + <link href="http://fonts.googleapis.com/css?family=Roboto:wght@100;400;500;&display=swap" rel="stylesheet" type="text/css" - /> - <style> - .heading { - font-family: Arial, Helvetica, sans-serif; - margin-top: 0; - margin-bottom: 0; - color: #454a4f; - font-size: 36px; - font-style: normal; - font-weight: 700; - line-height: 48px; - text-align: left; - } + /> + <style> + .heading { + font-family: Arial, Helvetica, sans-serif; + margin-top: 0; + margin-bottom: 0; + color: #454a4f; + font-size: 36px; + font-style: normal; + font-weight: 700; + line-height: 48px; + text-align: left; + } - .main-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - font-family: Arial, Helvetica, sans-serif; - color: #545454; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 22px; - } + .main-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + font-family: Arial, Helvetica, sans-serif; + color: #545454; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } - .footer-content-heading { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 13px; - font-style: normal; - font-weight: 500; - line-height: 20px; - } + .footer-content-heading { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 13px; + font-style: normal; + font-weight: 500; + line-height: 20px; + } - .footer-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 11px; - font-style: normal; - font-weight: 400; - line-height: 16px; - } - </style> + .footer-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 11px; + font-style: normal; + font-weight: 400; + line-height: 16px; + } + </style> - <title>Report Portal</title> - </head> - <body + <title>Report Portal</title> +</head> +<body style=" font-family: Arial, Helvetica, sans-serif; margin-top: 0; @@ -81,217 +87,219 @@ padding-top: 0; padding-bottom: 0px; " +> +<center> + <table + width="630" + border="0" + cellspacing="0" + cellpadding="0" + align="center" > - <center> - <table - width="630" - border="0" - cellspacing="0" - cellpadding="0" - align="center" - > - <tbody> + <tbody> + <tr> + <td> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> <tr> - <td> - <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tbody> - <tr> - <td align="center" style="padding-top: 48px"> - <a - href="http://reportportal.io" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-logo.png" alt="Report Portal logo" - /></a> - </td> - </tr> - <tr> - <td - align="center" - style=" + <td align="center" style="padding-top: 48px"> + <a + href="http://reportportal.io" + target="_blank" + rel="noopener noreferrer" + ><img src="cid:new-logo.png" alt="Report Portal logo" + /></a> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-top: 37px; padding-bottom: 38px; background-color: rgb(244, 251, 251); border-spacing: 0; " - > - <img - src="cid:delete-account-notification.png" - alt="Calendar" - /> - </td> - </tr> - </tbody> - </table> + > + <img + src="cid:delete-account-notification.png" + alt="Calendar" + /> </td> </tr> - <tr> - <td - align="center" - style=" + </tbody> + </table> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-left: 50px; padding-right: 50px; padding-bottom: 40px; padding-top: 32px; background-color: #ffffff; " - > - <table width="100%" border="0" cellspacing="0" cellpadding="0"> - <thead> - <th> - <h1 class="heading"> - Your account will be <br /> - deleted soon - </h1> - </th> - </thead> - <tbody> - <tr> - <td style="padding-bottom: 12px; padding-top: 24px"> - <p class="main-content"> - We are writing to inform you that according to our data - retention procedure your account and all your personal - data (your account name, email and photo) will be - deleted from ReportPortal database - <b>${remainingTime}</b>. As it has already been inactive - for ${inactivityPeriod}. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - If you would like to keep your account, please log in to - our platform ${deadlineDate} and your - account will not be deleted. If you do not log in before - this date, your account and all associated data will be - erased from our platform, while all the previously - reported and created in ReportPortal data (launches, - filters, widgets, dashboards, etc.) will remain in the - app. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - If you have any questions or concerns about this - process, please contact our support team for assistance. - </p> - </td> - </tr> - <tr> - <td> - <p class="main-content"> - <br>Kind regards,<br>ReportPortal team - </p> - </td> - </tr> - </tbody> - </table> + > + <table width="100%" border="0" cellspacing="0" cellpadding="0"> + <thead> + <th> + <h1 class="heading"> + Your account will be <br/> + deleted soon + </h1> + </th> + </thead> + <tbody> + <tr> + <td style="padding-bottom: 12px; padding-top: 24px"> + <p class="main-content"> + We are writing to inform you that according to our data + retention procedure your account and all your personal + data (your account name, email and photo) will be + deleted from ReportPortal database + <b>${remainingTime}</b>. As it has already been inactive + for ${inactivityPeriod}. + </p> </td> </tr> <tr> - <td align="center"> + <td style="padding-bottom: 12px"> + <p class="main-content"> + If you would like to keep your account, please log in to + our platform ${deadlineDate} and your + account will not be deleted. If you do not log in before + this date, your account and all associated data will be + erased from our platform, while all the previously + reported and created in ReportPortal data (launches, + filters, widgets, dashboards, etc.) will remain in the + app. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + If you have any questions or concerns about this + process, please contact our support team for assistance. + </p> + </td> + </tr> + <tr> + <td> + <p class="main-content"> + <br>Kind regards,<br>ReportPortal team + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td align="center"> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> + <tr> + <td align="center" + style="padding-top: 32px; + padding-bottom: 24px"> <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" > - <tbody> - <tr> - <td - align="center" - style="padding-top: 32px; padding-bottom: 24px" + <tr> + <td style="padding-right: 22px"> + <a href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-twitter.png" + alt="Twitter icon" + /> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://slack.epmrpp.reportportal.io/" + target="_blank" + rel="noopener noreferrer" + > + <img src="cid:new-ic-slack.png" + alt="Slack icon"/> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.youtube.com/c/ReportPortal" + target="_blank" + rel="noopener noreferrer" > - <table - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tr> - <td style="padding-right: 22px"> - <a - href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-twitter.png" - alt="Twitter icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://slack.epmrpp.reportportal.io/" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-ic-slack.png" alt="Slack icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://www.youtube.com/c/ReportPortal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-youtube.png" - alt="YouTube icon" - /></a> - </td> - <td style="padding-right: 10px"> - <a - href="https://www.linkedin.com/company/reportportal/" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-linkedin.png" - alt="Linkedin icon" - /></a> - </td> - <td> - <a - href="https://github.com/reportportal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-github.png" - alt="Github icon" - /></a> - </td> - </tr> - </table> - </td> - </tr> - <tr> - <td align="center"> - <h4 class="footer-content-heading"> - ReportPortal Notification Center - </h4> - </td> - </tr> - <tr> - <td align="center" style="padding-bottom: 32px"> - <p class="footer-content"> - This notification was created automatically. Please - don't reply to this e-mail. - </p> - </td> - </tr> - </tbody> + <img src="cid:new-ic-youtube.png" + alt="YouTube icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.linkedin.com/company/reportportal/" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-linkedin.png" + alt="Linkedin icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.facebook.com/ReportPortal.io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-facebook.png" + alt="Facebook icon"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-github.png" + alt="Github icon"> + </a> + </td> + </tr> </table> </td> </tr> - </tbody> - </table> - </center> - </body> + <tr> + <td align="center"> + <h4 class="footer-content-heading"> + ReportPortal Notification Center + </h4> + </td> + </tr> + <tr> + <td align="center" style="padding-bottom: 32px"> + <p class="footer-content"> + This notification was created automatically. Please + don't reply to this e-mail. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> +</center> +</body> </html> diff --git a/src/main/resources/templates/email/delete-account-template.ftl b/src/main/resources/templates/email/delete-account-template.ftl index 0a9e8308e7..efeadaf7dd 100644 --- a/src/main/resources/templates/email/delete-account-template.ftl +++ b/src/main/resources/templates/email/delete-account-template.ftl @@ -1,73 +1,80 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <link +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <link href="http://fonts.googleapis.com/css?family=Roboto:wght@100;400;500;&display=swap" rel="stylesheet" type="text/css" - /> - <!--[if mso - ]><xml - ><o:OfficeDocumentSettings - ><o:PixelsPerInch>96</o:PixelsPerInch - ><o:AllowPNG /></o:OfficeDocumentSettings></xml - ><![endif]--> - <style> - .heading { - font-family: Arial, Helvetica, sans-serif; - margin-top: 0; - margin-bottom: 0; - color: #454a4f; - font-size: 36px; - font-style: normal; - font-weight: 700; - line-height: 48px; - } + /> + <!--[if mso + ]> + <xml + > + <o:OfficeDocumentSettings + > + <o:PixelsPerInch>96 + </o:PixelsPerInch + > + <o:AllowPNG/> + </o:OfficeDocumentSettings> + </xml + ><![endif]--> + <style> + .heading { + font-family: Arial, Helvetica, sans-serif; + margin-top: 0; + margin-bottom: 0; + color: #454a4f; + font-size: 36px; + font-style: normal; + font-weight: 700; + line-height: 48px; + } - .main-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - font-family: Arial, Helvetica, sans-serif; - color: #545454; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 22px; - } + .main-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + font-family: Arial, Helvetica, sans-serif; + color: #545454; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } - .footer-content-heading { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 13px; - font-style: normal; - font-weight: 500; - line-height: 20px; - } + .footer-content-heading { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 13px; + font-style: normal; + font-weight: 500; + line-height: 20px; + } - .footer-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 11px; - font-style: normal; - font-weight: 400; - line-height: 16px; - } - </style> + .footer-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 11px; + font-style: normal; + font-weight: 400; + line-height: 16px; + } + </style> - <title>Report Portal</title> - </head> - <body + <title>Report Portal</title> +</head> +<body style=" font-family: Arial, Helvetica, sans-serif; margin-top: 0; @@ -79,212 +86,213 @@ padding-top: 0; padding-bottom: 0px; " +> +<center> + <table + width="630" + border="0" + cellspacing="0" + cellpadding="0" + align="center" > - <center> - <table - width="630" - border="0" - cellspacing="0" - cellpadding="0" - align="center" - > - <tbody> + <tbody> + <tr> + <td> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> <tr> - <td> - <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tbody> - <tr> - <td align="center" style="padding-top: 48px"> - <a - href="http://reportportal.io" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-logo.png" alt="Report Portal logo" - /></a> - </td> - </tr> - <tr> - <td - align="center" - style=" + <td align="center" style="padding-top: 48px"> + <a + href="http://reportportal.io" + target="_blank" + rel="noopener noreferrer" + ><img src="cid:new-logo.png" alt="Report Portal logo" + /></a> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-top: 37px; padding-bottom: 38px; background-color: rgb(244, 251, 251); border-spacing: 0; " - > - <img - src="cid:deleted-account.png" - alt="Deleted account img" - /> - </td> - </tr> - </tbody> - </table> + > + <img + src="cid:deleted-account.png" + alt="Deleted account img" + /> </td> </tr> - <tr> - <td - align="center" - style=" + </tbody> + </table> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-left: 50px; padding-right: 50px; padding-bottom: 40px; padding-top: 38px; background-color: #ffffff; " - > - <table width="100%" border="0" cellspacing="0" cellpadding="0"> - <thead> - <th> - <h1 class="heading">Your account has been deleted</h1> - </th> - </thead> - <tbody> - <tr> - <td style="padding-bottom: 12px; padding-top: 24px"> - <p class="main-content"> - We regret to inform you that your account has been - deleted. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - Please note that all the associated personal data has - been deleted from our database in a safe and secure - manner. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - If you have any questions or concerns about this - process, please contact our support team for assistance. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - Thank you for using ReportPortal. - </p> - </td> - </tr> - <tr> - <td> - <p class="main-content"> - <br>Kind regards,<br>ReportPortal team - </p> - </td> - </tr> - </tbody> - </table> + > + <table width="100%" border="0" cellspacing="0" cellpadding="0"> + <thead> + <th> + <h1 class="heading">Your account has been deleted</h1> + </th> + </thead> + <tbody> + <tr> + <td style="padding-bottom: 12px; padding-top: 24px"> + <p class="main-content"> + We regret to inform you that your account has been + deleted. + </p> </td> </tr> <tr> - <td align="center"> + <td style="padding-bottom: 12px"> + <p class="main-content"> + Please note that all the associated personal data has + been deleted from our database in a safe and secure + manner. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + If you have any questions or concerns about this + process, please contact our support team for assistance. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + Thank you for using ReportPortal. + </p> + </td> + </tr> + <tr> + <td> + <p class="main-content"> + <br>Kind regards,<br>ReportPortal team + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td align="center"> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> + <tr> + <td + align="center" + style="padding-top: 32px; padding-bottom: 24px" + > <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" > - <tbody> - <tr> - <td - align="center" - style="padding-top: 32px; padding-bottom: 24px" - > - <table - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tr> - <td style="padding-right: 22px"> - <a - href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-twitter.png" - alt="Twitter icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://slack.epmrpp.reportportal.io/" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-ic-slack.png" alt="Slack icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://www.youtube.com/c/ReportPortal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-youtube.png" - alt="YouTube icon" - /></a> - </td> - <td style="padding-right: 10px"> - <a - href="https://www.linkedin.com/company/reportportal/" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-linkedin.png" - alt="Linkedin icon" - /></a> - </td> - <td> - <a - href="https://github.com/reportportal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-github.png" - alt="Github icon" - /></a> - </td> - </tr> - </table> - </td> - </tr> - <tr> - <td align="center"> - <h4 class="footer-content-heading"> - ReportPortal Notification Center - </h4> - </td> - </tr> - <tr> - <td align="center" style="padding-bottom: 32px"> - <p class="footer-content"> - This notification was created automatically. Please - don't reply to this e-mail. - </p> - </td> - </tr> - </tbody> + <tr> + <td style="padding-right: 22px"> + <a + href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-twitter.png" + alt="Twitter icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://slack.epmrpp.reportportal.io/" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-slack.png" + alt="Slack icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.youtube.com/c/ReportPortal" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-youtube.png" + alt="YouTube icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.linkedin.com/company/reportportal/" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-linkedin.png" + alt="Linkedin icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.facebook.com/ReportPortal.io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-facebook.png" + alt="Facebook icon"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-github.png" + alt="Github icon"> + </a> + </td> + </tr> </table> </td> </tr> - </tbody> - </table> - </center> - </body> + <tr> + <td align="center"> + <h4 class="footer-content-heading"> + ReportPortal Notification Center + </h4> + </td> + </tr> + <tr> + <td align="center" style="padding-bottom: 32px"> + <p class="footer-content"> + This notification was created automatically. Please + don't reply to this e-mail. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> +</center> +</body> </html> diff --git a/src/main/resources/templates/email/email-connection.ftl b/src/main/resources/templates/email/email-connection.ftl index da90d0c4b4..9290534e47 100644 --- a/src/main/resources/templates/email/email-connection.ftl +++ b/src/main/resources/templates/email/email-connection.ftl @@ -1,134 +1,156 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } + .rplogo { + margin-left: 15px; + } - table[class="mainimgwrapper"] { - height: 130px; - background-size: cover; - background-position: center; - } + table[class="mainimgwrapper"] { + height: 130px; + background-size: cover; + background-position: center; + } - .mainimg { - display: none; - } - } - </style> + .mainimg { + display: none; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" vlink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <h2 style="font-size: 20px; color: #777777;" align="center">Email server integration has + been successfully + created</h2> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <h2 style="font-size: 20px; color: #777777;" align="center">Email server integration has been successfully - created</h2> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" border="0" - width="20" height="21" alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img src="cid:ic-twitter.png" border="0" - width="20" height="16" alt="twitter"></a> - </td> - <td><a href="https://www.youtube.com/c/ReportPortal" target="_blank"><img src="cid:ic-youtube.png" - border="0" width="20" - height="15" alt="youtube"></a> - </td> - <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a></td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="85" class="footercontent" style="padding: 4px;"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> - <b>ReportPortal Notification Center</b><br> - This notification was created automatically. Please don't reply to this e-mail. - </p> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="85" class="footercontent" style="padding: 4px;"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> + <b>ReportPortal Notification Center</b><br> + This notification was created automatically. Please don't reply to this e-mail. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/email/finish-launch-template.ftl b/src/main/resources/templates/email/finish-launch-template.ftl index 47d79ab982..bb63fcde32 100644 --- a/src/main/resources/templates/email/finish-launch-template.ftl +++ b/src/main/resources/templates/email/finish-launch-template.ftl @@ -1,264 +1,306 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - font-family: OpenSans, sans-serif; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + font-family: OpenSans, sans-serif; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } - } - </style> + .rplogo { + margin-left: 15px; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <table class="content" width="100%" border="0" cellspacing="0" cellpadding="0" style="border-collapse:collapse;"> - <#assign rowCounter = 1> - <#macro subtypes sbt> - <#list sbt as key,value> - <#if rowCounter % 2 == 0> - <tr bgcolor="#ffffff" style="background-color:#ffffff;"> - <#else> - <tr bgcolor="#f9f9f9" style="background-color:#f9f9f9;"> - </#if> - <td height="25" - style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;">${key}</td> - <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;">${value}</td> - </tr> - <#assign rowCounter++> - + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <table class="content" width="100%" border="0" cellspacing="0" cellpadding="0" + style="border-collapse:collapse;"> + <#assign rowCounter = 1> + <#macro subtypes sbt> + <#list sbt as key,value> + <#if rowCounter % 2 == 0> + <tr bgcolor="#ffffff" style="background-color:#ffffff;"> + <#else> + <tr bgcolor="#f9f9f9" style="background-color:#f9f9f9;"> + </#if> + <td height="25" + style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;">${key}</td> + <td width="40" + style="font-size: 14px; color: #464547; border-width: 0px;">${value}</td> + </tr> + <#assign rowCounter++> - </#list> - </#macro> - <#macro maintype name counter> - <#if rowCounter % 2 == 0> - <tr bg="#ffffff" style="background-color:#ffffff;"> - <#else> - <tr bgcolor="#f9f9f9" style="background-color:#f9f9f9;"> - </#if> - <td height="40" style="font-size: 14px; color: #464547; padding-left: 20px; border-width: 0px;"><b>${name}</b> - </td> - <td style="font-size: 14px; color: #464547; border-width: 0px;"><b>${counter}</b></td> - </tr> - <#assign rowCounter++> + </#list> + </#macro> - </#macro> - </table> - <!-- Launch name and link to ReportPortal instance --> - <h2 style="font-size: 20px; color: #777777;" align="center">Launch "${name}" #${number} has been - finished</h2> - <p style="font-size: 14px; color: #777777;">To view it on ReportPortal just visit this <a - href="${url}" target="_blank">link</a>.</p> - <#if attributes??> - <p style="font-size: 14px; color: #777777;">Attributes to launch: - <#list attributes as name, link> - <a href="${link}" target="_blank" style="padding-left:5px;">${name}</a> - </#list> - </p> + <#macro maintype name counter> + <#if rowCounter % 2 == 0> + <tr bg="#ffffff" style="background-color:#ffffff;"> + <#else> + <tr bgcolor="#f9f9f9" style="background-color:#f9f9f9;"> </#if> - <!-- Launch name, link and description (if exists) --> - <#if description??> - <p style="font-size: 14px; color: #777777;">Description of launch:<br>${description}</p> + <td height="40" + style="font-size: 14px; color: #464547; padding-left: 20px; border-width: 0px;"> + <b>${name}</b> + </td> + <td style="font-size: 14px; color: #464547; border-width: 0px;"><b>${counter}</b> + </td> + </tr> + <#assign rowCounter++> + + </#macro> + </table> + <!-- Launch name and link to ReportPortal instance --> + <h2 style="font-size: 20px; color: #777777;" align="center">Launch "${name}" #${number} + has been + finished</h2> + <p style="font-size: 14px; color: #777777;">To view it on ReportPortal just visit this + <a + href="${url}" target="_blank">link</a>.</p> + <#if attributes??> + <p style="font-size: 14px; color: #777777;">Attributes to launch: + <#list attributes as name, link> + <a href="${link}" target="_blank" style="padding-left:5px;">${name}</a> + </#list> + </p> + </#if> + <!-- Launch name, link and description (if exists) --> + <#if description??> + <p style="font-size: 14px; color: #777777;">Description of launch:<br>${description} + </p> + </#if> + <table width="300" cellspacing="0" cellpadding="0" style="border: 1px solid #e9e9e9;"> + <tr> + <td> + <table width="300" border="0" cellspacing="0" cellpadding="6" + style="border: none; border-collapse: collapse;"> + <tbody> + <tr bgcolor="#f5f5f5" style="background: #f5f5f5;"> + <td height="40" + style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9; padding-left: 20px;"> + <b>LAUNCH STATISTICS</b></td> + <td width="40" + style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9;"></td> + </tr> + <tr bgcolor="#ffffff" style="background: #ffffff;"> + <td height="40" + style="font-size: 14px; color: #464547; padding-left: 20px; border-width: 0px;"> + <b>TOTAL</b> + </td> + <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;"> + <b>${total}</b></td> + </tr> + <tr bgcolor="#f9f9f9" style="background: #f9f9f9;"> + <td height="25" + style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;"> + Passed + </td> + <td width="40" + style="font-size: 14px; color: #464547; border-width: 0px;">${passed}</td> + </tr> + <tr bgcolor="#ffffff" style="background: #ffffff;"> + <td height="25" + style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;"> + Failed + </td> + <td width="40" + style="font-size: 14px; color: #464547; border-width: 0px;">${failed}</td> + </tr> + <tr bgcolor="#f9f9f9" style="background: #f9f9f9;"> + <td height="25" + style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;"> + Skipped + </td> + <td width="40" + style="font-size: 14px; color: #464547; border-width: 0px;">${skipped}</td> + </tr> + </tbody> + </table> + </td> + </tr> + </table> + <br> + <table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid #e9e9e9;"> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="6" + style="border: none; border-collapse: collapse;"> + <tbody> + <tr bgcolor="#f5f5f5" style="background: #f5f5f5;"> + <td height="40" + style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9; padding-left: 20px;"> + <b>LAUNCH DEFECTS</b></td> + <td width="40" + style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9;"></td> + </tr> + <!-- PRODUCT BUG bugs section --> + <#assign name="Product Bugs"> + <@maintype name="${name}" counter="${productBugTotal}" /> + <#if pbInfo??> + <@subtypes sbt=pbInfo/> </#if> - <table width="300" cellspacing="0" cellpadding="0" style="border: 1px solid #e9e9e9;"> - <tr> - <td> - <table width="300" border="0" cellspacing="0" cellpadding="6" style="border: none; border-collapse: collapse;"> - <tbody> - <tr bgcolor="#f5f5f5" style="background: #f5f5f5;"> - <td height="40" - style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9; padding-left: 20px;"> - <b>LAUNCH STATISTICS</b></td> - <td width="40" - style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9;"></td> - </tr> - <tr bgcolor="#ffffff" style="background: #ffffff;"> - <td height="40" style="font-size: 14px; color: #464547; padding-left: 20px; border-width: 0px;"> - <b>TOTAL</b> - </td> - <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;"><b>${total}</b></td> - </tr> - <tr bgcolor="#f9f9f9" style="background: #f9f9f9;"> - <td height="25" style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;">Passed - </td> - <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;">${passed}</td> - </tr> - <tr bgcolor="#ffffff" style="background: #ffffff;"> - <td height="25" style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;">Failed - </td> - <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;">${failed}</td> - </tr> - <tr bgcolor="#f9f9f9" style="background: #f9f9f9;"> - <td height="25" style="font-size: 14px; color: #464547; padding-left: 38px; border-width: 0px;"> - Skipped - </td> - <td width="40" style="font-size: 14px; color: #464547; border-width: 0px;">${skipped}</td> - </tr> - </tbody> - </table> - </td> - </tr> - </table> - <br> - <table width="100%" cellspacing="0" cellpadding="0" style="border: 1px solid #e9e9e9;"> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="6" style="border: none; border-collapse: collapse;"> - <tbody> - <tr bgcolor="#f5f5f5" style="background: #f5f5f5;"> - <td height="40" - style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9; padding-left: 20px;"> - <b>LAUNCH DEFECTS</b></td> - <td width="40" - style="font-size: 12px; color: #777777; border-bottom: 1px solid #e9e9e9;"></td> - </tr> - <!-- PRODUCT BUG bugs section --> - <#assign name="Product Bugs"> - <@maintype name="${name}" counter="${productBugTotal}" /> - <#if pbInfo??> - <@subtypes sbt=pbInfo/> - </#if> - <!-- AUTOMATION BUG bugs section --> - <#assign name="Automation Bugs"> - <@maintype name="${name}" counter="${automationBugTotal}" /> - <#if abInfo??> - <@subtypes sbt=abInfo/> - </#if> + <!-- AUTOMATION BUG bugs section --> + <#assign name="Automation Bugs"> + <@maintype name="${name}" counter="${automationBugTotal}" /> + <#if abInfo??> + <@subtypes sbt=abInfo/> + </#if> - <!-- SYSTEM ISSUE bugs section --> - <#assign name="System Issues"> - <@maintype name="${name}" counter="${systemIssueTotal}" /> - <#if siInfo??> - <@subtypes sbt=siInfo/> - </#if> + <!-- SYSTEM ISSUE bugs section --> + <#assign name="System Issues"> + <@maintype name="${name}" counter="${systemIssueTotal}" /> + <#if siInfo??> + <@subtypes sbt=siInfo/> + </#if> - <!-- NO DEFECT bugs section --> - <#assign name="No Defects"> - <@maintype name="${name}" counter="${noDefectTotal}" /> - <#if ndInfo??> - <@subtypes sbt=ndInfo/> - </#if> + <!-- NO DEFECT bugs section --> + <#assign name="No Defects"> + <@maintype name="${name}" counter="${noDefectTotal}" /> + <#if ndInfo??> + <@subtypes sbt=ndInfo/> + </#if> - <!-- TO INVESTIGATE bugs section --> - <#assign name="To Investigate"> - <@maintype name="${name}" counter="${toInvestigateTotal}" /> - <#if tiInfo??> - <@subtypes sbt=tiInfo/> - </#if> - </tbody> - </table> - </td> - </tr> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" - border="0" width="20" - height="21" - alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img - src="cid:ic-twitter.png" border="0" width="20" height="16" alt="twitter"></a></td> - <td><a href="https://www.youtube.com/c/ReportPortal" - target="_blank"><img src="cid:ic-youtube.png" border="0" width="20" height="15" - alt="youtube"></a></td> - <td><a href="https://slack.epmrpp.reportportal.io/" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> + <!-- TO INVESTIGATE bugs section --> + <#assign name="To Investigate"> + <@maintype name="${name}" counter="${toInvestigateTotal}" /> + <#if tiInfo??> + <@subtypes sbt=tiInfo/> + </#if> + </tbody> + </table> + </td> + </tr> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="52" class="footercontent"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"><b>ReportPortal Notification - Center</b><br> - This notification was created automatically. Please don't reply to this e-mail.</p> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td> + <a href="https://slack.epmrpp.reportportal.io/" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="52" class="footercontent"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"><b>ReportPortal + Notification + Center</b><br> + This notification was created automatically. Please don't reply to this e-mail.</p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/email/ic-github.png b/src/main/resources/templates/email/ic-github.png deleted file mode 100644 index b03969a75aaa5ed0ce2469f86e594c35834b4932..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 816 zcmV-01JC@4P)<h;3K|Lk000e1NJLTq000yK000#T1^@s6M%B)!00001b5ch_0Itp) z=>Px%>PbXFR5%fpR82@!Q4~JszURQiKp|1kWF#hyjYUC_<v5IiS_^{~E)0SQB3uTR zLD3&>ln825ND*yX=%$@Ukv7w41V(6?HW7gsxax-yotby<>D)KHH*frz>cV^XJKs6y zd*|JI?nPK-5D`Wb(@}}o1PHrHsm(eJg_s9|NrUKFyde}vL|UGX%ZY|~YL|sp7dyhs zeZ@9TA<CX)B>ch47YQCprkY9SZt#~)Z_rwp|HR_DuZ~4)o;oqEU?h=>DX?xjj{liW zffwTSp%*$w=vULL=`D(^YZ@cq7q0Lw!(ZB7a}f6HSnanITsb^C6V%uiTp;LRrGO@Y z@Le(zda%y#I}QqmIO37v_qW;)iEj2!2!vas(NHgc_^q7-6j+kfp|KeoPHoMSY+*rr z5GkJq&-YjT<ms|a7G6&n>c<|Wz~|)g?l;F?r|yZYA!C4KS87KI<c0pXK}gb#WR0wp zF~O}==aAe~*7`Ezj${9A4wjeS=9rutr{JLA9^T;)2qHaLS6zBDoM4^@!kf~(QfZeW zs1jWE2A2Tk!3DMyB0x7sYw_B7*9@tR$S5V?^{tFWOK=-}F9Z?Jjeg!<uuG%)H#6IG zpSe-2B@Cn~mterhz13@%!nq|l=JjhWfrMjTl9X)M$I#2Ih9ilOF+@1w^=U0^o1OK~ zeO(yj%2LWSdr-=A0O|nOI%JUXI1#Nb`h!?<sy0X1P6RDpF>dU1urhE|3{+Gsa+!U+ zL;HlXF8VCrB^I0DwK*ce>McrQBO|eMg&6ZfK%cFp6U_QhKU3p;9qrASnYvp4&a<Xz zoD3Lcr?uZZP{2m7oyTH4ukq({7(ukSvMzR}5U6`{>C=77g7b^gy1pV=i9#diohhBG zHMHrT;gQD5A3;l<VQvIT@og>lNTh{)PT@_UzBv}J`>@W@xeix!GY>R|_18P~4oZSk uye?TM(3$z_$|!>OocJ&it$FG2&iotoOdO<%($3NV0000<MNUMnLSTYu$%9}3 diff --git a/src/main/resources/templates/email/ic-slack.png b/src/main/resources/templates/email/ic-slack.png deleted file mode 100644 index e343de86155b2b04b8c5f1ad6cf9d7b19ee0d1a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 686 zcmV;f0#W^mP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00001b5ch_0Itp) z=>Px%Xh}ptR5%fRR8MPDK@gwWB=uhoeh0C>+=L1qlGNBHu}HyF#gkt^JXP^%1QA6& ziO_=|K=dR?C~2tmB@qO@c<{X>C&8n~B2@c!oZlw<cqz35Z)bL9_P4Y1=P?~YEB*Lf zV(FT?l!<9xNGub@Z1`oT9BgNgs(zLlVT?m-Byv@V&dyq=J7zIV_d1o}skf&<E4`?e z5Iqy21#di(D_EXnX|r0|fuF(B?8kTaiMJ02;a_xe?liG!!8aul#>IZm%|X0mEp_!N zljxZKs<5M=4e!)lEIC^}jD(p!67eY!xd1y8SGE>|fe|aWQV<v<-`J{_nwo<L9>{Y5 zs;wp_6CLuYWHh0HcLZnNzYN}~mRdOIqk#_8>_sg~lJ}FHu38kxdNI2^IRo=U062NN zEPozW>%Gw%uhWZbUIs^H(Ix;Hr-l=SG<nc1_u>uSvmr^ccIDIXCUiNX7PuzohvT}S z*Nj5;y@G!K`H6%!!to{Oj?EQb>01R~lJF{YC^w#4EFM3P{glckXXu^ZDKA3S!nVNM z7tefQYhI8|7P{5>>(F`H-Q8RFGP<6zX@t=TZ}kRL>|n0E4IBx#LibZ0)AvcDncJx{ zms>pug6HCM6;nr%{D;&Zf^amAC@$+jx?E|)y=FGwthJAP=>g&os%>4!KGxh8oDOqm zsO};{XDYx~2QG92Ads73blW+Tj>(in?DH8A46ptPTtx7}&|==QUG5Jb#&NN>!W}=f zDG;17yqd%({{vI!v9>~6BYKNhWG|Qja$q{dm_JQQ;JRLDr1}BcWU~?svxl?tKXH=v U|7RsVMF0Q*07*qoM6N<$f=T8&NdN!< diff --git a/src/main/resources/templates/email/ic-twitter.png b/src/main/resources/templates/email/ic-twitter.png deleted file mode 100644 index b0d3d1c094eae75d7ecaa818dd62ba8441cddc7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 593 zcmV-X0<QguP)<h;3K|Lk000e1NJLTq000yK000mO1^@s678qX}00001b5ch_0Itp) z=>Px%3rR#lR5%fpQ_o9OQ4~JszSrnR3R($?AdJ4LHW7u6PjTlW5Xy%B0f`p5h&Huq z)mGfpe-JGU-6^ih`AKbxN*Hl!Wfnw16f%x)?&-UCyu<i(WahxT=iKky^PPL{JBO(Y zNf#=YsUAHQlIu()L|jyg7yVu;?^pGFDNH@_Gn<n5_G|0e*?#Z-S~9ucj(<GAJ*xG= z2K)(g25e@Xt!sRHFqw>x)X$5gk#X+N_j=CWz@R6H=x6~fmh1#KAg+w%${F>BIRbkP zq}Nc+hjhODeDYmoARZ*lm*QCKo=J8}6TuRmf+(FWzXIWG^8mA{XoHEDnCTM=`K@*I zx#^D?Ac=~TsWS%l&64QrnXCP+_JZYx*^`J#G=(HnVjoLexZQ%=n^&}A32XnVUjd#2 zk;A*xvf~1jHH5Q=w{mz_8s+3&K!ecp9s>B`z;3l7UU4y&usELlqLhCVnch1`$C~+L zE*x2R=j|Js4gTUis4LFVsaDL7xzQCiq){@=3+IEoXpxtl5;e~8Vj&z^ZH+PQaYWFQ zw~6Hue)!cRj`)UYxhD+n*uiM=HE);^@y3c<0enMf!}cSF@=(dbbQomfWQLc`(2LYx zU`_|o$X-jbV<yTeDfS-ZCx+i1a~=Y=WQ>D<P}rUkt#4tjM?u_=;nT2pg?Lv9zxI5+ fl1-;DhNsJad-J#YtB}Z=00000NkvXXu0mjf5ilJ} diff --git a/src/main/resources/templates/email/ic-youtube.png b/src/main/resources/templates/email/ic-youtube.png deleted file mode 100644 index 2e92439291a3f9e6d1ada2917c6bb5444993e290..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 297 zcmV+^0oMMBP)<h;3K|Lk000e1NJLTq000yK000jN1^@s6<e2YO00001b5ch_0Itp) z=>Px#<4Ht8R5%f1v^sPnhJlfx_y7O@Vhj`jMn=Y0jEoFLj8=zlyrk4Hm^(m*GEvJg zkf9*6m|&(;iza9wFkI4sVf>3&3ke!{%vN(2BNK}QBLl;8Vhkl{Ajpto)~d&uxj2o1 zh8`zmC{YH23^{C~@LXD0!vPosv+x;8w1FT)p1->-1Ei$z8OVZ95+>(x|31gBC%?-7 z{r^|-pMik`CXS6}v^;bjs0I&UWcFob_%{)l#+2}=f=dy0;s3vz@!JSD3(O!X3{kaW v=P`luA9g9yMZtNQ;Xgw$H4Fur0V-_(>}5QQoiqvp00000NkvXXu0mjfxgK-s diff --git a/src/main/resources/templates/email/create-user.png b/src/main/resources/templates/email/images/create-user.png similarity index 100% rename from src/main/resources/templates/email/create-user.png rename to src/main/resources/templates/email/images/create-user.png diff --git a/src/main/resources/templates/email/delete-account-notification.png b/src/main/resources/templates/email/images/delete-account-notification.png similarity index 100% rename from src/main/resources/templates/email/delete-account-notification.png rename to src/main/resources/templates/email/images/delete-account-notification.png diff --git a/src/main/resources/templates/email/deleted-account.png b/src/main/resources/templates/email/images/deleted-account.png similarity index 100% rename from src/main/resources/templates/email/deleted-account.png rename to src/main/resources/templates/email/images/deleted-account.png diff --git a/src/main/resources/templates/email/images/ic-facebook.png b/src/main/resources/templates/email/images/ic-facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..de08b4da48f90e6b5be2cde1849438f61efddf95 GIT binary patch literal 896 zcmV-`1AqL9P)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3=F9Y71hX4Qpen~_@R5;7klrc<GQ51&1|2`aW zav@G8CdSl4nDr5gI5Lnpn3%A1aWln^E*KUEH99!DIOqTa3xg82zBbQ9Czd`KbZ{ah zY!X63-p^1Zgp}7dF$C{+@BPnz&pF@Cfy=(sQ(@~~vNacit2Q@*2-u4h9=0l_UuWf^ zm)}Hl>x1OaHrIq2LO+1<Ls9CcA1X9UHXj*3k^DTZjJ^W6+i2eo(&O`D3Jr~`hK+BN z<=1he{S>Jtbk!Ky?iSOdWZwe5BN^!puxtCP#oPQ!ln$IBXb7`^ycw3XoKD?&Ulh^R zFmANJAeDd{3MZx6_KP^lo&kTNkk7Uz$A0&hp)>=e;Pr^;W9LY9=N_X&_r8gS`~IA9 zl6j)JIe*UGyEw^qur){z|CU!1UPz}#mrk|ex?v5ef69{Tm=$0ox8hT6*am-+^Oplb zNh=+aagsea^U!iyDHl=>|9Uw5=Y|4HRO2N3d5k{qWmr5M#3DJ<9UvTpkgs0AMS W;Egm{vtn8R0000<MNUMnLSTXd9g$K1 literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/images/ic-github.png b/src/main/resources/templates/email/images/ic-github.png new file mode 100644 index 0000000000000000000000000000000000000000..e5fd9694a3bf9ebc24541b05303cc4be9e1e4db6 GIT binary patch literal 1125 zcmV-r1e*JaP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3=HfOamM*si<V@X6oR5;7Mlut<0VHn3h-=E8& z2_aOMqDzFE6Ot0rxsAL8Mu#p19fA%)w+Mq0!Y&1p1=77Bf=)$XVRR|jW}Ai{n~D`= zR37@X2%T>G{hkh`Z8>8`^xU48_x<ob&-490@Q*{KN%x}}f3~4;&ZK#tyn7>&&}^kg zd&kE&)aL3Bndj`2bUz(ydR`IO8P6Q_q+y@{n86(hKgKpQ{79cAZwAvrU>A^=h^L~# z1IrAj6zGZ;V8QP$ZZ+9}pc^BA_$2XGSS_X_pjpSU4#71uLZu8}Y2u(S26aVWjYgx* zeL&xz`V~%0o&vJvjFRxgG2mUUF27XO1Wd1hKzkyyXB9B~>_w}LE~K7`wzh?8cwaZW z1Hc=h)2n~z*0cb)OZK!{iM$Af@}LnxOU04_YW)Roz1lO(T?I6=*8ukOr|ZDA7<#=5 z==bKH19M)DbEaBUdvbC=&?@6$MPY}Nnd4@<Ex08|7oJ4|@7Hq5hWUo0l3fR0Zl4Qu z-aRUJ1sF}tY{{#*V=Nk+XisEL3g;@=Cd9N%4^pwfd4O;{6EmqFXa(xQhVpLB$%(F} zk7XqnR6On&<Ke{AmC;!94SdC&f>RhxhVA?1e5VlzV?6OhTRPT!xD>Vm9E}79L6;0W z*AbuWO?QN{1uH%VBs92uITZ^GfxSY!9E%1gDz)Q>^(0Hf#c*PBqlx~G<Wvv(=}Pmy zl&>dcfyT84Ri?vKEO^#)oG9X^VEAwLq3`#Du}IShFcL{l?{>{QAu}seona=dYT$C@ r>b_<Cx%%G4hFn>%BwYr5;D5z;yesKU98iu*00000NkvXXu0mjf^$h^X literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/images/ic-linkedin.png b/src/main/resources/templates/email/images/ic-linkedin.png new file mode 100644 index 0000000000000000000000000000000000000000..523755e1bf802ee23c9248d70d08f266af3b0c9c GIT binary patch literal 1015 zcmV<T0|@+yP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3>0I?L7p8x;>^+`lQR5;7!(m!ZZQ547V@40!2 z_K(3qTB)LFQ4<U8P(%{iY9~REQU@g{PIk@U;NsFnr*<;p>>vo@>OX`^(lkUW_y_wM zEh2)TU@fE+8sB^OI3$gQDAr~X{7v`5xgYMi_Xz8fm?`bTvwOF%IL{xPJWyd1F?B3A zH;QlHBjlIb{bKK<mu*dfYUQ$^&p<~7`r5WeMw$XeSX5*WZ~{Q!Yg1q#Tmrs;q*R!k zITnAs8BqSFIGJDQ(7=luqm{7N^5W_6zSZA?iJY6la=g}l#TYv=J<#(J;OLXrohIUB zfYa-`S_UR|e~w+fdq#pa$EnN8xC))XqQd^bnzulvf2y>@gn~TKfpSHSozg&}CS=Z{ zI{s<r{6XM+<1d4#a;q>D@2=ib3_v(!uYq(KV-qW@->-``-NuM148|@3X@zsi?EFXr z_^b5K&V~h20ym@O$U<vNB#&?#c$mz(lZC<94NzA_FKh_hQfci1+O10QThtyA=tDRK zWE92_Q9+6*hc*NTJ`n&yvMjI-z*;Sd$UD~dN*QW(e*&8t?0*(?elFD)k#r*KrfYBG zDaHpyti4~KS1X<sJOL6}S8He822e3$Mzp7jsddD=H$Bw5l+4bh5Q$ccv|JcI{9z#X l>W;6DXKJ%*)x6>V%?}a`yMJFvf|URO002ovPDHLkV1g)&&ujny literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/images/ic-slack.png b/src/main/resources/templates/email/images/ic-slack.png new file mode 100644 index 0000000000000000000000000000000000000000..28976ec8fa0a9d5d433b8ff18105dc720cf9000c GIT binary patch literal 1285 zcmV+g1^W7lP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3>1;Kt|5C8xJ14%?dR5;7MlwWAoWgNyo&wGAn z^QhH?(!#pif&HN}a5?9;8dA}&x@eMi(?Up!QPf=_QLtjLn{JFC?axJOjp!m!NU?2g zr=buw+C-%Yt)v1gHuvZJe(%$Tay)|x4x;z+`|^JHKJW8<zwjR)EmwT_#80aha`U^v z>tdGwV4|ydam%sE4WTA^4sov3(Rgr0z_yVyhm3oGIpA__78@6G;V7^PSc9~q)Y0(S za&N<OMdNOvK`U+t?w(J=W}sE(b>L@A+l@L*Zcv{v-Xn+ht2#mf#~eXr>_yvQMZkn) zS4#G(<Yrr6Waad`B)62&F>>yXl<XjQi{Z<4Gs!bYx{C`HVC(Ri9g;gRHL25U(m5UF zLnphMFKr!}UII*2ehq6g_+6n_{=TI=3hYY&wvJBk#QsF+g5`3RW48wL{I+k-6l3%p zc0EuBnj`u?#A(P4L43j1?bjunB5(yUD44G@rwQvtr`o6xKQ!tCW<_?G5Q><`Ax;1n zNy7e0Y}&@ouXjv`u-kxKm9ja+fl_-z-&G}NTN1Jhqn%B^Z8<i%LAAMiWtC^=7EgWu z*!{DW*o<$h|GhTNx`FMMA4#)#SE;j6A*ddQkFWEy-W2_~b!6J1Cb=Z*E8zIrLjGvm z*!lI94qJvN?@35Xh>h1i@AC+61v3JywzW^vM-V5F-w~RsnvGSq-v$OsosDlM0J)Gn zi>Xr#4?4s_q6;GQAkPZ+BkvA@{usF;>uJM3RmSCk)xu{hrYQPPq=G}%1KNbb0qg?s z7t(p`!dQF5udO3f9l%pqw^fXj7lnq$I~#{8z`EJ|`<K_I?LvEi(qg9meDL1t+_jwe z;Z70uN?v1mDsjGlw6plfvXgS8ySM=CtiEU+UK-?FK6!u`pRgGR^=3+&fJbj?IRHqC zKn>A(Aj_qmzbY}l41Uk1btTIIo07y!7H=Sp=bfEgaQH=p<3Is8eADX-;M<29K1J*T v4=5y0e%;kP6Jyc}9+2EuH<R@8f1G~-jKWE_G^3Y400000NkvXXu0mjfM^9i% literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/images/ic-twitter.png b/src/main/resources/templates/email/images/ic-twitter.png new file mode 100644 index 0000000000000000000000000000000000000000..5974ab542b228eb7e31f9435a9d257a7715da78f GIT binary patch literal 1233 zcmV;?1TOoDP)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3>3Q@s-fdBvk&q+i<R5;7clwXL{RTRfR=gzph zsA2llf<?keGqXw$;x@l&W@nZLWGzBuOYzTxh;9%RMY%!{1VNDz^&nDUf|Owpp^1WQ z%+Bw(<BaQok+#3zKCKY7_Mj2&Htp>E?&-m{WOv4go;*+Yp6~sBIEQmN@SsJ$IMs!! zEZqM+q`ZlOQF&is_1%nK3mdY3ypXun4wmx#yeQu(d{ymB90V{6qCpNRtV0<=83B`v zbjay^u^4RybKJ>ZQO*J@4f6YcoPR<s-vDbs$1AzSkQ&(qnxBhwA6Wt``5VEW2OdKC zwj-Q=Ye~y@A5I)cWUsOInR33zb4vbUg!d5HU&+Ql2XKnlV?-h@&<$LCcqaP%g{|x7 zS_1RMsjj(5y#(@@4WpYc=VQO5yx^3;HZVCGnqN(%=>d-e<=J{;%a2>0oV}MJi`&V% z6WvXu2HYgNG6NvZ8Bc|^sNMmIfsPwv3gt}v&SJk=obdXR)7F?Bzy@v39Id1ut=o`6 zRM&vS5Uvxo1Fc{!fdH2?PmC$@s=&UK7ravKPuws>hCx(A{h^ZHaQlCKTBkH|JmvcK zX?OB9fVAho?zq0D+~B2l9@9?PRI4phctk)f_DF9jSa&I#_(<V|pr1T7HkoPVla@49 zlk$Qu1$HX(hp7Dvk>6(PjdZv+I=||ce6K3&n>06H$!+}k{uQc<;|9kBb^^1&v!DY& zY{l}9lRqVs^Yfv;05qc#J+rA+TYg`l;{_ie90ckrJXh_Dmn*rRtAY%nY<JvX_)34z zO%u^UAldoniqF~t9oK&ccmtS6c(IyIj4o)G`r==Je2nmJYHV_#oJm$ueOY0*Q}TzF z0Ml-;2Y4F@Rb@{ln>e?)`p$6rO^{KsddeyJpMvxPw-L52T@GqHfrf}2sOI8dx0=;x ve}6M<=nk+YgaSfAU<&Mqw43e&x557g*Nz{tB)=jw00000NkvXXu0mjfPLD#b literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/images/ic-youtube.png b/src/main/resources/templates/email/images/ic-youtube.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa386b1eca7ef36b54702346f94a46a6185e1d8 GIT binary patch literal 1076 zcmV-41k3x0P)<h;3K|Lk000e1NJLTq000yK000yS1^@s6jfou%0004lX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9WW3T6=LkfAzR5EXIMDionYs1;guFuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx7Fxu3aNLh~_a1le0HI!Cy4^Jf=!RpZ zlL;xCTaiMq2t!0aqJY9|b5@p9@Eu?G2=MhT&a?c_{W*HIyv=}sL_EVx%OPGTp4xOw z&ilk7D=8ZBIq|4P7bJe<y4vJ7&P9&}o+(<H^c=BBEEPLg?O;~2bmB?kn5G+)FJzmn zao*yrSE{UaPyWJ4-dJAZI?X7OSimA=NKjEl85KB)(`t}nBTf4WAODc&m&v7)s|-et zd2B$3;`zb<;CHunVPd?Q6iEQxFRuGB41{)pM$L7<k6pKM0tBCdE2Hh-r~}iVq}SS7 z><H-F1}?7Knz{#E?f`>NreZ0c6r?E>3c&jreNzq?xCO$i&E8u3IDG&z)K%&RI5-4G zij=+P^X{I`-u^w)>hA|D7IKQ}?mZ9y000JJOGiWi{{a60|De66lK=n!32;bRa{vGh z*8l(w*8xH(n|J^K00(qQO+^Ri3KS3>5Uity`v3p}GD$>1R5;7!lTAp}K^Vq=@9g>) zUEK-~N>m$Sp-6^l)M{7@LAMT}-a2&%f=<!d=pLPdI&`Z`UAvS;yN1<4u?%&S3Z*aX zgEe#g-2XgXEFxEtPC@TwnBke<JoC&u@UNHsJ~?pzMYRipge;8XEpE;t@|bhl41hEv zb0L86IppRQMkaTBuKReq+rnSKw!Unq&}CrTU)d5<!p=QCTz}J&nXx?>gTOsQH}Ezo zxts;zyz_;bV*3}pRYbj&Dr!}RZN=M3jN=yZtx-93n_PaTDm*dL*toPoPq~%x6+p|t zz@1<&HbucYos-)oDO(KIp3bJ)GGiB7dS7o^k3QJix(tlVtk!ucfiY1u8t1!Y^aQ0# z<H^j}>8@Lfto^z+0VJFmm4>F*3H&|KhjH~?O?K$uqtT;9Wzsi{xC6?;Ev(&Gnt9UE z(B-`E04hz^o9xS;U#+t_M7aYBlH7V3we^oCLg&r^31HN`rHdR~Vo-<*=FC}ao!(C< zWXwTc(%Di!buFDr6;|_z3Gz|Hz93bv0h<S+z?C3exR_2gPp=&{HNdB+&>MsHVxl1Q zJ<BDLOZ|uHKWyL+*Mc56upwY~GBeWrrzo9joZSelE&X!8pboQV)^zuIELIjg1{w^8 zg}uf2iZm}-zNi~h46`ysm7(o|CS)T^vDtP5IP!3$V$nrTf%akSG>8edtXw57_}S0} u;QPvYPLM}Tn6tszxy9?l$M)v=|LO;$80;8TZvSuq0000<MNUMnLSTaKl=gc7 literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/illustration.png b/src/main/resources/templates/email/images/illustration.png similarity index 100% rename from src/main/resources/templates/email/illustration.png rename to src/main/resources/templates/email/images/illustration.png diff --git a/src/main/resources/templates/email/logo.png b/src/main/resources/templates/email/images/logo.png similarity index 100% rename from src/main/resources/templates/email/logo.png rename to src/main/resources/templates/email/images/logo.png diff --git a/src/main/resources/templates/email/images/new-ic-facebook.png b/src/main/resources/templates/email/images/new-ic-facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..a0e162be75f4f31b3dbe954795d4e941476eeaf5 GIT binary patch literal 976 zcmV;>126oEP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T70004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iTWh7XIJAR^Lx$>PK~%(1t5Adrp;l<s!Q|2}XktiG zTpR`0f`cE6RR<SmT^(EnLGS~_)x}BCMN0f%QfLw5!Ery{-Fw`<1N_YzQ_Y?+K-DZG zn@$P&!io@jMHn#z5k;@WOnp`qGw>W=_we!cF3GdJ&;2=~O3`G1PavLQx?vHo6Hjeg zI_G`jIIBns@j3CRK^G)`<htzg8|Sjaex4aOa@jfJII&RfV!4Z1#ZZYSi4%&dQNBO# zvch?bvs$aO_C5IvBSmd_iR(0nkj4TQAwqzRI;yC_LXuXE6cbt6PkHzU9luB}nOs#c za?E1`DkR4b{s+IiHA@rYZc-!#1Yd0XV;BhS0<DH^e;?a+>jVfq16NwdztIGyKS^(N zw8Rn6zYSbmcQknqxZD8-o^;8O94SE4Un&9bXY@@4Aa)CcSKZ#)`#607a@1Ak1~@nb zM#_}E=JD>n?%w`A)9&vF_I7f0@Al3}00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru=L!=BDKbZu(~|%I0nJH7K~z}7?Uuhw8(|oLpZ9XK zgFoodu}e26TSXL0+oe-UGGxd>3yDTC{uSN(C)6&16fzukskv??h(Sb<wtqpOW(eru zAXaE{ufv@hC0%kyF2nas_x<Gg-tT?64-5u_!7$cHTpKkS4g1gO#kwd(&{>el+fi*6 zoy@CY_O;`XtJQWMAD{gFCa^sC-12hRy{)KnuIr|Hw)GWs8E7Hu{Cn7)E;?x`I_bza z6gh&IOuPqP1MMEXDCIMqICC(vprR`hT<M3BlkQZucV<$)^-<tSFrKiWAoBoS!~;nA zRt=cDC)Q3(5O@So%D+8b3);^Ce01S@LKnN0q@VzZi1xQvoy<{UIaqb;>tHQjXW`&E z-?wf~AbL>9rz<0jpnL-DTdU`Hzhx4%eAA=614bzrtP^w-K>XCtzN&s>g?XsL0xBDz zzZ1#9f|L1tzi-9K9s-BKHG5A3YuQUg@QYh7hZXxP6r;NBEs3ws!f0lLnz5Rr7VHAH zB3ohEo&!?^wm%e^=%3qraJfHHK~>olVJU2t@4j3J<s`g*-7V#EXNkSns;;M1*VF&C yqhc}U7(pYLG<KZTJf;!UL4S!o3<iV25DQnF6q51Xt4BZp0000<MNUMnLSTX%r?_JP literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/new-ic-github.png b/src/main/resources/templates/email/images/new-ic-github.png similarity index 100% rename from src/main/resources/templates/email/new-ic-github.png rename to src/main/resources/templates/email/images/new-ic-github.png diff --git a/src/main/resources/templates/email/new-ic-linkedin.png b/src/main/resources/templates/email/images/new-ic-linkedin.png similarity index 100% rename from src/main/resources/templates/email/new-ic-linkedin.png rename to src/main/resources/templates/email/images/new-ic-linkedin.png diff --git a/src/main/resources/templates/email/new-ic-slack.png b/src/main/resources/templates/email/images/new-ic-slack.png similarity index 100% rename from src/main/resources/templates/email/new-ic-slack.png rename to src/main/resources/templates/email/images/new-ic-slack.png diff --git a/src/main/resources/templates/email/images/new-ic-twitter.png b/src/main/resources/templates/email/images/new-ic-twitter.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e4d788c8c7d4df182949dbb5bd8cfed2bd647a GIT binary patch literal 1593 zcmV-92FCe`P)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T70004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iTWh7XIJAR^Lx$>PK~%(1t5Adrp;l<s!Q|2}XktiG zTpR`0f`cE6RR<SmT^(EnLGS~_)x}BCMN0f%QfLw5!Ery{-Fw`<1N_YzQ_Y?+K-DZG zn@$P&!io@jMHn#z5k;@WOnp`qGw>W=_we!cF3GdJ&;2=~O3`G1PavLQx?vHo6Hjeg zI_G`jIIBns@j3CRK^G)`<htzg8|Sjaex4aOa@jfJII&RfV!4Z1#ZZYSi4%&dQNBO# zvch?bvs$aO_C5IvBSmd_iR(0nkj4TQAwqzRI;yC_LXuXE6cbt6PkHzU9luB}nOs#c za?E1`DkR4b{s+IiHA@rYZc-!#1Yd0XV;BhS0<DH^e;?a+>jVfq16NwdztIGyKS^(N zw8Rn6zYSbmcQknqxZD8-o^;8O94SE4Un&9bXY@@4Aa)CcSKZ#)`#607a@1Ak1~@nb zM#_}E=JD>n?%w`A)9&vF_I7f0@Al3}00006VoOIv0RI600RN!9r;`8x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru=L!=BC?u*{SAzfm1U5-TK~z}7?U!wclvNbRf9ILi zeJwF9i(<usJ_x2P8d_!;NV+qtf$g)4>&%jAOOh30nh?}LV7L?_y)B9D%xv4vom_Bd zXUqgwD0*@IVx&c}iGm+Q@}+inX4{#2`Y<DDh>o?cADaKC=Q;PBdw=)d=bZaoD5|KU ziu!*`#(O|x`l?14UQo)=SFY=(uIFD;NT*?wd>k|cO#j=egQ)ZI!13>14hDm^kbXkl z-BZ$;;XYtiimD!9#r0yG0w=!hN;m+iLUh9eGar7lkPbRJlDA8ybRRG)w{<$TkhlT? zwG2RnHv+C#0<Kq7^$8$@@M<KQaId|srd%g#9GI7%+;3QI88bkEEkIV4*CWy7Qvl5k zzCIP*2#5;1BVF;?SBq_HJ2D|nWlUjF-t@a;Wm%xn_rsVbNysE#5!enoh-Ja00YcHl zM<T2RPG*pKYuwtim#v&9P30#*L*A4Uv9<pCx<iGITj)1Pv+HdI+Ci#tq^GkpJ{2H+ zVcL4&OJI5lw%Zsp5kOTXrIjCE1~)2b{f)rg5FkKysN#8`ADEFTaXO7Lo|cxmqgil) z(;y4eQrQX+F^Sgv$^v8+@%vq0;-=TZu!&cL(+}Jw(CT-+n*lnylJl*jhk#Ongo5`{ zhKcZ;zuvoR+zNGjH2J6_dJvchGzDC5CqN{Y45-@B72S$#3e?xWJ?<w-DAv1PRNe#9 zj&&BTZd}$65RN6jM{~6fWqY8(yXC)}JkGxjY_9jcugWf<%sTe7$ez#d0Z5&jHXq?a ze)<b{CX=PN1Q6ijZSn%}HBhbD?6J1CBNZ(zbB9MXTLYW~9+~uqzI)36U#zVi!RihX z6qsCg$C+;c*15}1h_x$#AraPwV!i8c31HalTZkj=s=04jl!wA*-?ISz#=4`TtOHb3 zcC<$mi^df&ceL3apdyzKdMwvsKZwM79|Q0=ct1sH1tvHm-C@%+V_X13U5N+ParOg~ zb8viHPUU=roxlWDF&%r7_W=wXKfDz*2|7jabhpLh6*m<yY~t18Z~&N=Hyte*)mqnG zJXoef8$tF1ciSv`jWOlHV9<I-S*`Gk!kqGy6INBZDS#mpzZaZ7pgM2*xg?W$vZ={; z9>8_o?4LNRfC12&G?i@tO-;V@*0IZhi@?foEV*gS0XsY6Qw8S>;QqYn6xb!JR;@U5 zx!+oM={d1>B`^f|L$Tfs0M9&K_mc|EfC_Ajn8cDX12pEqq)drtKQJ?II_+_EaloxR zbv6Hd2CvCy@H?Ss@8Vo>_wE%T2zV5EtB|n^x|5`2WV5K$<X_KXbxD)!`}JBe{sylJ zM-y`pwu;EXu*v<%s9y50!(+CB4ss&@cwVes8ff(WSV-K!@x!m>GFu1#(R4zrzBH!S r#Yk6t_HL8Bvv^Z4s;Huh8ejbdXOyDwoU_2-00000NkvXXu0mjfMAYR} literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/email/new-ic-youtube.png b/src/main/resources/templates/email/images/new-ic-youtube.png similarity index 100% rename from src/main/resources/templates/email/new-ic-youtube.png rename to src/main/resources/templates/email/images/new-ic-youtube.png diff --git a/src/main/resources/templates/email/new-logo.png b/src/main/resources/templates/email/images/new-logo.png similarity index 100% rename from src/main/resources/templates/email/new-logo.png rename to src/main/resources/templates/email/images/new-logo.png diff --git a/src/main/resources/templates/email/restore-password.png b/src/main/resources/templates/email/images/restore-password.png similarity index 100% rename from src/main/resources/templates/email/restore-password.png rename to src/main/resources/templates/email/images/restore-password.png diff --git a/src/main/resources/templates/email/index-finished-template.ftl b/src/main/resources/templates/email/index-finished-template.ftl index cc168b5d4c..132eec19f4 100644 --- a/src/main/resources/templates/email/index-finished-template.ftl +++ b/src/main/resources/templates/email/index-finished-template.ftl @@ -70,7 +70,7 @@ You can start to use Auto-Analyzer on your project. </p> <p height='34' style="margin: 5px 0 0 0;font-size: 14px;color: #777777;"> - ElasticSearch Index contains <b>${indexedLogsCount}</b> record(s) now. + The search engine Index contains <b>${indexedLogsCount}</b> record(s) now. </p> <h3 style="margin:25px 0 0 0;font-size: 14px;font-weight: bold;color: #777777;">Your ReportPortal.io Team</h3> </td> diff --git a/src/main/resources/templates/email/new-ic-twitter.png b/src/main/resources/templates/email/new-ic-twitter.png deleted file mode 100644 index 1101c16d5b293ffefebc6683048c43ec2b5ac3c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 690 zcmV;j0!{siP)<h;3K|Lk000e1NJLTq001Ze001Zm1^@s6jQ+T700009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP<VFdsH0!K+iK~#7F?Uqq) z(?Af0XEsj70}nZZxj{KW!wV9MBH;&uDioTWfO3M86VRT(lz=KFNGU=gkK_h*Z{Q>3 zp)b_y9cD{gMN#b?JBic>f0Cs{`7`@_W@mQ*Dk>@}DjqcmTVyz%H3?{!3^f#B^mOO% zJP3ltvgT|u^Y?>SF|1>7GMO}11Lt8E)tW*gYOeeg^D}tgX??Ng0q6*bF1wx9VOA^! z0<Ls@@_jVjm1ynDBnka_z?{YBCmfEZ7ewYpqf>R97td+XW`hWuDX(omyYyH3$p_9% zu8sh1UY1P``uo}C6&ciNa+f(jNzBF9(X^NU5AzyC;Q7JZ_9vIhX^_bCm%cXm3BUcA zhFRGp0?}6B@?J`Go-+`4Ag;8MG0-!{^oHZ#b1v6U<POyy#Qh+@TxD<?%;UBZ>`?-> z1c1vg{x1@WP6cO)QK9&FDFRm|mgw9DA&p=QX!K%<&fUeHj(DGKI*W0?^HTKUPJ?}W zgAkm+W|>QcqMO9*Tpw>Ti-_h_sudZuSyX5O*Z_z)@4jizrFxM;%Wcp;tcfD}SV&() zY^RVkRnIsNF_ggGz3)1$LZ?FMdC=a;ye~iF|Lae(P{d=^b0|om4BlbyVWnWNh&f%q zegP#AXE0<_wZt@elOJTvdKn9tlWwPd2qnoiI2`|K0@RM!keyIO*}4zR-3pKnigfIQ zaU>#Z)EMj`sy)Xry5LQ7j$}^PHCD*rGU3_G_dLy0w({?TsC1!g^=KR8Rz*ccMa3iM YA5GBjPjzfvwEzGB07*qoM6N<$g4NbCo&W#< diff --git a/src/main/resources/templates/email/registration-template.ftl b/src/main/resources/templates/email/registration-template.ftl index 8501ed695a..6b731360c8 100644 --- a/src/main/resources/templates/email/registration-template.ftl +++ b/src/main/resources/templates/email/registration-template.ftl @@ -1,167 +1,194 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } + .rplogo { + margin-left: 15px; + } - table[class="mainimgwrapper"] { - height: 130px; - background-image: url("create-user.png"); - background-size: cover; - background-position: center; - } + table[class="mainimgwrapper"] { + height: 130px; + background-image: url("images/create-user.png"); + background-size: cover; + background-position: center; + } - .mainimg { - display: none; - } - } - </style> + .mainimg { + display: none; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" vlink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> + <tbody> + <tr> + <td height="130"> + <img class="mainimg" src="cid:create-user.png" border="0" width="540" height="130" + alt="You’ve been invited to join ReportPortal"> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <h2 style="font-size: 20px; color: #777777;" align="center">Welcome to + ReportPortal!</h2> + <p style="font-size: 14px; color: #777777;">You’ve been invited to join + ReportPortal.</p> + <p style="font-size: 14px; line-height: 1.7; color: #777777">Click the link below to + create your account and get + started.</p> + <table border="0" cellspacing="8" cellpadding="0" align="center"> + <tbody> + <tr> + <td width="130" height="35" align="center" bgcolor="#a3c644"> + <a href="${url}" + style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 100px;"> + Get Started + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> - <tbody> - <tr> - <td height="130"> - <img class="mainimg" src="cid:create-user.png" border="0" width="540" height="130" - alt="You’ve been invited to join ReportPortal"> - </td> - </tr> - </tbody> + <p style="font-size: 14px; color: #777777;">New to ReportPortal? Check out the <a + href="https://reportportal.io/docs/reportportal-tutorial/?utm_source=trigger&utm_medium=email&utm_campaign=tutorial&utm_content=invitation" + target="_blank">ReportPortal Tutorial</a>.</p> + <br> + <p style="font-size: 14px; line-height: 1.7; color: #777777;">Thanks,<br> + ReportPortal.io Team</p> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td> + <a href="https://slack.epmrpp.reportportal.io" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <h2 style="font-size: 20px; color: #777777;" align="center">Welcome to ReportPortal!</h2> - <p style="font-size: 14px; color: #777777;">You’ve been invited to join ReportPortal.</p> - <p style="font-size: 14px; line-height: 1.7; color: #777777">Click the link below to create your account and get - started.</p> - <table border="0" cellspacing="8" cellpadding="0" align="center"> - <tbody> - <tr> - <td width="130" height="35" align="center" bgcolor="#a3c644"> - <a href="${url}" - style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 100px;"> - Get Started - </a> - </td> - </tr> - </tbody> - </table> - <p style="font-size: 14px; color: #777777;">New to ReportPortal? Check out the <a - href="https://reportportal.io/docs/reportportal-tutorial/?utm_source=trigger&utm_medium=email&utm_campaign=tutorial&utm_content=invitation" - target="_blank">ReportPortal Tutorial</a>.</p> - <br> - <p style="font-size: 14px; line-height: 1.7; color: #777777;">Thanks,<br> - ReportPortal.io Team</p> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" border="0" - width="20" height="21" alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img src="cid:ic-twitter.png" border="0" - width="20" height="16" alt="twitter"></a> - </td> - <td><a href="https://www.youtube.com/c/ReportPortal" target="_blank"><img src="cid:ic-youtube.png" - border="0" width="20" - height="15" alt="youtube"></a> - </td> - <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a></td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="52" class="footercontent" style="padding: 4px;"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> - <b>ReportPortal Notification Center</b><br> - This is an automatically generated notification - please do not reply to this message. You are receiving this - email to complete the registration initiated on the ReportPortal application; if you are not waiting - for the ReportPortal's invitation then just ignore this message. - </p> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="52" class="footercontent" style="padding: 4px;"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> + <b>ReportPortal Notification Center</b><br> + This is an automatically generated notification - please do not reply to this message. + You are receiving this + email to complete the registration initiated on the ReportPortal application; if you + are not waiting + for the ReportPortal's invitation then just ignore this message. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> -</html> \ No newline at end of file +</html> diff --git a/src/main/resources/templates/email/restore-password-template.ftl b/src/main/resources/templates/email/restore-password-template.ftl index b54d40756b..818531fa57 100644 --- a/src/main/resources/templates/email/restore-password-template.ftl +++ b/src/main/resources/templates/email/restore-password-template.ftl @@ -1,161 +1,188 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>ReportPortal</title> - <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> - <style> - body { - margin: 0; - padding: 0; - font-family: OpenSans, sans-serif; - } + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>ReportPortal</title> + <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'> + <style> + body { + margin: 0; + padding: 0; + font-family: OpenSans, sans-serif; + } - a, a:active, a:visited { - color: #39c2d7; - text-decoration: underline; - } + a, a:active, a:visited { + color: #39c2d7; + text-decoration: underline; + } - a:hover { - text-decoration: none; - } + a:hover { + text-decoration: none; + } - .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { - display: inline-block; - text-decoration: none; - } + .rplogo, .rplogo:hover, .rplogo:active, .rplogo:visited { + display: inline-block; + text-decoration: none; + } - @media only screen and (max-width: 540px) { - body { - margin: 0; - padding: 0; - } + @media only screen and (max-width: 540px) { + body { + margin: 0; + padding: 0; + } - table[class="mainwrapper"] { - width: 100% !important; - } + table[class="mainwrapper"] { + width: 100% !important; + } - .rplogo { - margin-left: 15px; - } + .rplogo { + margin-left: 15px; + } - table[class="mainimgwrapper"] { - height: 130px; - background-image: url("restore-password.png"); - background-size: cover; - background-position: center; - } + table[class="mainimgwrapper"] { + height: 130px; + background-image: url("images/restore-password.png"); + background-size: cover; + background-position: center; + } - .mainimg { - display: none; - } - } - </style> + .mainimg { + display: none; + } + } + </style> </head> -<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" alink="#39c2d7" vlink="#39c2d7" +<body bgcolor="#f9f9f9" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" link="#39c2d7" + alink="#39c2d7" vlink="#39c2d7" style="font-family: OpenSans, sans-serif;"> <table width="540" border="0" cellspacing="0" cellpadding="0" align="center" class="mainwrapper"> - <tbody> - <tr> - <td> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> - <tbody> - <tr> - <td height="48"> - <a class="rplogo" href="http://reportportal.io" target="_blank" - style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> - ReportPortal.io - </a> - </td> - </tr> - </tbody> + <tbody> + <tr> + <td> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="logowrapper"> + <tbody> + <tr> + <td height="48"> + <a class="rplogo" href="http://reportportal.io" target="_blank" + style="font-size: 15px; color: #595c5c; font-weight: bold; font-family: 'Roboto', sans-serif;"> + ReportPortal.io + </a> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> + <tbody> + <tr> + <td height="130"> + <img class="mainimg" src="cid:restore-password.png" border="0" width="540" height="130" + alt="Restore your password to ReportPortal"> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" + bgcolor="#ffffff"> + <tbody> + <tr> + <td align="left" height="170"> + <h2 style="font-size: 20px; color: #777777;" align="center">Forgot your password to + ReportPortal?</h2> + <p style="font-size: 14px; color: #777777;">Click the link below to choose a new + one.</p> + <table border="0" cellspacing="8" cellpadding="0" align="center"> + <tbody> + <tr> + <td width="150" height="35" align="center" bgcolor="#a3c644"> + <a href="${url}" + style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 120px;"> + Reset Password + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="mainimgwrapper"> - <tbody> - <tr> - <td height="130"> - <img class="mainimg" src="cid:restore-password.png" border="0" width="540" height="130" - alt="Restore your password to ReportPortal"> - </td> - </tr> - </tbody> + <p style="font-size: 14px; color: #777777;">P.S. If you didn’t request this email, you + can just ignore it.</p> + </td> + </tr> + </tbody> + </table> + <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" + class="linkswrapper"> + <tbody> + <tr> + <td height="82" align="center"> + <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> + <tbody> + <tr> + <td> + <p style="font-size: 13px; color: #464547;">Keep in touch with us:</p> + </td> + <td> + <a href="http://twitter.com/ReportPortal_io" target="_blank"> + <img src="cid:ic-twitter.png" alt="twitter"> + </a> + </td> + <td> + <a href="https://slack.epmrpp.reportportal.io" target="_blank"> + <img src="cid:ic-slack.png" alt="slack"> + </a> + </td> + <td> + <a href="https://www.youtube.com/c/ReportPortal" target="_blank"> + <img src="cid:ic-youtube.png" alt="youtube"> + </a> + </td> + <td> + <a href="https://www.linkedin.com/company/reportportal/" target="_blank"> + <img src="cid:ic-linkedin.png" alt="linkedin"> + </a> + </td> + <td> + <a href="https://www.facebook.com/ReportPortal.io" target="_blank"> + <img src="cid:ic-facebook.png" alt="facebook"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" target="_blank"> + <img src="cid:ic-github.png" alt="github"> + </a> + </td> + </tr> + </tbody> </table> - <table width="100%" border="0" cellspacing="0" cellpadding="30" class="contentwrapper" bgcolor="#ffffff"> - <tbody> - <tr> - <td align="left" height="170"> - <h2 style="font-size: 20px; color: #777777;" align="center">Forgot your password to ReportPortal?</h2> - <p style="font-size: 14px; color: #777777;">Click the link below to choose a new one.</p> - <table border="0" cellspacing="8" cellpadding="0" align="center"> - <tbody> - <tr> - <td width="150" height="35" align="center" bgcolor="#a3c644"> - <a href="${url}" - style="font-size: 14px; text-decoration: none; color: #ffffff; display: inline-block; padding: 10px 15px; width: 120px;"> - Reset Password - </a> - </td> - </tr> - </tbody> - </table> - <p style="font-size: 14px; color: #777777;">P.S. If you didn’t request this email, you can just ignore it.</p> - </td> - </tr> - </tbody> - </table> - <table width="100%" height="82" border="0" cellspacing="0" cellpadding="0" class="linkswrapper"> - <tbody> - <tr> - <td height="82" align="center"> - <table border="0" cellspacing="0" cellpadding="12" class="linksline" align="center"> - <tbody> - <tr> - <td><p style="font-size: 13px; color: #464547;">Keep in touch with us:</p></td> - <td><a href="https://github.com/reportportal" target="_blank"><img src="cid:ic-github.png" border="0" - width="20" height="21" alt="github"></a> - </td> - <td><a href="http://twitter.com/ReportPortal_io" target="_blank"><img src="cid:ic-twitter.png" border="0" - width="20" height="16" alt="twitter"></a> - </td> - <td><a href="https://www.youtube.com/c/ReportPortal" target="_blank"><img src="cid:ic-youtube.png" - border="0" width="20" - height="15" alt="youtube"></a> - </td> - <td><a href="https://slack.epmrpp.reportportal.io" target="_blank"><img src="cid:ic-slack.png" - border="0" width="18" - height="18" - alt="slack"></a></td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" class="footerline"> - <tbody> - <tr> - <td height="1"><!-- --></td> - </tr> - </tbody> - </table> - <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> - <tbody> - <tr> - <td align="center" height="52" class="footercontent" style="padding: 4px;"> - <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> - <b>ReportPortal Notification Center</b><br> - This is an automatically generated notification - please do not reply to this message. You are receiving this - email to complete the registration initiated on the ReportPortal application; if you are not waiting - for the ReportPortal's invitation then just ignore this message. - </p> - </td> - </tr> - </tbody> - </table> - </td> - </tr> - </tbody> + </td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#bdc7cc" + class="footerline"> + <tbody> + <tr> + <td height="1"><!-- --></td> + </tr> + </tbody> + </table> + <table width="100%" border="0" cellspacing="0" cellpadding="0" class="footerwrapper"> + <tbody> + <tr> + <td align="center" height="52" class="footercontent" style="padding: 4px;"> + <p style="font-size: 11px; line-height: 1.5; color: #6d6d6d"> + <b>ReportPortal Notification Center</b><br> + This is an automatically generated notification - please do not reply to this message. + You are receiving this + email to complete the registration initiated on the ReportPortal application; if you + are not waiting + for the ReportPortal's invitation then just ignore this message. + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> </table> </body> </html> diff --git a/src/main/resources/templates/email/self-delete-account-template.ftl b/src/main/resources/templates/email/self-delete-account-template.ftl index cc5f32aa57..c1b0d2afa5 100644 --- a/src/main/resources/templates/email/self-delete-account-template.ftl +++ b/src/main/resources/templates/email/self-delete-account-template.ftl @@ -1,73 +1,75 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <link +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <link href="http://fonts.googleapis.com/css?family=Roboto:wght@100;400;500;&display=swap" rel="stylesheet" type="text/css" - /> - <!--[if mso - ]><xml - ><o:OfficeDocumentSettings - ><o:PixelsPerInch>96</o:PixelsPerInch - ><o:AllowPNG /></o:OfficeDocumentSettings></xml - ><![endif]--> - <style> - .heading { - font-family: Arial, Helvetica, sans-serif; - margin-top: 0; - margin-bottom: 0; - color: #454a4f; - font-size: 36px; - font-style: normal; - font-weight: 700; - line-height: 48px; - } + /> + <!--[if mso]> + <xml> + <o:OfficeDocumentSettings> + <o:PixelsPerInch>96</o:PixelsPerInch> + <o:AllowPNG/> + </o:OfficeDocumentSettings> + </xml> + <![endif]--> + <style> + .heading { + font-family: Arial, Helvetica, sans-serif; + margin-top: 0; + margin-bottom: 0; + color: #454a4f; + font-size: 36px; + font-style: normal; + font-weight: 700; + line-height: 48px; + } - .main-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - font-family: Arial, Helvetica, sans-serif; - color: #545454; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 22px; - } + .main-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + font-family: Arial, Helvetica, sans-serif; + color: #545454; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } - .footer-content-heading { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 13px; - font-style: normal; - font-weight: 500; - line-height: 20px; - } + .footer-content-heading { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 13px; + font-style: normal; + font-weight: 500; + line-height: 20px; + } - .footer-content { - margin-top: 0; - margin-bottom: 0; - margin-left: 0; - margin-right: 0; - color: #a2aab5; - font-family: 'Roboto', sans-serif; - font-size: 11px; - font-style: normal; - font-weight: 400; - line-height: 16px; - } - </style> + .footer-content { + margin-top: 0; + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + color: #a2aab5; + font-family: 'Roboto', sans-serif; + font-size: 11px; + font-style: normal; + font-weight: 400; + line-height: 16px; + } + </style> - <title>Report Portal</title> - </head> - <body + <title>Report Portal</title> +</head> +<body style=" font-family: Arial, Helvetica, sans-serif; margin-top: 0; @@ -79,215 +81,214 @@ padding-top: 0; padding-bottom: 0px; " +> +<center> + <table + width="630" + border="0" + cellspacing="0" + cellpadding="0" + align="center" > - <center> - <table - width="630" - border="0" - cellspacing="0" - cellpadding="0" - align="center" - > - <tbody> + <tbody> + <tr> + <td> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> <tr> - <td> - <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tbody> - <tr> - <td align="center" style="padding-top: 48px"> - <a - href="http://reportportal.io" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-logo.png" alt="Report Portal logo" - /></a> - </td> - </tr> - <tr> - <td - align="center" - style=" + <td align="center" style="padding-top: 48px"> + <a + href="http://reportportal.io" + target="_blank" + rel="noopener noreferrer" + ><img src="cid:new-logo.png" alt="Report Portal logo" + /></a> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-top: 37px; padding-bottom: 38px; background-color: rgb(244, 251, 251); border-spacing: 0; " - > - <img - src="cid:deleted-account.png" - alt="Deleted account img" - /> - </td> - </tr> - </tbody> - </table> + > + <img + src="cid:deleted-account.png" + alt="Deleted account img" + /> </td> </tr> - <tr> - <td - align="center" - style=" + </tbody> + </table> + </td> + </tr> + <tr> + <td + align="center" + style=" padding-left: 50px; padding-right: 50px; padding-bottom: 40px; padding-top: 38px; background-color: #ffffff; " + > + <table width="100%" border="0" cellspacing="0" cellpadding="0"> + <thead> + <th> + <h1 class="heading">Your account has been deleted</h1> + </th> + </thead> + <tbody> + <tr> + <td style="padding-bottom: 12px; padding-top: 24px"> + <p class="main-content"> + This email is to confirm that your account and personal + data have been successfully deleted from ReportPortal + database. We're sorry to see you go, and we hope you had + a positive experience using our app. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + Please note that any data that you have reported to + ReportPortal or created there will remain in the app. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + If you haven't deleted your account or if you have any + questions or concerns, please contact our support team + for assistance. + </p> + </td> + </tr> + <tr> + <td style="padding-bottom: 12px"> + <p class="main-content"> + Thank you for your time and we wish you all the best in + your future testing endeavors. + </p> + </td> + </tr> + <tr> + <td> + <p class="main-content"> + <br>Kind regards,<br>ReportPortal team + </p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + <tr> + <td align="center"> + <table + width="100%" + border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tbody> + <tr> + <td + align="center" + style="padding-top: 32px; padding-bottom: 24px" > - <table width="100%" border="0" cellspacing="0" cellpadding="0"> - <thead> - <th> - <h1 class="heading">Your account has been deleted</h1> - </th> - </thead> - <tbody> - <tr> - <td style="padding-bottom: 12px; padding-top: 24px"> - <p class="main-content"> - This email is to confirm that your account and personal - data have been successfully deleted from ReportPortal - database. We're sorry to see you go, and we hope you had - a positive experience using our app. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - Please note that any data that you have reported to - ReportPortal or created there will remain in the app. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - If you haven't deleted your account or if you have any - questions or concerns, please contact our support team - for assistance. - </p> - </td> - </tr> - <tr> - <td style="padding-bottom: 12px"> - <p class="main-content"> - Thank you for your time and we wish you all the best in - your future testing endeavors. - </p> - </td> - </tr> - <tr> - <td> - <p class="main-content"> - <br>Kind regards,<br>ReportPortal team - </p> - </td> - </tr> - </tbody> + <table border="0" + cellspacing="0" + cellpadding="0" + bgcolor="#f4fbfb" + > + <tr> + <td style="padding-right: 22px"> + <a href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-twitter.png" + alt="Twitter icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://slack.epmrpp.reportportal.io/" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-slack.png" + alt="Slack icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.youtube.com/c/ReportPortal" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-youtube.png" + alt="YouTube icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.linkedin.com/company/reportportal/" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-linkedin.png" + alt="Linkedin icon"> + </a> + </td> + <td style="padding-right: 22px"> + <a href="https://www.facebook.com/ReportPortal.io" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-facebook.png" + alt="Facebook icon"> + </a> + </td> + <td> + <a href="https://github.com/reportportal" + target="_blank" + rel="noopener noreferrer"> + <img src="cid:new-ic-github.png" + alt="Github icon"> + </a> + </td> + </tr> </table> </td> </tr> <tr> <td align="center"> - <table - width="100%" - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tbody> - <tr> - <td - align="center" - style="padding-top: 32px; padding-bottom: 24px" - > - <table - border="0" - cellspacing="0" - cellpadding="0" - bgcolor="#f4fbfb" - > - <tr> - <td style="padding-right: 22px"> - <a - href="https://twitter.com/i/flow/login?redirect_after_login=%2FReportPortal_io" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-twitter.png" - alt="Twitter icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://slack.epmrpp.reportportal.io/" - target="_blank" - rel="noopener noreferrer" - ><img src="cid:new-ic-slack.png" alt="Slack icon" - /></a> - </td> - <td style="padding-right: 22px"> - <a - href="https://www.youtube.com/c/ReportPortal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-youtube.png" - alt="YouTube icon" - /></a> - </td> - <td style="padding-right: 10px"> - <a - href="https://www.linkedin.com/company/reportportal/" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-linkedin.png" - alt="Linkedin icon" - /></a> - </td> - <td> - <a - href="https://github.com/reportportal" - target="_blank" - rel="noopener noreferrer" - ><img - src="cid:new-ic-github.png" - alt="Github icon" - /></a> - </td> - </tr> - </table> - </td> - </tr> - <tr> - <td align="center"> - <h4 class="footer-content-heading"> - ReportPortal Notification Center - </h4> - </td> - </tr> - <tr> - <td align="center" style="padding-bottom: 32px"> - <p class="footer-content"> - This notification was created automatically. Please - don't reply to this e-mail. - </p> - </td> - </tr> - </tbody> - </table> + <h4 class="footer-content-heading"> + ReportPortal Notification Center + </h4> + </td> + </tr> + <tr> + <td align="center" style="padding-bottom: 32px"> + <p class="footer-content"> + This notification was created automatically. Please + don't reply to this e-mail. + </p> </td> </tr> - </tbody> - </table> - </center> - </body> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> +</center> +</body> </html> diff --git a/src/main/resources/templates/report/projects.jrxml b/src/main/resources/templates/report/projects.jrxml index 13e8b202a9..abf539ad3a 100644 --- a/src/main/resources/templates/report/projects.jrxml +++ b/src/main/resources/templates/report/projects.jrxml @@ -16,130 +16,158 @@ --> <!-- Created with Jaspersoft Studio version 6.6.0.final using JasperReports Library version 6.6.0 --> -<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" - name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" rightMargin="20" - topMargin="20" bottomMargin="20" uuid="7a5c9b49-9dc5-422a-ac69-e92cf61ef530" isIgnorePagination="true"> - <style name="Title" forecolor="#FFFFFF" fontName="Noto Sans" fontSize="50" isBold="false"/> - <style name="SubTitle" forecolor="#CCCCCC" fontName="Noto Sans" fontSize="18" isBold="false"/> - <style name="Column header" forecolor="#666666" fontName="Noto Sans" fontSize="14" isBold="true"/> - <style name="Detail" mode="Transparent" fontName="Noto Sans"/> - <style name="Row" mode="Transparent" fontName="Noto Sans" pdfFontName="Times-Roman"> - <conditionalStyle> - <conditionExpression><![CDATA[$V{REPORT_COUNT}%2 == 0]]></conditionExpression> - <style mode="Opaque" backcolor="#F0EFEF"/> - </conditionalStyle> - </style> - <queryString> - <![CDATA[]]> - </queryString> - <field name="Project name" class="java.lang.String"/> - <field name="Project type" class="java.lang.String"/> - <field name="Organization" class="java.lang.String"/> - <field name="Members" class="java.lang.Integer"/> - <field name="Launches" class="java.lang.Integer"/> - <field name="Last launch date" class="java.lang.String"/> - <background> - <band splitType="Stretch"/> - </background> - <columnHeader> - <band height="19" splitType="Stretch"> - <staticText> - <reportElement x="0" y="0" width="217" height="18" uuid="1e0d3905-6d0e-4660-ac0a-9b6ca6b47b93"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Project name]]></text> - </staticText> - <staticText> - <reportElement x="217" y="0" width="100" height="18" uuid="64cc94b9-8766-49b1-8b9f-e45296c5c9c7"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Project type]]></text> - </staticText> - <staticText> - <reportElement x="317" y="0" width="150" height="18" uuid="b0549432-b1b4-41af-931e-7e25e63d738c"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Organization]]></text> - </staticText> - <staticText> - <reportElement x="467" y="0" width="100" height="18" uuid="e0ddb3e8-ddc4-41af-b0bb-5299862be558"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Members]]></text> - </staticText> - <staticText> - <reportElement x="567" y="0" width="100" height="18" uuid="ac60d496-d8c7-4543-b8da-1112cde3fc2c"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="d4571106-56c2-445d-a317-a38effb2595b"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Launches]]></text> - </staticText> - <staticText> - <reportElement x="667" y="0" width="130" height="18" uuid="c171c5b6-8de5-4c4e-8bcf-e00a8d4c4e04"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="2f7dc42d-b03f-4000-b7c3-4143e6e1f44d"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Last launch date]]></text> - </staticText> - </band> - </columnHeader> - <detail> - <band height="18" splitType="Stretch"> - <frame> - <reportElement style="Row" mode="Opaque" x="0" y="0" width="797" height="18" uuid="34a2ae4b-4055-476b-8676-d499f6af510b"/> - <textField> - <reportElement x="0" y="0" width="217" height="30" uuid="42609d3f-7d28-44f2-b8ea-650fbbcf746f"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Project name}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="217" y="0" width="100" height="30" uuid="66d3c031-147d-40f1-a43b-d1d9a3a6e457"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Project type}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="317" y="0" width="150" height="30" uuid="d4aa9cdc-f50c-4cb9-9246-f0f57250f17f"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Organization}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="467" y="0" width="100" height="30" uuid="47939077-bc56-4fc7-85b9-2942fcaddaa0"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Members}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="567" y="0" width="100" height="30" uuid="5fc335bb-6c5a-46ac-b345-fbefa1deec6a"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="d4571106-56c2-445d-a317-a38effb2595b"/> - </reportElement> - <textElement textAlignment="Center" verticalAlignment="Top"/> - <textFieldExpression><![CDATA[$F{Launches}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="667" y="0" width="130" height="30" uuid="e2f3ad6a-109e-4eca-accc-eb0c7aa3bbb9"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="2f7dc42d-b03f-4000-b7c3-4143e6e1f44d"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Last launch date}]]></textFieldExpression> - </textField> - </frame> - </band> - </detail> - <summary> - <band splitType="Stretch"/> - </summary> +<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" + name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" + leftMargin="20" rightMargin="20" + topMargin="20" bottomMargin="20" uuid="7a5c9b49-9dc5-422a-ac69-e92cf61ef530" + isIgnorePagination="true"> + <style name="Title" forecolor="#FFFFFF" fontName="Noto Sans" fontSize="50" isBold="false"/> + <style name="SubTitle" forecolor="#CCCCCC" fontName="Noto Sans" fontSize="18" isBold="false"/> + <style name="Column header" forecolor="#666666" fontName="Noto Sans" fontSize="14" isBold="true"/> + <style name="Detail" mode="Transparent" fontName="Noto Sans"/> + <style name="Row" mode="Transparent" fontName="Noto Sans" pdfFontName="Times-Roman"> + <conditionalStyle> + <conditionExpression><![CDATA[$V{REPORT_COUNT}%2 == 0]]></conditionExpression> + <style mode="Opaque" backcolor="#F0EFEF"/> + </conditionalStyle> + </style> + <queryString> + <![CDATA[]]> + </queryString> + <field name="Project name" class="java.lang.String"/> + <field name="Project type" class="java.lang.String"/> + <field name="Organization" class="java.lang.String"/> + <field name="Members" class="java.lang.Integer"/> + <field name="Launches" class="java.lang.Integer"/> + <field name="Last launch date" class="java.lang.String"/> + <background> + <band splitType="Stretch"/> + </background> + <columnHeader> + <band height="19" splitType="Stretch"> + <staticText> + <reportElement x="0" y="0" width="217" height="18" + uuid="1e0d3905-6d0e-4660-ac0a-9b6ca6b47b93"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Project name]]></text> + </staticText> + <staticText> + <reportElement x="217" y="0" width="100" height="18" + uuid="64cc94b9-8766-49b1-8b9f-e45296c5c9c7"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Project type]]></text> + </staticText> + <staticText> + <reportElement x="317" y="0" width="150" height="18" + uuid="b0549432-b1b4-41af-931e-7e25e63d738c"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Organization]]></text> + </staticText> + <staticText> + <reportElement x="467" y="0" width="100" height="18" + uuid="e0ddb3e8-ddc4-41af-b0bb-5299862be558"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Members]]></text> + </staticText> + <staticText> + <reportElement x="567" y="0" width="100" height="18" + uuid="ac60d496-d8c7-4543-b8da-1112cde3fc2c"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="d4571106-56c2-445d-a317-a38effb2595b"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Launches]]></text> + </staticText> + <staticText> + <reportElement x="667" y="0" width="130" height="18" + uuid="c171c5b6-8de5-4c4e-8bcf-e00a8d4c4e04"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="2f7dc42d-b03f-4000-b7c3-4143e6e1f44d"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Last launch date]]></text> + </staticText> + </band> + </columnHeader> + <detail> + <band height="18" splitType="Stretch"> + <frame> + <reportElement style="Row" mode="Opaque" x="0" y="0" width="797" height="18" + uuid="34a2ae4b-4055-476b-8676-d499f6af510b"/> + <textField> + <reportElement x="0" y="0" width="217" height="30" + uuid="42609d3f-7d28-44f2-b8ea-650fbbcf746f"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Project name}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="217" y="0" width="100" height="30" + uuid="66d3c031-147d-40f1-a43b-d1d9a3a6e457"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Project type}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="317" y="0" width="150" height="30" + uuid="d4aa9cdc-f50c-4cb9-9246-f0f57250f17f"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Organization}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="467" y="0" width="100" height="30" + uuid="47939077-bc56-4fc7-85b9-2942fcaddaa0"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Members}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="567" y="0" width="100" height="30" + uuid="5fc335bb-6c5a-46ac-b345-fbefa1deec6a"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="d4571106-56c2-445d-a317-a38effb2595b"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Top"/> + <textFieldExpression><![CDATA[$F{Launches}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="667" y="0" width="130" height="30" + uuid="e2f3ad6a-109e-4eca-accc-eb0c7aa3bbb9"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="2f7dc42d-b03f-4000-b7c3-4143e6e1f44d"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Last launch date}]]></textFieldExpression> + </textField> + </frame> + </band> + </detail> + <summary> + <band splitType="Stretch"/> + </summary> </jasperReport> diff --git a/src/main/resources/templates/report/report.jrxml b/src/main/resources/templates/report/report.jrxml index 2b49d853bf..459ff581d0 100644 --- a/src/main/resources/templates/report/report.jrxml +++ b/src/main/resources/templates/report/report.jrxml @@ -17,772 +17,838 @@ <!-- Created with Jaspersoft Studio version 6.2.2.final using JasperReports Library version 6.2.2 --> <!-- 2016-07-25T16:43:03 --> -<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" - name="Blank_A4_Landscape" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" - rightMargin="20" topMargin="20" bottomMargin="20" uuid="438bfacd-17a2-4c73-99de-5e4210041df7"> - <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> - <style name="Table_TH" mode="Opaque" backcolor="#484866"> +<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" + name="Blank_A4_Landscape" pageWidth="842" pageHeight="595" orientation="Landscape" + columnWidth="802" leftMargin="20" + rightMargin="20" topMargin="20" bottomMargin="20" uuid="438bfacd-17a2-4c73-99de-5e4210041df7"> + <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> + <style name="Table_TH" mode="Opaque" backcolor="#484866"> + <box> + <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + </box> + </style> + <style name="Table_CH" mode="Opaque" backcolor="#CFCFE6"> + <box> + <topPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + </box> + </style> + <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF"> + <box> + <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + </box> + </style> + <style name="Table 1_TH" mode="Opaque" backcolor="#F0F8FF"> + <box> + <pen lineWidth="0.5" lineColor="#000000"/> + <topPen lineWidth="0.5" lineColor="#000000"/> + <leftPen lineWidth="0.5" lineColor="#000000"/> + <bottomPen lineWidth="0.5" lineColor="#000000"/> + <rightPen lineWidth="0.5" lineColor="#000000"/> + </box> + </style> + <subDataset name="TestItemsTableDS" whenResourceMissingType="Empty" + uuid="60da51c9-2b0f-4af5-8fe6-4544ac18aa83"> + <queryString> + <![CDATA[]]> + </queryString> + <field name="type" class="java.lang.String"/> + <field name="name" class="java.lang.String"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + <field name="duration" class="java.lang.Double"/> + <field name="status" class="java.lang.String"/> + <field name="total" class="java.lang.Integer"/> + <field name="passed" class="java.lang.Integer"/> + <field name="failed" class="java.lang.Integer"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + <field name="skipped" class="java.lang.Integer"/> + <field name="automationBug" class="java.lang.Integer"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + <field name="productBug" class="java.lang.Integer"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + <field name="systemIssue" class="java.lang.Integer"/> + <field name="noDefect" class="java.lang.Integer"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + <field name="toInvestigate" class="java.lang.Integer"> + <fieldDescription><![CDATA[]]></fieldDescription> + </field> + </subDataset> + <subDataset name="Dataset1" uuid="8b099eea-c143-479c-8970-4217b14379d7"> + <queryString> + <![CDATA[]]> + </queryString> + </subDataset> + <parameter name="LAUNCH_NAME" class="java.lang.String"/> + <parameter name="LAUNCH_DURATION" class="java.lang.String"> + <parameterDescription><![CDATA[]]></parameterDescription> + </parameter> + <parameter name="LAUNCH_DESCRIPTION" class="java.lang.String"> + <parameterDescription><![CDATA[]]></parameterDescription> + </parameter> + <parameter name="LAUNCH_OWNER" class="java.lang.String"/> + <parameter name="LAUNCH_TAGS" class="java.lang.String"/> + <parameter name="TOTAL" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="PASSED" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="FAILED" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="SKIPPED" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="AB" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="PB" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="SI" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="ND" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="TI" class="java.lang.Integer"> + <defaultValueExpression><![CDATA[0]]></defaultValueExpression> + </parameter> + <parameter name="TEST_ITEMS" class="java.util.Collection"/> + <queryString> + <![CDATA[]]> + </queryString> + <background> + <band splitType="Stretch"/> + </background> + <title> + <band height="85" splitType="Stretch"> + <textField isBlankWhenNull="true"> + <reportElement x="82" y="60" width="140" height="20" + uuid="f4f1aa0a-7460-4ec1-9568-6c2101c918de"/> + <textElement verticalAlignment="Top"> + <font fontName="Noto Sans"/> + </textElement> + <textFieldExpression><![CDATA[$P{LAUNCH_DURATION}]]></textFieldExpression> + </textField> + <staticText> + <reportElement x="0" y="40" width="82" height="20" + uuid="bf3f95f3-b14a-492b-8b8b-fd8d9ba6d088"/> + <textElement verticalAlignment="Top"> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Owner:]]></text> + </staticText> + <staticText> + <reportElement x="0" y="60" width="82" height="20" + uuid="813174c3-f36a-4c64-b0d3-60726c2ea891"/> + <textElement verticalAlignment="Top"> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Duration:]]></text> + </staticText> + <textField isBlankWhenNull="true"> + <reportElement x="82" y="40" width="388" height="20" + uuid="bafe2045-04c0-40b6-803e-03941dd6f77a"/> + <textElement verticalAlignment="Top"> + <font fontName="Noto Sans"/> + </textElement> + <textFieldExpression><![CDATA[$P{LAUNCH_OWNER}]]></textFieldExpression> + </textField> + <staticText> + <reportElement x="0" y="0" width="82" height="20" + uuid="e15dcb90-a675-4b87-9a32-eaac213feea1"/> + <textElement> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Launch name:]]></text> + </staticText> + <textField> + <reportElement x="82" y="0" width="388" height="20" + uuid="7661c90b-7b58-4292-8333-154705ff0701"/> + <textElement> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <textFieldExpression><![CDATA[$P{LAUNCH_NAME}]]></textFieldExpression> + </textField> + <staticText> + <reportElement x="0" y="20" width="82" height="20" + uuid="e4b2bcf3-cc0a-4156-a4aa-cddf2a16d5c0"/> + <textElement> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Description:]]></text> + </staticText> + <textField> + <reportElement x="82" y="20" width="388" height="20" + uuid="b0b0090b-1fe2-4349-afd2-5f08bfa31187"/> + <textElement> + <font fontName="Noto Sans"/> + </textElement> + <textFieldExpression><![CDATA[$P{LAUNCH_DESCRIPTION}]]></textFieldExpression> + </textField> + <staticText> + <reportElement x="480" y="0" width="320" height="20" + uuid="fa79751f-81e6-40fb-b2aa-de1031768dc8"/> <box> - <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> </box> - </style> - <style name="Table_CH" mode="Opaque" backcolor="#CFCFE6"> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Launch statistic]]></text> + </staticText> + <staticText> + <reportElement x="480" y="20" width="168" height="20" + uuid="d018d389-4a79-4095-b4f8-fbfaef41246d"/> <box> - <topPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> </box> - </style> - <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF"> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Execution statistic]]></text> + </staticText> + <staticText> + <reportElement x="648" y="20" width="152" height="20" + uuid="7fd8af2f-840f-4b1c-927b-18168bc9422c"/> <box> - <topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> </box> - </style> - <style name="Table 1_TH" mode="Opaque" backcolor="#F0F8FF"> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" isBold="true"/> + </textElement> + <text><![CDATA[Issue statistic]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="480" y="40" width="30" height="20" backcolor="#489BEB" + uuid="364a016c-13cc-476e-a112-c293a2e4aa9c"/> <box> - <pen lineWidth="0.5" lineColor="#000000"/> - <topPen lineWidth="0.5" lineColor="#000000"/> - <leftPen lineWidth="0.5" lineColor="#000000"/> - <bottomPen lineWidth="0.5" lineColor="#000000"/> - <rightPen lineWidth="0.5" lineColor="#000000"/> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> </box> - </style> - <subDataset name="TestItemsTableDS" whenResourceMissingType="Empty" uuid="60da51c9-2b0f-4af5-8fe6-4544ac18aa83"> - <queryString> - <![CDATA[]]> - </queryString> - <field name="type" class="java.lang.String"/> - <field name="name" class="java.lang.String"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - <field name="duration" class="java.lang.Double"/> - <field name="status" class="java.lang.String"/> - <field name="total" class="java.lang.Integer"/> - <field name="passed" class="java.lang.Integer"/> - <field name="failed" class="java.lang.Integer"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - <field name="skipped" class="java.lang.Integer"/> - <field name="automationBug" class="java.lang.Integer"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - <field name="productBug" class="java.lang.Integer"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - <field name="systemIssue" class="java.lang.Integer"/> - <field name="noDefect" class="java.lang.Integer"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - <field name="toInvestigate" class="java.lang.Integer"> - <fieldDescription><![CDATA[]]></fieldDescription> - </field> - </subDataset> - <subDataset name="Dataset1" uuid="8b099eea-c143-479c-8970-4217b14379d7"> - <queryString> - <![CDATA[]]> - </queryString> - </subDataset> - <parameter name="LAUNCH_NAME" class="java.lang.String"/> - <parameter name="LAUNCH_DURATION" class="java.lang.String"> - <parameterDescription><![CDATA[]]></parameterDescription> - </parameter> - <parameter name="LAUNCH_DESCRIPTION" class="java.lang.String"> - <parameterDescription><![CDATA[]]></parameterDescription> - </parameter> - <parameter name="LAUNCH_OWNER" class="java.lang.String"/> - <parameter name="LAUNCH_TAGS" class="java.lang.String"/> - <parameter name="TOTAL" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="PASSED" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="FAILED" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="SKIPPED" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="AB" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="PB" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="SI" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="ND" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="TI" class="java.lang.Integer"> - <defaultValueExpression><![CDATA[0]]></defaultValueExpression> - </parameter> - <parameter name="TEST_ITEMS" class="java.util.Collection"/> - <queryString> - <![CDATA[]]> - </queryString> - <background> - <band splitType="Stretch"/> - </background> - <title> - <band height="85" splitType="Stretch"> - <textField isBlankWhenNull="true"> - <reportElement x="82" y="60" width="140" height="20" uuid="f4f1aa0a-7460-4ec1-9568-6c2101c918de"/> - <textElement verticalAlignment="Top"> - <font fontName="Noto Sans"/> - </textElement> - <textFieldExpression><![CDATA[$P{LAUNCH_DURATION}]]></textFieldExpression> - </textField> - <staticText> - <reportElement x="0" y="40" width="82" height="20" uuid="bf3f95f3-b14a-492b-8b8b-fd8d9ba6d088"/> - <textElement verticalAlignment="Top"> - <font fontName="Noto Sans" isBold="true"/> - </textElement> - <text><![CDATA[Owner:]]></text> - </staticText> - <staticText> - <reportElement x="0" y="60" width="82" height="20" uuid="813174c3-f36a-4c64-b0d3-60726c2ea891"/> - <textElement verticalAlignment="Top"> - <font fontName="Noto Sans" isBold="true"/> - </textElement> - <text><![CDATA[Duration:]]></text> - </staticText> - <textField isBlankWhenNull="true"> - <reportElement x="82" y="40" width="388" height="20" uuid="bafe2045-04c0-40b6-803e-03941dd6f77a"/> - <textElement verticalAlignment="Top"> - <font fontName="Noto Sans"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + <paragraph lineSpacing="AtLeast"/> + </textElement> + <text><![CDATA[Total]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="510" y="40" width="50" height="20" backcolor="#87B77B" + uuid="1cb41bf6-b644-4dae-8e8e-690d8a9295a7"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[Passed]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="560" y="40" width="40" height="20" backcolor="#F36C4A" + uuid="9d8e885a-6c11-4500-a95e-b60c3eaf55c9"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[Failed]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="600" y="40" width="48" height="20" backcolor="#BDC7CC" + uuid="b85b72e9-4054-457b-bb42-b44bd3e4b858"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[Skipped]]></text> + </staticText> + <textField> + <reportElement x="480" y="60" width="30" height="20" + uuid="be0a5e88-b3b2-4bb2-881d-90ff51d7caf1"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{TOTAL}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="510" y="60" width="50" height="20" + uuid="3c0d9905-b60e-4c9b-80b4-d7d6b60e174e"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{PASSED}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="560" y="60" width="40" height="20" + uuid="c6fcfe12-2e78-44dd-b271-b16b191b3fc9"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{FAILED}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="600" y="60" width="48" height="20" + uuid="4272b431-fab3-40fd-92f5-1de979e56249"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{SKIPPED}]]></textFieldExpression> + </textField> + <staticText> + <reportElement mode="Opaque" x="648" y="40" width="30" height="20" backcolor="#F7D63E" + uuid="10a4b295-cd29-4a96-8b83-2b8031a5f79e"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[AB]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="678" y="40" width="30" height="20" backcolor="#EC3900" + uuid="0fa281e5-f495-4c9b-8ead-0346399f7f89"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[PB]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="708" y="40" width="30" height="20" backcolor="#0274D1" + uuid="6aef0f86-27df-4967-9692-9b7dd7abb2fa"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[SI]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="738" y="40" width="30" height="20" backcolor="#BDC7CC" + uuid="b9208960-ff59-4de2-8059-9a607f220fbd"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[ND]]></text> + </staticText> + <staticText> + <reportElement mode="Opaque" x="768" y="40" width="32" height="20" backcolor="#FFB743" + uuid="c5c69ffe-8bf0-4290-bb2c-07ae27a82627"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> + </textElement> + <text><![CDATA[TI]]></text> + </staticText> + <textField> + <reportElement x="648" y="60" width="30" height="20" + uuid="2011a38d-2f02-43fa-8004-a0d49df5cd99"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{AB}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="678" y="60" width="30" height="20" + uuid="80d81588-1312-4554-8aa3-72d52c50ed83"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{PB}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="708" y="60" width="30" height="20" + uuid="2c8561e8-61af-4709-861e-d89b1be0cd6b"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{SI}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="738" y="60" width="30" height="20" + uuid="e348f9a4-6e6a-4815-b20e-0ebcfe8a3f40"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{ND}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="768" y="60" width="32" height="20" + uuid="7e2ef588-7105-4960-a393-44371e5652a2"/> + <box> + <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> + </box> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> + </textElement> + <textFieldExpression><![CDATA[$P{TI}]]></textFieldExpression> + </textField> + </band> + </title> + <detail> + <band height="303" splitType="Stretch"> + <componentElement> + <reportElement x="0" y="0" width="800" height="300" + uuid="854b8278-360a-4dba-9bd1-3a77189f6478"> + <property name="com.jaspersoft.studio.layout" + value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/> + <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/> + <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/> + <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/> + </reportElement> + <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" + xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" + whenNoDataType="Blank"> + <datasetRun subDataset="TestItemsTableDS" uuid="05506102-a762-4b4f-8c9f-0bb284545e94"> + <dataSourceExpression> + <![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{TEST_ITEMS}, false)]]></dataSourceExpression> + </datasetRun> + <jr:column width="90" uuid="b2569992-2bd8-4ff9-a9b3-368d2ca026b7"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column1"/> + <property name="com.jaspersoft.studio.unit.height" value="pixel"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="90" height="30" + uuid="6ac25c5d-aa07-4c0d-a578-53d2e0f96d42"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{LAUNCH_OWNER}]]></textFieldExpression> - </textField> - <staticText> - <reportElement x="0" y="0" width="82" height="20" uuid="e15dcb90-a675-4b87-9a32-eaac213feea1"/> - <textElement> - <font fontName="Noto Sans" isBold="true"/> + <text><![CDATA[Type]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <property name="com.jaspersoft.studio.unit.height" value="px"/> + <textField> + <reportElement x="0" y="0" width="90" height="20" + uuid="113268f0-68f2-4c5e-b580-ff200e7b853c"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Launch name:]]></text> - </staticText> - <textField> - <reportElement x="82" y="0" width="388" height="20" uuid="7661c90b-7b58-4292-8333-154705ff0701"/> - <textElement> - <font fontName="Noto Sans" isBold="true"/> + <textFieldExpression><![CDATA[$F{type}]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="209" uuid="44a6a309-83bd-4546-b0cd-b10728e874dd"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column2"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="209" height="30" + uuid="ca534fe2-78f2-44f6-9b03-9bc32970c178"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{LAUNCH_NAME}]]></textFieldExpression> - </textField> - <staticText> - <reportElement x="0" y="20" width="82" height="20" uuid="e4b2bcf3-cc0a-4156-a4aa-cddf2a16d5c0"/> - <textElement> - <font fontName="Noto Sans" isBold="true"/> + <text><![CDATA[Name]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField isStretchWithOverflow="true"> + <reportElement x="0" y="0" width="209" height="20" + uuid="1ed705a6-1478-4fa5-82d0-f626e5aa6f7e"/> + <textElement verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Description:]]></text> - </staticText> - <textField> - <reportElement x="82" y="20" width="388" height="20" uuid="b0b0090b-1fe2-4349-afd2-5f08bfa31187"/> - <textElement> - <font fontName="Noto Sans"/> + <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="50" uuid="4c3f0fac-1fb3-467d-81a7-36b9b2d84302"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column13"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="50" height="30" + uuid="3fe70789-6869-4b8d-bf21-be0fc66b623e"/> + <textElement textAlignment="Center" verticalAlignment="Middle"> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{LAUNCH_DESCRIPTION}]]></textFieldExpression> - </textField> - <staticText> - <reportElement x="480" y="0" width="320" height="20" uuid="fa79751f-81e6-40fb-b2aa-de1031768dc8"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[Duration (sec)]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="50" height="20" + uuid="ba201ea1-3041-4d50-b546-d3b9a4ce5543"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Launch statistic]]></text> - </staticText> - <staticText> - <reportElement x="480" y="20" width="168" height="20" uuid="d018d389-4a79-4095-b4f8-fbfaef41246d"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{duration}]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="70" uuid="4c3f0fac-1fb3-467d-81a7-36b9b2d84401"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column3"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="70" height="30" + uuid="3fe70789-6869-4b8d-bf21-be0fc66b619e"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" isBold="true"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <text><![CDATA[Execution statistic]]></text> - </staticText> - <staticText> - <reportElement x="648" y="20" width="152" height="20" uuid="7fd8af2f-840f-4b1c-927b-18168bc9422c"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[Status]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="70" height="20" + uuid="ba201ea1-3041-4d50-b546-d3b9a4ce5433"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Issue statistic]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="480" y="40" width="30" height="20" backcolor="#489BEB" - uuid="364a016c-13cc-476e-a112-c293a2e4aa9c"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{status}]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="299a618c-60b1-45ee-bfd3-dfee01b8a36c"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column4"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="c4fef87b-707e-4406-8821-a3690eaf04a9"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - <paragraph lineSpacing="AtLeast"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> <text><![CDATA[Total]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="510" y="40" width="50" height="20" backcolor="#87B77B" - uuid="1cb41bf6-b644-4dae-8e8e-690d8a9295a7"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="ba96f816-5077-44a1-b820-76375d356550"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Passed]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="560" y="40" width="40" height="20" backcolor="#F36C4A" - uuid="9d8e885a-6c11-4500-a95e-b60c3eaf55c9"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{total}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="51" uuid="036301ab-1dbb-4ab1-a25b-206fc3871d54"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column5"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="51" height="30" + uuid="a5bfbd41-ceb3-4cc0-a823-dbccdc163799"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <text><![CDATA[Failed]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="600" y="40" width="48" height="20" backcolor="#BDC7CC" - uuid="b85b72e9-4054-457b-bb42-b44bd3e4b858"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[Passed]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="51" height="20" + uuid="c714fea4-aa63-4704-a36d-148cc6720185"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[Skipped]]></text> - </staticText> - <textField> - <reportElement x="480" y="60" width="30" height="20" uuid="be0a5e88-b3b2-4bb2-881d-90ff51d7caf1"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{passed}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="012751ee-ecd0-4259-aaaa-8bf219a2269a"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column6"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="e705346a-5e09-4d83-addd-1f514ec17b6d"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{TOTAL}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="510" y="60" width="50" height="20" uuid="3c0d9905-b60e-4c9b-80b4-d7d6b60e174e"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[Failed]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="258d73ee-ddef-4902-bbce-a424d2c4f130"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <textFieldExpression><![CDATA[$P{PASSED}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="560" y="60" width="40" height="20" uuid="c6fcfe12-2e78-44dd-b271-b16b191b3fc9"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{failed}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="50" uuid="08db46ac-76eb-416c-97e7-c3748e6671fa"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column7"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="50" height="30" + uuid="1ae2a81b-db01-49f0-b25c-89cfc989eb41"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{FAILED}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="600" y="60" width="48" height="20" uuid="4272b431-fab3-40fd-92f5-1de979e56249"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[Skipped]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="50" height="20" + uuid="508d7d97-04ff-4734-b0e9-826fdc2b30f6"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <textFieldExpression><![CDATA[$P{SKIPPED}]]></textFieldExpression> - </textField> - <staticText> - <reportElement mode="Opaque" x="648" y="40" width="30" height="20" backcolor="#F7D63E" - uuid="10a4b295-cd29-4a96-8b83-2b8031a5f79e"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{skipped}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="6fe1d4d9-e98e-408a-bbfd-9217632c4248"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column8"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="ed1bfe30-4c47-4fc2-9902-7e98261b56b0"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> <text><![CDATA[AB]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="678" y="40" width="30" height="20" backcolor="#EC3900" - uuid="0fa281e5-f495-4c9b-8ead-0346399f7f89"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="568bf98d-a032-4242-8ea5-c509d07952a5"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[PB]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="708" y="40" width="30" height="20" backcolor="#0274D1" - uuid="6aef0f86-27df-4967-9692-9b7dd7abb2fa"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{automationBug}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="64a44a55-7fd1-4937-977a-d393be83748a"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column9"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="3e6f717a-5f91-4db4-a849-4aeeac81ecb2"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <text><![CDATA[SI]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="738" y="40" width="30" height="20" backcolor="#BDC7CC" - uuid="b9208960-ff59-4de2-8059-9a607f220fbd"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[PB]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="65fe9d6e-8e44-46d6-a795-3298db9b40b2"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <text><![CDATA[ND]]></text> - </staticText> - <staticText> - <reportElement mode="Opaque" x="768" y="40" width="32" height="20" backcolor="#FFB743" - uuid="c5c69ffe-8bf0-4290-bb2c-07ae27a82627"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{productBug}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="fbe03a89-85d3-489a-82bf-571bc9901603"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column10"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="9175f909-a932-455c-8719-00c20d39fd21"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <text><![CDATA[TI]]></text> - </staticText> - <textField> - <reportElement x="648" y="60" width="30" height="20" uuid="2011a38d-2f02-43fa-8004-a0d49df5cd99"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[SI]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="f917ddc4-503b-4911-89ca-a8c1b63ce588"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <textFieldExpression><![CDATA[$P{AB}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="678" y="60" width="30" height="20" uuid="80d81588-1312-4554-8aa3-72d52c50ed83"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{systemIssue}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="2ef87095-2dc4-4b56-9383-06bcca1017a6"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column11"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="b1c0a90a-1757-45fc-95cb-370a7d20b262"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{PB}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="708" y="60" width="30" height="20" uuid="2c8561e8-61af-4709-861e-d89b1be0cd6b"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[ND]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="d18e6732-4b1b-4dbe-af93-53af34f8a530"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <textFieldExpression><![CDATA[$P{SI}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="738" y="60" width="30" height="20" uuid="e348f9a4-6e6a-4815-b20e-0ebcfe8a3f40"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <textFieldExpression><![CDATA[$F{noDefect}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + <jr:column width="40" uuid="ea408a50-e25d-487f-aaa8-ce4686ce4d2f"> + <property name="com.jaspersoft.studio.components.table.model.column.name" + value="Column12"/> + <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> + <staticText> + <reportElement x="0" y="0" width="40" height="30" + uuid="03c2d2fb-cb4a-48fc-b18d-4a6b3ba2fabc"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9" isBold="true"/> </textElement> - <textFieldExpression><![CDATA[$P{ND}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="768" y="60" width="32" height="20" uuid="7e2ef588-7105-4960-a393-44371e5652a2"/> - <box> - <topPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <leftPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <bottomPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - <rightPen lineWidth="1.0" lineStyle="Solid" lineColor="#000000"/> - </box> + <text><![CDATA[TI]]></text> + </staticText> + </jr:columnHeader> + <jr:detailCell style="Table_TD" height="20"> + <textField> + <reportElement x="0" y="0" width="40" height="20" + uuid="798423a0-99ec-4bc6-a82a-e95235ffbdd7"/> <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> + <font fontName="Noto Sans" size="9"/> </textElement> - <textFieldExpression><![CDATA[$P{TI}]]></textFieldExpression> - </textField> - </band> - </title> - <detail> - <band height="303" splitType="Stretch"> - <componentElement> - <reportElement x="0" y="0" width="800" height="300" uuid="854b8278-360a-4dba-9bd1-3a77189f6478"> - <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/> - <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/> - <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/> - <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/> - </reportElement> - <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" - xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" - whenNoDataType="Blank"> - <datasetRun subDataset="TestItemsTableDS" uuid="05506102-a762-4b4f-8c9f-0bb284545e94"> - <dataSourceExpression> - <![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{TEST_ITEMS}, false)]]></dataSourceExpression> - </datasetRun> - <jr:column width="90" uuid="b2569992-2bd8-4ff9-a9b3-368d2ca026b7"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/> - <property name="com.jaspersoft.studio.unit.height" value="pixel"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="90" height="30" uuid="6ac25c5d-aa07-4c0d-a578-53d2e0f96d42"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Type]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <property name="com.jaspersoft.studio.unit.height" value="px"/> - <textField> - <reportElement x="0" y="0" width="90" height="20" uuid="113268f0-68f2-4c5e-b580-ff200e7b853c"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{type}]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="209" uuid="44a6a309-83bd-4546-b0cd-b10728e874dd"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="209" height="30" uuid="ca534fe2-78f2-44f6-9b03-9bc32970c178"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Name]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField isStretchWithOverflow="true"> - <reportElement x="0" y="0" width="209" height="20" uuid="1ed705a6-1478-4fa5-82d0-f626e5aa6f7e"/> - <textElement verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="50" uuid="4c3f0fac-1fb3-467d-81a7-36b9b2d84302"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column13"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="50" height="30" uuid="3fe70789-6869-4b8d-bf21-be0fc66b623e"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Duration (sec)]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="50" height="20" uuid="ba201ea1-3041-4d50-b546-d3b9a4ce5543"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{duration}]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="70" uuid="4c3f0fac-1fb3-467d-81a7-36b9b2d84401"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="70" height="30" uuid="3fe70789-6869-4b8d-bf21-be0fc66b619e"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Status]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="70" height="20" uuid="ba201ea1-3041-4d50-b546-d3b9a4ce5433"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{status}]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="299a618c-60b1-45ee-bfd3-dfee01b8a36c"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column4"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="c4fef87b-707e-4406-8821-a3690eaf04a9"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Total]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="ba96f816-5077-44a1-b820-76375d356550"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{total}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="51" uuid="036301ab-1dbb-4ab1-a25b-206fc3871d54"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column5"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="51" height="30" uuid="a5bfbd41-ceb3-4cc0-a823-dbccdc163799"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Passed]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="51" height="20" uuid="c714fea4-aa63-4704-a36d-148cc6720185"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{passed}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="012751ee-ecd0-4259-aaaa-8bf219a2269a"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column6"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="e705346a-5e09-4d83-addd-1f514ec17b6d"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Failed]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="258d73ee-ddef-4902-bbce-a424d2c4f130"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{failed}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="50" uuid="08db46ac-76eb-416c-97e7-c3748e6671fa"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column7"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="50" height="30" uuid="1ae2a81b-db01-49f0-b25c-89cfc989eb41"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[Skipped]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="50" height="20" uuid="508d7d97-04ff-4734-b0e9-826fdc2b30f6"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{skipped}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="6fe1d4d9-e98e-408a-bbfd-9217632c4248"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column8"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="ed1bfe30-4c47-4fc2-9902-7e98261b56b0"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[AB]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="568bf98d-a032-4242-8ea5-c509d07952a5"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{automationBug}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="64a44a55-7fd1-4937-977a-d393be83748a"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column9"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="3e6f717a-5f91-4db4-a849-4aeeac81ecb2"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[PB]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="65fe9d6e-8e44-46d6-a795-3298db9b40b2"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{productBug}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="fbe03a89-85d3-489a-82bf-571bc9901603"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column10"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="9175f909-a932-455c-8719-00c20d39fd21"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[SI]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="f917ddc4-503b-4911-89ca-a8c1b63ce588"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{systemIssue}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="2ef87095-2dc4-4b56-9383-06bcca1017a6"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column11"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="b1c0a90a-1757-45fc-95cb-370a7d20b262"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[ND]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="d18e6732-4b1b-4dbe-af93-53af34f8a530"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{noDefect}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - <jr:column width="40" uuid="ea408a50-e25d-487f-aaa8-ce4686ce4d2f"> - <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column12"/> - <jr:columnHeader style="Table_CH" height="30" rowSpan="1"> - <staticText> - <reportElement x="0" y="0" width="40" height="30" uuid="03c2d2fb-cb4a-48fc-b18d-4a6b3ba2fabc"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9" isBold="true"/> - </textElement> - <text><![CDATA[TI]]></text> - </staticText> - </jr:columnHeader> - <jr:detailCell style="Table_TD" height="20"> - <textField> - <reportElement x="0" y="0" width="40" height="20" uuid="798423a0-99ec-4bc6-a82a-e95235ffbdd7"/> - <textElement textAlignment="Center" verticalAlignment="Middle"> - <font fontName="Noto Sans" size="9"/> - </textElement> - <textFieldExpression><![CDATA[$F{toInvestigate}.toString()]]></textFieldExpression> - </textField> - </jr:detailCell> - </jr:column> - </jr:table> - </componentElement> - </band> - </detail> - <pageFooter> - <band height="22"> - <textField> - <reportElement x="680" y="0" width="60" height="20" uuid="27912fc5-278f-4ede-aff7-d2bbe49124b8"/> - <textElement textAlignment="Right"/> - <textFieldExpression><![CDATA["Page " + $V{PAGE_NUMBER}]]></textFieldExpression> - </textField> - <textField evaluationTime="Report"> - <reportElement x="740" y="0" width="60" height="20" uuid="1f1297e2-e72a-49b7-9220-7ae53baf1c09"/> - <textElement textAlignment="Left"/> - <textFieldExpression><![CDATA[" of " + $V{PAGE_NUMBER}]]></textFieldExpression> - </textField> - </band> - </pageFooter> + <textFieldExpression><![CDATA[$F{toInvestigate}.toString()]]></textFieldExpression> + </textField> + </jr:detailCell> + </jr:column> + </jr:table> + </componentElement> + </band> + </detail> + <pageFooter> + <band height="22"> + <textField> + <reportElement x="680" y="0" width="60" height="20" + uuid="27912fc5-278f-4ede-aff7-d2bbe49124b8"/> + <textElement textAlignment="Right"/> + <textFieldExpression><![CDATA["Page " + $V{PAGE_NUMBER}]]></textFieldExpression> + </textField> + <textField evaluationTime="Report"> + <reportElement x="740" y="0" width="60" height="20" + uuid="1f1297e2-e72a-49b7-9220-7ae53baf1c09"/> + <textElement textAlignment="Left"/> + <textFieldExpression><![CDATA[" of " + $V{PAGE_NUMBER}]]></textFieldExpression> + </textField> + </band> + </pageFooter> </jasperReport> diff --git a/src/main/resources/templates/report/users.jrxml b/src/main/resources/templates/report/users.jrxml index 43a0d2822f..b5802d2091 100644 --- a/src/main/resources/templates/report/users.jrxml +++ b/src/main/resources/templates/report/users.jrxml @@ -16,135 +16,163 @@ --> <!-- Created with Jaspersoft Studio version 6.6.0.final using JasperReports Library version 6.6.0 --> -<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" - name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" rightMargin="20" - topMargin="20" bottomMargin="20" uuid="7a5c9b49-9dc5-422a-ac69-e92cf61ef530" isIgnorePagination="true"> - <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> - <style name="Title" forecolor="#FFFFFF" fontName="Noto Sans" fontSize="50" isBold="false"/> - <style name="SubTitle" forecolor="#CCCCCC" fontName="Noto Sans" fontSize="18" isBold="false"/> - <style name="Column header" forecolor="#666666" fontName="Noto Sans" fontSize="14" isBold="true"/> - <style name="Detail" mode="Transparent" fontName="Noto Sans"/> - <style name="Row" mode="Transparent" fontName="Noto Sans" pdfFontName="Times-Roman"> - <conditionalStyle> - <conditionExpression><![CDATA[$V{REPORT_COUNT}%2 == 0]]></conditionExpression> - <style mode="Opaque" backcolor="#F0EFEF"/> - </conditionalStyle> - </style> - <queryString> - <![CDATA[]]> - </queryString> - <field name="Full name" class="java.lang.String"/> - <field name="Type" class="java.lang.String"/> - <field name="Login" class="java.lang.String"/> - <field name="Email" class="java.lang.String"/> - <field name="Last login" class="java.lang.String"/> - <field name="Projects and Roles" class="java.lang.String"/> - <background> - <band splitType="Stretch"/> - </background> - <columnHeader> - <band height="23" splitType="Stretch"> - <staticText> - <reportElement x="0" y="0" width="180" height="18" uuid="1e0d3905-6d0e-4660-ac0a-9b6ca6b47b93"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Full name]]></text> - </staticText> - <staticText> - <reportElement x="180" y="0" width="80" height="18" uuid="82d59e26-2731-4f85-b1ee-3179b20e6f07"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Type]]></text> - </staticText> - <staticText> - <reportElement x="260" y="0" width="150" height="18" uuid="64cc94b9-8766-49b1-8b9f-e45296c5c9c7"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Login]]></text> - </staticText> - <staticText> - <reportElement x="410" y="0" width="150" height="18" uuid="b0549432-b1b4-41af-931e-7e25e63d738c"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Email]]></text> - </staticText> - <staticText> - <reportElement x="560" y="0" width="120" height="18" uuid="e0ddb3e8-ddc4-41af-b0bb-5299862be558"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Last login]]></text> - </staticText> - <staticText> - <reportElement x="680" y="0" width="117" height="18" uuid="ac60d496-d8c7-4543-b8da-1112cde3fc2c"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="d4571106-56c2-445d-a317-a38effb2595b"/> - </reportElement> - <textElement textAlignment="Center"/> - <text><![CDATA[Projects and Roles]]></text> - </staticText> - </band> - </columnHeader> - <detail> - <band height="18" splitType="Stretch"> - <frame> - <reportElement style="Row" mode="Opaque" x="0" y="0" width="797" height="18" uuid="34a2ae4b-4055-476b-8676-d499f6af510b"/> - <textField> - <reportElement x="0" y="0" width="180" height="30" uuid="42609d3f-7d28-44f2-b8ea-650fbbcf746f"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Full name}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="180" y="0" width="80" height="30" uuid="9d167ef4-d39b-4963-9d55-593d5a6e388a"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Type}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="260" y="0" width="150" height="30" uuid="66d3c031-147d-40f1-a43b-d1d9a3a6e457"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Login}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="410" y="0" width="150" height="30" uuid="d4aa9cdc-f50c-4cb9-9246-f0f57250f17f"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Email}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="560" y="0" width="120" height="30" uuid="47939077-bc56-4fc7-85b9-2942fcaddaa0"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center"/> - <textFieldExpression><![CDATA[$F{Last login}]]></textFieldExpression> - </textField> - <textField> - <reportElement x="680" y="0" width="117" height="30" uuid="5fc335bb-6c5a-46ac-b345-fbefa1deec6a"> - <property name="com.jaspersoft.studio.spreadsheet.connectionID" value="d4571106-56c2-445d-a317-a38effb2595b"/> - <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> - </reportElement> - <textElement textAlignment="Center" verticalAlignment="Top"/> - <textFieldExpression><![CDATA[$F{Projects and Roles}]]></textFieldExpression> - </textField> - </frame> - </band> - </detail> - <summary> - <band splitType="Stretch"/> - </summary> +<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" + name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" + leftMargin="20" rightMargin="20" + topMargin="20" bottomMargin="20" uuid="7a5c9b49-9dc5-422a-ac69-e92cf61ef530" + isIgnorePagination="true"> + <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> + <style name="Title" forecolor="#FFFFFF" fontName="Noto Sans" fontSize="50" isBold="false"/> + <style name="SubTitle" forecolor="#CCCCCC" fontName="Noto Sans" fontSize="18" isBold="false"/> + <style name="Column header" forecolor="#666666" fontName="Noto Sans" fontSize="14" isBold="true"/> + <style name="Detail" mode="Transparent" fontName="Noto Sans"/> + <style name="Row" mode="Transparent" fontName="Noto Sans" pdfFontName="Times-Roman"> + <conditionalStyle> + <conditionExpression><![CDATA[$V{REPORT_COUNT}%2 == 0]]></conditionExpression> + <style mode="Opaque" backcolor="#F0EFEF"/> + </conditionalStyle> + </style> + <queryString> + <![CDATA[]]> + </queryString> + <field name="Full name" class="java.lang.String"/> + <field name="Type" class="java.lang.String"/> + <field name="Login" class="java.lang.String"/> + <field name="Email" class="java.lang.String"/> + <field name="Last login" class="java.lang.String"/> + <field name="Projects and Roles" class="java.lang.String"/> + <background> + <band splitType="Stretch"/> + </background> + <columnHeader> + <band height="23" splitType="Stretch"> + <staticText> + <reportElement x="0" y="0" width="180" height="18" + uuid="1e0d3905-6d0e-4660-ac0a-9b6ca6b47b93"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Full name]]></text> + </staticText> + <staticText> + <reportElement x="180" y="0" width="80" height="18" + uuid="82d59e26-2731-4f85-b1ee-3179b20e6f07"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Type]]></text> + </staticText> + <staticText> + <reportElement x="260" y="0" width="150" height="18" + uuid="64cc94b9-8766-49b1-8b9f-e45296c5c9c7"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Login]]></text> + </staticText> + <staticText> + <reportElement x="410" y="0" width="150" height="18" + uuid="b0549432-b1b4-41af-931e-7e25e63d738c"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Email]]></text> + </staticText> + <staticText> + <reportElement x="560" y="0" width="120" height="18" + uuid="e0ddb3e8-ddc4-41af-b0bb-5299862be558"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Last login]]></text> + </staticText> + <staticText> + <reportElement x="680" y="0" width="117" height="18" + uuid="ac60d496-d8c7-4543-b8da-1112cde3fc2c"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="d4571106-56c2-445d-a317-a38effb2595b"/> + </reportElement> + <textElement textAlignment="Center"/> + <text><![CDATA[Projects and Roles]]></text> + </staticText> + </band> + </columnHeader> + <detail> + <band height="18" splitType="Stretch"> + <frame> + <reportElement style="Row" mode="Opaque" x="0" y="0" width="797" height="18" + uuid="34a2ae4b-4055-476b-8676-d499f6af510b"/> + <textField> + <reportElement x="0" y="0" width="180" height="30" + uuid="42609d3f-7d28-44f2-b8ea-650fbbcf746f"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Full name}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="180" y="0" width="80" height="30" + uuid="9d167ef4-d39b-4963-9d55-593d5a6e388a"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="f172f0b8-1df3-4c59-bec2-45f6582696e3"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Type}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="260" y="0" width="150" height="30" + uuid="66d3c031-147d-40f1-a43b-d1d9a3a6e457"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="3ebec559-1ba4-4dc0-978b-ff46d0298c59"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Login}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="410" y="0" width="150" height="30" + uuid="d4aa9cdc-f50c-4cb9-9246-f0f57250f17f"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="0eca9f7f-619a-44d6-9cf6-46dc79e5e251"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Email}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="560" y="0" width="120" height="30" + uuid="47939077-bc56-4fc7-85b9-2942fcaddaa0"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="7d2a698e-beb1-4dbb-b059-0654b305955e"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center"/> + <textFieldExpression><![CDATA[$F{Last login}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="680" y="0" width="117" height="30" + uuid="5fc335bb-6c5a-46ac-b345-fbefa1deec6a"> + <property name="com.jaspersoft.studio.spreadsheet.connectionID" + value="d4571106-56c2-445d-a317-a38effb2595b"/> + <property name="net.sf.jasperreports.print.keep.full.text" value="true"/> + </reportElement> + <textElement textAlignment="Center" verticalAlignment="Top"/> + <textFieldExpression><![CDATA[$F{Projects and Roles}]]></textFieldExpression> + </textField> + </frame> + </band> + </detail> + <summary> + <band splitType="Stretch"/> + </summary> </jasperReport> diff --git a/src/test/java/com/epam/ta/reportportal/ReportPortalUserUtil.java b/src/test/java/com/epam/ta/reportportal/ReportPortalUserUtil.java index 2ce24d750f..1b72d998e8 100644 --- a/src/test/java/com/epam/ta/reportportal/ReportPortalUserUtil.java +++ b/src/test/java/com/epam/ta/reportportal/ReportPortalUserUtil.java @@ -28,23 +28,24 @@ */ public class ReportPortalUserUtil { - public static final String TEST_PROJECT_NAME = "test_project"; + public static final String TEST_PROJECT_NAME = "test_project"; - private ReportPortalUserUtil() { - //static only - } + private ReportPortalUserUtil() { + //static only + } - public static ReportPortalUser getRpUser(String login, UserRole userRole, ProjectRole projectRole, Long projectId) { - return ReportPortalUser.userBuilder() - .withUserName(login) - .withPassword("test") - .withAuthorities(Sets.newHashSet(new SimpleGrantedAuthority(userRole.getAuthority()))) - .withUserId(1L) - .withEmail("test@email.com") - .withUserRole(userRole) - .withProjectDetails(Maps.newHashMap("test_project", - new ReportPortalUser.ProjectDetails(projectId, TEST_PROJECT_NAME, projectRole) - )) - .build(); - } + public static ReportPortalUser getRpUser(String login, UserRole userRole, ProjectRole projectRole, + Long projectId) { + return ReportPortalUser.userBuilder() + .withUserName(login) + .withPassword("test") + .withAuthorities(Sets.newHashSet(new SimpleGrantedAuthority(userRole.getAuthority()))) + .withUserId(1L) + .withEmail("test@email.com") + .withUserRole(userRole) + .withProjectDetails(Maps.newHashMap("test_project", + new ReportPortalUser.ProjectDetails(projectId, TEST_PROJECT_NAME, projectRole) + )) + .build(); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/TestConfig.java b/src/test/java/com/epam/ta/reportportal/TestConfig.java index 2975908dd5..0effafeacb 100644 --- a/src/test/java/com/epam/ta/reportportal/TestConfig.java +++ b/src/test/java/com/epam/ta/reportportal/TestConfig.java @@ -24,14 +24,20 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.rabbitmq.http.client.Client; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; +import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Profile; import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; @@ -40,58 +46,65 @@ * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Configuration -@EnableAutoConfiguration(exclude = { QuartzAutoConfiguration.class, RabbitAutoConfiguration.class }) -@ComponentScan(value = { "com.epam.ta.reportportal" }, excludeFilters = { - @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.epam.ta.reportportal.ws.rabbit.*"), - @ComponentScan.Filter(type = FilterType.REGEX, pattern = { "com.epam.ta.reportportal.job.*" }), - @ComponentScan.Filter(type = FilterType.REGEX, pattern = { "com.epam.ta.reportportal.core.integration.migration.*" }), - @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ApplicationContextAwareFactoryBeanTest.TestConfig.class) }) +@EnableAutoConfiguration(exclude = {QuartzAutoConfiguration.class, RabbitAutoConfiguration.class}) +@ComponentScan(value = {"com.epam.ta.reportportal"}, excludeFilters = { + @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.epam.ta.reportportal.ws.rabbit.*"), + @ComponentScan.Filter(type = FilterType.REGEX, pattern = {"com.epam.ta.reportportal.job.*"}), + @ComponentScan.Filter(type = FilterType.REGEX, pattern = { + "com.epam.ta.reportportal.core.integration.migration.*"}), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ApplicationContextAwareFactoryBeanTest.TestConfig.class)}) public class TestConfig { - @MockBean - protected Client rabbitClient; + @MockBean + protected Client rabbitClient; - @MockBean(name = "analyzerRabbitTemplate") - protected RabbitTemplate analyzerRabbitTemplate; + @MockBean(name = "analyzerRabbitTemplate") + protected RabbitTemplate analyzerRabbitTemplate; - @MockBean(name = "rabbitTemplate") - protected RabbitTemplate rabbitTemplate; + @MockBean(name = "rabbitTemplate") + protected RabbitTemplate rabbitTemplate; - @MockBean - protected MessageConverter messageConverter; + @MockBean(name = "connectionFactory") + protected ConnectionFactory connectionFactory; - @Autowired - private DatabaseUserDetailsService userDetailsService; + @MockBean(name = "simpleRabbitListenerContainerFactoryConfigurer") + protected SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContainerFactoryConfigurer; - @Bean - @Profile("unittest") - protected RabbitMqManagementClient managementTemplate() { - return new RabbitMqManagementClientTemplate(rabbitClient, "analyzer"); - } + @MockBean + protected MessageConverter messageConverter; - @Bean - @Profile("unittest") - public JwtAccessTokenConverter accessTokenConverter() { - JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter(); - jwtConverter.setSigningKey("123"); + @Autowired + private DatabaseUserDetailsService userDetailsService; - DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); - DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); - defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); - accessTokenConverter.setUserTokenConverter(defaultUserAuthenticationConverter); + @Bean + @Profile("unittest") + protected RabbitMqManagementClient managementTemplate() { + return new RabbitMqManagementClientTemplate(rabbitClient, "analyzer"); + } - jwtConverter.setAccessTokenConverter(accessTokenConverter); + @Bean + @Profile("unittest") + public JwtAccessTokenConverter accessTokenConverter() { + JwtAccessTokenConverter jwtConverter = new JwtAccessTokenConverter(); + jwtConverter.setSigningKey("123"); - return jwtConverter; - } + DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); + DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter(); + defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService); + accessTokenConverter.setUserTokenConverter(defaultUserAuthenticationConverter); - @Bean - public ObjectMapper testObjectMapper() { - ObjectMapper objectMapper = new ObjectMapper(); + jwtConverter.setAccessTokenConverter(accessTokenConverter); - objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); - objectMapper.registerModule(new JavaTimeModule()); + return jwtConverter; + } - return objectMapper; - } + @Bean + public ObjectMapper testObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + + objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false); + objectMapper.registerModule(new JavaTimeModule()); + + return objectMapper; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/auth/OAuthHelper.java b/src/test/java/com/epam/ta/reportportal/auth/OAuthHelper.java index dfe60f28d6..407a7f4cdb 100644 --- a/src/test/java/com/epam/ta/reportportal/auth/OAuthHelper.java +++ b/src/test/java/com/epam/ta/reportportal/auth/OAuthHelper.java @@ -17,6 +17,13 @@ package com.epam.ta.reportportal.auth; import com.epam.ta.reportportal.entity.user.UserRole; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; @@ -28,66 +35,66 @@ import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.stereotype.Component; -import java.util.*; -import java.util.stream.Collectors; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Component public class OAuthHelper { - @Autowired - private AuthorizationServerTokenServices tokenService; + @Autowired + private AuthorizationServerTokenServices tokenService; - private String defaultToken; + private String defaultToken; - private String superadminToken; + private String superadminToken; - private String customerToken; + private String customerToken; - public String getDefaultToken() { - return defaultToken == null ? defaultToken = createAccessToken("default", "1q2w3e", UserRole.USER).getValue() : defaultToken; - } + public String getDefaultToken() { + return defaultToken == null ? defaultToken = createAccessToken("default", "1q2w3e", + UserRole.USER).getValue() : defaultToken; + } - public String getSuperadminToken() { - return superadminToken == null ? - superadminToken = createAccessToken("superadmin", "erebus", UserRole.ADMINISTRATOR).getValue() : - superadminToken; - } + public String getSuperadminToken() { + return superadminToken == null ? + superadminToken = createAccessToken("superadmin", "erebus", + UserRole.ADMINISTRATOR).getValue() : + superadminToken; + } - public String getCustomerToken() { - return customerToken == null ? - customerToken = createAccessToken("default_customer", "erebus", UserRole.USER).getValue() : - customerToken; - } + public String getCustomerToken() { + return customerToken == null ? + customerToken = createAccessToken("default_customer", "erebus", UserRole.USER).getValue() : + customerToken; + } - private OAuth2AccessToken createAccessToken(String username, String password, UserRole... roles) { - Collection<GrantedAuthority> authorities = Arrays.stream(roles) - .map(it -> new SimpleGrantedAuthority(it.getAuthority())) - .collect(Collectors.toList()); + private OAuth2AccessToken createAccessToken(String username, String password, UserRole... roles) { + Collection<GrantedAuthority> authorities = Arrays.stream(roles) + .map(it -> new SimpleGrantedAuthority(it.getAuthority())) + .collect(Collectors.toList()); - Set<String> scopes = Collections.singleton("ui"); + Set<String> scopes = Collections.singleton("ui"); - Map<String, String> requestParameters = new HashMap<>(); - requestParameters.put("password", password); - requestParameters.put("grand_type", "password"); - requestParameters.put("username", username); + Map<String, String> requestParameters = new HashMap<>(); + requestParameters.put("password", password); + requestParameters.put("grand_type", "password"); + requestParameters.put("username", username); - OAuth2Request oAuth2Request = new OAuth2Request( - requestParameters, - "ui", - authorities, - true, - scopes, - Collections.emptySet(), - null, - Collections.emptySet(), - Collections.emptyMap() - ); - User userPrincipal = new User(username, password, true, true, true, true, authorities); - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal, null, authorities); - OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken); - return tokenService.createAccessToken(auth); - } + OAuth2Request oAuth2Request = new OAuth2Request( + requestParameters, + "ui", + authorities, + true, + scopes, + Collections.emptySet(), + null, + Collections.emptySet(), + Collections.emptyMap() + ); + User userPrincipal = new User(username, password, true, true, true, true, authorities); + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + userPrincipal, null, authorities); + OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken); + return tokenService.createAccessToken(auth); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/auth/UserRoleHierarchyTest.java b/src/test/java/com/epam/ta/reportportal/auth/UserRoleHierarchyTest.java index e7bc03d8a3..dbc8717f8d 100644 --- a/src/test/java/com/epam/ta/reportportal/auth/UserRoleHierarchyTest.java +++ b/src/test/java/com/epam/ta/reportportal/auth/UserRoleHierarchyTest.java @@ -16,33 +16,33 @@ package com.epam.ta.reportportal.auth; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Collection; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; -import java.util.Collection; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - /** * Created by Andrey_Ivanov1 on 05-Jun-17. */ class UserRoleHierarchyTest { - @InjectMocks - private UserRoleHierarchy userRoleHierarchy = new UserRoleHierarchy(); - - @Test - void getReachableGrantedAuthoritiesTest() { - String string_for_auth = "ROLE_1,ROLE_2,ROLE_3,ROLE_4"; - Collection<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(string_for_auth); - assertNotNull(userRoleHierarchy.getReachableGrantedAuthorities(authorities)); - } - - @Test - void nullAuthoritiesTest() { - Collection<GrantedAuthority> authorities = null; - assertNotNull(userRoleHierarchy.getReachableGrantedAuthorities(authorities)); - } + @InjectMocks + private UserRoleHierarchy userRoleHierarchy = new UserRoleHierarchy(); + + @Test + void getReachableGrantedAuthoritiesTest() { + String string_for_auth = "ROLE_1,ROLE_2,ROLE_3,ROLE_4"; + Collection<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList( + string_for_auth); + assertNotNull(userRoleHierarchy.getReachableGrantedAuthorities(authorities)); + } + + @Test + void nullAuthoritiesTest() { + Collection<GrantedAuthority> authorities = null; + assertNotNull(userRoleHierarchy.getReachableGrantedAuthorities(authorities)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsServiceTest.java b/src/test/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsServiceTest.java index 704cbfd361..10f7797491 100644 --- a/src/test/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/auth/basic/DatabaseUserDetailsServiceTest.java @@ -16,7 +16,12 @@ package com.epam.ta.reportportal.auth.basic; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.UserRepository; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -24,32 +29,26 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class DatabaseUserDetailsServiceTest { - @Mock - private UserRepository userRepository; + @Mock + private UserRepository userRepository; - @InjectMocks - private DatabaseUserDetailsService userDetailsService; + @InjectMocks + private DatabaseUserDetailsService userDetailsService; - @Test - void userNotFoundTest() { - when(userRepository.findReportPortalUser("not_exist")).thenReturn(Optional.empty()); + @Test + void userNotFoundTest() { + when(userRepository.findReportPortalUser("not_exist")).thenReturn(Optional.empty()); - UsernameNotFoundException exception = assertThrows(UsernameNotFoundException.class, - () -> userDetailsService.loadUserByUsername("not_exist") - ); + UsernameNotFoundException exception = assertThrows(UsernameNotFoundException.class, + () -> userDetailsService.loadUserByUsername("not_exist") + ); - assertEquals("User not found", exception.getMessage()); - } + assertEquals("User not found", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtilsTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtilsTest.java index 39a100fa5c..3c1e0d843e 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtilsTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/AnalyzerUtilsTest.java @@ -16,49 +16,55 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_INDEX; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_LOG_SEARCH; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_PRIORITY; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.DOES_SUPPORT_SEARCH; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.google.common.collect.ImmutableMap; import com.rabbitmq.http.client.domain.ExchangeInfo; -import org.junit.jupiter.api.Test; - import java.util.Collections; - -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; /** * @author Pavel Bortnik */ class AnalyzerUtilsTest { - @Test - void testParsing() { - ExchangeInfo mock = mock(ExchangeInfo.class); - when(mock.getArguments()).thenReturn(ImmutableMap.<String, Object>builder().put(ANALYZER_PRIORITY, 1) - .put(ANALYZER_INDEX, true) - .build()); - assertEquals(1, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); - assertTrue(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); - } + @Test + void testParsing() { + ExchangeInfo mock = mock(ExchangeInfo.class); + when(mock.getArguments()).thenReturn( + ImmutableMap.<String, Object>builder().put(ANALYZER_PRIORITY, 1) + .put(ANALYZER_INDEX, true) + .build()); + assertEquals(1, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); + assertTrue(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); + } - @Test - void testDefaultValues() { - ExchangeInfo mock = mock(ExchangeInfo.class); - when(mock.getArguments()).thenReturn(Collections.emptyMap()); - assertEquals(Integer.MAX_VALUE, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); - assertFalse(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); - } + @Test + void testDefaultValues() { + ExchangeInfo mock = mock(ExchangeInfo.class); + when(mock.getArguments()).thenReturn(Collections.emptyMap()); + assertEquals(Integer.MAX_VALUE, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); + assertFalse(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); + } - @Test - void testBadValues() { - ExchangeInfo mock = mock(ExchangeInfo.class); - when(mock.getArguments()).thenReturn(ImmutableMap.<String, Object>builder().put(ANALYZER_PRIORITY, "abracadabra") - .put(ANALYZER_INDEX, "666") - .put(ANALYZER_LOG_SEARCH, "666") - .build()); - assertEquals(Integer.MAX_VALUE, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); - assertFalse(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); - assertFalse(DOES_SUPPORT_SEARCH.test(mock)); - } + @Test + void testBadValues() { + ExchangeInfo mock = mock(ExchangeInfo.class); + when(mock.getArguments()).thenReturn( + ImmutableMap.<String, Object>builder().put(ANALYZER_PRIORITY, "abracadabra") + .put(ANALYZER_INDEX, "666") + .put(ANALYZER_LOG_SEARCH, "666") + .build()); + assertEquals(Integer.MAX_VALUE, AnalyzerUtils.EXCHANGE_PRIORITY.applyAsInt(mock)); + assertFalse(AnalyzerUtils.DOES_SUPPORT_INDEX.test(mock)); + assertFalse(DOES_SUPPORT_SEARCH.test(mock)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImplTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImplTest.java index 314c8d9437..42fa363bff 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/IndexerServiceClientImplTest.java @@ -1,97 +1,108 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_INDEX; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_PRIORITY; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.IndexerServiceClientImpl.DEFECT_UPDATE_ROUTE; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.IndexerServiceClientImpl.DELETE_ROUTE; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.IndexerServiceClientImpl.ITEM_REMOVE_ROUTE; +import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.IndexerServiceClientImpl.LAUNCH_REMOVE_ROUTE; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.AUTO_ANALYZER_KEY; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; + import com.epam.ta.reportportal.core.analyzer.auto.client.RabbitMqManagementClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.IndexDefectsUpdate; import com.epam.ta.reportportal.core.analyzer.auto.client.model.IndexItemsRemove; import com.epam.ta.reportportal.core.analyzer.auto.client.model.IndexLaunchRemove; import com.rabbitmq.http.client.domain.ExchangeInfo; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.assertj.core.util.Lists; import org.assertj.core.util.Maps; import org.junit.jupiter.api.Test; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.core.ParameterizedTypeReference; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_INDEX; -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.AnalyzerUtils.ANALYZER_PRIORITY; -import static com.epam.ta.reportportal.core.analyzer.auto.client.impl.IndexerServiceClientImpl.*; -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache.AUTO_ANALYZER_KEY; -import static org.mockito.Mockito.*; -import static org.mockito.internal.verification.VerificationModeFactory.times; - class IndexerServiceClientImplTest { - private RabbitTemplate rabbitTemplate = mock(RabbitTemplate.class); + private RabbitTemplate rabbitTemplate = mock(RabbitTemplate.class); - private RabbitMqManagementClient rabbitMqManagementClient = mock(RabbitMqManagementClient.class); + private RabbitMqManagementClient rabbitMqManagementClient = mock(RabbitMqManagementClient.class); - private IndexerServiceClientImpl indexerServiceClient = new IndexerServiceClientImpl(rabbitMqManagementClient, rabbitTemplate); + private IndexerServiceClientImpl indexerServiceClient = new IndexerServiceClientImpl( + rabbitMqManagementClient, rabbitTemplate); - @Test - void deleteIndex() { - when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); - when(rabbitTemplate.convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, DELETE_ROUTE, 1L, new ParameterizedTypeReference<Integer>() { - })).thenReturn(1); - indexerServiceClient.deleteIndex(1L); - verify(rabbitTemplate, times(1)).convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, - DELETE_ROUTE, - 1L, - new ParameterizedTypeReference<Integer>() { - } - ); - } + @Test + void deleteIndex() { + when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); + when(rabbitTemplate.convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, DELETE_ROUTE, 1L, + new ParameterizedTypeReference<Integer>() { + })).thenReturn(1); + indexerServiceClient.deleteIndex(1L); + verify(rabbitTemplate, times(1)).convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, + DELETE_ROUTE, + 1L, + new ParameterizedTypeReference<Integer>() { + } + ); + } - @Test - void indexDefectsUpdate() { - Map<Long, String> update = Maps.newHashMap(1L, "pb001"); - IndexDefectsUpdate indexDefectsUpdate = new IndexDefectsUpdate(1L, update); - when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); - when(rabbitTemplate.convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, - DEFECT_UPDATE_ROUTE, - indexDefectsUpdate, - new ParameterizedTypeReference<List<Long>>() { - } - )).thenReturn(Lists.emptyList()); - indexerServiceClient.indexDefectsUpdate(1L, update); - verify(rabbitTemplate, times(1)).convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, - DEFECT_UPDATE_ROUTE, - indexDefectsUpdate, - new ParameterizedTypeReference<List<Long>>() { - } - ); - } + @Test + void indexDefectsUpdate() { + Map<Long, String> update = Maps.newHashMap(1L, "pb001"); + IndexDefectsUpdate indexDefectsUpdate = new IndexDefectsUpdate(1L, update); + when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); + when(rabbitTemplate.convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, + DEFECT_UPDATE_ROUTE, + indexDefectsUpdate, + new ParameterizedTypeReference<List<Long>>() { + } + )).thenReturn(Lists.emptyList()); + indexerServiceClient.indexDefectsUpdate(1L, update); + verify(rabbitTemplate, times(1)).convertSendAndReceiveAsType(AUTO_ANALYZER_KEY, + DEFECT_UPDATE_ROUTE, + indexDefectsUpdate, + new ParameterizedTypeReference<List<Long>>() { + } + ); + } - @Test - void indexItemsRemove() { - List<Long> list = Lists.newArrayList(1L); - IndexItemsRemove indexItemsRemove = new IndexItemsRemove(1L, list); - when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); - doNothing().when(rabbitTemplate).convertAndSend(AUTO_ANALYZER_KEY, ITEM_REMOVE_ROUTE, indexItemsRemove); - indexerServiceClient.indexItemsRemoveAsync(1L, list); - verify(rabbitTemplate, times(1)).convertAndSend(AUTO_ANALYZER_KEY, ITEM_REMOVE_ROUTE, indexItemsRemove); - } + @Test + void indexItemsRemove() { + List<Long> list = Lists.newArrayList(1L); + IndexItemsRemove indexItemsRemove = new IndexItemsRemove(1L, list); + when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); + doNothing().when(rabbitTemplate) + .convertAndSend(AUTO_ANALYZER_KEY, ITEM_REMOVE_ROUTE, indexItemsRemove); + indexerServiceClient.indexItemsRemoveAsync(1L, list); + verify(rabbitTemplate, times(1)).convertAndSend(AUTO_ANALYZER_KEY, ITEM_REMOVE_ROUTE, + indexItemsRemove); + } - @Test - void indexLaunchesRemove() { - List<Long> list = Lists.newArrayList(1L); - IndexLaunchRemove indexLaunchRemove = new IndexLaunchRemove(1L, list); - when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); - doNothing().when(rabbitTemplate).convertAndSend(AUTO_ANALYZER_KEY, LAUNCH_REMOVE_ROUTE, indexLaunchRemove); - indexerServiceClient.indexLaunchesRemove(1L, list); - verify(rabbitTemplate, times(1)).convertAndSend(AUTO_ANALYZER_KEY, LAUNCH_REMOVE_ROUTE, indexLaunchRemove); - } + @Test + void indexLaunchesRemove() { + List<Long> list = Lists.newArrayList(1L); + IndexLaunchRemove indexLaunchRemove = new IndexLaunchRemove(1L, list); + when(rabbitMqManagementClient.getAnalyzerExchangesInfo()).thenReturn(getExchanges()); + doNothing().when(rabbitTemplate) + .convertAndSend(AUTO_ANALYZER_KEY, LAUNCH_REMOVE_ROUTE, indexLaunchRemove); + indexerServiceClient.indexLaunchesRemove(1L, list); + verify(rabbitTemplate, times(1)).convertAndSend(AUTO_ANALYZER_KEY, LAUNCH_REMOVE_ROUTE, + indexLaunchRemove); + } - private List<ExchangeInfo> getExchanges() { - ExchangeInfo exchangeInfo = new ExchangeInfo(); - Map<String, Object> params = new HashMap<>(); - params.put(ANALYZER_PRIORITY, 0); - params.put(ANALYZER_INDEX, true); - exchangeInfo.setArguments(params); - exchangeInfo.setName(AUTO_ANALYZER_KEY); - return Lists.newArrayList(exchangeInfo); - } + private List<ExchangeInfo> getExchanges() { + ExchangeInfo exchangeInfo = new ExchangeInfo(); + Map<String, Object> params = new HashMap<>(); + params.put(ANALYZER_PRIORITY, 0); + params.put(ANALYZER_INDEX, true); + exchangeInfo.setArguments(params); + exchangeInfo.setName(AUTO_ANALYZER_KEY); + return Lists.newArrayList(exchangeInfo); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplateTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplateTest.java index 282d7ed811..e465dfbcdc 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplateTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/client/impl/RabbitMqManagementClientTemplateTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.analyzer.auto.client.impl; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.exception.ReportPortalException; import com.rabbitmq.http.client.Client; import org.junit.jupiter.api.Test; @@ -23,23 +26,21 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) public class RabbitMqManagementClientTemplateTest { - @Mock - private Client rabbitClient; + @Mock + private Client rabbitClient; - private RabbitMqManagementClientTemplate template; + private RabbitMqManagementClientTemplate template; - @Test - public void testReportPortalExceptionOnGetExchanges() { - template = new RabbitMqManagementClientTemplate(rabbitClient, "analyzer"); + @Test + public void testReportPortalExceptionOnGetExchanges() { + template = new RabbitMqManagementClientTemplate(rabbitClient, "analyzer"); - when(rabbitClient.getExchanges("analyzer")).thenReturn(null); + when(rabbitClient.getExchanges("analyzer")).thenReturn(null); - assertThatThrownBy(() -> template.getAnalyzerExchangesInfo()).isInstanceOf(ReportPortalException.class); - } + assertThatThrownBy(() -> template.getAnalyzerExchangesInfo()).isInstanceOf( + ReportPortalException.class); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceServiceTest.java index 6dbd87acbe..ac87b36b49 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerServiceServiceTest.java @@ -16,10 +16,23 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; +import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.PRODUCT_BUG; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; + import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.preparer.LaunchPreparerService; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; +import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.enums.StatusEnum; @@ -34,153 +47,159 @@ import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; -import static com.epam.ta.reportportal.entity.enums.TestItemIssueGroup.PRODUCT_BUG; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.*; -import static org.mockito.internal.verification.VerificationModeFactory.times; +import org.junit.jupiter.api.Test; /** * @author Pavel Bortnik */ class AnalyzerServiceServiceTest { - private AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); + private AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); - private IssueTypeHandler issueTypeHandler = mock(IssueTypeHandler.class); + private IssueTypeHandler issueTypeHandler = mock(IssueTypeHandler.class); - private TestItemRepository testItemRepository = mock(TestItemRepository.class); + private TestItemRepository testItemRepository = mock(TestItemRepository.class); - private MessageBus messageBus = mock(MessageBus.class); - - private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + private LaunchRepository launchRepository = mock(LaunchRepository.class); + + private MessageBus messageBus = mock(MessageBus.class); - private AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); - - private AnalyzerServiceImpl issuesAnalyzer = new AnalyzerServiceImpl(100, analyzerStatusCache, - launchPreparerService, - analyzerServiceClient, - issueTypeHandler, - testItemRepository, - messageBus - ); - - @Test - void hasAnalyzers() { - when(analyzerServiceClient.hasClients()).thenReturn(true); - assertTrue(issuesAnalyzer.hasAnalyzers()); - } - - @Test - void analyze() { - int itemsCount = 2; - - Launch launch = launch(); - - List<TestItem> items = testItemsTI(itemsCount); - items.forEach(item -> item.setLaunchId(launch.getId())); - - AnalyzerConfig analyzerConfig = analyzerConfig(); - - final IndexLaunch indexLaunch = new IndexLaunch(); - indexLaunch.setLaunchId(launch.getId()); - indexLaunch.setAnalyzerConfig(analyzerConfig); - - final List<IndexTestItem> indexTestItems = items.stream().map(AnalyzerUtils::fromTestItem).peek(item -> item.setLogs(errorLogs(2))).collect(Collectors.toList()); - indexLaunch.setTestItems(indexTestItems); - - when(testItemRepository.findAllById(anyList())).thenReturn(items); - - when(launchPreparerService.prepare(any(Launch.class), anyList(), any(AnalyzerConfig.class))).thenReturn(Optional.of(indexLaunch)); - - when(analyzerServiceClient.analyze(any())).thenReturn(analyzedItems(itemsCount)); - - when(issueTypeHandler.defineIssueType(anyLong(), eq("pb001"))).thenReturn(issueProductBug().getIssueType()); - - issuesAnalyzer.runAnalyzers(launch, items.stream().map(TestItem::getItemId).collect(Collectors.toList()), analyzerConfig); - - verify(analyzerServiceClient, times(1)).analyze(any()); - verify(testItemRepository, times(itemsCount)).save(any()); - verify(messageBus, times(4)).publishActivity(any()); - } - - private AnalyzerConfig analyzerConfig() { - AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); - return analyzerConfig; - } - - private Project project() { - Project project = new Project(); - project.setId(1L); - return project; - } - - private Launch launch() { - Launch launch = new Launch(); - launch.setId(1L); - launch.setName("launch"); - launch.setProjectId(1L); - return launch; - } - - private List<TestItem> testItemsTI(int count) { - List<TestItem> list = new ArrayList<>(count); - for (int i = 1; i <= count; i++) { - TestItem test = new TestItem(); - test.setItemId((long) i); - test.setName("test" + i); - test.setUniqueId("unique" + i); - test.setItemResults(new TestItemResults()); - test.getItemResults().setIssue(issueToInvestigate()); - test.getItemResults().setStatus(StatusEnum.FAILED); - list.add(test); - } - return list; - } - - private IssueEntity issueToInvestigate() { - IssueType issueType = new IssueType(); - issueType.setLocator("ti001"); - IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueType(issueType); - return issueEntity; - } - - private IssueEntity issueProductBug() { - IssueType issueType = new IssueType(); - issueType.setLocator("pb001"); - IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueType(issueType); - return issueEntity; - } - - private Set<IndexLog> errorLogs(int count) { - Set<IndexLog> logs = new HashSet<>(count); - for (int i = 1; i <= count; i++) { - IndexLog log = new IndexLog(); - log.setMessage("Error message " + i); - log.setLogLevel(LogLevel.ERROR.toInt()); - logs.add(log); - } - return logs; - } - - private Map<String, List<AnalyzedItemRs>> analyzedItems(int itemsCount) { - Map<String, List<AnalyzedItemRs>> res = new HashMap<>(); - List<AnalyzedItemRs> list = new ArrayList<>(); - for (int i = 1; i <= itemsCount; i++) { - AnalyzedItemRs testItem = new AnalyzedItemRs(); - testItem.setItemId((long) i); - testItem.setLocator(PRODUCT_BUG.getLocator()); - list.add(testItem); - } - res.put("test", list); - return res; - } + private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + + private AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); + + private AnalyzerServiceImpl issuesAnalyzer = new AnalyzerServiceImpl(100, analyzerStatusCache, + launchPreparerService, + analyzerServiceClient, + issueTypeHandler, + testItemRepository, + messageBus, + launchRepository + ); + + @Test + void hasAnalyzers() { + when(analyzerServiceClient.hasClients()).thenReturn(true); + assertTrue(issuesAnalyzer.hasAnalyzers()); + } + + @Test + void analyze() { + int itemsCount = 2; + + Launch launch = launch(); + + List<TestItem> items = testItemsTI(itemsCount); + items.forEach(item -> item.setLaunchId(launch.getId())); + + AnalyzerConfig analyzerConfig = analyzerConfig(); + + final IndexLaunch indexLaunch = new IndexLaunch(); + indexLaunch.setLaunchId(launch.getId()); + indexLaunch.setAnalyzerConfig(analyzerConfig); + + final List<IndexTestItem> indexTestItems = items.stream().map(AnalyzerUtils::fromTestItem) + .peek(item -> item.setLogs(errorLogs(2))).collect(Collectors.toList()); + indexLaunch.setTestItems(indexTestItems); + + when(testItemRepository.findAllById(anyList())).thenReturn(items); + + when(launchPreparerService.prepare(any(Launch.class), anyList(), + any(AnalyzerConfig.class))).thenReturn(Optional.of(indexLaunch)); + + when(analyzerServiceClient.analyze(any())).thenReturn(analyzedItems(itemsCount)); + + when(issueTypeHandler.defineIssueType(anyLong(), eq("pb001"))).thenReturn( + issueProductBug().getIssueType()); + + issuesAnalyzer.runAnalyzers(launch, + items.stream().map(TestItem::getItemId).collect(Collectors.toList()), analyzerConfig); + + verify(analyzerServiceClient, times(1)).analyze(any()); + verify(testItemRepository, times(itemsCount)).save(any()); + verify(messageBus, times(4)).publishActivity(any()); + } + + private AnalyzerConfig analyzerConfig() { + AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); + return analyzerConfig; + } + + private Project project() { + Project project = new Project(); + project.setId(1L); + return project; + } + + private Launch launch() { + Launch launch = new Launch(); + launch.setId(1L); + launch.setName("launch"); + launch.setProjectId(1L); + return launch; + } + + private List<TestItem> testItemsTI(int count) { + List<TestItem> list = new ArrayList<>(count); + for (int i = 1; i <= count; i++) { + TestItem test = new TestItem(); + test.setItemId((long) i); + test.setName("test" + i); + test.setUniqueId("unique" + i); + test.setItemResults(new TestItemResults()); + test.getItemResults().setIssue(issueToInvestigate()); + test.getItemResults().setStatus(StatusEnum.FAILED); + list.add(test); + } + return list; + } + + private IssueEntity issueToInvestigate() { + IssueType issueType = new IssueType(); + issueType.setLocator("ti001"); + IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueType(issueType); + return issueEntity; + } + + private IssueEntity issueProductBug() { + IssueType issueType = new IssueType(); + issueType.setLocator("pb001"); + IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueType(issueType); + return issueEntity; + } + + private Set<IndexLog> errorLogs(int count) { + Set<IndexLog> logs = new HashSet<>(count); + for (int i = 1; i <= count; i++) { + IndexLog log = new IndexLog(); + log.setMessage("Error message " + i); + log.setLogLevel(LogLevel.ERROR.toInt()); + logs.add(log); + } + return logs; + } + + private Map<String, List<AnalyzedItemRs>> analyzedItems(int itemsCount) { + Map<String, List<AnalyzedItemRs>> res = new HashMap<>(); + List<AnalyzedItemRs> list = new ArrayList<>(); + for (int i = 1; i <= itemsCount; i++) { + AnalyzedItemRs testItem = new AnalyzedItemRs(); + testItem.setItemId((long) i); + testItem.setLocator(PRODUCT_BUG.getLocator()); + list.add(testItem); + } + res.put("test", list); + return res; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtilsTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtilsTest.java index f1a8d1877e..79b91877e8 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtilsTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/AnalyzerUtilsTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.fromTestItem; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.attribute.Attribute; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; @@ -23,7 +28,7 @@ import com.epam.ta.reportportal.entity.item.TestItemResults; import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueType; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectUtils; import com.epam.ta.reportportal.ws.model.analyzer.IndexLog; @@ -31,131 +36,143 @@ import com.epam.ta.reportportal.ws.model.analyzer.RelevantItemInfo; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.epam.ta.reportportal.ws.model.project.UniqueErrorConfig; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerUtils.fromTestItem; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * @author Pavel Bortnik */ class AnalyzerUtilsTest { - @Test - void testConverting() { - TestItem testItem = createTest(); - testItem.getItemResults().setIssue(createIssue(false)); - IndexTestItem indexTestItem = fromTestItem(testItem); - indexTestItem.setLogs(createSameLogs(5)); - assertEquals(testItem.getItemId(), indexTestItem.getTestItemId()); - assertEquals(testItem.getUniqueId(), indexTestItem.getUniqueId()); - assertEquals(testItem.getStartTime(), indexTestItem.getStartTime()); - assertEquals(testItem.getItemResults().getIssue().getIssueType().getLocator(), indexTestItem.getIssueTypeLocator()); - assertEquals(1, indexTestItem.getLogs().size()); - assertFalse(indexTestItem.isAutoAnalyzed()); + @Test + void testConverting() { + TestItem testItem = createTest(); + testItem.getItemResults().setIssue(createIssue(false)); + IndexTestItem indexTestItem = fromTestItem(testItem); + indexTestItem.setLogs(createSameLogs(5)); + assertEquals(testItem.getItemId(), indexTestItem.getTestItemId()); + assertEquals(testItem.getUniqueId(), indexTestItem.getUniqueId()); + assertEquals(testItem.getStartTime(), indexTestItem.getStartTime()); + assertEquals(testItem.getItemResults().getIssue().getIssueType().getLocator(), + indexTestItem.getIssueTypeLocator()); + assertEquals(1, indexTestItem.getLogs().size()); + assertFalse(indexTestItem.isAutoAnalyzed()); + } + + @Test + void testConvertingAnalyzed() { + TestItem test = createTest(); + test.getItemResults().setIssue(createIssue(true)); + IndexTestItem indexTestItem = fromTestItem(test); + indexTestItem.setLogs(createSameLogs(1)); + assertTrue(indexTestItem.isAutoAnalyzed()); + } + + @Test + void testAnalyzerConfig() { + AnalyzerConfig config = AnalyzerUtils.getAnalyzerConfig(project()); + assertEquals(String.valueOf(config.getIsAutoAnalyzerEnabled()), + ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getDefaultValue()); + assertEquals(String.valueOf(config.getNumberOfLogLines()), + ProjectAttributeEnum.NUMBER_OF_LOG_LINES.getDefaultValue()); + assertEquals(config.getAnalyzerMode(), + ProjectAttributeEnum.AUTO_ANALYZER_MODE.getDefaultValue()); + assertEquals(String.valueOf(config.getMinShouldMatch()), + ProjectAttributeEnum.MIN_SHOULD_MATCH.getDefaultValue()); + assertEquals(String.valueOf(config.getSearchLogsMinShouldMatch()), + ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH.getDefaultValue()); + assertEquals(String.valueOf(config.isIndexingRunning()), + ProjectAttributeEnum.INDEXING_RUNNING.getDefaultValue()); + assertEquals(String.valueOf(config.isAllMessagesShouldMatch()), + ProjectAttributeEnum.ALL_MESSAGES_SHOULD_MATCH.getDefaultValue()); + } + + @Test + void testUniqueErrorConfig() { + final Map<String, String> configParameters = ProjectUtils.getConfigParameters( + project().getProjectAttributes()); + final UniqueErrorConfig config = AnalyzerUtils.getUniqueErrorConfig(configParameters); + assertEquals(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getDefaultValue(), + String.valueOf(config.isEnabled())); + assertEquals(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getDefaultValue(), + String.valueOf(config.isRemoveNumbers())); + } + + @Test + void testFromLogs() { + final LogFull logFull = new LogFull(); + logFull.setId(1L); + logFull.setLogMessage("Log message"); + logFull.setLogLevel(40000); + logFull.setClusterId(2L); + + final Set<IndexLog> indexLogs = AnalyzerUtils.fromLogs(List.of(logFull)); + final IndexLog indexLog = indexLogs.stream().findFirst().get(); + assertEquals(logFull.getId(), indexLog.getLogId()); + assertEquals(logFull.getLogMessage(), indexLog.getMessage()); + assertEquals(logFull.getLogLevel().intValue(), indexLog.getLogLevel()); + assertEquals(logFull.getClusterId(), indexLog.getClusterId()); + } + + @Test + void testToRelevantItemInfo() { + final TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setLaunchId(2L); + testItem.setPath("1"); + + final RelevantItemInfo itemInfo = AnalyzerUtils.TO_RELEVANT_ITEM_INFO.apply(testItem); + assertEquals(String.valueOf(testItem.getItemId()), itemInfo.getItemId()); + assertEquals(String.valueOf(testItem.getLaunchId()), itemInfo.getLaunchId()); + assertEquals(testItem.getPath(), itemInfo.getPath()); + } + + private TestItem createTest() { + TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); + testItem.setUniqueId("uniqueId"); + testItem.setItemResults(new TestItemResults()); + return testItem; + } + + private IssueEntity createIssue(boolean isAutoAnalyzed) { + IssueType issueType = new IssueType(); + issueType.setId(1L); + issueType.setLocator("locator"); + IssueEntity issue = new IssueEntity(); + issue.setAutoAnalyzed(isAutoAnalyzed); + issue.setIssueType(issueType); + return issue; + } + + private Set<IndexLog> createSameLogs(int count) { + Set<IndexLog> logs = new HashSet<>(); + for (int i = 0; i < count; i++) { + IndexLog log = new IndexLog(); + log.setLogLevel(LogLevel.ERROR.toInt()); + log.setMessage("Current message of the log"); + logs.add(log); } - - @Test - void testConvertingAnalyzed() { - TestItem test = createTest(); - test.getItemResults().setIssue(createIssue(true)); - IndexTestItem indexTestItem = fromTestItem(test); - indexTestItem.setLogs(createSameLogs(1)); - assertTrue(indexTestItem.isAutoAnalyzed()); - } - - @Test - void testAnalyzerConfig() { - AnalyzerConfig config = AnalyzerUtils.getAnalyzerConfig(project()); - assertEquals(String.valueOf(config.getIsAutoAnalyzerEnabled()), ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getDefaultValue()); - assertEquals(String.valueOf(config.getNumberOfLogLines()), ProjectAttributeEnum.NUMBER_OF_LOG_LINES.getDefaultValue()); - assertEquals(config.getAnalyzerMode(), ProjectAttributeEnum.AUTO_ANALYZER_MODE.getDefaultValue()); - assertEquals(String.valueOf(config.getMinShouldMatch()), ProjectAttributeEnum.MIN_SHOULD_MATCH.getDefaultValue()); - assertEquals(String.valueOf(config.getSearchLogsMinShouldMatch()), ProjectAttributeEnum.SEARCH_LOGS_MIN_SHOULD_MATCH.getDefaultValue()); - assertEquals(String.valueOf(config.isIndexingRunning()), ProjectAttributeEnum.INDEXING_RUNNING.getDefaultValue()); - assertEquals(String.valueOf(config.isAllMessagesShouldMatch()), ProjectAttributeEnum.ALL_MESSAGES_SHOULD_MATCH.getDefaultValue()); - } - - @Test - void testUniqueErrorConfig() { - final Map<String, String> configParameters = ProjectUtils.getConfigParameters(project().getProjectAttributes()); - final UniqueErrorConfig config = AnalyzerUtils.getUniqueErrorConfig(configParameters); - assertEquals(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getDefaultValue(), String.valueOf(config.isEnabled())); - assertEquals(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getDefaultValue(), String.valueOf(config.isRemoveNumbers())); - } - - @Test - void testFromLogs() { - final Log log = new Log(); - log.setId(1L); - log.setLogMessage("Log message"); - log.setLogLevel(40000); - log.setClusterId(2L); - - final Set<IndexLog> indexLogs = AnalyzerUtils.fromLogs(List.of(log)); - final IndexLog indexLog = indexLogs.stream().findFirst().get(); - assertEquals(log.getId(), indexLog.getLogId()); - assertEquals(log.getLogMessage(), indexLog.getMessage()); - assertEquals(log.getLogLevel().intValue(), indexLog.getLogLevel()); - assertEquals(log.getClusterId(), indexLog.getClusterId()); - } - - @Test - void testToRelevantItemInfo() { - final TestItem testItem = new TestItem(); - testItem.setItemId(1L); - testItem.setLaunchId(2L); - testItem.setPath("1"); - - final RelevantItemInfo itemInfo = AnalyzerUtils.TO_RELEVANT_ITEM_INFO.apply(testItem); - assertEquals(String.valueOf(testItem.getItemId()), itemInfo.getItemId()); - assertEquals(String.valueOf(testItem.getLaunchId()), itemInfo.getLaunchId()); - assertEquals(testItem.getPath(), itemInfo.getPath()); - } - - private TestItem createTest() { - TestItem testItem = new TestItem(); - testItem.setItemId(1L); - testItem.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); - testItem.setUniqueId("uniqueId"); - testItem.setItemResults(new TestItemResults()); - return testItem; - } - - private IssueEntity createIssue(boolean isAutoAnalyzed) { - IssueType issueType = new IssueType(); - issueType.setId(1L); - issueType.setLocator("locator"); - IssueEntity issue = new IssueEntity(); - issue.setAutoAnalyzed(isAutoAnalyzed); - issue.setIssueType(issueType); - return issue; - } - - private Set<IndexLog> createSameLogs(int count) { - Set<IndexLog> logs = new HashSet<>(); - for (int i = 0; i < count; i++) { - IndexLog log = new IndexLog(); - log.setLogLevel(LogLevel.ERROR.toInt()); - log.setMessage("Current message of the log"); - logs.add(log); - } - return logs; - } - - public static Project project() { - Project project = new Project(); - project.setProjectAttributes(ProjectUtils.defaultProjectAttributes(project, Arrays.stream(ProjectAttributeEnum.values()).map(it -> { - Attribute attribute = new Attribute(); - attribute.setName(it.getAttribute()); - return attribute; + return logs; + } + + public static Project project() { + Project project = new Project(); + project.setProjectAttributes(ProjectUtils.defaultProjectAttributes(project, + Arrays.stream(ProjectAttributeEnum.values()).map(it -> { + Attribute attribute = new Attribute(); + attribute.setName(it.getAttribute()); + return attribute; }).collect(Collectors.toSet()))); - return project; - } + return project; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerServiceTest.java index 73b79085c2..13439ad2e1 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/LogIndexerServiceTest.java @@ -16,6 +16,16 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.IndexerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.preparer.LaunchPreparerService; import com.epam.ta.reportportal.core.analyzer.auto.indexer.BatchLogIndexer; @@ -37,21 +47,16 @@ import com.epam.ta.reportportal.ws.model.analyzer.IndexRsIndex; import com.epam.ta.reportportal.ws.model.analyzer.IndexRsItem; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.assertj.core.util.Lists; import org.assertj.core.util.Maps; import org.junit.jupiter.api.Test; import org.springframework.core.task.SyncTaskExecutor; import org.springframework.core.task.TaskExecutor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.*; - /** * Tests for {@link LogIndexerService} * @@ -59,118 +64,118 @@ */ class LogIndexerServiceTest { - private BatchLogIndexer batchLogIndexer = mock(BatchLogIndexer.class); - - private TaskExecutor taskExecutor = new SyncTaskExecutor(); - - private IndexerServiceClient indexerServiceClient = mock(IndexerServiceClient.class); - - private LaunchRepository launchRepository = mock(LaunchRepository.class); - - private TestItemRepository testItemRepository = mock(TestItemRepository.class); - - private LogRepository logRepository = mock(LogRepository.class); - - private IndexerStatusCache indexerStatusCache = mock(IndexerStatusCache.class); - - private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); - - private LogIndexerService logIndexerService = new LogIndexerService(batchLogIndexer, - taskExecutor, - launchRepository, - testItemRepository, - indexerServiceClient, - launchPreparerService, - indexerStatusCache - ); - - @Test - void testIndexWithZeroCount() { - Long launchId = 2L; - final IndexLaunch indexLaunch = new IndexLaunch(); - indexLaunch.setLaunchId(launchId); - when(batchLogIndexer.index(eq(1L), any(AnalyzerConfig.class))).thenReturn(0L); - Long result = logIndexerService.index(1L, analyzerConfig()).join(); - assertThat(result, org.hamcrest.Matchers.equalTo(0L)); - verify(indexerStatusCache, times(1)).indexingFinished(1L); - } - - @Test - void testIndexDefectsUpdate() { - final Map<Long, String> toUpdate = Maps.newHashMap(1L, "pb001"); - when(indexerServiceClient.indexDefectsUpdate(1L, toUpdate)).thenReturn(Collections.emptyList()); - logIndexerService.indexDefectsUpdate( - 1L, - new AnalyzerConfig(), - Lists.newArrayList(createTestItem(1L, TestItemIssueGroup.PRODUCT_BUG)) - ); - verify(indexerServiceClient, times(1)).indexDefectsUpdate(1L, toUpdate); - } - - @Test - void testIndexItemsRemove() { - List<Long> list = Lists.newArrayList(1L); - doNothing().when(indexerServiceClient).indexItemsRemoveAsync(1L, list); - logIndexerService.indexItemsRemoveAsync(1L, list); - verify(indexerServiceClient, times(1)).indexItemsRemoveAsync(1L, list); - } - - private AnalyzerConfig analyzerConfig() { - AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); - return analyzerConfig; - } - - private Launch createLaunch(Long id) { - Launch l = new Launch(); - l.setId(id); - l.setMode(LaunchModeEnum.DEFAULT); - l.setName("launch" + id); - return l; - } - - private TestItem createTestItem(Long id, TestItemIssueGroup issueGroup) { - TestItem ti = new TestItem(); - ti.setItemId(id); - ti.setLaunchId(id); - ti.setItemResults(new TestItemResults()); - IssueType issueType = new IssueType(); - issueType.setLocator(issueGroup.getLocator()); - IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueType(issueType); - issueEntity.setIgnoreAnalyzer(false); - ti.getItemResults().setIssue(issueEntity); - return ti; - } - - private Log createLog(Long id) { - Log l = new Log(); - l.setId(id); - l.setTestItem(new TestItem(id)); - l.setLogLevel(LogLevel.ERROR.toInt()); - return l; - } - - private List<TestItem> createTestItems(int count, TestItemIssueGroup issueGroup) { - List<TestItem> testItems = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - testItems.add(createTestItem((long) i, issueGroup)); - } - return testItems; - } - - private IndexRs createIndexRs(int count) { - IndexRs rs = new IndexRs(); - rs.setTook(100); - rs.setErrors(false); - List<IndexRsItem> rsItems = new ArrayList<>(count); - for (int i = 0; i < count; i++) { - IndexRsItem rsItem = new IndexRsItem(); - rsItem.setIndex(new IndexRsIndex()); - rsItems.add(rsItem); - } - rs.setItems(rsItems); - return rs; - } + private BatchLogIndexer batchLogIndexer = mock(BatchLogIndexer.class); + + private TaskExecutor taskExecutor = new SyncTaskExecutor(); + + private IndexerServiceClient indexerServiceClient = mock(IndexerServiceClient.class); + + private LaunchRepository launchRepository = mock(LaunchRepository.class); + + private TestItemRepository testItemRepository = mock(TestItemRepository.class); + + private LogRepository logRepository = mock(LogRepository.class); + + private IndexerStatusCache indexerStatusCache = mock(IndexerStatusCache.class); + + private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + + private LogIndexerService logIndexerService = new LogIndexerService(batchLogIndexer, + taskExecutor, + launchRepository, + testItemRepository, + indexerServiceClient, + launchPreparerService, + indexerStatusCache + ); + + @Test + void testIndexWithZeroCount() { + Long launchId = 2L; + final IndexLaunch indexLaunch = new IndexLaunch(); + indexLaunch.setLaunchId(launchId); + when(batchLogIndexer.index(eq(1L), any(AnalyzerConfig.class))).thenReturn(0L); + Long result = logIndexerService.index(1L, analyzerConfig()).join(); + assertThat(result, org.hamcrest.Matchers.equalTo(0L)); + verify(indexerStatusCache, times(1)).indexingFinished(1L); + } + + @Test + void testIndexDefectsUpdate() { + final Map<Long, String> toUpdate = Maps.newHashMap(1L, "pb001"); + when(indexerServiceClient.indexDefectsUpdate(1L, toUpdate)).thenReturn(Collections.emptyList()); + logIndexerService.indexDefectsUpdate( + 1L, + new AnalyzerConfig(), + Lists.newArrayList(createTestItem(1L, TestItemIssueGroup.PRODUCT_BUG)) + ); + verify(indexerServiceClient, times(1)).indexDefectsUpdate(1L, toUpdate); + } + + @Test + void testIndexItemsRemove() { + List<Long> list = Lists.newArrayList(1L); + doNothing().when(indexerServiceClient).indexItemsRemoveAsync(1L, list); + logIndexerService.indexItemsRemoveAsync(1L, list); + verify(indexerServiceClient, times(1)).indexItemsRemoveAsync(1L, list); + } + + private AnalyzerConfig analyzerConfig() { + AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); + return analyzerConfig; + } + + private Launch createLaunch(Long id) { + Launch l = new Launch(); + l.setId(id); + l.setMode(LaunchModeEnum.DEFAULT); + l.setName("launch" + id); + return l; + } + + private TestItem createTestItem(Long id, TestItemIssueGroup issueGroup) { + TestItem ti = new TestItem(); + ti.setItemId(id); + ti.setLaunchId(id); + ti.setItemResults(new TestItemResults()); + IssueType issueType = new IssueType(); + issueType.setLocator(issueGroup.getLocator()); + IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueType(issueType); + issueEntity.setIgnoreAnalyzer(false); + ti.getItemResults().setIssue(issueEntity); + return ti; + } + + private Log createLog(Long id) { + Log l = new Log(); + l.setId(id); + l.setTestItem(new TestItem(id)); + l.setLogLevel(LogLevel.ERROR.toInt()); + return l; + } + + private List<TestItem> createTestItems(int count, TestItemIssueGroup issueGroup) { + List<TestItem> testItems = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + testItems.add(createTestItem((long) i, issueGroup)); + } + return testItems; + } + + private IndexRs createIndexRs(int count) { + IndexRs rs = new IndexRs(); + rs.setTook(100); + rs.setErrors(false); + List<IndexRsItem> rsItems = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + IndexRsItem rsItem = new IndexRsItem(); + rsItem.setIndex(new IndexRsIndex()); + rsItems.add(rsItem); + } + rs.setItems(rsItems); + return rs; + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImplTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImplTest.java index 64244ca51f..6472fb5151 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SearchLogServiceImplTest.java @@ -16,11 +16,20 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.core.analyzer.auto.strategy.search.SearchLogsMode.CURRENT_LAUNCH; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.strategy.search.CurrentLaunchCollector; import com.epam.ta.reportportal.core.analyzer.auto.strategy.search.SearchCollectorFactory; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.core.log.LogService; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.TestItemRepository; +import com.epam.ta.reportportal.dao.UserFilterRepository; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.filter.ObjectType; @@ -30,7 +39,7 @@ import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.ws.model.analyzer.SearchRq; @@ -38,111 +47,107 @@ import com.epam.ta.reportportal.ws.model.log.SearchLogRq; import com.epam.ta.reportportal.ws.model.log.SearchLogRs; import com.google.common.collect.Lists; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.Optional; - -import static com.epam.ta.reportportal.core.analyzer.auto.strategy.search.SearchLogsMode.CURRENT_LAUNCH; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class SearchLogServiceImplTest { - private final Project project = mock(Project.class); - private final Launch launch = mock(Launch.class); - private final TestItem testItem = mock(TestItem.class); - private final TestItem testItemOfFoundLog = mock(TestItem.class); - private final TestItemResults testItemResults = mock(TestItemResults.class); - private final UserFilter userFilter = mock(UserFilter.class); - - private final ProjectRepository projectRepository = mock(ProjectRepository.class); - - private final LaunchRepository launchRepository = mock(LaunchRepository.class); - - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - - private final LogRepository logRepository = mock(LogRepository.class); - - private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); - - private final UserFilterRepository userFilterRepository = mock(UserFilterRepository.class); - - private SearchCollectorFactory searchCollectorFactory = mock(SearchCollectorFactory.class); - - private CurrentLaunchCollector currentLaunchCollector = mock(CurrentLaunchCollector.class); - - private final SearchLogServiceImpl searchLogService = new SearchLogServiceImpl(projectRepository, - launchRepository, - testItemRepository, - logRepository, - analyzerServiceClient, - searchCollectorFactory - ); - - @Test - void searchTest() { - - ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, "project", ProjectRole.PROJECT_MANAGER); - - when(projectRepository.findById(projectDetails.getProjectId())).thenReturn(Optional.of(project)); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); - when(testItemRepository.findAllById(any())).thenReturn(Lists.newArrayList(testItemOfFoundLog)); - when(testItem.getLaunchId()).thenReturn(1L); - when(testItemOfFoundLog.getItemId()).thenReturn(2L); - when(testItemOfFoundLog.getLaunchId()).thenReturn(1L); - when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); - when(launch.getId()).thenReturn(1L); - when(testItem.getPath()).thenReturn("1"); - when(testItem.getItemResults()).thenReturn(testItemResults); - when(testItem.isHasStats()).thenReturn(true); - when(testItemOfFoundLog.getItemResults()).thenReturn(testItemResults); - when(testItemOfFoundLog.isHasStats()).thenReturn(true); - - when(testItemResults.getStatus()).thenReturn(StatusEnum.FAILED); - - IssueType issueType = new IssueType(); - issueType.setLocator("locator"); - IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueType(issueType); - issueEntity.setIgnoreAnalyzer(false); - when(testItemResults.getIssue()).thenReturn(issueEntity); - - when(userFilterRepository.findByIdAndProjectId(1L, 1L)).thenReturn(Optional.of(userFilter)); - when(userFilter.getTargetClass()).thenReturn(ObjectType.Launch); - when(userFilter.getFilterCondition()).thenReturn(Collections.emptySet()); - - when(logRepository.findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(launch.getId(), - testItem.getItemId(), - testItem.getPath(), - LogLevel.ERROR_INT - )).thenReturn(Lists.newArrayList("message")); - SearchRs searchRs = new SearchRs(); - searchRs.setLogId(1L); - searchRs.setTestItemId(2L); - when(analyzerServiceClient.searchLogs(any(SearchRq.class))).thenReturn(Lists.newArrayList(searchRs)); - Log log = new Log(); - log.setId(1L); - log.setTestItem(testItem); - log.setLogMessage("message"); - log.setLogLevel(40000); - when(logRepository.findAllById(any())).thenReturn(Lists.newArrayList(log)); - - SearchLogRq searchLogRq = new SearchLogRq(); - searchLogRq.setSearchMode(CURRENT_LAUNCH.getValue()); - searchLogRq.setFilterId(1L); - - when(searchCollectorFactory.getCollector(CURRENT_LAUNCH)).thenReturn(currentLaunchCollector); - when(currentLaunchCollector.collect(any(), any())).thenReturn(Collections.singletonList(1L)); - - Iterable<SearchLogRs> responses = searchLogService.search(1L, searchLogRq, projectDetails); - Assertions.assertNotNull(responses); - Assertions.assertEquals(1, Lists.newArrayList(responses).size()); - - } + private final Project project = mock(Project.class); + private final Launch launch = mock(Launch.class); + private final TestItem testItem = mock(TestItem.class); + private final TestItem testItemOfFoundLog = mock(TestItem.class); + private final TestItemResults testItemResults = mock(TestItemResults.class); + private final UserFilter userFilter = mock(UserFilter.class); + + private final ProjectRepository projectRepository = mock(ProjectRepository.class); + + private final LaunchRepository launchRepository = mock(LaunchRepository.class); + + private final TestItemRepository testItemRepository = mock(TestItemRepository.class); + + private final LogService logService = mock(LogService.class); + + private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); + + private final UserFilterRepository userFilterRepository = mock(UserFilterRepository.class); + + private SearchCollectorFactory searchCollectorFactory = mock(SearchCollectorFactory.class); + + private CurrentLaunchCollector currentLaunchCollector = mock(CurrentLaunchCollector.class); + + private final SearchLogServiceImpl searchLogService = new SearchLogServiceImpl(projectRepository, + launchRepository, + testItemRepository, + logService, analyzerServiceClient, + searchCollectorFactory + ); + + @Test + void searchTest() { + + ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, + "project", ProjectRole.PROJECT_MANAGER); + + when(projectRepository.findById(projectDetails.getProjectId())).thenReturn( + Optional.of(project)); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); + when(testItemRepository.findAllById(any())).thenReturn(Lists.newArrayList(testItemOfFoundLog)); + when(testItem.getLaunchId()).thenReturn(1L); + when(testItemOfFoundLog.getItemId()).thenReturn(2L); + when(testItemOfFoundLog.getLaunchId()).thenReturn(1L); + when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); + when(launch.getId()).thenReturn(1L); + when(testItem.getPath()).thenReturn("1"); + when(testItem.getItemResults()).thenReturn(testItemResults); + when(testItem.isHasStats()).thenReturn(true); + when(testItemOfFoundLog.getItemResults()).thenReturn(testItemResults); + when(testItemOfFoundLog.isHasStats()).thenReturn(true); + + when(testItemResults.getStatus()).thenReturn(StatusEnum.FAILED); + + IssueType issueType = new IssueType(); + issueType.setLocator("locator"); + IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueType(issueType); + issueEntity.setIgnoreAnalyzer(false); + when(testItemResults.getIssue()).thenReturn(issueEntity); + + when(userFilterRepository.findByIdAndProjectId(1L, 1L)).thenReturn(Optional.of(userFilter)); + when(userFilter.getTargetClass()).thenReturn(ObjectType.Launch); + when(userFilter.getFilterCondition()).thenReturn(Collections.emptySet()); + + when(logService.findMessagesByLaunchIdAndItemIdAndPathAndLevelGte(launch.getId(), + testItem.getItemId(), + testItem.getPath(), + LogLevel.ERROR_INT + )).thenReturn(Lists.newArrayList("message")); + SearchRs searchRs = new SearchRs(); + searchRs.setLogId(1L); + searchRs.setTestItemId(2L); + when(analyzerServiceClient.searchLogs(any(SearchRq.class))).thenReturn( + Lists.newArrayList(searchRs)); + LogFull log = new LogFull(); + log.setId(1L); + log.setTestItem(testItem); + log.setLogMessage("message"); + log.setLogLevel(40000); + when(logService.findAllById(any())).thenReturn(Lists.newArrayList(log)); + + SearchLogRq searchLogRq = new SearchLogRq(); + searchLogRq.setSearchMode(CURRENT_LAUNCH.getValue()); + searchLogRq.setFilterId(1L); + + when(searchCollectorFactory.getCollector(CURRENT_LAUNCH)).thenReturn(currentLaunchCollector); + when(currentLaunchCollector.collect(any(), any())).thenReturn(Collections.singletonList(1L)); + + Iterable<SearchLogRs> responses = searchLogService.search(1L, searchLogRq, projectDetails); + Assertions.assertNotNull(responses); + Assertions.assertEquals(1, Lists.newArrayList(responses).size()); + + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemServiceTest.java index bc1a73933e..59919308c1 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/SuggestItemServiceTest.java @@ -1,5 +1,14 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.entity.enums.LogLevel.ERROR_INT; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; @@ -8,224 +17,231 @@ import com.epam.ta.reportportal.core.item.validator.state.TestItemValidator; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.core.launch.cluster.GetClusterHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.core.project.GetProjectHandler; -import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.item.TestItemResults; import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.entity.enums.LogLevel.ERROR_INT; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; class SuggestItemServiceTest { - private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); + private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); - private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final GetClusterHandler getClusterHandler = mock(GetClusterHandler.class); + private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final GetClusterHandler getClusterHandler = mock(GetClusterHandler.class); - private final LaunchAccessValidator launchAccessValidator = mock(LaunchAccessValidator.class); + private final LaunchAccessValidator launchAccessValidator = mock(LaunchAccessValidator.class); - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - private final LogRepository logRepository = mock(LogRepository.class); + private final TestItemRepository testItemRepository = mock(TestItemRepository.class); + private final LogService logService = mock(LogService.class); - private final TestItemValidator testItemValidator = mock(TestItemValidator.class); - private final List<TestItemValidator> validators = List.of(testItemValidator); + private final TestItemValidator testItemValidator = mock(TestItemValidator.class); + private final List<TestItemValidator> validators = List.of(testItemValidator); - private final SuggestItemService suggestItemService = new SuggestItemService(analyzerServiceClient, - getProjectHandler, - getLaunchHandler, - getClusterHandler, - launchAccessValidator, - testItemRepository, - logRepository, - validators - ); + private final SuggestItemService suggestItemService = new SuggestItemService( + analyzerServiceClient, + getProjectHandler, + getLaunchHandler, + getClusterHandler, + launchAccessValidator, + testItemRepository, + logService, validators + ); - @Test - void suggestItems() { - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - final Project project = new Project(1L, "default"); + @Test + void suggestItems() { + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + final Project project = new Project(1L, "default"); - TestItem testItem = new TestItem(); - testItem.setItemId(1L); - testItem.setLaunchId(1L); + TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setLaunchId(1L); - TestItem relevantItem = getRelevantItem(); + TestItem relevantItem = getRelevantItem(); - Launch launch = new Launch(); - launch.setId(1L); + Launch launch = new Launch(); + launch.setId(1L); - final Log log = new Log(); + final LogFull logFull = new LogFull(); - SuggestInfo suggestInfo = new SuggestInfo(); - suggestInfo.setRelevantItem(2L); + SuggestInfo suggestInfo = new SuggestInfo(); + suggestInfo.setRelevantItem(2L); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); - when(testItemValidator.validate(any(TestItem.class))).thenReturn(true); - when(testItemRepository.findById(2L)).thenReturn(Optional.of(relevantItem)); - when(getLaunchHandler.get(testItem.getLaunchId())).thenReturn(launch); - when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); - when(logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), - Collections.singletonList(testItem.getItemId()), - ERROR_INT - )).thenReturn(Collections.singletonList(log)); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); + when(testItemValidator.validate(any(TestItem.class))).thenReturn(true); + when(testItemRepository.findById(2L)).thenReturn(Optional.of(relevantItem)); + when(getLaunchHandler.get(testItem.getLaunchId())).thenReturn(launch); + when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); + when(logService.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), + Collections.singletonList(testItem.getItemId()), + ERROR_INT + )).thenReturn(Collections.singletonList(logFull)); - when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn(Collections.singletonList(suggestInfo)); + when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn( + Collections.singletonList(suggestInfo)); - final List<SuggestedItem> suggestedItems = suggestItemService.suggestItems(1L, - ReportPortalUser.ProjectDetails.builder().withProjectId(1L).withProjectRole(ProjectRole.MEMBER.name()).build(), - rpUser - ); + final List<SuggestedItem> suggestedItems = suggestItemService.suggestItems(1L, + ReportPortalUser.ProjectDetails.builder().withProjectId(1L) + .withProjectRole(ProjectRole.MEMBER.name()).build(), + rpUser + ); - Assertions.assertEquals(1, suggestedItems.size()); + Assertions.assertEquals(1, suggestedItems.size()); - } + } - @Test - void suggestRemovedItems() { - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - final Project project = new Project(1L, "default"); + @Test + void suggestRemovedItems() { + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + final Project project = new Project(1L, "default"); - TestItem testItem = new TestItem(); - testItem.setItemId(1L); - testItem.setLaunchId(1L); + TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setLaunchId(1L); - Launch launch = new Launch(); - launch.setId(1L); + Launch launch = new Launch(); + launch.setId(1L); - SuggestInfo suggestInfo = new SuggestInfo(); - suggestInfo.setRelevantItem(2L); + SuggestInfo suggestInfo = new SuggestInfo(); + suggestInfo.setRelevantItem(2L); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); - when(testItemValidator.validate(any(TestItem.class))).thenReturn(true); - when(getLaunchHandler.get(testItem.getLaunchId())).thenReturn(launch); - when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); - when(testItemRepository.findById(2L)).thenReturn(Optional.empty()); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); + when(testItemValidator.validate(any(TestItem.class))).thenReturn(true); + when(getLaunchHandler.get(testItem.getLaunchId())).thenReturn(launch); + when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); + when(testItemRepository.findById(2L)).thenReturn(Optional.empty()); - when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn(Collections.singletonList(suggestInfo)); + when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn( + Collections.singletonList(suggestInfo)); - final List<SuggestedItem> suggestedItems = suggestItemService.suggestItems(1L, - ReportPortalUser.ProjectDetails.builder().withProjectId(1L).withProjectRole(ProjectRole.MEMBER.name()).build(), - rpUser - ); + final List<SuggestedItem> suggestedItems = suggestItemService.suggestItems(1L, + ReportPortalUser.ProjectDetails.builder().withProjectId(1L) + .withProjectRole(ProjectRole.MEMBER.name()).build(), + rpUser + ); - Assertions.assertTrue(suggestedItems.isEmpty()); + Assertions.assertTrue(suggestedItems.isEmpty()); - } + } - @Test - void showThrowExceptionWhenNotValid() { - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + @Test + void showThrowExceptionWhenNotValid() { + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem testItem = new TestItem(); - testItem.setItemId(1L); + TestItem testItem = new TestItem(); + testItem.setItemId(1L); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); - when(testItemValidator.validate(testItem)).thenReturn(false); - when(testItemValidator.provide(testItem)).thenReturn("Test item = 1 is a nested step"); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(testItem)); + when(testItemValidator.validate(testItem)).thenReturn(false); + when(testItemValidator.provide(testItem)).thenReturn("Test item = 1 is a nested step"); - final ReportPortalException exception = Assertions.assertThrows(ReportPortalException.class, - () -> suggestItemService.suggestItems(1L, - ReportPortalUser.ProjectDetails.builder().withProjectId(1L).withProjectRole(ProjectRole.MEMBER.name()).build(), - rpUser - ) - ); + final ReportPortalException exception = Assertions.assertThrows(ReportPortalException.class, + () -> suggestItemService.suggestItems(1L, + ReportPortalUser.ProjectDetails.builder().withProjectId(1L) + .withProjectRole(ProjectRole.MEMBER.name()).build(), + rpUser + ) + ); - Assertions.assertEquals("Error in handled Request. Please, check specified parameters: 'Test item = 1 is a nested step'", exception.getMessage()); - } + Assertions.assertEquals( + "Error in handled Request. Please, check specified parameters: 'Test item = 1 is a nested step'", + exception.getMessage()); + } - @Test - void showThrowExceptionWhenNotFound() { - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + @Test + void showThrowExceptionWhenNotFound() { + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - when(testItemRepository.findById(1L)).thenReturn(Optional.empty()); + when(testItemRepository.findById(1L)).thenReturn(Optional.empty()); - final ReportPortalException exception = Assertions.assertThrows(ReportPortalException.class, - () -> suggestItemService.suggestItems(1L, - ReportPortalUser.ProjectDetails.builder().withProjectId(1L).withProjectRole(ProjectRole.MEMBER.name()).build(), - rpUser - ) - ); + final ReportPortalException exception = Assertions.assertThrows(ReportPortalException.class, + () -> suggestItemService.suggestItems(1L, + ReportPortalUser.ProjectDetails.builder().withProjectId(1L) + .withProjectRole(ProjectRole.MEMBER.name()).build(), + rpUser + ) + ); - Assertions.assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", exception.getMessage()); - } + Assertions.assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", + exception.getMessage()); + } - @Test - void suggestClusterItems() { - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - final Project project = new Project(1L, "default"); + @Test + void suggestClusterItems() { + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + final Project project = new Project(1L, "default"); - final Cluster cluster = new Cluster(); - cluster.setId(1L); - cluster.setLaunchId(1L); + final Cluster cluster = new Cluster(); + cluster.setId(1L); + cluster.setLaunchId(1L); - TestItem relevantItem = getRelevantItem(); + TestItem relevantItem = getRelevantItem(); - Launch launch = new Launch(); - launch.setId(1L); + Launch launch = new Launch(); + launch.setId(1L); - final Log log = new Log(); + final LogFull logFull = new LogFull(); - SuggestInfo suggestInfo = new SuggestInfo(); - suggestInfo.setRelevantItem(2L); + SuggestInfo suggestInfo = new SuggestInfo(); + suggestInfo.setRelevantItem(2L); - when(getClusterHandler.getById(1L)).thenReturn(cluster); - when(testItemRepository.findById(2L)).thenReturn(Optional.of(relevantItem)); - when(getLaunchHandler.get(cluster.getLaunchId())).thenReturn(launch); - when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); - when(logRepository.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), - Collections.singletonList(relevantItem.getItemId()), - ERROR_INT - )).thenReturn(Collections.singletonList(log)); + when(getClusterHandler.getById(1L)).thenReturn(cluster); + when(testItemRepository.findById(2L)).thenReturn(Optional.of(relevantItem)); + when(getLaunchHandler.get(cluster.getLaunchId())).thenReturn(launch); + when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(project); + when(logService.findAllUnderTestItemByLaunchIdAndTestItemIdsAndLogLevelGte(launch.getId(), + Collections.singletonList(relevantItem.getItemId()), + ERROR_INT + )).thenReturn(Collections.singletonList(logFull)); - when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn(Collections.singletonList(suggestInfo)); + when(analyzerServiceClient.searchSuggests(any(SuggestRq.class))).thenReturn( + Collections.singletonList(suggestInfo)); - final List<SuggestedItem> suggestedItems = suggestItemService.suggestClusterItems(1L, - ReportPortalUser.ProjectDetails.builder().withProjectId(1L).withProjectRole(ProjectRole.MEMBER.name()).build(), - rpUser - ); + final List<SuggestedItem> suggestedItems = suggestItemService.suggestClusterItems(1L, + ReportPortalUser.ProjectDetails.builder().withProjectId(1L) + .withProjectRole(ProjectRole.MEMBER.name()).build(), + rpUser + ); - Assertions.assertEquals(1, suggestedItems.size()); + Assertions.assertEquals(1, suggestedItems.size()); - } + } - @Test - void handleSuggestChoice() { - final OperationCompletionRS operationCompletionRS = suggestItemService.handleSuggestChoice(new ArrayList<>()); - verify(analyzerServiceClient, times(1)).handleSuggestChoice(anyList()); - Assertions.assertEquals("User choice of suggested item was sent for handling to ML", operationCompletionRS.getResultMessage()); - } + @Test + void handleSuggestChoice() { + final OperationCompletionRS operationCompletionRS = suggestItemService.handleSuggestChoice( + new ArrayList<>()); + verify(analyzerServiceClient, times(1)).handleSuggestChoice(anyList()); + Assertions.assertEquals("User choice of suggested item was sent for handling to ML", + operationCompletionRS.getResultMessage()); + } - private TestItem getRelevantItem() { + private TestItem getRelevantItem() { - TestItem relevantItem = new TestItem(); - relevantItem.setItemId(2L); + TestItem relevantItem = new TestItem(); + relevantItem.setItemId(2L); - TestItemResults relevantItemRes = new TestItemResults(); - relevantItemRes.setEndTime(LocalDateTime.now()); + TestItemResults relevantItemRes = new TestItemResults(); + relevantItemRes.setEndTime(LocalDateTime.now()); - relevantItem.setItemResults(relevantItemRes); + relevantItem.setItemResults(relevantItemRes); - return relevantItem; - } + return relevantItem; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImplTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImplTest.java index 4b24920d18..d4ae30d995 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/impl/preparer/LaunchPreparerServiceImplTest.java @@ -16,55 +16,58 @@ package com.epam.ta.reportportal.core.analyzer.auto.impl.preparer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.ClusterRepository; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.util.List; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchPreparerServiceImplTest { - private final LaunchRepository launchRepository = mock(LaunchRepository.class); - private final ClusterRepository clusterRepository = mock(ClusterRepository.class); - private final TestItemPreparerService testItemPreparerService = mock(TestItemPreparerService.class); + private final LaunchRepository launchRepository = mock(LaunchRepository.class); + private final ClusterRepository clusterRepository = mock(ClusterRepository.class); + private final TestItemPreparerService testItemPreparerService = mock( + TestItemPreparerService.class); - private final LaunchPreparerServiceImpl preparerService = new LaunchPreparerServiceImpl(launchRepository, - clusterRepository, - testItemPreparerService - ); + private final LaunchPreparerServiceImpl preparerService = new LaunchPreparerServiceImpl( + launchRepository, + clusterRepository, + testItemPreparerService + ); - @Test - void prepare() { + @Test + void prepare() { - final long launchId = 1L; + final long launchId = 1L; - final IndexLaunch indexLaunch = new IndexLaunch(); - indexLaunch.setLaunchId(launchId); - indexLaunch.setLaunchName("name"); - indexLaunch.setProjectId(1L); + final IndexLaunch indexLaunch = new IndexLaunch(); + indexLaunch.setLaunchId(launchId); + indexLaunch.setLaunchName("name"); + indexLaunch.setProjectId(1L); - when(launchRepository.findIndexLaunchByIds(List.of(launchId))).thenReturn(List.of(indexLaunch)); + when(launchRepository.findIndexLaunchByIds(List.of(launchId))).thenReturn(List.of(indexLaunch)); - final IndexTestItem indexTestItem = new IndexTestItem(); - when(testItemPreparerService.prepare(indexLaunch.getLaunchId())).thenReturn(List.of(indexTestItem)); + final IndexTestItem indexTestItem = new IndexTestItem(); + when(testItemPreparerService.prepare(indexLaunch.getLaunchId())).thenReturn( + List.of(indexTestItem)); - final Cluster cluster = new Cluster(); - cluster.setIndexId(1L); - cluster.setMessage("hello"); - when(clusterRepository.findAllByLaunchId(indexLaunch.getLaunchId())).thenReturn(List.of(cluster)); + final Cluster cluster = new Cluster(); + cluster.setIndexId(1L); + cluster.setMessage("hello"); + when(clusterRepository.findAllByLaunchId(indexLaunch.getLaunchId())).thenReturn( + List.of(cluster)); - final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - preparerService.prepare(List.of(launchId), analyzerConfig); - } + final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + preparerService.prepare(List.of(launchId), analyzerConfig); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexerTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexerTest.java index 991f086d82..e1f94a535f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexerTest.java @@ -1,5 +1,15 @@ package com.epam.ta.reportportal.core.analyzer.auto.indexer; +import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.IndexerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.preparer.LaunchPreparerService; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -9,106 +19,110 @@ import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.analyzer.IndexTestItem; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Collection; import java.util.List; import java.util.stream.Stream; - -import static com.epam.ta.reportportal.entity.AnalyzeMode.ALL_LAUNCHES; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; class BatchLogIndexerTest { - private Integer batchSize = 2; - - private IndexerServiceClient indexerServiceClient = mock(IndexerServiceClient.class); - private LaunchRepository launchRepository = mock(LaunchRepository.class); - private TestItemRepository testItemRepository = mock(TestItemRepository.class); - private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); - - private final BatchLogIndexer batchLogIndexer = new BatchLogIndexer(batchSize, - batchSize, - launchRepository, - testItemRepository, - launchPreparerService, - indexerServiceClient - ); - - @Test - void indexWhenHasErrorLogs() { - - final List<Long> firstPortionIds = List.of(1L, 2L); - final List<Long> secondPortionIds = List.of(3L); - when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(eq(1L), - any(JLaunchModeEnum.class), - any(JStatusEnum.class), - anyInt() - )).thenReturn(firstPortionIds); - when(launchRepository.hasItemsWithLogsWithLogLevel(eq(1L), anyList(), anyInt())).thenReturn(true); - when(launchRepository.hasItemsWithLogsWithLogLevel(eq(2L), anyList(), anyInt())).thenReturn(true); - when(launchRepository.hasItemsWithLogsWithLogLevel(eq(3L), anyList(), anyInt())).thenReturn(true); - - final IndexLaunch firstIndex = new IndexLaunch(); - final List<IndexTestItem> firstIndexItems = List.of(new IndexTestItem()); - firstIndex.setTestItems(firstIndexItems); - final IndexLaunch secondIndex = new IndexLaunch(); - final List<IndexTestItem> secondIndexItems = List.of(new IndexTestItem()); - secondIndex.setTestItems(secondIndexItems); - when(launchPreparerService.prepare(eq(firstPortionIds), any(AnalyzerConfig.class))).thenReturn(List.of(firstIndex, secondIndex)); - - when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEqAfterId(eq(1L), - any(JLaunchModeEnum.class), - any(JStatusEnum.class), - eq(2L), - anyInt() - )).thenReturn(secondPortionIds); - - final IndexLaunch thirdIndex = new IndexLaunch(); - final List<IndexTestItem> thirdIndexItems = List.of(new IndexTestItem(), new IndexTestItem(), new IndexTestItem()); - thirdIndex.setTestItems(thirdIndexItems); - when(launchPreparerService.prepare(eq(secondPortionIds), any(AnalyzerConfig.class))).thenReturn(List.of(thirdIndex)); - - batchLogIndexer.index(1L, analyzerConfig()); - - final int expectedIndexedTimes = Stream.of(firstIndexItems, secondIndexItems, thirdIndexItems) - .map(Collection::size) - .mapToInt(this::getIndexedTimes) - .sum(); - - verify(indexerServiceClient, times(expectedIndexedTimes)).index(anyList()); - - } - - private int getIndexedTimes(int expectedIndexedItems) { - return BigDecimal.valueOf(expectedIndexedItems).divide(BigDecimal.valueOf(batchSize), RoundingMode.CEILING).intValue(); - } - - @Test - void indexWhenLaunchHasNoErrorLogs() { - - final List<Long> ids = List.of(1L, 2L); - when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(eq(1L), - any(JLaunchModeEnum.class), - any(JStatusEnum.class), - anyInt() - )).thenReturn(ids); - when(launchRepository.hasItemsWithLogsWithLogLevel(eq(1L), anyList(), anyInt())).thenReturn(false); - when(launchRepository.hasItemsWithLogsWithLogLevel(eq(2L), anyList(), anyInt())).thenReturn(false); - - batchLogIndexer.index(1L, analyzerConfig()); - - verify(launchPreparerService, times(0)).prepare(anyList(), any(AnalyzerConfig.class)); - verify(indexerServiceClient, times(0)).index(anyList()); - - } - - private AnalyzerConfig analyzerConfig() { - AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); - return analyzerConfig; - } + private Integer batchSize = 2; + + private IndexerServiceClient indexerServiceClient = mock(IndexerServiceClient.class); + private LaunchRepository launchRepository = mock(LaunchRepository.class); + private TestItemRepository testItemRepository = mock(TestItemRepository.class); + private LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + + private final BatchLogIndexer batchLogIndexer = new BatchLogIndexer(batchSize, + batchSize, + launchRepository, + testItemRepository, + launchPreparerService, + indexerServiceClient + ); + + @Test + void indexWhenHasErrorLogs() { + + final List<Long> firstPortionIds = List.of(1L, 2L); + final List<Long> secondPortionIds = List.of(3L); + when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(eq(1L), + any(JLaunchModeEnum.class), + any(JStatusEnum.class), + anyInt() + )).thenReturn(firstPortionIds); + when(launchRepository.hasItemsWithLogsWithLogLevel(eq(1L), anyList(), anyInt())).thenReturn( + true); + when(launchRepository.hasItemsWithLogsWithLogLevel(eq(2L), anyList(), anyInt())).thenReturn( + true); + when(launchRepository.hasItemsWithLogsWithLogLevel(eq(3L), anyList(), anyInt())).thenReturn( + true); + + final IndexLaunch firstIndex = new IndexLaunch(); + final List<IndexTestItem> firstIndexItems = List.of(new IndexTestItem()); + firstIndex.setTestItems(firstIndexItems); + final IndexLaunch secondIndex = new IndexLaunch(); + final List<IndexTestItem> secondIndexItems = List.of(new IndexTestItem()); + secondIndex.setTestItems(secondIndexItems); + when(launchPreparerService.prepare(eq(firstPortionIds), any(AnalyzerConfig.class))).thenReturn( + List.of(firstIndex, secondIndex)); + + when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEqAfterId(eq(1L), + any(JLaunchModeEnum.class), + any(JStatusEnum.class), + eq(2L), + anyInt() + )).thenReturn(secondPortionIds); + + final IndexLaunch thirdIndex = new IndexLaunch(); + final List<IndexTestItem> thirdIndexItems = List.of(new IndexTestItem(), new IndexTestItem(), + new IndexTestItem()); + thirdIndex.setTestItems(thirdIndexItems); + when(launchPreparerService.prepare(eq(secondPortionIds), any(AnalyzerConfig.class))).thenReturn( + List.of(thirdIndex)); + + batchLogIndexer.index(1L, analyzerConfig()); + + final int expectedIndexedTimes = Stream.of(firstIndexItems, secondIndexItems, thirdIndexItems) + .map(Collection::size) + .mapToInt(this::getIndexedTimes) + .sum(); + + verify(indexerServiceClient, times(expectedIndexedTimes)).index(anyList()); + + } + + private int getIndexedTimes(int expectedIndexedItems) { + return BigDecimal.valueOf(expectedIndexedItems) + .divide(BigDecimal.valueOf(batchSize), RoundingMode.CEILING).intValue(); + } + + @Test + void indexWhenLaunchHasNoErrorLogs() { + + final List<Long> ids = List.of(1L, 2L); + when(launchRepository.findIdsByProjectIdAndModeAndStatusNotEq(eq(1L), + any(JLaunchModeEnum.class), + any(JStatusEnum.class), + anyInt() + )).thenReturn(ids); + when(launchRepository.hasItemsWithLogsWithLogLevel(eq(1L), anyList(), anyInt())).thenReturn( + false); + when(launchRepository.hasItemsWithLogsWithLogLevel(eq(2L), anyList(), anyInt())).thenReturn( + false); + + batchLogIndexer.index(1L, analyzerConfig()); + + verify(launchPreparerService, times(0)).prepare(anyList(), any(AnalyzerConfig.class)); + verify(indexerServiceClient, times(0)).index(anyList()); + + } + + private AnalyzerConfig analyzerConfig() { + AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setAnalyzerMode(ALL_LAUNCHES.getValue()); + return analyzerConfig; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarterTest.java index a74f97d54c..6bbeab1cbe 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/CollectingAutoAnalysisStarterTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerService; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; @@ -33,63 +41,67 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.Lists; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class CollectingAutoAnalysisStarterTest { - public static final Long INDEXED_LOG_COUNT = 5L; - - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final AnalyzeCollectorFactory analyzeCollectorFactory = mock(AnalyzeCollectorFactory.class); - private final AnalyzeItemsCollector analyzeItemsCollector = mock(AnalyzeItemsCollector.class); - private final AnalyzerService analyzerService = mock(AnalyzerService.class); - private final LogIndexer logIndexer = mock(LogIndexer.class); - - private final CollectingAutoAnalysisStarter starter = new CollectingAutoAnalysisStarter(getLaunchHandler, - analyzeCollectorFactory, - analyzerService, - logIndexer - ); - - @Test - void shouldAnalyze() { - - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - - final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setIsAutoAnalyzerEnabled(true); - final StartLaunchAutoAnalysisConfig startLaunchAutoAnalysisConfig = StartLaunchAutoAnalysisConfig.of(launch.getId(), - analyzerConfig, - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); - - when(analyzerService.hasAnalyzers()).thenReturn(true); - - when(getLaunchHandler.get(event.getId())).thenReturn(launch); - when(logIndexer.indexLaunchLogs(eq(launch), any(AnalyzerConfig.class))).thenReturn(INDEXED_LOG_COUNT); - - when(analyzeCollectorFactory.getCollector(AnalyzeItemsMode.TO_INVESTIGATE)).thenReturn(analyzeItemsCollector); - final List<Long> itemIds = Lists.newArrayList(1L, 2L); - when(analyzeItemsCollector.collectItems(launch.getProjectId(), launch.getId(), user)).thenReturn(itemIds); - - starter.start(startLaunchAutoAnalysisConfig); - - verify(analyzerService, times(1)).runAnalyzers(eq(launch), eq(itemIds), any(AnalyzerConfig.class)); - verify(logIndexer, times(1)).indexItemsLogs(eq(launch.getProjectId()), eq(launch.getId()), eq(itemIds), any(AnalyzerConfig.class)); - } + public static final Long INDEXED_LOG_COUNT = 5L; + + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final AnalyzeCollectorFactory analyzeCollectorFactory = mock( + AnalyzeCollectorFactory.class); + private final AnalyzeItemsCollector analyzeItemsCollector = mock(AnalyzeItemsCollector.class); + private final AnalyzerService analyzerService = mock(AnalyzerService.class); + private final LogIndexer logIndexer = mock(LogIndexer.class); + + private final CollectingAutoAnalysisStarter starter = new CollectingAutoAnalysisStarter( + getLaunchHandler, + analyzeCollectorFactory, + analyzerService, + logIndexer + ); + + @Test + void shouldAnalyze() { + + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + + final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setIsAutoAnalyzerEnabled(true); + final StartLaunchAutoAnalysisConfig startLaunchAutoAnalysisConfig = StartLaunchAutoAnalysisConfig.of( + launch.getId(), + analyzerConfig, + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); + + when(analyzerService.hasAnalyzers()).thenReturn(true); + + when(getLaunchHandler.get(event.getId())).thenReturn(launch); + when(logIndexer.indexLaunchLogs(eq(launch), any(AnalyzerConfig.class))).thenReturn( + INDEXED_LOG_COUNT); + + when(analyzeCollectorFactory.getCollector(AnalyzeItemsMode.TO_INVESTIGATE)).thenReturn( + analyzeItemsCollector); + final List<Long> itemIds = Lists.newArrayList(1L, 2L); + when( + analyzeItemsCollector.collectItems(launch.getProjectId(), launch.getId(), user)).thenReturn( + itemIds); + + starter.start(startLaunchAutoAnalysisConfig); + + verify(analyzerService, times(1)).runAnalyzers(eq(launch), eq(itemIds), + any(AnalyzerConfig.class)); + verify(logIndexer, times(1)).indexItemsLogs(eq(launch.getProjectId()), eq(launch.getId()), + eq(itemIds), any(AnalyzerConfig.class)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarterTest.java index 03fb8692a4..f108e9d353 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AsyncAutoAnalysisStarterTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; @@ -23,39 +30,35 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; +import java.util.Set; import org.junit.jupiter.api.Test; import org.springframework.core.task.SyncTaskExecutor; -import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class AsyncAutoAnalysisStarterTest { - private final SyncTaskExecutor taskExecutor = mock(SyncTaskExecutor.class); - private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); + private final SyncTaskExecutor taskExecutor = mock(SyncTaskExecutor.class); + private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); - private final AsyncAutoAnalysisStarter asyncAutoAnalysisStarter = new AsyncAutoAnalysisStarter(taskExecutor, delegate); + private final AsyncAutoAnalysisStarter asyncAutoAnalysisStarter = new AsyncAutoAnalysisStarter( + taskExecutor, delegate); - @Test - void shouldExecute() { - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, - new AnalyzerConfig(), - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + @Test + void shouldExecute() { + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, + new AnalyzerConfig(), + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - doCallRealMethod().when(taskExecutor).execute(any()); + doCallRealMethod().when(taskExecutor).execute(any()); - asyncAutoAnalysisStarter.start(config); + asyncAutoAnalysisStarter.start(config); - verify(delegate, times(1)).start(config); - } + verify(delegate, times(1)).start(config); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarterTest.java index f01bc612c7..e339b01ad7 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/AutoAnalysisEnabledStarterTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; @@ -23,54 +28,51 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class AutoAnalysisEnabledStarterTest { - private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); - private final AutoAnalysisEnabledStarter autoAnalysisEnabledStarter = new AutoAnalysisEnabledStarter(delegate); + private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); + private final AutoAnalysisEnabledStarter autoAnalysisEnabledStarter = new AutoAnalysisEnabledStarter( + delegate); - @Test - void shouldRunWhenAutoAnalysisEnabled() { + @Test + void shouldRunWhenAutoAnalysisEnabled() { - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setIsAutoAnalyzerEnabled(true); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setIsAutoAnalyzerEnabled(true); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, - analyzerConfig, - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, + analyzerConfig, + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - autoAnalysisEnabledStarter.start(config); + autoAnalysisEnabledStarter.start(config); - verify(delegate, times(1)).start(config); - } + verify(delegate, times(1)).start(config); + } - @Test - void shouldNotRunWhenAutoAnalysisDisabled() { - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setIsAutoAnalyzerEnabled(false); + @Test + void shouldNotRunWhenAutoAnalysisDisabled() { + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setIsAutoAnalyzerEnabled(false); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, - analyzerConfig, - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, + analyzerConfig, + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - autoAnalysisEnabledStarter.start(config); + autoAnalysisEnabledStarter.start(config); - verify(delegate, times(0)).start(config); - } + verify(delegate, times(0)).start(config); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarterTest.java index fbdec07075..c94030457a 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/ExistingAnalyzerStarterTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.AnalyzerService; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; @@ -25,57 +33,56 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ExistingAnalyzerStarterTest { - private final AnalyzerService analyzerService = mock(AnalyzerService.class); - private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); + private final AnalyzerService analyzerService = mock(AnalyzerService.class); + private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); - private final ExistingAnalyzerStarter existingAnalyzerStarter = new ExistingAnalyzerStarter(analyzerService, delegate); + private final ExistingAnalyzerStarter existingAnalyzerStarter = new ExistingAnalyzerStarter( + analyzerService, delegate); - @Test - void shouldRunWhenHasAnalyzers() { + @Test + void shouldRunWhenHasAnalyzers() { - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, - new AnalyzerConfig(), - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, + new AnalyzerConfig(), + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - when(analyzerService.hasAnalyzers()).thenReturn(Boolean.TRUE); + when(analyzerService.hasAnalyzers()).thenReturn(Boolean.TRUE); - existingAnalyzerStarter.start(config); + existingAnalyzerStarter.start(config); - verify(delegate, times(1)).start(config); - } + verify(delegate, times(1)).start(config); + } - @Test - void shouldThrowReportPortalExceptionWhenNoAnalyzers() { - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, - new AnalyzerConfig(), - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + @Test + void shouldThrowReportPortalExceptionWhenNoAnalyzers() { + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(1L, + new AnalyzerConfig(), + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - when(analyzerService.hasAnalyzers()).thenReturn(Boolean.FALSE); + when(analyzerService.hasAnalyzers()).thenReturn(Boolean.FALSE); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> existingAnalyzerStarter.start(config)); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> existingAnalyzerStarter.start(config)); - assertEquals("Impossible interact with integration. There are no analyzer services are deployed.", exception.getMessage()); + assertEquals( + "Impossible interact with integration. There are no analyzer services are deployed.", + exception.getMessage()); - verify(delegate, times(0)).start(config); - } + verify(delegate, times(0)).start(config); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarterTest.java index 3d28d4f798..a7229fbf56 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/auto/starter/decorator/IndexingAutoAnalysisStarterTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.analyzer.auto.starter.decorator; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; @@ -29,43 +35,40 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class IndexingAutoAnalysisStarterTest { - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final LogIndexer logIndexer = mock(LogIndexer.class); - private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final LogIndexer logIndexer = mock(LogIndexer.class); + private final LaunchAutoAnalysisStarter delegate = mock(LaunchAutoAnalysisStarter.class); - private final IndexingAutoAnalysisStarter indexingAutoAnalysisStarter = new IndexingAutoAnalysisStarter(getLaunchHandler, - logIndexer, - delegate - ); + private final IndexingAutoAnalysisStarter indexingAutoAnalysisStarter = new IndexingAutoAnalysisStarter( + getLaunchHandler, + logIndexer, + delegate + ); - @Test - void shouldIndex() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + @Test + void shouldIndex() { + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(launch.getId(), - new AnalyzerConfig(), - Set.of(AnalyzeItemsMode.TO_INVESTIGATE), - user - ); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + final StartLaunchAutoAnalysisConfig config = StartLaunchAutoAnalysisConfig.of(launch.getId(), + new AnalyzerConfig(), + Set.of(AnalyzeItemsMode.TO_INVESTIGATE), + user + ); - when(getLaunchHandler.get(config.getLaunchId())).thenReturn(launch); + when(getLaunchHandler.get(config.getLaunchId())).thenReturn(launch); - indexingAutoAnalysisStarter.start(config); + indexingAutoAnalysisStarter.start(config); - verify(logIndexer, times(1)).indexLaunchLogs(launch, config.getAnalyzerConfig()); - } + verify(logIndexer, times(1)).indexLaunchLogs(launch, config.getAnalyzerConfig()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerTypeTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerTypeTest.java index 66222c2226..a2cc3ffd12 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerTypeTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/config/AnalyzerTypeTest.java @@ -16,30 +16,34 @@ package com.epam.ta.reportportal.core.analyzer.config; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class AnalyzerTypeTest { - @Test - void testFromStringPositive() { - String autoAnalyser = "autoAnalyzer"; - AnalyzerType analyzer = AnalyzerType.fromString(autoAnalyser); - assertTrue(analyzer.getName().equalsIgnoreCase(autoAnalyser)); - } + @Test + void testFromStringPositive() { + String autoAnalyser = "autoAnalyzer"; + AnalyzerType analyzer = AnalyzerType.fromString(autoAnalyser); + assertTrue(analyzer.getName().equalsIgnoreCase(autoAnalyser)); + } - @Test - void testFromStringNegative() { - String autoAnalyser = "incorrect"; - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> AnalyzerType.fromString(autoAnalyser)); - assertEquals(exception.getErrorType(), ErrorType.INCORRECT_REQUEST); - assertEquals(exception.getMessage(), "Incorrect Request. Incorrect analyzer type. Allowed are: [autoAnalyzer, patternAnalyzer]"); - } + @Test + void testFromStringNegative() { + String autoAnalyser = "incorrect"; + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> AnalyzerType.fromString(autoAnalyser)); + assertEquals(exception.getErrorType(), ErrorType.INCORRECT_REQUEST); + assertEquals(exception.getMessage(), + "Incorrect Request. Incorrect analyzer type. Allowed are: [autoAnalyzer, patternAnalyzer]"); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzerTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzerTest.java deleted file mode 100644 index 398ec83b35..0000000000 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/pattern/PatternAnalyzerTest.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.analyzer.pattern; - -import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; -import com.epam.ta.reportportal.commons.querygen.FilterCondition; -import com.epam.ta.reportportal.commons.querygen.Queryable; -import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; -import com.epam.ta.reportportal.core.analyzer.pattern.impl.PatternAnalyzerImpl; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.PatternAnalysisSelector; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.condition.PatternConditionProviderChain; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.impl.RegexPatternAnalysisSelector; -import com.epam.ta.reportportal.core.analyzer.pattern.selector.impl.StringPartPatternAnalysisSelector; -import com.epam.ta.reportportal.core.events.MessageBus; -import com.epam.ta.reportportal.dao.IssueGroupRepository; -import com.epam.ta.reportportal.dao.PatternTemplateRepository; -import com.epam.ta.reportportal.dao.TestItemRepository; -import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; -import com.epam.ta.reportportal.entity.item.issue.IssueGroup; -import com.epam.ta.reportportal.entity.launch.Launch; -import com.epam.ta.reportportal.entity.pattern.PatternTemplate; -import com.epam.ta.reportportal.entity.pattern.PatternTemplateTestItemPojo; -import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -/** - * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> - */ -class PatternAnalyzerTest { - - private final PatternAnalysisSelector stringSelector = mock(StringPartPatternAnalysisSelector.class); - private final PatternAnalysisSelector regexSelector = mock(RegexPatternAnalysisSelector.class); - private final MessageBus messageBus = mock(MessageBus.class); - - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - private final IssueGroupRepository issueGroupRepository = mock(IssueGroupRepository.class); - private final PatternTemplateRepository patternTemplateRepository = mock(PatternTemplateRepository.class); - private final AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); - private final PatternConditionProviderChain patternConditionProviderChain = mock(PatternConditionProviderChain.class); - - private final TaskExecutor taskExecutor = new ThreadPoolTaskExecutor() { - @Override - public void execute(Runnable task) { - task.run(); - } - }; - - private final IssueGroup issueGroup = mock(IssueGroup.class); - private final Launch launch = mock(Launch.class); - - private final Map<PatternTemplateType, PatternAnalysisSelector> analysisSelectorMapping = mock(Map.class); - - private final int batchSize = 100; - - private final PatternAnalyzer patternAnalyzer = new PatternAnalyzerImpl(batchSize, - testItemRepository, - patternTemplateRepository, - analysisSelectorMapping, - taskExecutor, - patternConditionProviderChain, - analyzerStatusCache, - messageBus - ); - - @Test - void analyzeTestItems() { - when(issueGroupRepository.findByTestItemIssueGroup(any(TestItemIssueGroup.class))).thenReturn(issueGroup); - when(patternTemplateRepository.findAllByProjectIdAndEnabled(launch.getProjectId(), true)).thenReturn(getPatternTemplates()); - - when(launch.getId()).thenReturn(1L); - - final List<Long> itemIds = List.of(10L, 11L, 12L); - - when(patternConditionProviderChain.provideCondition(anySet())).thenReturn(Optional.of(getConvertibleCondition())); - when(testItemRepository.selectIdsByFilter(eq(launch.getId()), any(Queryable.class), eq(batchSize), eq(0))).thenReturn(itemIds); - when(analysisSelectorMapping.get(PatternTemplateType.STRING)).thenReturn(stringSelector); - when(analysisSelectorMapping.get(PatternTemplateType.REGEX)).thenReturn(regexSelector); - - final List<Long> firstPatternMatch = List.of(10L, 11L); - final List<Long> secondPatternMatch = List.of(11L, 12L); - when(stringSelector.selectItemsByPattern(eq(launch.getId()), eq(itemIds), anyString())).thenReturn(firstPatternMatch); - when(regexSelector.selectItemsByPattern(eq(launch.getId()), eq(itemIds), anyString())).thenReturn(secondPatternMatch); - - patternAnalyzer.analyzeTestItems(launch, Sets.newHashSet()); - - final ArgumentCaptor<List<PatternTemplateTestItemPojo>> pojoCaptor = ArgumentCaptor.forClass(List.class); - verify(patternTemplateRepository, times(2)).saveInBatch(pojoCaptor.capture()); - - final List<PatternTemplateTestItemPojo> stringPatternPojos = pojoCaptor.getAllValues().get(0); - final List<PatternTemplateTestItemPojo> regexPatternPojos = pojoCaptor.getAllValues().get(1); - - Assertions.assertEquals(firstPatternMatch, - stringPatternPojos.stream().map(PatternTemplateTestItemPojo::getTestItemId).collect(Collectors.toList()) - ); - Assertions.assertEquals(secondPatternMatch, - regexPatternPojos.stream().map(PatternTemplateTestItemPojo::getTestItemId).collect(Collectors.toList()) - ); - } - - private ConvertibleCondition getConvertibleCondition() { - return FilterCondition.builder().eq(CRITERIA_ID, String.valueOf(1L)).build(); - } - - private List<PatternTemplate> getPatternTemplates() { - - return Lists.newArrayList(getPatternTemplate(1L, "name", "value", PatternTemplateType.STRING), - getPatternTemplate(2L, "name1", "value1", PatternTemplateType.REGEX) - ); - } - - private PatternTemplate getPatternTemplate(Long id, String name, String value, PatternTemplateType type) { - PatternTemplate patternTemplate = new PatternTemplate(); - patternTemplate.setId(id); - patternTemplate.setName(name); - patternTemplate.setValue(value); - patternTemplate.setEnabled(true); - patternTemplate.setTemplateType(type); - patternTemplate.setProjectId(1L); - return patternTemplate; - } - - private List<PatternTemplateTestItemPojo> getPatternTemplateTestItemPojos(Long patternId) { - - return Lists.newArrayList(new PatternTemplateTestItemPojo(patternId, 1L), new PatternTemplateTestItemPojo(patternId, 2L)); - } -} \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategyTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategyTest.java index 184aab0ec2..1e7c6134e5 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategyTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchAutoAnalysisStrategyTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.analyzer.strategy; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; @@ -30,58 +36,59 @@ import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import java.util.Optional; -import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchAutoAnalysisStrategyTest { - private final Launch launch = mock(Launch.class); - private final Project project = mock(Project.class); - private final ProjectRepository projectRepository = mock(ProjectRepository.class); - private final LaunchRepository launchRepository = mock(LaunchRepository.class); - private final LaunchAutoAnalysisStarter autoAnalysisStarter = mock(LaunchAutoAnalysisStarter.class); - private final LaunchAutoAnalysisStrategy launchAutoAnalysisStrategy = new LaunchAutoAnalysisStrategy(projectRepository, - launchRepository, - autoAnalysisStarter - ); + private final Launch launch = mock(Launch.class); + private final Project project = mock(Project.class); + + private final ProjectRepository projectRepository = mock(ProjectRepository.class); + private final LaunchRepository launchRepository = mock(LaunchRepository.class); + private final LaunchAutoAnalysisStarter autoAnalysisStarter = mock( + LaunchAutoAnalysisStarter.class); + private final LaunchAutoAnalysisStrategy launchAutoAnalysisStrategy = new LaunchAutoAnalysisStrategy( + projectRepository, + launchRepository, + autoAnalysisStarter + ); - @Test - void analyzeTest() { + @Test + void analyzeTest() { - when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); - when(launch.getId()).thenReturn(1L); - when(launch.getProjectId()).thenReturn(1L); - when(launch.getMode()).thenReturn(LaunchModeEnum.DEFAULT); - when(projectRepository.findById(1L)).thenReturn(Optional.of(project)); - when(project.getId()).thenReturn(1L); + when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); + when(launch.getId()).thenReturn(1L); + when(launch.getProjectId()).thenReturn(1L); + when(launch.getMode()).thenReturn(LaunchModeEnum.DEFAULT); + when(projectRepository.findById(1L)).thenReturn(Optional.of(project)); + when(project.getId()).thenReturn(1L); - when(project.getProjectAttributes()).thenReturn(Sets.newHashSet()); - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); + when(project.getProjectAttributes()).thenReturn(Sets.newHashSet()); + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); - ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, "name", ProjectRole.PROJECT_MANAGER); - AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); - analyzeLaunchRQ.setLaunchId(1L); - analyzeLaunchRQ.setAnalyzerHistoryMode("ALL"); - analyzeLaunchRQ.setAnalyzeItemsModes(Lists.newArrayList("TO_INVESTIGATE")); - analyzeLaunchRQ.setAnalyzerTypeName("patternAnalyzer"); - launchAutoAnalysisStrategy.analyze(analyzeLaunchRQ, projectDetails, user); + ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, "name", + ProjectRole.PROJECT_MANAGER); + AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); + analyzeLaunchRQ.setLaunchId(1L); + analyzeLaunchRQ.setAnalyzerHistoryMode("ALL"); + analyzeLaunchRQ.setAnalyzeItemsModes(Lists.newArrayList("TO_INVESTIGATE")); + analyzeLaunchRQ.setAnalyzerTypeName("patternAnalyzer"); + launchAutoAnalysisStrategy.analyze(analyzeLaunchRQ, projectDetails, user); - final ArgumentCaptor<StartLaunchAutoAnalysisConfig> configArgumentCaptor = ArgumentCaptor.forClass(StartLaunchAutoAnalysisConfig.class); - verify(autoAnalysisStarter, times(1)).start(configArgumentCaptor.capture()); + final ArgumentCaptor<StartLaunchAutoAnalysisConfig> configArgumentCaptor = ArgumentCaptor.forClass( + StartLaunchAutoAnalysisConfig.class); + verify(autoAnalysisStarter, times(1)).start(configArgumentCaptor.capture()); - final StartLaunchAutoAnalysisConfig config = configArgumentCaptor.getValue(); - Assertions.assertEquals(launch.getId(), config.getLaunchId()); - Assertions.assertEquals(Set.of(AnalyzeItemsMode.TO_INVESTIGATE), config.getAnalyzeItemsModes()); - Assertions.assertEquals(user, config.getUser()); - } + final StartLaunchAutoAnalysisConfig config = configArgumentCaptor.getValue(); + Assertions.assertEquals(launch.getId(), config.getLaunchId()); + Assertions.assertEquals(Set.of(AnalyzeItemsMode.TO_INVESTIGATE), config.getAnalyzeItemsModes()); + Assertions.assertEquals(user, config.getUser()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategyTest.java b/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategyTest.java index bcded18910..7f9b432aae 100644 --- a/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategyTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/analyzer/strategy/LaunchPatternAnalysisStrategyTest.java @@ -16,14 +16,19 @@ package com.epam.ta.reportportal.core.analyzer.strategy; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.core.analyzer.pattern.PatternAnalyzer; +import com.epam.ta.reportportal.core.analyzer.pattern.service.LaunchPatternAnalyzer; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.attribute.Attribute; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; -import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectAttribute; @@ -32,54 +37,53 @@ import com.epam.ta.reportportal.ws.model.launch.AnalyzeLaunchRQ; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchPatternAnalysisStrategyTest { - private final Launch launch = mock(Launch.class); - private final Project project = mock(Project.class); + private final Launch launch = mock(Launch.class); + private final Project project = mock(Project.class); - private final ProjectRepository projectRepository = mock(ProjectRepository.class); - private final LaunchRepository launchRepository = mock(LaunchRepository.class); - private final PatternAnalyzer patternAnalyzer = mock(PatternAnalyzer.class); + private final ProjectRepository projectRepository = mock(ProjectRepository.class); + private final LaunchRepository launchRepository = mock(LaunchRepository.class); + private final LaunchPatternAnalyzer launchPatternAnalyzer = mock(LaunchPatternAnalyzer.class); - private final LaunchPatternAnalysisStrategy launchPatternAnalysisStrategy = new LaunchPatternAnalysisStrategy(projectRepository, - launchRepository, - patternAnalyzer - ); + private final LaunchPatternAnalysisStrategy launchPatternAnalysisStrategy = new LaunchPatternAnalysisStrategy( + projectRepository, + launchRepository, + launchPatternAnalyzer + ); - @Test - void analyzeTest() { + @Test + void analyzeTest() { - when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); - when(launch.getProjectId()).thenReturn(1L); - when(launch.getMode()).thenReturn(LaunchModeEnum.DEFAULT); - when(projectRepository.findById(1L)).thenReturn(Optional.of(project)); + when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); + when(launch.getProjectId()).thenReturn(1L); + when(launch.getMode()).thenReturn(LaunchModeEnum.DEFAULT); + when(projectRepository.findById(1L)).thenReturn(Optional.of(project)); - ProjectAttribute projectAttribute = new ProjectAttribute(); - projectAttribute.setValue("true"); - Attribute attribute = new Attribute(); - projectAttribute.setAttribute(attribute); + ProjectAttribute projectAttribute = new ProjectAttribute(); + projectAttribute.setValue("true"); + Attribute attribute = new Attribute(); + projectAttribute.setAttribute(attribute); - when(project.getProjectAttributes()).thenReturn(Sets.newHashSet(projectAttribute)); + when(project.getProjectAttributes()).thenReturn(Sets.newHashSet(projectAttribute)); - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); - ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, "name", ProjectRole.PROJECT_MANAGER); - AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); - analyzeLaunchRQ.setLaunchId(1L); - analyzeLaunchRQ.setAnalyzeItemsModes(Lists.newArrayList("TO_INVESTIGATE")); - analyzeLaunchRQ.setAnalyzerTypeName("patternAnalyzer"); - launchPatternAnalysisStrategy.analyze(analyzeLaunchRQ, projectDetails, user); + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); + ReportPortalUser.ProjectDetails projectDetails = new ReportPortalUser.ProjectDetails(1L, "name", + ProjectRole.PROJECT_MANAGER); + AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); + analyzeLaunchRQ.setLaunchId(1L); + analyzeLaunchRQ.setAnalyzeItemsModes(Lists.newArrayList("TO_INVESTIGATE")); + analyzeLaunchRQ.setAnalyzerTypeName("patternAnalyzer"); + launchPatternAnalysisStrategy.analyze(analyzeLaunchRQ, projectDetails, user); - verify(patternAnalyzer, times(1)).analyzeTestItems(launch, Sets.newHashSet(AnalyzeItemsMode.TO_INVESTIGATE)); + verify(launchPatternAnalyzer, times(1)).analyzeLaunch(launch, + Sets.newHashSet(AnalyzeItemsMode.TO_INVESTIGATE)); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelperTest.java b/src/test/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelperTest.java index 7ed1a45aa2..b86151e212 100644 --- a/src/test/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelperTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/configs/ReportPortalClassLoadHelperTest.java @@ -1,33 +1,32 @@ package com.epam.ta.reportportal.core.configs; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.core.io.ResourceLoader; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ReportPortalClassLoadHelperTest { - private ResourceLoader resourceLoader = mock(ResourceLoader.class); - private ReportPortalClassLoadHelper classLoadHelper; + private ResourceLoader resourceLoader = mock(ResourceLoader.class); + private ReportPortalClassLoadHelper classLoadHelper; - @Test - void initializeTest() { - classLoadHelper = new ReportPortalClassLoadHelper(); - classLoadHelper.initialize(); - Assertions.assertNotNull(classLoadHelper.getClassLoader()); - } + @Test + void initializeTest() { + classLoadHelper = new ReportPortalClassLoadHelper(); + classLoadHelper.initialize(); + Assertions.assertNotNull(classLoadHelper.getClassLoader()); + } - @Test - void loadClassTest() throws ClassNotFoundException { - classLoadHelper = new ReportPortalClassLoadHelper(resourceLoader); - when(resourceLoader.getClassLoader()).thenReturn(this.getClass().getClassLoader()); - Class<?> clazz = classLoadHelper.loadClass(this.getClass().getCanonicalName()); - Assertions.assertEquals(this.getClass(), clazz); - } + @Test + void loadClassTest() throws ClassNotFoundException { + classLoadHelper = new ReportPortalClassLoadHelper(resourceLoader); + when(resourceLoader.getClassLoader()).thenReturn(this.getClass().getClassLoader()); + Class<?> clazz = classLoadHelper.loadClass(this.getClass().getCanonicalName()); + Assertions.assertEquals(this.getClass(), clazz); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/dashboard/impl/CreateDashboardHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/dashboard/impl/CreateDashboardHandlerImplTest.java index 46c38bc9aa..398175001f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/dashboard/impl/CreateDashboardHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/dashboard/impl/CreateDashboardHandlerImplTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.dashboard.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.DashboardRepository; import com.epam.ta.reportportal.entity.project.ProjectRole; @@ -28,36 +34,33 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class CreateDashboardHandlerImplTest { - @Mock - private DashboardRepository dashboardRepository; + @Mock + private DashboardRepository dashboardRepository; - @InjectMocks - private CreateDashboardHandlerImpl handler; + @InjectMocks + private CreateDashboardHandlerImpl handler; - @Test - void createAlreadyExistDashboard() { - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName("exist"); + @Test + void createAlreadyExistDashboard() { + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName("exist"); - final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); + final ReportPortalUser rpUser = getRpUser("owner", UserRole.USER, ProjectRole.MEMBER, 1L); - when(dashboardRepository.existsByNameAndOwnerAndProjectId("exist", "owner", 1L)).thenReturn(true); - final ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.createDashboard(extractProjectDetails(rpUser, "test_project"), createDashboardRQ, rpUser) - ); - assertEquals("Resource 'exist' already exists. You couldn't create the duplicate.", exception.getMessage()); - } + when(dashboardRepository.existsByNameAndOwnerAndProjectId("exist", "owner", 1L)).thenReturn( + true); + final ReportPortalException exception = assertThrows( + ReportPortalException.class, + () -> handler.createDashboard(extractProjectDetails(rpUser, "test_project"), + createDashboardRQ, rpUser) + ); + assertEquals("Resource 'exist' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/MessageBusImplTest.java b/src/test/java/com/epam/ta/reportportal/core/events/MessageBusImplTest.java index e3c2ec4a8f..d474652b52 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/MessageBusImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/MessageBusImplTest.java @@ -1,9 +1,6 @@ package com.epam.ta.reportportal.core.events; import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_ACTIVITY; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_ATTACHMENT; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.EXCHANGE_EVENTS; -import static com.epam.ta.reportportal.core.configs.rabbit.InternalConfiguration.QUEUE_ATTACHMENT_DELETE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -11,7 +8,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.epam.ta.reportportal.core.events.attachment.DeleteAttachmentEvent; import com.epam.ta.reportportal.entity.activity.Activity; import com.epam.ta.reportportal.entity.activity.EventObject; import org.junit.jupiter.api.BeforeEach; @@ -68,14 +64,7 @@ public void whenPublishWithExchange_thenCallConvertAndSend() { public void whenPublishWithoutExchange_thenCallConvertSendAndReceive() { messageBus.publish(ROUTE, MESSAGE); - verify(amqpTemplate).convertSendAndReceive(ROUTE, MESSAGE); - } - - @Test - public void whenBroadcastEvent_thenCallConvertAndSendWithExchangeEvents() { - messageBus.broadcastEvent(MESSAGE); - - verify(amqpTemplate).convertAndSend(EXCHANGE_EVENTS, "", MESSAGE); + verify(amqpTemplate).convertAndSend(ROUTE, MESSAGE); } @Test @@ -104,12 +93,4 @@ public void whenPublishActivity_andActivityIsNotNull_andSavedEvent_thenCallConve verify(amqpTemplate).convertAndSend(EXCHANGE_ACTIVITY, activityKey, activity); } - @Test - public void whenPublishDeleteAttachmentEvent_thenCallConvertAndSendWithAttachmentExchange() { - DeleteAttachmentEvent deleteAttachmentEvent = mock(DeleteAttachmentEvent.class); - messageBus.publishDeleteAttachmentEvent(deleteAttachmentEvent); - - verify(amqpTemplate).convertAndSend( - EXCHANGE_ATTACHMENT, QUEUE_ATTACHMENT_DELETE, deleteAttachmentEvent); - } } diff --git a/src/test/java/com/epam/ta/reportportal/core/events/activity/LaunchEventsTest.java b/src/test/java/com/epam/ta/reportportal/core/events/activity/LaunchEventsTest.java index aeca64ce28..d64974813b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/activity/LaunchEventsTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/activity/LaunchEventsTest.java @@ -68,7 +68,7 @@ void finished() { launch.setName(name); launch.setProjectId(3L); launch.setMode(LaunchModeEnum.DEFAULT); - final Activity actual = new LaunchFinishedEvent(launch, 1L, "user").toActivity(); + final Activity actual = new LaunchFinishedEvent(launch, 1L, "user", false).toActivity(); final Activity expected = getExpectedActivity(EventAction.FINISH, EventPriority.LOW); checkActivity(expected, actual); } @@ -88,4 +88,4 @@ void deleted() { final Activity expected = getExpectedActivity(EventAction.DELETE, EventPriority.MEDIUM); checkActivity(expected, actual); } -} \ No newline at end of file +} diff --git a/src/test/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEventTest.java b/src/test/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEventTest.java index 46e59c84cd..8467597593 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEventTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/activity/UserCreatedEventTest.java @@ -59,7 +59,7 @@ private static UserActivityResource getUser() { @Test void toActivity() { - final Activity actual = new UserCreatedEvent(getUser(), 1L, "user").toActivity(); + final Activity actual = new UserCreatedEvent(getUser(), 1L, "user", false).toActivity(); final Activity expected = getExpectedActivity(); checkActivity(expected, actual); diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/ComponentHealthCheckTableEventHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/ComponentHealthCheckTableEventHandlerTest.java index 8c7690a513..4631af88f3 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/ComponentHealthCheckTableEventHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/ComponentHealthCheckTableEventHandlerTest.java @@ -1,5 +1,15 @@ package com.epam.ta.reportportal.core.events.handler; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.REFRESH; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.core.events.widget.GenerateWidgetViewEvent; @@ -12,6 +22,10 @@ import com.epam.ta.reportportal.entity.widget.WidgetType; import com.epam.ta.reportportal.ws.converter.builders.WidgetBuilder; import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; @@ -19,93 +33,87 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.REFRESH; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ComponentHealthCheckTableEventHandlerTest { - private final WidgetRepository widgetRepository = mock(WidgetRepository.class); - private final BuildFilterStrategy buildFilterStrategy = mock(BuildFilterStrategy.class); - private final MaterializedViewNameGenerator materializedViewNameGenerator = mock(MaterializedViewNameGenerator.class); - private final Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping = ImmutableMap.<WidgetType, BuildFilterStrategy>builder() - .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, buildFilterStrategy) - .build(); - private ThreadPoolTaskExecutor healthCheckTableExecutor = new ThreadPoolTaskExecutor(); - - private final HealthCheckTableGenerator healthCheckTableGenerator = mock(HealthCheckTableGenerator.class); - private final Map<WidgetType, ViewGenerator> viewGeneratorMapping = new HashMap<>() { - { - put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, healthCheckTableGenerator); - } - }; - - private final GenerateWidgetViewEventHandler generateWidgetViewEventHandler; - - { - healthCheckTableExecutor.setWaitForTasksToCompleteOnShutdown(true); - healthCheckTableExecutor.setAwaitTerminationSeconds(2); - generateWidgetViewEventHandler = new GenerateWidgetViewEventHandler(widgetRepository, - buildFilterStrategyMapping, - materializedViewNameGenerator, - healthCheckTableExecutor, - viewGeneratorMapping - ); - - } - - @BeforeEach - public void init() { - healthCheckTableExecutor.initialize(); - } - - @Test - void shouldGenerate() { - Widget widget = getWidget(); - when(widgetRepository.findById(anyLong())).thenReturn(Optional.of(widget)); - - Map<Filter, Sort> filterSortMap = new HashMap<>(); - Filter filter = Filter.builder().withTarget(Widget.class).withCondition(FilterCondition.builder().eq("id", "1").build()).build(); - Sort sort = Sort.unsorted(); - filterSortMap.put(filter, sort); - - when(buildFilterStrategy.buildFilter(widget)).thenReturn(filterSortMap); - when(materializedViewNameGenerator.generate(widget)).thenReturn("widget_1_1"); - - MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); - params.put(REFRESH, Collections.singletonList(Boolean.FALSE.toString())); - - GenerateWidgetViewEvent event = new GenerateWidgetViewEvent(1L, params); - - generateWidgetViewEventHandler.onApplicationEvent(event); - - healthCheckTableExecutor.shutdown(); - - verify(healthCheckTableGenerator, times(1)).generate(anyBoolean(), - anyString(), - any(Widget.class), - any(Filter.class), - any(Sort.class), - any(MultiValueMap.class) - ); - - } - - private Widget getWidget() { - - Widget widget = new Widget(); - widget.setId(1L); - widget.setWidgetType("componentHealthCheckTable"); - - return new WidgetBuilder(widget).addProject(1L).get(); - } + private final WidgetRepository widgetRepository = mock(WidgetRepository.class); + private final BuildFilterStrategy buildFilterStrategy = mock(BuildFilterStrategy.class); + private final MaterializedViewNameGenerator materializedViewNameGenerator = mock( + MaterializedViewNameGenerator.class); + private final Map<WidgetType, BuildFilterStrategy> buildFilterStrategyMapping = ImmutableMap.<WidgetType, BuildFilterStrategy>builder() + .put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, buildFilterStrategy) + .build(); + private ThreadPoolTaskExecutor healthCheckTableExecutor = new ThreadPoolTaskExecutor(); + + private final HealthCheckTableGenerator healthCheckTableGenerator = mock( + HealthCheckTableGenerator.class); + private final Map<WidgetType, ViewGenerator> viewGeneratorMapping = new HashMap<>() { + { + put(WidgetType.COMPONENT_HEALTH_CHECK_TABLE, healthCheckTableGenerator); + } + }; + + private final GenerateWidgetViewEventHandler generateWidgetViewEventHandler; + + { + healthCheckTableExecutor.setWaitForTasksToCompleteOnShutdown(true); + healthCheckTableExecutor.setAwaitTerminationSeconds(2); + generateWidgetViewEventHandler = new GenerateWidgetViewEventHandler(widgetRepository, + buildFilterStrategyMapping, + materializedViewNameGenerator, + healthCheckTableExecutor, + viewGeneratorMapping + ); + + } + + @BeforeEach + public void init() { + healthCheckTableExecutor.initialize(); + } + + @Test + void shouldGenerate() { + Widget widget = getWidget(); + when(widgetRepository.findById(anyLong())).thenReturn(Optional.of(widget)); + + Map<Filter, Sort> filterSortMap = new HashMap<>(); + Filter filter = Filter.builder().withTarget(Widget.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()).build(); + Sort sort = Sort.unsorted(); + filterSortMap.put(filter, sort); + + when(buildFilterStrategy.buildFilter(widget)).thenReturn(filterSortMap); + when(materializedViewNameGenerator.generate(widget)).thenReturn("widget_1_1"); + + MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); + params.put(REFRESH, Collections.singletonList(Boolean.FALSE.toString())); + + GenerateWidgetViewEvent event = new GenerateWidgetViewEvent(1L, params); + + generateWidgetViewEventHandler.onApplicationEvent(event); + + healthCheckTableExecutor.shutdown(); + + verify(healthCheckTableGenerator, times(1)).generate(anyBoolean(), + anyString(), + any(Widget.class), + any(Filter.class), + any(Sort.class), + any(MultiValueMap.class) + ); + + } + + private Widget getWidget() { + + Widget widget = new Widget(); + widget.setId(1L); + widget.setWidgetType("componentHealthCheckTable"); + + return new WidgetBuilder(widget).addProject(1L).get(); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandlerTest.java index 5b3ab25130..e8dbcf8f22 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/DefectTypeDeletedHandlerTest.java @@ -16,6 +16,15 @@ package com.epam.ta.reportportal.core.events.handler; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; @@ -31,122 +40,126 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Sets; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class DefectTypeDeletedHandlerTest { - @Mock - private AnalyzerStatusCache analyzerStatusCache; - - @Mock - private AnalyzerServiceClient analyzerServiceClient; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private LogIndexer logIndexer; - - @Mock - private ProjectRepository projectRepository; - - @InjectMocks - private DefectTypeDeletedHandler handler; - - @Test - void deleteSubTypeOnNotExistProject() { - long projectId = 2L; - - when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.handleDefectTypeDeleted(new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)) - ); - - assertEquals("Project '2' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void noClientsTest() { - long projectId = 2L; - - when(projectRepository.findById(projectId)).thenReturn(Optional.of(new Project())); - when(analyzerServiceClient.hasClients()).thenReturn(false); - - handler.handleDefectTypeDeleted(new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)); - - verifyNoInteractions(logIndexer); - } - - @Test - void analysisAlreadyRunningTest() { - long projectId = 2L; - - when(projectRepository.findById(projectId)).thenReturn(Optional.of(new Project())); - when(analyzerServiceClient.hasClients()).thenReturn(true); - Cache<Long, Long> cache = CacheBuilder.newBuilder().build(); - cache.put(2L, projectId); - when(analyzerStatusCache.getAnalyzeStatus(AnalyzerStatusCache.AUTO_ANALYZER_KEY)).thenReturn(Optional.of(cache)); - - ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.handleDefectTypeDeleted(new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)) - ); - assertEquals("Forbidden operation. Index can not be removed until auto-analysis proceeds.", exception.getMessage()); - } - - @Test - void successfullyReindex() { - long projectId = 2L; - - when(projectRepository.findById(projectId)).thenReturn(Optional.of(getProjectWithAnalyzerAttributes(projectId))); - when(analyzerServiceClient.hasClients()).thenReturn(true); - when(analyzerStatusCache.getAnalyzeStatus(AnalyzerStatusCache.AUTO_ANALYZER_KEY)).thenReturn(Optional.of(CacheBuilder.newBuilder().build())); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L); - - handler.handleDefectTypeDeleted(new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)); - - verify(logIndexer, times(1)).index(eq(projectId), any(AnalyzerConfig.class)); - } - - private Project getProjectWithAnalyzerAttributes(Long projectId) { - Project project = new Project(); - project.setProjectAttributes(Sets.newHashSet( - getProjectAttribute(project, getAttribute("analyzer.isAutoAnalyzerEnabled"), "false"), - getProjectAttribute(project, getAttribute("analyzer.minDocFreq"), "7"), - getProjectAttribute(project, getAttribute("analyzer.minTermFreq"), "2"), - getProjectAttribute(project, getAttribute("analyzer.minShouldMatch"), "80"), - getProjectAttribute(project, getAttribute("analyzer.numberOfLogLines"), "5"), - getProjectAttribute(project, getAttribute("analyzer.indexingRunning"), "false") - )); - project.setId(projectId); - return project; - } - - private ProjectAttribute getProjectAttribute(Project project, Attribute attribute, String value) { - return new ProjectAttribute().withProject(project).withAttribute(attribute).withValue(value); - } - - private Attribute getAttribute(String name) { - Attribute attribute = new Attribute(); - attribute.setName(name); - return attribute; - } + @Mock + private AnalyzerStatusCache analyzerStatusCache; + + @Mock + private AnalyzerServiceClient analyzerServiceClient; + + @Mock + private LaunchRepository launchRepository; + + @Mock + private LogIndexer logIndexer; + + @Mock + private ProjectRepository projectRepository; + + @InjectMocks + private DefectTypeDeletedHandler handler; + + @Test + void deleteSubTypeOnNotExistProject() { + long projectId = 2L; + + when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows( + ReportPortalException.class, + () -> handler.handleDefectTypeDeleted( + new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)) + ); + + assertEquals("Project '2' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void noClientsTest() { + long projectId = 2L; + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(new Project())); + when(analyzerServiceClient.hasClients()).thenReturn(false); + + handler.handleDefectTypeDeleted( + new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)); + + verifyNoInteractions(logIndexer); + } + + @Test + void analysisAlreadyRunningTest() { + long projectId = 2L; + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(new Project())); + when(analyzerServiceClient.hasClients()).thenReturn(true); + Cache<Long, Long> cache = CacheBuilder.newBuilder().build(); + cache.put(2L, projectId); + when(analyzerStatusCache.getAnalyzeStatus(AnalyzerStatusCache.AUTO_ANALYZER_KEY)).thenReturn( + Optional.of(cache)); + + ReportPortalException exception = assertThrows( + ReportPortalException.class, + () -> handler.handleDefectTypeDeleted( + new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)) + ); + assertEquals("Forbidden operation. Index can not be removed until auto-analysis proceeds.", + exception.getMessage()); + } + + @Test + void successfullyReindex() { + long projectId = 2L; + + when(projectRepository.findById(projectId)).thenReturn( + Optional.of(getProjectWithAnalyzerAttributes(projectId))); + when(analyzerServiceClient.hasClients()).thenReturn(true); + when(analyzerStatusCache.getAnalyzeStatus(AnalyzerStatusCache.AUTO_ANALYZER_KEY)).thenReturn( + Optional.of(CacheBuilder.newBuilder().build())); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L); + + handler.handleDefectTypeDeleted( + new DefectTypeDeletedEvent(new IssueTypeActivityResource(), 1L, "user", projectId)); + + verify(logIndexer, times(1)).index(eq(projectId), any(AnalyzerConfig.class)); + } + + private Project getProjectWithAnalyzerAttributes(Long projectId) { + Project project = new Project(); + project.setProjectAttributes(Sets.newHashSet( + getProjectAttribute(project, getAttribute("analyzer.isAutoAnalyzerEnabled"), "false"), + getProjectAttribute(project, getAttribute("analyzer.minDocFreq"), "7"), + getProjectAttribute(project, getAttribute("analyzer.minTermFreq"), "2"), + getProjectAttribute(project, getAttribute("analyzer.minShouldMatch"), "80"), + getProjectAttribute(project, getAttribute("analyzer.numberOfLogLines"), "5"), + getProjectAttribute(project, getAttribute("analyzer.indexingRunning"), "false") + )); + project.setId(projectId); + return project; + } + + private ProjectAttribute getProjectAttribute(Project project, Attribute attribute, String value) { + return new ProjectAttribute().withProject(project).withAttribute(attribute).withValue(value); + } + + private Attribute getAttribute(String name) { + Attribute attribute = new Attribute(); + attribute.setName(name); + return attribute; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunnerTest.java index 347dc079d9..6407c8e38e 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemIndexRunnerTest.java @@ -16,46 +16,48 @@ package com.epam.ta.reportportal.core.events.handler.item; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class TestItemIndexRunnerTest { - private final LogIndexer logIndexer = mock(LogIndexer.class); + private final LogIndexer logIndexer = mock(LogIndexer.class); - private final TestItemIndexRunner runner = new TestItemIndexRunner(logIndexer); + private final TestItemIndexRunner runner = new TestItemIndexRunner(logIndexer); - @Test - void shouldInvokeIndexer() { + @Test + void shouldInvokeIndexer() { - final ItemFinishedEvent event = new ItemFinishedEvent(3L, 2L, 1L); + final IssueResolvedEvent event = new IssueResolvedEvent(3L, 2L, 1L); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "false") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "false") + .build(); - final List<Long> itemIds = List.of(event.getItemId()); + final List<Long> itemIds = List.of(event.getItemId()); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - verify(logIndexer, times(1)).indexItemsLogs(eq(event.getProjectId()), - eq(event.getLaunchId()), - eq(itemIds), - any(AnalyzerConfig.class) - ); - } + verify(logIndexer, times(1)).indexItemsLogs(eq(event.getProjectId()), + eq(event.getLaunchId()), + eq(itemIds), + any(AnalyzerConfig.class) + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunnerTest.java new file mode 100644 index 0000000000..0871cd40e6 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemPatternAnalysisRunnerTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ +package com.epam.ta.reportportal.core.events.handler.item; + +import static com.epam.ta.reportportal.core.events.handler.item.TestItemPatternAnalysisRunner.IMMEDIATE_PATTERN_ANALYSIS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +import com.epam.ta.reportportal.core.analyzer.pattern.handler.proxy.ItemsPatternAnalyzeProducer; +import com.epam.ta.reportportal.core.events.activity.item.TestItemFinishedEvent; +import com.epam.ta.reportportal.entity.ItemAttribute; +import com.epam.ta.reportportal.entity.item.TestItem; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> + */ +public class TestItemPatternAnalysisRunnerTest { + + private final ItemsPatternAnalyzeProducer itemsPatternAnalyzer = mock( + ItemsPatternAnalyzeProducer.class); + private final TestItemPatternAnalysisRunner runner = new TestItemPatternAnalysisRunner( + itemsPatternAnalyzer); + + @Test + void shouldNotInvokePatternAnalyzer() { + TestItem testItem = new TestItem(); + TestItemFinishedEvent event = new TestItemFinishedEvent(testItem, 1L); + runner.handle(event, Collections.emptyMap()); + verifyNoInteractions(itemsPatternAnalyzer); + } + + @Test + void shouldNotInvokeFalseFlagPatternAnalyzer() { + TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setLaunchId(1L); + testItem.setAttributes( + Sets.newHashSet(new ItemAttribute(IMMEDIATE_PATTERN_ANALYSIS, "false", true))); + TestItemFinishedEvent event = new TestItemFinishedEvent(testItem, 1L); + runner.handle(event, Collections.emptyMap()); + verifyNoInteractions(itemsPatternAnalyzer); + } + + @Test + void shouldInvokePatternAnalyzer() { + TestItem testItem = new TestItem(); + testItem.setItemId(1L); + testItem.setLaunchId(1L); + testItem.setAttributes( + Sets.newHashSet(new ItemAttribute(IMMEDIATE_PATTERN_ANALYSIS, "true", true))); + TestItemFinishedEvent event = new TestItemFinishedEvent(testItem, 1L); + runner.handle(event, Collections.emptyMap()); + + verify(itemsPatternAnalyzer, times(1)).analyze(1L, 1L, Lists.newArrayList(1L)); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunnerTest.java index 30c224af04..82d0383443 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/item/TestItemUniqueErrorAnalysisRunnerTest.java @@ -16,69 +16,70 @@ package com.epam.ta.reportportal.core.events.handler.item; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; import com.epam.ta.reportportal.core.launch.cluster.ClusterGenerator; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.entity.enums.ProjectAttributeEnum; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import org.springframework.context.ApplicationEventPublisher; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class TestItemUniqueErrorAnalysisRunnerTest { - private final ClusterGenerator clusterGenerator = mock(ClusterGenerator.class); - private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); - - private final TestItemUniqueErrorAnalysisRunner runner = new TestItemUniqueErrorAnalysisRunner(clusterGenerator, eventPublisher); + private final ClusterGenerator clusterGenerator = mock(ClusterGenerator.class); + private final TestItemUniqueErrorAnalysisRunner runner = new TestItemUniqueErrorAnalysisRunner( + clusterGenerator); - @Test - void shouldAnalyzeWhenEnabled() { + @Test + void shouldAnalyzeWhenEnabled() { - final ItemFinishedEvent event = new ItemFinishedEvent(3L, 2L, 1L); + final IssueResolvedEvent event = new IssueResolvedEvent(3L, 2L, 1L); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "true") - .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "true") + .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") + .build(); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass(GenerateClustersConfig.class); - verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); + final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass( + GenerateClustersConfig.class); + verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); - final GenerateClustersConfig config = configArgumentCaptor.getValue(); + final GenerateClustersConfig config = configArgumentCaptor.getValue(); - assertEquals(event.getLaunchId(), config.getEntityContext().getLaunchId()); - assertEquals(event.getProjectId(), config.getEntityContext().getProjectId()); - assertEquals(event.getItemId(), config.getEntityContext().getItemIds().get(0)); - assertTrue(config.isForUpdate()); - assertTrue(config.isCleanNumbers()); - } + assertEquals(event.getLaunchId(), config.getEntityContext().getLaunchId()); + assertEquals(event.getProjectId(), config.getEntityContext().getProjectId()); + assertEquals(event.getItemId(), config.getEntityContext().getItemIds().get(0)); + assertTrue(config.isForUpdate()); + assertTrue(config.isCleanNumbers()); + } - @Test - void shouldNotAnalyzeWhenDisabled() { + @Test + void shouldNotAnalyzeWhenDisabled() { - final ItemFinishedEvent event = new ItemFinishedEvent(3L, 2L, 1L); + final IssueResolvedEvent event = new IssueResolvedEvent(3L, 2L, 1L); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "false") - .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "false") + .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") + .build(); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - verify(clusterGenerator, times(0)).generate(any(GenerateClustersConfig.class)); + verify(clusterGenerator, times(0)).generate(any(GenerateClustersConfig.class)); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisherTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisherTest.java index 4ecb50e733..5236481437 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisherTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAnalysisFinishEventPublisherTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil; @@ -26,39 +32,36 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationEventPublisher; -import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchAnalysisFinishEventPublisherTest { - private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); + private final ApplicationEventPublisher eventPublisher = mock(ApplicationEventPublisher.class); - private final LaunchAnalysisFinishEventPublisher publisher = new LaunchAnalysisFinishEventPublisher(eventPublisher); + private final LaunchAnalysisFinishEventPublisher publisher = new LaunchAnalysisFinishEventPublisher( + eventPublisher); - @Test - void shouldSendEvent() { + @Test + void shouldSendEvent() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "true") + .build(); - publisher.handle(event, projectConfig); + publisher.handle(event, projectConfig); - verify(eventPublisher, times(1)).publishEvent(any()); + verify(eventPublisher, times(1)).publishEvent(any()); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunnerTest.java index 58fcc9d12f..3e1cc48188 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchAutoAnalysisRunnerTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.starter.LaunchAutoAnalysisStarter; import com.epam.ta.reportportal.core.analyzer.config.StartLaunchAutoAnalysisConfig; @@ -28,38 +34,34 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; - import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchAutoAnalysisRunnerTest { - private final LaunchAutoAnalysisStarter starter = mock(LaunchAutoAnalysisStarter.class); + private final LaunchAutoAnalysisStarter starter = mock(LaunchAutoAnalysisStarter.class); - private final LaunchAutoAnalysisRunner runner = new LaunchAutoAnalysisRunner(starter); + private final LaunchAutoAnalysisRunner runner = new LaunchAutoAnalysisRunner(starter); - @Test - void shouldAnalyzeWhenEnabled() { + @Test + void shouldAnalyzeWhenEnabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_ANALYZER_ENABLED.getAttribute(), "true") + .build(); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - verify(starter, times(1)).start(any(StartLaunchAutoAnalysisConfig.class)); + verify(starter, times(1)).start(any(StartLaunchAutoAnalysisConfig.class)); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunnerTest.java index 6cbe50e121..f1f94dcec9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchNotificationRunnerTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.events.handler.util.LaunchFinishedTestUtils; @@ -36,86 +43,86 @@ import com.epam.ta.reportportal.util.email.EmailService; import com.epam.ta.reportportal.util.email.MailServiceFactory; import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; - import java.util.Map; import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchNotificationRunnerTest { - private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final GetIntegrationHandler getIntegrationHandler = mock(GetIntegrationHandler.class); - private final MailServiceFactory mailServiceFactory = mock(MailServiceFactory.class); - private final UserRepository userRepository = mock(UserRepository.class); + private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final GetIntegrationHandler getIntegrationHandler = mock(GetIntegrationHandler.class); + private final MailServiceFactory mailServiceFactory = mock(MailServiceFactory.class); + private final UserRepository userRepository = mock(UserRepository.class); - private Integration emailIntegration = mock(Integration.class); + private Integration emailIntegration = mock(Integration.class); - private EmailService emailService = mock(EmailService.class); + private EmailService emailService = mock(EmailService.class); - private final LaunchNotificationRunner runner = new LaunchNotificationRunner(getProjectHandler, - getLaunchHandler, - getIntegrationHandler, - mailServiceFactory, - userRepository - ); + private final LaunchNotificationRunner runner = new LaunchNotificationRunner(getProjectHandler, + getLaunchHandler, + getIntegrationHandler, + mailServiceFactory, + userRepository + ); - @Test - void shouldNotSendWhenNotificationsDisabled() { + @Test + void shouldNotSendWhenNotificationsDisabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> mapping = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute(), "false") - .build(); + final Map<String, String> mapping = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute(), "false") + .build(); - runner.handle(event, mapping); + runner.handle(event, mapping); - verify(getIntegrationHandler, times(0)).getEnabledByProjectIdOrGlobalAndIntegrationGroup(event.getProjectId(), - IntegrationGroupEnum.NOTIFICATION - ); + verify(getIntegrationHandler, times(0)).getEnabledByProjectIdOrGlobalAndIntegrationGroup( + event.getProjectId(), + IntegrationGroupEnum.NOTIFICATION + ); - } + } - @Test - void shouldSendWhenNotificationsEnabled() { + @Test + void shouldSendWhenNotificationsEnabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - launch.setName("name1"); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + launch.setName("name1"); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> mapping = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute(), "true") - .build(); + final Map<String, String> mapping = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.NOTIFICATIONS_ENABLED.getAttribute(), "true") + .build(); - final Project project = new Project(); - project.setId(1L); - project.setSenderCases(LaunchFinishedTestUtils.getSenderCases()); + final Project project = new Project(); + project.setId(1L); + project.setSenderCases(LaunchFinishedTestUtils.getSenderCases()); - when(getIntegrationHandler.getEnabledByProjectIdOrGlobalAndIntegrationGroup(event.getProjectId(), - IntegrationGroupEnum.NOTIFICATION - )).thenReturn(Optional.ofNullable(emailIntegration)); + when( + getIntegrationHandler.getEnabledByProjectIdOrGlobalAndIntegrationGroup(event.getProjectId(), + IntegrationGroupEnum.NOTIFICATION + )).thenReturn(Optional.ofNullable(emailIntegration)); - when(userRepository.findLoginById(any())).thenReturn(Optional.of("owner")); - when(mailServiceFactory.getDefaultEmailService(emailIntegration)).thenReturn(Optional.ofNullable(emailService)); + when(userRepository.findLoginById(any())).thenReturn(Optional.of("owner")); + when(mailServiceFactory.getDefaultEmailService(emailIntegration)).thenReturn( + Optional.ofNullable(emailService)); - when(getLaunchHandler.get(event.getId())).thenReturn(launch); - when(getProjectHandler.get(event.getProjectId())).thenReturn(project); - when(getLaunchHandler.hasItemsWithIssues(launch)).thenReturn(Boolean.TRUE); + when(getLaunchHandler.get(event.getId())).thenReturn(launch); + when(getProjectHandler.get(event.getProjectId())).thenReturn(project); + when(getLaunchHandler.hasItemsWithIssues(launch)).thenReturn(Boolean.TRUE); - runner.handle(event, mapping); - verify(emailService, times(2)).sendLaunchFinishNotification(any(), any(), any(), any()); + runner.handle(event, mapping); + verify(emailService, times(2)).sendLaunchFinishNotification(any(), any(), any(), any()); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunnerTest.java index 3e72682cf3..6666c0f352 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchPatternAnalysisRunnerTest.java @@ -16,9 +16,15 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.strategy.analyze.AnalyzeItemsMode; -import com.epam.ta.reportportal.core.analyzer.pattern.PatternAnalyzer; +import com.epam.ta.reportportal.core.analyzer.pattern.service.LaunchPatternAnalyzer; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; import com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil; @@ -29,57 +35,59 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.ImmutableMap; -import org.junit.jupiter.api.Test; - +import com.google.common.collect.Sets; import java.util.Collections; import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchPatternAnalysisRunnerTest { - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final PatternAnalyzer patternAnalyzer = mock(PatternAnalyzer.class); + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final LaunchPatternAnalyzer launchPatternAnalyzer = mock(LaunchPatternAnalyzer.class); - private final LaunchPatternAnalysisRunner runner = new LaunchPatternAnalysisRunner(getLaunchHandler, patternAnalyzer); + private final LaunchPatternAnalysisRunner runner = new LaunchPatternAnalysisRunner( + getLaunchHandler, launchPatternAnalyzer); - @Test - public void shouldAnalyzeWhenEnabled() { + @Test + public void shouldAnalyzeWhenEnabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> mapping = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute(), "true") - .build(); + final Map<String, String> mapping = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute(), "true") + .build(); - when(getLaunchHandler.get(event.getId())).thenReturn(launch); - runner.handle(event, mapping); + when(getLaunchHandler.get(event.getId())).thenReturn(launch); + runner.handle(event, mapping); - verify(patternAnalyzer, times(1)).analyzeTestItems(launch, Collections.singleton(AnalyzeItemsMode.TO_INVESTIGATE)); + verify(launchPatternAnalyzer, times(1)).analyzeLaunch(launch, + Sets.newHashSet(AnalyzeItemsMode.TO_INVESTIGATE, AnalyzeItemsMode.IGNORE_IMMEDIATE)); - } + } - @Test - public void shouldNotAnalyzeWhenDisabled() { + @Test + public void shouldNotAnalyzeWhenDisabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> mapping = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute(), "false") - .build(); + final Map<String, String> mapping = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_PATTERN_ANALYZER_ENABLED.getAttribute(), "false") + .build(); - runner.handle(event, mapping); + runner.handle(event, mapping); - verify(getLaunchHandler, times(0)).get(event.getId()); - verify(patternAnalyzer, times(0)).analyzeTestItems(launch, Collections.singleton(AnalyzeItemsMode.TO_INVESTIGATE)); + verify(getLaunchHandler, times(0)).get(event.getId()); + verify(launchPatternAnalyzer, times(0)).analyzeLaunch(launch, + Collections.singleton(AnalyzeItemsMode.TO_INVESTIGATE)); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunnerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunnerTest.java index d0b367bb90..4f2fa087b9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunnerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/handler/launch/LaunchUniqueErrorAnalysisRunnerTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.events.handler.launch; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyMap; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.activity.LaunchFinishedEvent; import com.epam.ta.reportportal.core.launch.cluster.UniqueErrorAnalysisStarter; @@ -28,63 +36,62 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchUniqueErrorAnalysisRunnerTest { - private final UniqueErrorAnalysisStarter starter = mock(UniqueErrorAnalysisStarter.class); + private final UniqueErrorAnalysisStarter starter = mock(UniqueErrorAnalysisStarter.class); - private final LaunchUniqueErrorAnalysisRunner runner = new LaunchUniqueErrorAnalysisRunner(starter); + private final LaunchUniqueErrorAnalysisRunner runner = new LaunchUniqueErrorAnalysisRunner( + starter); - @Test - void shouldStartWhenEnabled() { + @Test + void shouldStartWhenEnabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "true") - .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "true") + .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") + .build(); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - final ArgumentCaptor<ClusterEntityContext> entityContextCaptor = ArgumentCaptor.forClass(ClusterEntityContext.class); - verify(starter, times(1)).start(entityContextCaptor.capture(), anyMap()); + final ArgumentCaptor<ClusterEntityContext> entityContextCaptor = ArgumentCaptor.forClass( + ClusterEntityContext.class); + verify(starter, times(1)).start(entityContextCaptor.capture(), anyMap()); - final ClusterEntityContext entityContext = entityContextCaptor.getValue(); + final ClusterEntityContext entityContext = entityContextCaptor.getValue(); - assertEquals(event.getId(), entityContext.getLaunchId()); - assertEquals(event.getProjectId(), entityContext.getProjectId()); - } + assertEquals(event.getId(), entityContext.getLaunchId()); + assertEquals(event.getProjectId(), entityContext.getProjectId()); + } - @Test - void shouldNotStartWhenDisabled() { + @Test + void shouldNotStartWhenDisabled() { - final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); - final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, launch.getProjectId()); - final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); + final Launch launch = LaunchTestUtil.getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT).get(); + final ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, + launch.getProjectId()); + final LaunchFinishedEvent event = new LaunchFinishedEvent(launch, user, "baseUrl"); - final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() - .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "false") - .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") - .build(); + final Map<String, String> projectConfig = ImmutableMap.<String, String>builder() + .put(ProjectAttributeEnum.AUTO_UNIQUE_ERROR_ANALYZER_ENABLED.getAttribute(), "false") + .put(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute(), "true") + .build(); - runner.handle(event, projectConfig); + runner.handle(event, projectConfig); - verify(starter, times(0)).start(any(ClusterEntityContext.class), anyMap()); + verify(starter, times(0)).start(any(ClusterEntityContext.class), anyMap()); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListenerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListenerTest.java index b7273120a4..f437d39c4a 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListenerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/listener/StartLaunchUniqueErrorAnalysisEventListenerTest.java @@ -1,47 +1,52 @@ package com.epam.ta.reportportal.core.events.listener; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.reportportal.extension.event.LaunchStartUniqueErrorAnalysisEvent; import com.epam.ta.reportportal.core.launch.cluster.UniqueErrorAnalysisStarter; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.project.config.ProjectConfigProvider; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - import java.util.Collections; import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class StartLaunchUniqueErrorAnalysisEventListenerTest { - private final ProjectConfigProvider projectConfigProvider = mock(ProjectConfigProvider.class); - private final UniqueErrorAnalysisStarter starter = mock(UniqueErrorAnalysisStarter.class); + private final ProjectConfigProvider projectConfigProvider = mock(ProjectConfigProvider.class); + private final UniqueErrorAnalysisStarter starter = mock(UniqueErrorAnalysisStarter.class); - private final StartLaunchUniqueErrorAnalysisEventListener listener = new StartLaunchUniqueErrorAnalysisEventListener( - projectConfigProvider, - starter - ); + private final StartLaunchUniqueErrorAnalysisEventListener listener = new StartLaunchUniqueErrorAnalysisEventListener( + projectConfigProvider, + starter + ); - @Test - void shouldStart() { - final Map<String, String> projectConfig = Collections.emptyMap(); - when(projectConfigProvider.provide(anyLong())).thenReturn(projectConfig); + @Test + void shouldStart() { + final Map<String, String> projectConfig = Collections.emptyMap(); + when(projectConfigProvider.provide(anyLong())).thenReturn(projectConfig); - final LaunchStartUniqueErrorAnalysisEvent event = new LaunchStartUniqueErrorAnalysisEvent(1L, 1L); - listener.onApplicationEvent(event); + final LaunchStartUniqueErrorAnalysisEvent event = new LaunchStartUniqueErrorAnalysisEvent(1L, + 1L); + listener.onApplicationEvent(event); - final ArgumentCaptor<ClusterEntityContext> contextArgumentCaptor = ArgumentCaptor.forClass(ClusterEntityContext.class); - verify(starter, times(1)).start(contextArgumentCaptor.capture(), eq(projectConfig)); + final ArgumentCaptor<ClusterEntityContext> contextArgumentCaptor = ArgumentCaptor.forClass( + ClusterEntityContext.class); + verify(starter, times(1)).start(contextArgumentCaptor.capture(), eq(projectConfig)); - final ClusterEntityContext entityContext = contextArgumentCaptor.getValue(); + final ClusterEntityContext entityContext = contextArgumentCaptor.getValue(); - assertEquals(event.getSource(), entityContext.getLaunchId()); - assertEquals(event.getProjectId(), entityContext.getProjectId()); - } + assertEquals(event.getSource(), entityContext.getLaunchId()); + assertEquals(event.getProjectId(), entityContext.getProjectId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListenerTest.java b/src/test/java/com/epam/ta/reportportal/core/events/listener/TestIssueResolvedEventListenerTest.java similarity index 52% rename from src/test/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListenerTest.java rename to src/test/java/com/epam/ta/reportportal/core/events/listener/TestIssueResolvedEventListenerTest.java index 3a3e67fe47..b2e8897f5a 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/listener/TestItemFinishedEventListenerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/listener/TestIssueResolvedEventListenerTest.java @@ -16,31 +16,33 @@ package com.epam.ta.reportportal.core.events.listener; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; -import com.epam.ta.reportportal.core.events.subscriber.impl.delegate.ProjectConfigDelegatingSubscriber; -import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; +import com.epam.ta.reportportal.core.events.subscriber.impl.delegate.ProjectConfigDelegatingSubscriber; import java.util.List; - -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ -class TestItemFinishedEventListenerTest { +class TestIssueResolvedEventListenerTest { - private final ProjectConfigDelegatingSubscriber<ItemFinishedEvent> delegatingSubscriber = (ProjectConfigDelegatingSubscriber<ItemFinishedEvent>) mock( - ProjectConfigDelegatingSubscriber.class); + private final ProjectConfigDelegatingSubscriber<IssueResolvedEvent> delegatingSubscriber = (ProjectConfigDelegatingSubscriber<IssueResolvedEvent>) mock( + ProjectConfigDelegatingSubscriber.class); - private final TestItemFinishedEventListener eventListener = new TestItemFinishedEventListener(List.of(delegatingSubscriber)); + private final TestItemIssueResolvedEventListener eventListener = new TestItemIssueResolvedEventListener( + List.of(delegatingSubscriber)); - @Test - void shouldHandle() { - final ItemFinishedEvent event = new ItemFinishedEvent(3L, 2L, 1L); + @Test + void shouldHandle() { + final IssueResolvedEvent event = new IssueResolvedEvent(3L, 2L, 1L); - eventListener.onApplicationEvent(event); + eventListener.onApplicationEvent(event); - verify(delegatingSubscriber, times(1)).handleEvent(event); - } + verify(delegatingSubscriber, times(1)).handleEvent(event); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriberTest.java b/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriberTest.java index cfe3905abb..a3a4e911f9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriberTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/delegate/ProjectConfigDelegatingSubscriberTest.java @@ -16,8 +16,6 @@ package com.epam.ta.reportportal.core.events.subscriber.impl.delegate; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ diff --git a/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/launch/finish/LaunchFinishedMessagePublisherTest.java b/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/launch/finish/LaunchFinishedMessagePublisherTest.java index 33b540dc58..2d3d121e3b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/launch/finish/LaunchFinishedMessagePublisherTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/events/subscriber/impl/launch/finish/LaunchFinishedMessagePublisherTest.java @@ -16,8 +16,6 @@ package com.epam.ta.reportportal.core.events.subscriber.impl.launch.finish; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ diff --git a/src/test/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandlerTest.java index 987bc9d530..b2b191e199 100644 --- a/src/test/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/hierarchy/impl/FinishLaunchHierarchyHandlerTest.java @@ -1,5 +1,18 @@ package com.epam.ta.reportportal.core.hierarchy.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.item.impl.status.ToSkippedStatusChangingStrategy.SKIPPED_ISSUE_KEY; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.impl.IssueTypeHandler; import com.epam.ta.reportportal.core.item.impl.retry.RetryHandler; @@ -20,196 +33,200 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.google.common.collect.Lists; -import org.junit.jupiter.api.Test; - import java.time.LocalDate; import java.time.Month; import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.core.item.impl.status.ToSkippedStatusChangingStrategy.SKIPPED_ISSUE_KEY; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class FinishLaunchHierarchyHandlerTest { - private final LaunchRepository launchRepository = mock(LaunchRepository.class); - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - private final ItemAttributeRepository itemAttributeRepository = mock(ItemAttributeRepository.class); - private final RetryHandler retryHandler = mock(RetryHandler.class); - private final IssueTypeHandler issueTypeHandler = mock(IssueTypeHandler.class); - private final IssueEntityRepository issueEntityRepository = mock(IssueEntityRepository.class); - private final ChangeStatusHandler changeStatusHandler = mock(ChangeStatusHandler.class); - - private final FinishLaunchHierarchyHandler finishLaunchHierarchyHandler = new FinishLaunchHierarchyHandler(launchRepository, - testItemRepository, - itemAttributeRepository, - retryHandler, - issueTypeHandler, - issueEntityRepository, - changeStatusHandler - ); - - @Test - void finishWithPassedStatus() { - - Launch launch = getLaunch(); - - List<Long> idsWithChildren = Lists.newArrayList(2L, 1L); - List<Long> idsWithoutChildren = Lists.newArrayList(3L, 4L); - - when(testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel(eq(launch.getId()), - eq(StatusEnum.IN_PROGRESS), - anyInt(), - anyLong() - )).thenReturn(idsWithChildren); - when(testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(eq(launch.getId()), - eq(StatusEnum.IN_PROGRESS), - anyInt(), - anyLong() - )).thenReturn(idsWithoutChildren); - - Date endTime = Date.from(LocalDate.of(2020, Month.OCTOBER, 30).atStartOfDay(ZoneId.systemDefault()).toInstant()); - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(testItemRepository.findAllById(idsWithChildren)).thenReturn(getTestItemsWithChildren(launch)); - when(testItemRepository.findAllById(idsWithoutChildren)).thenReturn(getTestItemsWithoutChildren(launch)); - - when(issueEntityRepository.findById(3L)).thenReturn(Optional.empty()); - when(issueEntityRepository.findById(4L)).thenReturn(Optional.empty()); - - finishLaunchHierarchyHandler.finishDescendants(launch, - StatusEnum.PASSED, - endTime, - rpUser, - rpUser.getProjectDetails().get(TEST_PROJECT_NAME) - ); - - verify(changeStatusHandler, times(2)).changeParentStatus(any(TestItem.class), any(), any()); - verify(issueEntityRepository, times(0)).save(any()); - } - - @Test - void finishWithSkippedStatus() { - - Launch launch = getLaunch(); - - when(itemAttributeRepository.findByLaunchIdAndKeyAndSystem(launch.getId(), - SKIPPED_ISSUE_KEY, - true - )).thenReturn(java.util.Optional.of(new ItemAttribute(SKIPPED_ISSUE_KEY, "true", true))); - - when(issueTypeHandler.defineIssueType(anyLong(), anyString())).thenReturn(getToInvestigateIssueType()); - - List<Long> idsWithChildren = Lists.newArrayList(2L, 1L); - List<Long> idsWithoutChildren = Lists.newArrayList(3L, 4L); - when(testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel(eq(launch.getId()), - eq(StatusEnum.IN_PROGRESS), - anyInt(), - anyLong() - )).thenReturn(idsWithChildren); - when(testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(eq(launch.getId()), - eq(StatusEnum.IN_PROGRESS), - anyInt(), - anyLong() - )).thenReturn(idsWithoutChildren); - - Date endTime = Date.from(LocalDate.of(2020, Month.OCTOBER, 30).atStartOfDay(ZoneId.systemDefault()).toInstant()); - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(testItemRepository.findAllById(idsWithChildren)).thenReturn(getTestItemsWithChildren(launch)); - when(testItemRepository.findAllById(idsWithoutChildren)).thenReturn(getTestItemsWithoutChildren(launch)); - - finishLaunchHierarchyHandler.finishDescendants(launch, - StatusEnum.SKIPPED, - endTime, - rpUser, - rpUser.getProjectDetails().get(TEST_PROJECT_NAME) - ); - - verify(changeStatusHandler, times(2)).changeParentStatus(any(TestItem.class), any(), any()); - verify(issueEntityRepository, times(2)).save(any()); - - } - - private Launch getLaunch() { - Launch launch = new Launch(); - launch.setId(1L); - return launch; - } - - private IssueType getToInvestigateIssueType() { - IssueType issueType = new IssueType(); - issueType.setId(1L); - issueType.setLocator(TestItemIssueGroup.TO_INVESTIGATE.getLocator()); - - IssueGroup issueGroup = new IssueGroup(); - issueGroup.setId(1); - issueGroup.setTestItemIssueGroup(TestItemIssueGroup.TO_INVESTIGATE); - issueType.setIssueGroup(issueGroup); - return issueType; - } - - private List<TestItem> getTestItemsWithChildren(Launch launch) { - - TestItem parent = new TestItem(); - parent.setItemId(1L); - parent.setType(TestItemTypeEnum.SUITE); - parent.setLaunchId(launch.getId()); - parent.setPath("1"); - parent.setHasStats(true); - parent.setHasChildren(true); - TestItemResults parentResults = new TestItemResults(); - parentResults.setStatus(StatusEnum.IN_PROGRESS); - parent.setItemResults(parentResults); - - TestItem child = new TestItem(); - child.setItemId(2L); - child.setType(TestItemTypeEnum.TEST); - child.setLaunchId(launch.getId()); - child.setPath("1.2"); - child.setParentId(parent.getItemId()); - child.setHasStats(true); - child.setHasChildren(true); - TestItemResults childResults = new TestItemResults(); - childResults.setStatus(StatusEnum.IN_PROGRESS); - child.setItemResults(childResults); - - return Lists.newArrayList(child, parent); - } - - private List<TestItem> getTestItemsWithoutChildren(Launch launch) { - - TestItem firstChild = new TestItem(); - firstChild.setItemId(3L); - firstChild.setType(TestItemTypeEnum.STEP); - firstChild.setLaunchId(launch.getId()); - firstChild.setPath("1.2.3"); - firstChild.setHasStats(true); - firstChild.setHasChildren(false); - TestItemResults parentResults = new TestItemResults(); - parentResults.setStatus(StatusEnum.IN_PROGRESS); - firstChild.setItemResults(parentResults); - - TestItem secondChild = new TestItem(); - secondChild.setItemId(4L); - secondChild.setType(TestItemTypeEnum.STEP); - secondChild.setLaunchId(launch.getId()); - secondChild.setPath("1.2.4"); - secondChild.setHasStats(true); - secondChild.setHasChildren(true); - TestItemResults childResults = new TestItemResults(); - childResults.setStatus(StatusEnum.IN_PROGRESS); - secondChild.setItemResults(childResults); - - return Lists.newArrayList(firstChild, secondChild); - } + private final LaunchRepository launchRepository = mock(LaunchRepository.class); + private final TestItemRepository testItemRepository = mock(TestItemRepository.class); + private final ItemAttributeRepository itemAttributeRepository = mock( + ItemAttributeRepository.class); + private final RetryHandler retryHandler = mock(RetryHandler.class); + private final IssueTypeHandler issueTypeHandler = mock(IssueTypeHandler.class); + private final IssueEntityRepository issueEntityRepository = mock(IssueEntityRepository.class); + private final ChangeStatusHandler changeStatusHandler = mock(ChangeStatusHandler.class); + + private final FinishLaunchHierarchyHandler finishLaunchHierarchyHandler = new FinishLaunchHierarchyHandler( + launchRepository, + testItemRepository, + itemAttributeRepository, + retryHandler, + issueTypeHandler, + issueEntityRepository, + changeStatusHandler + ); + + @Test + void finishWithPassedStatus() { + + Launch launch = getLaunch(); + + List<Long> idsWithChildren = Lists.newArrayList(2L, 1L); + List<Long> idsWithoutChildren = Lists.newArrayList(3L, 4L); + + when(testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel( + eq(launch.getId()), + eq(StatusEnum.IN_PROGRESS), + anyInt(), + anyLong() + )).thenReturn(idsWithChildren); + when(testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(eq(launch.getId()), + eq(StatusEnum.IN_PROGRESS), + anyInt(), + anyLong() + )).thenReturn(idsWithoutChildren); + + Date endTime = Date.from( + LocalDate.of(2020, Month.OCTOBER, 30).atStartOfDay(ZoneId.systemDefault()).toInstant()); + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(testItemRepository.findAllById(idsWithChildren)).thenReturn( + getTestItemsWithChildren(launch)); + when(testItemRepository.findAllById(idsWithoutChildren)).thenReturn( + getTestItemsWithoutChildren(launch)); + + when(issueEntityRepository.findById(3L)).thenReturn(Optional.empty()); + when(issueEntityRepository.findById(4L)).thenReturn(Optional.empty()); + + finishLaunchHierarchyHandler.finishDescendants(launch, + StatusEnum.PASSED, + endTime, + rpUser, + rpUser.getProjectDetails().get(TEST_PROJECT_NAME) + ); + + verify(changeStatusHandler, times(2)).changeParentStatus(any(TestItem.class), any(), any()); + verify(issueEntityRepository, times(0)).save(any()); + } + + @Test + void finishWithSkippedStatus() { + + Launch launch = getLaunch(); + + when(itemAttributeRepository.findByLaunchIdAndKeyAndSystem(launch.getId(), + SKIPPED_ISSUE_KEY, + true + )).thenReturn(java.util.Optional.of(new ItemAttribute(SKIPPED_ISSUE_KEY, "true", true))); + + when(issueTypeHandler.defineIssueType(anyLong(), anyString())).thenReturn( + getToInvestigateIssueType()); + + List<Long> idsWithChildren = Lists.newArrayList(2L, 1L); + List<Long> idsWithoutChildren = Lists.newArrayList(3L, 4L); + when(testItemRepository.findIdsByHasChildrenAndLaunchIdAndStatusOrderedByPathLevel( + eq(launch.getId()), + eq(StatusEnum.IN_PROGRESS), + anyInt(), + anyLong() + )).thenReturn(idsWithChildren); + when(testItemRepository.findIdsByNotHasChildrenAndLaunchIdAndStatus(eq(launch.getId()), + eq(StatusEnum.IN_PROGRESS), + anyInt(), + anyLong() + )).thenReturn(idsWithoutChildren); + + Date endTime = Date.from( + LocalDate.of(2020, Month.OCTOBER, 30).atStartOfDay(ZoneId.systemDefault()).toInstant()); + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(testItemRepository.findAllById(idsWithChildren)).thenReturn( + getTestItemsWithChildren(launch)); + when(testItemRepository.findAllById(idsWithoutChildren)).thenReturn( + getTestItemsWithoutChildren(launch)); + + finishLaunchHierarchyHandler.finishDescendants(launch, + StatusEnum.SKIPPED, + endTime, + rpUser, + rpUser.getProjectDetails().get(TEST_PROJECT_NAME) + ); + + verify(changeStatusHandler, times(2)).changeParentStatus(any(TestItem.class), any(), any()); + verify(issueEntityRepository, times(2)).save(any()); + + } + + private Launch getLaunch() { + Launch launch = new Launch(); + launch.setId(1L); + return launch; + } + + private IssueType getToInvestigateIssueType() { + IssueType issueType = new IssueType(); + issueType.setId(1L); + issueType.setLocator(TestItemIssueGroup.TO_INVESTIGATE.getLocator()); + + IssueGroup issueGroup = new IssueGroup(); + issueGroup.setId(1); + issueGroup.setTestItemIssueGroup(TestItemIssueGroup.TO_INVESTIGATE); + issueType.setIssueGroup(issueGroup); + return issueType; + } + + private List<TestItem> getTestItemsWithChildren(Launch launch) { + + TestItem parent = new TestItem(); + parent.setItemId(1L); + parent.setType(TestItemTypeEnum.SUITE); + parent.setLaunchId(launch.getId()); + parent.setPath("1"); + parent.setHasStats(true); + parent.setHasChildren(true); + TestItemResults parentResults = new TestItemResults(); + parentResults.setStatus(StatusEnum.IN_PROGRESS); + parent.setItemResults(parentResults); + + TestItem child = new TestItem(); + child.setItemId(2L); + child.setType(TestItemTypeEnum.TEST); + child.setLaunchId(launch.getId()); + child.setPath("1.2"); + child.setParentId(parent.getItemId()); + child.setHasStats(true); + child.setHasChildren(true); + TestItemResults childResults = new TestItemResults(); + childResults.setStatus(StatusEnum.IN_PROGRESS); + child.setItemResults(childResults); + + return Lists.newArrayList(child, parent); + } + + private List<TestItem> getTestItemsWithoutChildren(Launch launch) { + + TestItem firstChild = new TestItem(); + firstChild.setItemId(3L); + firstChild.setType(TestItemTypeEnum.STEP); + firstChild.setLaunchId(launch.getId()); + firstChild.setPath("1.2.3"); + firstChild.setHasStats(true); + firstChild.setHasChildren(false); + TestItemResults parentResults = new TestItemResults(); + parentResults.setStatus(StatusEnum.IN_PROGRESS); + firstChild.setItemResults(parentResults); + + TestItem secondChild = new TestItem(); + secondChild.setItemId(4L); + secondChild.setType(TestItemTypeEnum.STEP); + secondChild.setLaunchId(launch.getId()); + secondChild.setPath("1.2.4"); + secondChild.setHasStats(true); + secondChild.setHasChildren(true); + TestItemResults childResults = new TestItemResults(); + childResults.setStatus(StatusEnum.IN_PROGRESS); + secondChild.setItemResults(childResults); + + return Lists.newArrayList(firstChild, secondChild); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImplTest.java index 8e875fb626..d7a2014334 100644 --- a/src/test/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/imprt/ImportLaunchHandlerImplTest.java @@ -14,10 +14,14 @@ import com.epam.ta.reportportal.core.imprt.impl.ImportStrategyFactory; import com.epam.ta.reportportal.core.imprt.impl.ImportType; import com.epam.ta.reportportal.core.imprt.impl.XmlImportStrategy; +import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.util.sample.LaunchSampleUtil; import com.epam.ta.reportportal.ws.model.ErrorType; +import com.epam.ta.reportportal.ws.model.LaunchImportCompletionRS; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import java.io.File; -import java.util.HashMap; +import java.util.Optional; import org.apache.commons.io.FilenameUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,6 +47,9 @@ public class ImportLaunchHandlerImplTest { @Mock private MessageBus messageBus; + @Mock + private LaunchRepository launchRepository; + @Captor private ArgumentCaptor<ImportFinishedEvent> importFinishedEventCaptor; @@ -84,7 +91,7 @@ public void setUp() { public void whenImportLaunch_AndFileNameIsNotValid_ThenThrowException() { ReportPortalException reportPortalException = assertThrows(ReportPortalException.class, () -> importLaunchHandlerImpl.importLaunch(projectDetails, reportPortalUser, FORMAT, - multipartFile, BASE_URL, new HashMap<>() + multipartFile, BASE_URL, new LaunchImportRQ() ) ); @@ -98,7 +105,7 @@ public void whenImportLaunch_AndFileExtensionIsNotValid_ThenThrowException() { when(multipartFile.getOriginalFilename()).thenReturn(INCORRECT_FILE_NAME); ReportPortalException reportPortalException = assertThrows(ReportPortalException.class, () -> importLaunchHandlerImpl.importLaunch(projectDetails, reportPortalUser, FORMAT, - multipartFile, BASE_URL, new HashMap<>() + multipartFile, BASE_URL, new LaunchImportRQ() ) ); @@ -115,7 +122,7 @@ public void whenImportLaunch_AndFileSizeIsTooHigh_ThenThrowException() { when(multipartFile.getSize()).thenReturn(MAX_FILE_SIZE + 1L); ReportPortalException reportPortalException = assertThrows(ReportPortalException.class, () -> importLaunchHandlerImpl.importLaunch(projectDetails, reportPortalUser, FORMAT, - multipartFile, BASE_URL, new HashMap<>() + multipartFile, BASE_URL, new LaunchImportRQ() ) ); @@ -126,28 +133,39 @@ public void whenImportLaunch_AndFileSizeIsTooHigh_ThenThrowException() { } @Test - public void whenImportLaunch_AndFileIsValid_ThenCallImportLaunch() throws Exception { + public void whenImportLaunch_AndFileIsValid_ThenCallImportLaunch() { when(multipartFile.getOriginalFilename()).thenReturn(FILE_NAME); when(multipartFile.getSize()).thenReturn(FILE_SIZE); File tempFile = mock(File.class); try (MockedStatic<File> fileMockedStatic = Mockito.mockStatic(File.class)) { - fileMockedStatic.when(()->File.createTempFile(eq(FILE_NAME), eq("." + FilenameUtils.getExtension(FILE_NAME)))) + fileMockedStatic.when( + () -> File.createTempFile(eq(FILE_NAME), eq("." + FilenameUtils.getExtension(FILE_NAME)))) .thenReturn(tempFile); XmlImportStrategy xmlImportStrategy = mock(XmlImportStrategy.class); + LaunchImportRQ rq = new LaunchImportRQ(); when(xmlImportStrategy.importLaunch(projectDetails, reportPortalUser, tempFile, BASE_URL, - new HashMap<>() + rq )).thenReturn(LAUNCH_ID); when(importStrategyFactory.getImportStrategy(ImportType.XUNIT, FILE_NAME)).thenReturn( xmlImportStrategy); - importLaunchHandlerImpl.importLaunch(projectDetails, reportPortalUser, FORMAT, multipartFile, - BASE_URL, new HashMap<>() + var sampleLaunch = LaunchSampleUtil.getSampleLaunch(LAUNCH_ID); + when(launchRepository.findByUuid(LAUNCH_ID)).thenReturn(Optional.of(sampleLaunch)); + + var response = (LaunchImportCompletionRS) importLaunchHandlerImpl.importLaunch(projectDetails, + reportPortalUser, FORMAT, + multipartFile, + BASE_URL, rq ); + assertEquals(sampleLaunch.getUuid(), response.getData().getId()); + assertEquals(sampleLaunch.getName(), response.getData().getName()); + assertEquals(sampleLaunch.getNumber(), response.getData().getNumber()); + verify(importStrategyFactory).getImportStrategy(ImportType.XUNIT, FILE_NAME); verify(xmlImportStrategy).importLaunch(projectDetails, reportPortalUser, tempFile, BASE_URL, - new HashMap<>() + rq ); verify(messageBus).publishActivity(importFinishedEventCaptor.capture()); ImportFinishedEvent importFinishedEvent = importFinishedEventCaptor.getValue(); @@ -155,6 +173,7 @@ public void whenImportLaunch_AndFileIsValid_ThenCallImportLaunch() throws Except assertEquals(USER_NAME, importFinishedEvent.getUserLogin()); assertEquals(ID, importFinishedEvent.getUserId()); assertEquals(FILE_NAME, importFinishedEvent.getFileName()); + } } } diff --git a/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java b/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java index d22dfdc3ae..8dc2699d08 100644 --- a/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java @@ -16,6 +16,8 @@ import com.epam.ta.reportportal.core.launch.StartLaunchHandler; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.launch.Launch; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; +import com.epam.ta.reportportal.ws.model.launch.LaunchImportRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; import java.io.BufferedWriter; import java.io.File; @@ -24,8 +26,8 @@ import java.nio.file.Path; import java.time.Instant; import java.util.Date; -import java.util.HashMap; import java.util.Optional; +import java.util.Set; import javax.inject.Provider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -70,7 +72,7 @@ void setUp() { @Test void whenImportLaunch_thenProcessXmlFile(@TempDir Path tempDir) throws Exception { - HashMap<String, String> params = new HashMap<>(); + LaunchImportRQ rq = new LaunchImportRQ(); File xmlFile = createFile(tempDir); @@ -91,7 +93,7 @@ void whenImportLaunch_thenProcessXmlFile(@TempDir Path tempDir) throws Exception when(launchRepository.findByUuid(any())).thenReturn(Optional.of(launch)); when(xmlParseJobProvider.get()).thenReturn(xunitParseJob); - xmlImportStrategy.importLaunch(projectDetails, user, xmlFile, BASE_URL, params); + xmlImportStrategy.importLaunch(projectDetails, user, xmlFile, BASE_URL, rq); verify(startLaunchHandler, times(1)).startLaunch(any(), any(), any()); verify(finishLaunchHandler, times(1)).finishLaunch(any(), any(), any(), any(), any()); @@ -103,8 +105,8 @@ void whenImportLaunch_thenProcessXmlFile(@TempDir Path tempDir) throws Exception @Test void whenImportLaunch_andIsSkippedIssue_thenProcessXmlFileWithSkippedTrue(@TempDir Path tempDir) throws Exception { - HashMap<String, String> params = new HashMap<>(); - params.put(AbstractImportStrategy.SKIPPED_IS_NOT_ISSUE, "true"); + LaunchImportRQ rq = new LaunchImportRQ(); + rq.setAttributes(Set.of(new ItemAttributesRQ(AbstractImportStrategy.SKIPPED_IS_NOT_ISSUE, "true"))); File xmlFile = createFile(tempDir); @@ -125,7 +127,7 @@ void whenImportLaunch_andIsSkippedIssue_thenProcessXmlFileWithSkippedTrue(@TempD when(launchRepository.findByUuid(any())).thenReturn(Optional.of(launch)); when(xmlParseJobProvider.get()).thenReturn(xunitParseJob); - xmlImportStrategy.importLaunch(projectDetails, user, xmlFile, BASE_URL, params); + xmlImportStrategy.importLaunch(projectDetails, user, xmlFile, BASE_URL, rq); verify(startLaunchHandler, times(1)).startLaunch(any(), any(), any()); verify(finishLaunchHandler, times(1)).finishLaunch(any(), any(), any(), any(), any()); diff --git a/src/test/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandlerTest.java index d5293d61a3..8434eef739 100644 --- a/src/test/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/imprt/impl/junit/XunitImportHandlerTest.java @@ -18,6 +18,8 @@ import com.epam.ta.reportportal.ws.model.item.ItemCreatedRS; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -28,6 +30,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; @@ -65,6 +69,8 @@ public class XunitImportHandlerTest { private static final String TEST_CASE = "testcase"; + private static final ZoneId TEST_ZONE_ID = ZoneId.of("UTC"); + private static final String ATTR_NAME = "attribute"; private static final String TIMESTAMP = "1690210345"; @@ -96,12 +102,12 @@ public void whenStartElement_andQnameIsTestSuite_andItemUuidsAreEmpty_andStartTi LocalDateTime startSuiteTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(suiteTimestamp)), - ZoneId.systemDefault() + TEST_ZONE_ID ); LocalDateTime startItemTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(TIMESTAMP)), - ZoneId.systemDefault() + TEST_ZONE_ID ); setStartSuiteTime(xunitImportHandler, startSuiteTime); @@ -210,7 +216,7 @@ public void whenStartElement_andQnameIsTestCase_thenStartStepItem() { LocalDateTime startItemTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(TIMESTAMP)), - ZoneId.systemDefault() + TEST_ZONE_ID ); setStartItemTime(xunitImportHandler, startItemTime); @@ -328,6 +334,29 @@ public void whenStartElement_andQnameIsWarning_thenStatusIsWarning() { ); } + @ParameterizedTest + @CsvSource( + value = { + "2023-09-26T14:47:26+02:00", + "2023-09-26T07:47:26-05:00", + "2023-09-26T12:47:26+00:00", + "2023-09-26T12:47:26", + "2023-09-26T12:47:26 UTC", + "2023-09-26T12:47:26 GMT", + "2023-09-26T12:47:26+00:00 GMT", + "1695732446000" + } + ) + public void parseTimeStampDifferentFormats(String timestamp) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method method = XunitImportHandler.class.getDeclaredMethod("parseTimeStamp", String.class); + method.setAccessible(true); + + LocalDateTime startDateTime = (LocalDateTime) method.invoke(xunitImportHandler, timestamp); + + assertEquals("2023-09-26T12:47:26", startDateTime.toString()); + } + private void setStartSuiteTime(XunitImportHandler xunitImportHandler, LocalDateTime startSuiteTime) { try { diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerTest.java new file mode 100644 index 0000000000..a8dc44cf02 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/integration/impl/ExecuteIntegrationHandlerTest.java @@ -0,0 +1,112 @@ +package com.epam.ta.reportportal.core.integration.impl; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import com.epam.reportportal.extension.CommonPluginCommand; +import com.epam.reportportal.extension.ReportPortalExtensionPoint; +import com.epam.ta.reportportal.core.integration.ExecuteIntegrationHandler; +import com.epam.ta.reportportal.core.plugin.PluginBox; +import com.epam.ta.reportportal.dao.IntegrationRepository; +import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ExecuteIntegrationHandlerTest { + + private static final String PUBLIC_COMMAND_PREFIX = "public_"; + + private final IntegrationRepository integrationRepository = mock(IntegrationRepository.class); + private final PluginBox pluginBox = mock(PluginBox.class); + + private final ExecuteIntegrationHandler executeIntegrationHandler = new ExecuteIntegrationHandlerImpl( + integrationRepository, pluginBox); + + @Test + @DisplayName("Positive Test. Everything is fine") + public void executePublicCommandPositiveTest() { + final String pluginName = "signup"; + final String publicCommand = PUBLIC_COMMAND_PREFIX + "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + + CommonPluginCommand<String> commonPluginCommand = mock(CommonPluginCommand.class); + when(commonPluginCommand.executeCommand(params)).thenReturn("Ok"); + + ReportPortalExtensionPoint pluginInstance = mock(ReportPortalExtensionPoint.class); + when(pluginInstance.getCommonCommand(publicCommand)).thenReturn(commonPluginCommand); + + when(pluginBox.getInstance(pluginName, ReportPortalExtensionPoint.class)).thenReturn( + Optional.of(pluginInstance)); + + executeIntegrationHandler.executePublicCommand(pluginName, publicCommand, params); + + verify(pluginBox).getInstance(eq(pluginName), eq(ReportPortalExtensionPoint.class)); + verify(pluginInstance).getCommonCommand(eq(publicCommand)); + } + + @Test + @DisplayName("Negative Test. When command is not public") + public void executeNotPublicCommandTest() { + final String pluginName = "signup"; + final String publicCommand = "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + + assertThrows(ReportPortalException.class, () -> + executeIntegrationHandler.executePublicCommand(pluginName, publicCommand, params)); + + verifyNoInteractions(pluginBox); + } + + @Test + @DisplayName("Negative Test. When Plugin not found") + public void executePublicCommandWOPluginTest() { + final String pluginName = "signup"; + final String publicCommand = PUBLIC_COMMAND_PREFIX + "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + + CommonPluginCommand<String> commonPluginCommand = mock(CommonPluginCommand.class); + when(commonPluginCommand.executeCommand(params)).thenReturn("Ok"); + + ReportPortalExtensionPoint pluginInstance = mock(ReportPortalExtensionPoint.class); + + when(pluginBox.getInstance(pluginName, ReportPortalExtensionPoint.class)).thenReturn( + Optional.empty()); + + assertThrows(ReportPortalException.class, () -> + executeIntegrationHandler.executePublicCommand(pluginName, publicCommand, params)); + + verify(pluginBox).getInstance(eq(pluginName), eq(ReportPortalExtensionPoint.class)); + verifyNoInteractions(pluginInstance); + } + + @Test + @DisplayName("Negative Test. When Command not found") + public void executePublicCommandWOCommandTest() { + final String pluginName = "signup"; + final String publicCommand = PUBLIC_COMMAND_PREFIX + "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + + CommonPluginCommand<String> commonPluginCommand = mock(CommonPluginCommand.class); + when(commonPluginCommand.executeCommand(params)).thenReturn("Ok"); + + ReportPortalExtensionPoint pluginInstance = mock(ReportPortalExtensionPoint.class); + when(pluginInstance.getCommonCommand(publicCommand)).thenReturn(null); + + when(pluginBox.getInstance(pluginName, ReportPortalExtensionPoint.class)).thenReturn( + Optional.of(pluginInstance)); + + assertThrows(ReportPortalException.class, () -> + executeIntegrationHandler.executePublicCommand(pluginName, publicCommand, params)); + + verify(pluginBox).getInstance(eq(pluginName), eq(ReportPortalExtensionPoint.class)); + verify(pluginInstance).getCommonCommand(eq(publicCommand)); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerTest.java index c1714eb67c..0f4dead3bf 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/impl/GetIntegrationHandlerTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.integration.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.bts.handler.GetBugTrackingSystemHandler; import com.epam.ta.reportportal.core.integration.GetIntegrationHandler; import com.epam.ta.reportportal.core.integration.impl.util.IntegrationTestUtil; @@ -25,81 +32,81 @@ import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; -import org.junit.jupiter.api.Test; - import java.util.Map; import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class GetIntegrationHandlerTest { - private final Map integrationServiceMapming = mock(Map.class); - private final IntegrationService basicIntegrationService = mock(IntegrationService.class); - private final IntegrationRepository integrationRepository = mock(IntegrationRepository.class); - private final IntegrationTypeRepository integrationTypeRepository = mock(IntegrationTypeRepository.class); - private final ProjectRepository projectRepository = mock(ProjectRepository.class); - private final GetBugTrackingSystemHandler getBugTrackingSystemHandler = mock(GetBugTrackingSystemHandler.class); - - private final GetIntegrationHandler getIntegrationHandler = new GetIntegrationHandlerImpl(integrationServiceMapming, - basicIntegrationService, - integrationRepository, - integrationTypeRepository, - projectRepository, - getBugTrackingSystemHandler - ); - - @Test - void getProjectIntegrationById() { - - final long emailIntegrationId = 1L; - final long projectId = 1L; - - Project project = new Project(); - project.setId(projectId); - project.setName(TEST_PROJECT_NAME); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(project)); - - when(integrationRepository.findByIdAndProjectId(emailIntegrationId, - projectId - )).thenReturn(Optional.of(IntegrationTestUtil.getProjectEmailIntegration( - emailIntegrationId, - projectId - ))); - - IntegrationResource integrationResource = getIntegrationHandler.getProjectIntegrationById(emailIntegrationId, TEST_PROJECT_NAME); - - assertNotNull(integrationResource); - assertEquals(emailIntegrationId, (long) integrationResource.getId()); - assertEquals("superadmin", integrationResource.getCreator()); - assertEquals(false, integrationResource.getEnabled()); - assertEquals(projectId, (long) integrationResource.getProjectId()); - assertNotNull(integrationResource.getIntegrationParams()); - assertNotNull(integrationResource.getIntegrationType()); - } - - @Test - void getGlobalIntegrationById() { - - final long emailIntegrationId = 1L; - when(integrationRepository.findGlobalById(emailIntegrationId)).thenReturn(Optional.of(IntegrationTestUtil.getGlobalEmailIntegration( - emailIntegrationId))); - - IntegrationResource integrationResource = getIntegrationHandler.getGlobalIntegrationById(emailIntegrationId); - - assertNotNull(integrationResource); - assertEquals("superadmin", integrationResource.getCreator()); - assertEquals(emailIntegrationId, (long) integrationResource.getId()); - assertEquals(false, integrationResource.getEnabled()); - assertNull(integrationResource.getProjectId()); - assertNotNull(integrationResource.getIntegrationParams()); - assertNotNull(integrationResource.getIntegrationType()); - } + private final Map integrationServiceMapming = mock(Map.class); + private final IntegrationService basicIntegrationService = mock(IntegrationService.class); + private final IntegrationRepository integrationRepository = mock(IntegrationRepository.class); + private final IntegrationTypeRepository integrationTypeRepository = mock( + IntegrationTypeRepository.class); + private final ProjectRepository projectRepository = mock(ProjectRepository.class); + private final GetBugTrackingSystemHandler getBugTrackingSystemHandler = mock( + GetBugTrackingSystemHandler.class); + + private final GetIntegrationHandler getIntegrationHandler = new GetIntegrationHandlerImpl( + integrationServiceMapming, + basicIntegrationService, + integrationRepository, + integrationTypeRepository, + projectRepository, + getBugTrackingSystemHandler + ); + + @Test + void getProjectIntegrationById() { + + final long emailIntegrationId = 1L; + final long projectId = 1L; + + Project project = new Project(); + project.setId(projectId); + project.setName(TEST_PROJECT_NAME); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(project)); + + when(integrationRepository.findByIdAndProjectId(emailIntegrationId, + projectId + )).thenReturn(Optional.of(IntegrationTestUtil.getProjectEmailIntegration( + emailIntegrationId, + projectId + ))); + + IntegrationResource integrationResource = getIntegrationHandler.getProjectIntegrationById( + emailIntegrationId, TEST_PROJECT_NAME); + + assertNotNull(integrationResource); + assertEquals(emailIntegrationId, (long) integrationResource.getId()); + assertEquals("superadmin", integrationResource.getCreator()); + assertEquals(false, integrationResource.getEnabled()); + assertEquals(projectId, (long) integrationResource.getProjectId()); + assertNotNull(integrationResource.getIntegrationParams()); + assertNotNull(integrationResource.getIntegrationType()); + } + + @Test + void getGlobalIntegrationById() { + + final long emailIntegrationId = 1L; + when(integrationRepository.findGlobalById(emailIntegrationId)).thenReturn( + Optional.of(IntegrationTestUtil.getGlobalEmailIntegration( + emailIntegrationId))); + + IntegrationResource integrationResource = getIntegrationHandler.getGlobalIntegrationById( + emailIntegrationId); + + assertNotNull(integrationResource); + assertEquals("superadmin", integrationResource.getCreator()); + assertEquals(emailIntegrationId, (long) integrationResource.getId()); + assertEquals(false, integrationResource.getEnabled()); + assertNull(integrationResource.getProjectId()); + assertNotNull(integrationResource.getIntegrationParams()); + assertNotNull(integrationResource.getIntegrationType()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/impl/util/IntegrationTestUtil.java b/src/test/java/com/epam/ta/reportportal/core/integration/impl/util/IntegrationTestUtil.java index bba23ea3cd..99a5bcb692 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/impl/util/IntegrationTestUtil.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/impl/util/IntegrationTestUtil.java @@ -23,7 +23,6 @@ import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; import com.epam.ta.reportportal.entity.project.Project; import com.google.common.collect.Maps; - import java.time.LocalDateTime; import java.util.Map; import java.util.Optional; @@ -33,95 +32,96 @@ */ public final class IntegrationTestUtil { - private IntegrationTestUtil() { + private IntegrationTestUtil() { - //static only - } + //static only + } - public static Integration getGlobalEmailIntegration(long emailIntegrationId) { + public static Integration getGlobalEmailIntegration(long emailIntegrationId) { - Integration integration = new Integration(); + Integration integration = new Integration(); - integration.setCreator("superadmin"); - integration.setCreationDate(LocalDateTime.now()); - integration.setType(getEmailIntegrationType()); - integration.setParams(new IntegrationParams(getParams())); - integration.setId(emailIntegrationId); + integration.setCreator("superadmin"); + integration.setCreationDate(LocalDateTime.now()); + integration.setType(getEmailIntegrationType()); + integration.setParams(new IntegrationParams(getParams())); + integration.setId(emailIntegrationId); - return integration; - } + return integration; + } - public static Integration getProjectEmailIntegration(long emailIntegrationId, long projectId) { + public static Integration getProjectEmailIntegration(long emailIntegrationId, long projectId) { - Integration integration = getGlobalEmailIntegration(emailIntegrationId); + Integration integration = getGlobalEmailIntegration(emailIntegrationId); - integration.setProject(getProjectWithId(projectId).get()); + integration.setProject(getProjectWithId(projectId).get()); - return integration; - } + return integration; + } - public static Integration getGlobalJiraIntegration(long id, Map<String, Object> params) { + public static Integration getGlobalJiraIntegration(long id, Map<String, Object> params) { - Integration integration = new Integration(); + Integration integration = new Integration(); - integration.setCreator("superadmin"); - integration.setCreationDate(LocalDateTime.now()); - integration.setType(getJiraIntegrationType()); - integration.setParams(new IntegrationParams(params)); - integration.setId(id); + integration.setCreator("superadmin"); + integration.setCreationDate(LocalDateTime.now()); + integration.setType(getJiraIntegrationType()); + integration.setParams(new IntegrationParams(params)); + integration.setId(id); - return integration; - } + return integration; + } - public static Integration getProjectJiraIntegration(long id, Map<String, Object> params, long projectId) { + public static Integration getProjectJiraIntegration(long id, Map<String, Object> params, + long projectId) { - Integration integration = getGlobalJiraIntegration(id, params); + Integration integration = getGlobalJiraIntegration(id, params); - integration.setProject(getProjectWithId(projectId).get()); + integration.setProject(getProjectWithId(projectId).get()); - return integration; - } + return integration; + } - public static Map<String, Object> getParams() { + public static Map<String, Object> getParams() { - Map<String, Object> map = Maps.newHashMap(); - map.put("first", "first"); - map.put("second", "second"); - return map; - } + Map<String, Object> map = Maps.newHashMap(); + map.put("first", "first"); + map.put("second", "second"); + return map; + } - public static Optional<Project> getProjectWithId(long projectId) { - Project project = new Project(); + public static Optional<Project> getProjectWithId(long projectId) { + Project project = new Project(); - project.setId(projectId); + project.setId(projectId); - return Optional.of(project); - } + return Optional.of(project); + } - public static IntegrationType getJiraIntegrationType() { + public static IntegrationType getJiraIntegrationType() { - IntegrationType integrationType = new IntegrationType(); + IntegrationType integrationType = new IntegrationType(); - integrationType.setName("jira"); - integrationType.setCreationDate(LocalDateTime.now()); - integrationType.setId(1L); - integrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); - IntegrationTypeDetails details = new IntegrationTypeDetails(); - details.setDetails(Maps.newHashMap()); - integrationType.setDetails(details); + integrationType.setName("jira"); + integrationType.setCreationDate(LocalDateTime.now()); + integrationType.setId(1L); + integrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); + IntegrationTypeDetails details = new IntegrationTypeDetails(); + details.setDetails(Maps.newHashMap()); + integrationType.setDetails(details); - return integrationType; - } + return integrationType; + } - public static IntegrationType getEmailIntegrationType() { + public static IntegrationType getEmailIntegrationType() { - IntegrationType integrationType = new IntegrationType(); + IntegrationType integrationType = new IntegrationType(); - integrationType.setName("EMAIL"); - integrationType.setCreationDate(LocalDateTime.now()); - integrationType.setId(1L); - integrationType.setIntegrationGroup(IntegrationGroupEnum.NOTIFICATION); + integrationType.setName("EMAIL"); + integrationType.setCreationDate(LocalDateTime.now()); + integrationType.setId(1L); + integrationType.setIntegrationGroup(IntegrationGroupEnum.NOTIFICATION); - return integrationType; - } + return integrationType; + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationServiceTest.java index f5324b0296..dfd77065dc 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/AzureIntegrationServiceTest.java @@ -16,9 +16,18 @@ package com.epam.ta.reportportal.core.integration.util; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.integration.util.property.BtsProperties; import com.epam.ta.reportportal.entity.enums.AuthType; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.HashMap; +import java.util.Map; import org.jasypt.util.text.BasicTextEncryptor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,70 +35,64 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @ExtendWith(MockitoExtension.class) class AzureIntegrationServiceTest { - private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); - - @Mock - private BasicTextEncryptor encryptor; - - @InjectMocks - private BtsIntegrationService btsIntegrationService; - - @Test - void testParameters() { - when(encryptor.encrypt(any())).thenReturn("encrypted"); - Map<String, Object> res = btsIntegrationService.retrieveCreateParams("azure", getCorrectRallyIntegrationParams()); - assertThat(res.keySet(), hasSize(4)); - } - - @Test - void testParametersWithoutKey() { - Map<String, Object> params = getCorrectRallyIntegrationParams(); - params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsIntegrationService.retrieveCreateParams("azure",params) - ); - assertEquals("Impossible interact with integration. AccessKey value is not specified", exception.getMessage()); - } - - @Test - void testParametersUnsupportedAuthType() { - Map<String, Object> params = getCorrectRallyIntegrationParams(); - params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsIntegrationService.retrieveCreateParams("azure", params) - ); - assertEquals( - "Impossible interact with integration. Unsupported auth type for integration - " + UNSUPPORTED_AUTH_TYPE_NAME, - exception.getMessage() - ); - } - - private Map<String, Object> getCorrectRallyIntegrationParams() { - - Map<String, Object> params = new HashMap<>(); - params.put(BtsProperties.URL.getName(), "azure-url"); - params.put(BtsProperties.PROJECT.getName(), "azure-project"); - params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); - params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); - - return params; - } + + private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); + + @Mock + private BasicTextEncryptor encryptor; + + @InjectMocks + private BtsIntegrationService btsIntegrationService; + + @Test + void testParameters() { + when(encryptor.encrypt(any())).thenReturn("encrypted"); + Map<String, Object> res = btsIntegrationService.retrieveCreateParams("azure", + getCorrectRallyIntegrationParams()); + assertThat(res.keySet(), hasSize(4)); + } + + @Test + void testParametersWithoutKey() { + Map<String, Object> params = getCorrectRallyIntegrationParams(); + params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsIntegrationService.retrieveCreateParams("azure", params) + ); + assertEquals("Impossible interact with integration. AccessKey value is not specified", + exception.getMessage()); + } + + @Test + void testParametersUnsupportedAuthType() { + Map<String, Object> params = getCorrectRallyIntegrationParams(); + params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsIntegrationService.retrieveCreateParams("azure", params) + ); + assertEquals( + "Impossible interact with integration. Unsupported auth type for integration - " + + UNSUPPORTED_AUTH_TYPE_NAME, + exception.getMessage() + ); + } + + private Map<String, Object> getCorrectRallyIntegrationParams() { + + Map<String, Object> params = new HashMap<>(); + params.put(BtsProperties.URL.getName(), "azure-url"); + params.put(BtsProperties.PROJECT.getName(), "azure-project"); + params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); + params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); + + return params; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationServiceTest.java index a8220e5fcd..84cacacea3 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/EmailServerIntegrationServiceTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.integration.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.plugin.PluginBox; import com.epam.ta.reportportal.dao.IntegrationRepository; import com.epam.ta.reportportal.entity.integration.Integration; @@ -25,97 +31,97 @@ import com.epam.ta.reportportal.util.email.MailServiceFactory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.jasypt.util.text.BasicTextEncryptor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import javax.mail.MessagingException; import java.util.HashMap; import java.util.Map; import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import javax.mail.MessagingException; +import org.jasypt.util.text.BasicTextEncryptor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class EmailServerIntegrationServiceTest { - private static final String INTEGRATION_NAME = "email"; - - private IntegrationRepository integrationRepository = mock(IntegrationRepository.class); - private final PluginBox pluginBox = mock(PluginBox.class); - private MailServiceFactory mailServiceFactory = mock(MailServiceFactory.class); - private EmailService emailService = mock(EmailService.class); - - private EmailServerIntegrationService emailServerIntegrationService; - - @BeforeEach - void setUp() { - BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor(); - basicTextEncryptor.setPassword("123"); - emailServerIntegrationService = new EmailServerIntegrationService(integrationRepository, - pluginBox, - basicTextEncryptor, - mailServiceFactory - ); - } - - @Test - void validateGlobalIntegrationNegative() throws MessagingException { - //given - Integration integration = new Integration(); - IntegrationType integrationType = new IntegrationType(); - integrationType.setName("email"); - integration.setType(integrationType); - - //when - when(integrationRepository.findAllGlobalByType(integrationType)).thenReturn(Lists.newArrayList()); - when(mailServiceFactory.getEmailService(integration)).thenReturn(Optional.of(emailService)); - doThrow(MessagingException.class).when(emailService).testConnection(); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> emailServerIntegrationService.retrieveCreateParams("email", new HashMap<>()) - ); - - //then - assertEquals("Error in handled Request. Please, check specified parameters: 'No integration params provided'", - exception.getMessage() - ); - } - - @Test - void retrieveIntegrationParams() { - Map<String, Object> map = emailServerIntegrationService.retrieveCreateParams("email", getParams()); - assertEquals(defaultParams(), map); - } - - @Test - void retrieveIntegrationParamsInvalidPort() { - Map<String, Object> params = Maps.newHashMap(); - params.put("from", "from@mail.com"); - params.put("port", "123456789"); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> emailServerIntegrationService.retrieveCreateParams("email", params) - ); - assertEquals("Incorrect Request. Incorrect 'Port' value. Allowed value is [1..65535]", exception.getMessage()); - } - - private Map<String, Object> defaultParams() { - Map<String, Object> res = Maps.newHashMap(); - res.put("protocol", "value2"); - res.put("host", "value3"); - res.put("from", "from@mail.com"); - return res; - } - - private Map<String, Object> getParams() { - Map<String, Object> params = Maps.newHashMap(); - params.put("from", "from@mail.com"); - params.put("protocol", "value2"); - params.put("host", "value3"); - - return params; - } + private static final String INTEGRATION_NAME = "email"; + + private IntegrationRepository integrationRepository = mock(IntegrationRepository.class); + private final PluginBox pluginBox = mock(PluginBox.class); + private MailServiceFactory mailServiceFactory = mock(MailServiceFactory.class); + private EmailService emailService = mock(EmailService.class); + + private EmailServerIntegrationService emailServerIntegrationService; + + @BeforeEach + void setUp() { + BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor(); + basicTextEncryptor.setPassword("123"); + emailServerIntegrationService = new EmailServerIntegrationService(integrationRepository, + pluginBox, + basicTextEncryptor, + mailServiceFactory + ); + } + + @Test + void validateGlobalIntegrationNegative() throws MessagingException { + //given + Integration integration = new Integration(); + IntegrationType integrationType = new IntegrationType(); + integrationType.setName("email"); + integration.setType(integrationType); + + //when + when(integrationRepository.findAllGlobalByType(integrationType)).thenReturn( + Lists.newArrayList()); + when(mailServiceFactory.getEmailService(integration)).thenReturn(Optional.of(emailService)); + doThrow(MessagingException.class).when(emailService).testConnection(); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> emailServerIntegrationService.retrieveCreateParams("email", new HashMap<>()) + ); + + //then + assertEquals( + "Error in handled Request. Please, check specified parameters: 'No integration params provided'", + exception.getMessage() + ); + } + + @Test + void retrieveIntegrationParams() { + Map<String, Object> map = emailServerIntegrationService.retrieveCreateParams("email", + getParams()); + assertEquals(defaultParams(), map); + } + + @Test + void retrieveIntegrationParamsInvalidPort() { + Map<String, Object> params = Maps.newHashMap(); + params.put("from", "from@mail.com"); + params.put("port", "123456789"); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> emailServerIntegrationService.retrieveCreateParams("email", params) + ); + assertEquals("Incorrect Request. Incorrect 'Port' value. Allowed value is [1..65535]", + exception.getMessage()); + } + + private Map<String, Object> defaultParams() { + Map<String, Object> res = Maps.newHashMap(); + res.put("protocol", "value2"); + res.put("host", "value3"); + res.put("from", "from@mail.com"); + return res; + } + + private Map<String, Object> getParams() { + Map<String, Object> params = Maps.newHashMap(); + params.put("from", "from@mail.com"); + params.put("protocol", "value2"); + params.put("host", "value3"); + + return params; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/JiraIntegrationServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/JiraIntegrationServiceTest.java index 73cc599b96..d4b64eb9df 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/JiraIntegrationServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/JiraIntegrationServiceTest.java @@ -16,105 +16,109 @@ package com.epam.ta.reportportal.core.integration.util; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + import com.epam.ta.reportportal.core.integration.util.property.BtsProperties; import com.epam.ta.reportportal.core.plugin.PluginBox; import com.epam.ta.reportportal.dao.IntegrationRepository; import com.epam.ta.reportportal.entity.enums.AuthType; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.HashMap; +import java.util.Map; import org.jasypt.util.text.BasicTextEncryptor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class JiraIntegrationServiceTest { - private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); - private IntegrationRepository integrationRepository = mock(IntegrationRepository.class); - private PluginBox pluginBox = mock(PluginBox.class); - - private BtsIntegrationService btsService; - - @BeforeEach - void setUp() { - BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor(); - basicTextEncryptor.setPassword("123"); - btsService = new BtsIntegrationService(integrationRepository, pluginBox, basicTextEncryptor); - } - - @Test - void testParameters() { - Map<String, Object> res = btsService.retrieveCreateParams("jira", getCorrectJiraIntegrationParams()); - assertThat(res.keySet(), hasSize(5)); - } - - @Test - void testParametersWithoutUsername() { - Map<String, Object> params = getCorrectJiraIntegrationParams(); - params.remove(BtsProperties.USER_NAME.getName()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsService.retrieveCreateParams("jira", params) - ); - assertEquals("Impossible interact with integration. Username value is not specified", exception.getMessage()); - } - - @Test - void testParametersWithouPassword() { - Map<String, Object> params = getCorrectJiraIntegrationParams(); - params.remove(BtsProperties.PASSWORD.getName()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsService.retrieveCreateParams("jira", params) - ); - assertEquals("Impossible interact with integration. Password value is not specified", exception.getMessage()); - } - - @Test - void testParametersWithouKey() { - Map<String, Object> params = getCorrectJiraIntegrationParams(); - params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); - params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsService.retrieveCreateParams("jira", params) - ); - assertEquals("Impossible interact with integration. AccessKey value is not specified", exception.getMessage()); - } - - @Test - void testParametersUnopportetAuthType() { - Map<String, Object> params = getCorrectJiraIntegrationParams(); - params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsService.retrieveCreateParams("jira", params) - ); - assertEquals( - "Impossible interact with integration. Unsupported auth type for integration - " + UNSUPPORTED_AUTH_TYPE_NAME, - exception.getMessage() - ); - } - - private Map<String, Object> getCorrectJiraIntegrationParams() { - - Map<String, Object> params = new HashMap<>(); - params.put(BtsProperties.URL.getName(), "jira-url"); - params.put(BtsProperties.PROJECT.getName(), "jira-project"); - params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.BASIC.name()); - params.put(BtsProperties.USER_NAME.getName(), "USERNAME"); - params.put(BtsProperties.PASSWORD.getName(), "PASSWORD"); - params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); - - return params; - } + private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); + private IntegrationRepository integrationRepository = mock(IntegrationRepository.class); + private PluginBox pluginBox = mock(PluginBox.class); + + private BtsIntegrationService btsService; + + @BeforeEach + void setUp() { + BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor(); + basicTextEncryptor.setPassword("123"); + btsService = new BtsIntegrationService(integrationRepository, pluginBox, basicTextEncryptor); + } + + @Test + void testParameters() { + Map<String, Object> res = btsService.retrieveCreateParams("jira", + getCorrectJiraIntegrationParams()); + assertThat(res.keySet(), hasSize(5)); + } + + @Test + void testParametersWithoutUsername() { + Map<String, Object> params = getCorrectJiraIntegrationParams(); + params.remove(BtsProperties.USER_NAME.getName()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsService.retrieveCreateParams("jira", params) + ); + assertEquals("Impossible interact with integration. Username value is not specified", + exception.getMessage()); + } + + @Test + void testParametersWithouPassword() { + Map<String, Object> params = getCorrectJiraIntegrationParams(); + params.remove(BtsProperties.PASSWORD.getName()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsService.retrieveCreateParams("jira", params) + ); + assertEquals("Impossible interact with integration. Password value is not specified", + exception.getMessage()); + } + + @Test + void testParametersWithouKey() { + Map<String, Object> params = getCorrectJiraIntegrationParams(); + params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); + params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsService.retrieveCreateParams("jira", params) + ); + assertEquals("Impossible interact with integration. AccessKey value is not specified", + exception.getMessage()); + } + + @Test + void testParametersUnopportetAuthType() { + Map<String, Object> params = getCorrectJiraIntegrationParams(); + params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsService.retrieveCreateParams("jira", params) + ); + assertEquals( + "Impossible interact with integration. Unsupported auth type for integration - " + + UNSUPPORTED_AUTH_TYPE_NAME, + exception.getMessage() + ); + } + + private Map<String, Object> getCorrectJiraIntegrationParams() { + + Map<String, Object> params = new HashMap<>(); + params.put(BtsProperties.URL.getName(), "jira-url"); + params.put(BtsProperties.PROJECT.getName(), "jira-project"); + params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.BASIC.name()); + params.put(BtsProperties.USER_NAME.getName(), "USERNAME"); + params.put(BtsProperties.PASSWORD.getName(), "PASSWORD"); + params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); + + return params; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/RallyIntegrationServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/RallyIntegrationServiceTest.java index c69e086135..c63ffb5640 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/RallyIntegrationServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/RallyIntegrationServiceTest.java @@ -16,9 +16,18 @@ package com.epam.ta.reportportal.core.integration.util; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.integration.util.property.BtsProperties; import com.epam.ta.reportportal.entity.enums.AuthType; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.HashMap; +import java.util.Map; import org.jasypt.util.text.BasicTextEncryptor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,70 +35,64 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.HashMap; -import java.util.Map; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ @ExtendWith(MockitoExtension.class) class RallyIntegrationServiceTest { - private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); - - @Mock - private BasicTextEncryptor encryptor; - - @InjectMocks - private BtsIntegrationService btsIntegrationService; - - @Test - void testParameters() { - when(encryptor.encrypt(any())).thenReturn("encrypted"); - Map<String, Object> res = btsIntegrationService.retrieveCreateParams("rally", getCorrectRallyIntegrationParams()); - assertThat(res.keySet(), hasSize(4)); - } - - @Test - void testParametersWithoutKey() { - Map<String, Object> params = getCorrectRallyIntegrationParams(); - params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsIntegrationService.retrieveCreateParams("rally", params) - ); - assertEquals("Impossible interact with integration. AccessKey value is not specified", exception.getMessage()); - } - - @Test - void testParametersUnsupportedAuthType() { - Map<String, Object> params = getCorrectRallyIntegrationParams(); - params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> btsIntegrationService.retrieveCreateParams("rally", params) - ); - assertEquals( - "Impossible interact with integration. Unsupported auth type for integration - " + UNSUPPORTED_AUTH_TYPE_NAME, - exception.getMessage() - ); - } - - private Map<String, Object> getCorrectRallyIntegrationParams() { - - Map<String, Object> params = new HashMap<>(); - params.put(BtsProperties.URL.getName(), "rally-url"); - params.put(BtsProperties.PROJECT.getName(), "rally-project"); - params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); - params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); - - return params; - } + + private static final String UNSUPPORTED_AUTH_TYPE_NAME = AuthType.NTLM.name(); + + @Mock + private BasicTextEncryptor encryptor; + + @InjectMocks + private BtsIntegrationService btsIntegrationService; + + @Test + void testParameters() { + when(encryptor.encrypt(any())).thenReturn("encrypted"); + Map<String, Object> res = btsIntegrationService.retrieveCreateParams("rally", + getCorrectRallyIntegrationParams()); + assertThat(res.keySet(), hasSize(4)); + } + + @Test + void testParametersWithoutKey() { + Map<String, Object> params = getCorrectRallyIntegrationParams(); + params.remove(BtsProperties.OAUTH_ACCESS_KEY.getName()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsIntegrationService.retrieveCreateParams("rally", params) + ); + assertEquals("Impossible interact with integration. AccessKey value is not specified", + exception.getMessage()); + } + + @Test + void testParametersUnsupportedAuthType() { + Map<String, Object> params = getCorrectRallyIntegrationParams(); + params.put(BtsProperties.AUTH_TYPE.getName(), UNSUPPORTED_AUTH_TYPE_NAME); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> btsIntegrationService.retrieveCreateParams("rally", params) + ); + assertEquals( + "Impossible interact with integration. Unsupported auth type for integration - " + + UNSUPPORTED_AUTH_TYPE_NAME, + exception.getMessage() + ); + } + + private Map<String, Object> getCorrectRallyIntegrationParams() { + + Map<String, Object> params = new HashMap<>(); + params.put(BtsProperties.URL.getName(), "rally-url"); + params.put(BtsProperties.PROJECT.getName(), "rally-project"); + params.put(BtsProperties.AUTH_TYPE.getName(), AuthType.OAUTH.name()); + params.put(BtsProperties.OAUTH_ACCESS_KEY.getName(), "KEY"); + + return params; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationServiceTest.java index fcf95a8cab..a4a0097c4d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/SauceLabsIntegrationServiceTest.java @@ -16,9 +16,18 @@ package com.epam.ta.reportportal.core.integration.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.integration.util.property.SauceLabsProperties; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Maps; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.apache.commons.collections.MapUtils; import org.jasypt.util.text.BasicTextEncryptor; import org.junit.jupiter.api.Test; @@ -27,72 +36,70 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class SauceLabsIntegrationServiceTest { - @Mock - private BasicTextEncryptor encryptor; + @Mock + private BasicTextEncryptor encryptor; - @InjectMocks - private SauceLabsIntegrationService sauceLabsIntegrationService; + @InjectMocks + private SauceLabsIntegrationService sauceLabsIntegrationService; - @Test - void retrieveEmptyParamsTest() { - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> sauceLabsIntegrationService.retrieveCreateParams("saucelabs", Collections.emptyMap()) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'No integration params provided'", - exception.getMessage() - ); - } + @Test + void retrieveEmptyParamsTest() { + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> sauceLabsIntegrationService.retrieveCreateParams("saucelabs", Collections.emptyMap()) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'No integration params provided'", + exception.getMessage() + ); + } - @Test - void retrieveParamsWithoutAccessKeyTest() { - HashMap<String, Object> integrationParams = Maps.newHashMap(); - integrationParams.put(SauceLabsProperties.USERNAME.getName(), "user"); - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> { - sauceLabsIntegrationService.retrieveCreateParams("saucelabs", integrationParams); - }); - assertEquals("Error in handled Request. Please, check specified parameters: 'Access token value is not specified'", - exception.getMessage() - ); - } + @Test + void retrieveParamsWithoutAccessKeyTest() { + HashMap<String, Object> integrationParams = Maps.newHashMap(); + integrationParams.put(SauceLabsProperties.USERNAME.getName(), "user"); + ReportPortalException exception = assertThrows(ReportPortalException.class, () -> { + sauceLabsIntegrationService.retrieveCreateParams("saucelabs", integrationParams); + }); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Access token value is not specified'", + exception.getMessage() + ); + } - @Test - void retrieveParamsWithoutUsernameTest() { - HashMap<String, Object> integrationParams = Maps.newHashMap(); - integrationParams.put(SauceLabsProperties.ACCESS_TOKEN.getName(), "token"); - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> { - sauceLabsIntegrationService.retrieveCreateParams("saucelabs", integrationParams); - }); - assertEquals("Error in handled Request. Please, check specified parameters: 'Username value is not specified'", exception.getMessage()); - } + @Test + void retrieveParamsWithoutUsernameTest() { + HashMap<String, Object> integrationParams = Maps.newHashMap(); + integrationParams.put(SauceLabsProperties.ACCESS_TOKEN.getName(), "token"); + ReportPortalException exception = assertThrows(ReportPortalException.class, () -> { + sauceLabsIntegrationService.retrieveCreateParams("saucelabs", integrationParams); + }); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Username value is not specified'", + exception.getMessage()); + } - @Test - void retrieveParamsPositiveTest() { - final HashMap<String, Object> integrationParams = Maps.newHashMap(); - integrationParams.put(SauceLabsProperties.USERNAME.getName(), "username"); - integrationParams.put(SauceLabsProperties.ACCESS_TOKEN.getName(), "token"); - integrationParams.put("param", "value"); + @Test + void retrieveParamsPositiveTest() { + final HashMap<String, Object> integrationParams = Maps.newHashMap(); + integrationParams.put(SauceLabsProperties.USERNAME.getName(), "username"); + integrationParams.put(SauceLabsProperties.ACCESS_TOKEN.getName(), "token"); + integrationParams.put("param", "value"); - final String encryptedToken = "encryptedToken"; - when(encryptor.encrypt("token")).thenReturn(encryptedToken); + final String encryptedToken = "encryptedToken"; + when(encryptor.encrypt("token")).thenReturn(encryptedToken); - final Map<String, Object> params = sauceLabsIntegrationService.retrieveCreateParams("saucelabs", integrationParams); + final Map<String, Object> params = sauceLabsIntegrationService.retrieveCreateParams("saucelabs", + integrationParams); - assertNotNull(params); - assertTrue(MapUtils.isNotEmpty(params)); - assertEquals(3, params.size()); - assertEquals(encryptedToken, params.get(SauceLabsProperties.ACCESS_TOKEN.getName())); - } + assertNotNull(params); + assertTrue(MapUtils.isNotEmpty(params)); + assertEquals(3, params.size()); + assertEquals(encryptedToken, params.get(SauceLabsProperties.ACCESS_TOKEN.getName())); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidatorTest.java index 959b8dbd34..16a687238d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/util/validator/IntegrationValidatorTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.core.integration.util.validator; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.integration.IntegrationType; @@ -24,68 +27,67 @@ import com.google.common.collect.Sets; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IntegrationValidatorTest { - @Test - void validateNonGlobalIntegration() { - Integration integration = new Integration(); - integration.setId(1L); - integration.setProject(new Project()); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> IntegrationValidator.validateProjectLevelIntegrationConstraints(new Project(), integration) - ); - assertEquals("Impossible interact with integration. Integration with ID = '1' is not global.", exception.getMessage()); - } + @Test + void validateNonGlobalIntegration() { + Integration integration = new Integration(); + integration.setId(1L); + integration.setProject(new Project()); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> IntegrationValidator.validateProjectLevelIntegrationConstraints(new Project(), + integration) + ); + assertEquals("Impossible interact with integration. Integration with ID = '1' is not global.", + exception.getMessage()); + } - @Test - void validateIntegrationGroups() { - Integration integration = new Integration(); - integration.setId(1L); - IntegrationType type = new IntegrationType(); - type.setName("jira"); - type.setIntegrationGroup(IntegrationGroupEnum.BTS); - integration.setType(type); + @Test + void validateIntegrationGroups() { + Integration integration = new Integration(); + integration.setId(1L); + IntegrationType type = new IntegrationType(); + type.setName("jira"); + type.setIntegrationGroup(IntegrationGroupEnum.BTS); + integration.setType(type); - Project project = new Project(); - Integration projectIntegration = new Integration(); - IntegrationType projectIntegrationType = new IntegrationType(); - projectIntegrationType.setName("jira"); - projectIntegrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); - projectIntegration.setType(projectIntegrationType); - project.setIntegrations(Sets.newHashSet(projectIntegration)); + Project project = new Project(); + Integration projectIntegration = new Integration(); + IntegrationType projectIntegrationType = new IntegrationType(); + projectIntegrationType.setName("jira"); + projectIntegrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); + projectIntegration.setType(projectIntegrationType); + project.setIntegrations(Sets.newHashSet(projectIntegration)); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> IntegrationValidator.validateProjectLevelIntegrationConstraints(project, integration) - ); - assertEquals( - "Impossible interact with integration. Global integration with ID = '1' has been found, but you cannot use it, because you have project-level integration(s) of that type", - exception.getMessage() - ); - } + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> IntegrationValidator.validateProjectLevelIntegrationConstraints(project, integration) + ); + assertEquals( + "Impossible interact with integration. Global integration with ID = '1' has been found, but you cannot use it, because you have project-level integration(s) of that type", + exception.getMessage() + ); + } - @Test - void successfullyValidate() { - Integration integration = new Integration(); - integration.setId(1L); - IntegrationType type = new IntegrationType(); - type.setName("rally"); - type.setIntegrationGroup(IntegrationGroupEnum.BTS); - integration.setType(type); + @Test + void successfullyValidate() { + Integration integration = new Integration(); + integration.setId(1L); + IntegrationType type = new IntegrationType(); + type.setName("rally"); + type.setIntegrationGroup(IntegrationGroupEnum.BTS); + integration.setType(type); - Project project = new Project(); - Integration projectIntegration = new Integration(); - IntegrationType projectIntegrationType = new IntegrationType(); - projectIntegrationType.setName("jira"); - projectIntegrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); - projectIntegration.setType(projectIntegrationType); - project.setIntegrations(Sets.newHashSet(projectIntegration)); + Project project = new Project(); + Integration projectIntegration = new Integration(); + IntegrationType projectIntegrationType = new IntegrationType(); + projectIntegrationType.setName("jira"); + projectIntegrationType.setIntegrationGroup(IntegrationGroupEnum.BTS); + projectIntegration.setType(projectIntegrationType); + project.setIntegrations(Sets.newHashSet(projectIntegration)); - IntegrationValidator.validateProjectLevelIntegrationConstraints(project, integration); - } + IntegrationValidator.validateProjectLevelIntegrationConstraints(project, integration); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImplTest.java index ba2d1d8ecb..c5ec0b630e 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/DeleteTestItemHandlerImplTest.java @@ -16,8 +16,21 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.ElementsCounterService; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.core.remover.ContentRemover; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -31,20 +44,14 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import java.util.Collection; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collection; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.springframework.context.ApplicationEventPublisher; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -52,184 +59,203 @@ @ExtendWith(MockitoExtension.class) class DeleteTestItemHandlerImplTest { - @Mock - private TestItemRepository testItemRepository; - - @Mock - private ContentRemover<Long> itemContentRemover; - - @Mock - private LogIndexer logIndexer; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private AttachmentRepository attachmentRepository; - - @InjectMocks - private DeleteTestItemHandlerImpl handler; - - @Test - void testItemNotFound() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(testItemRepository.findById(1L)).thenReturn(Optional.empty()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", exception.getMessage()); - } - - @Test - void deleteInProgressItem() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.PASSED); - launch.setProjectId(1L); - launch.setUserId(1L); - - when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(getTestItem(StatusEnum.IN_PROGRESS, - StatusEnum.IN_PROGRESS, - 1L, - "test" - ))); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Unable to perform operation for non-finished test item. Unable to delete test item ['1'] in progress state", - exception.getMessage() - ); - } - - @Test - void deleteTestItemWithInProgressLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.IN_PROGRESS); - launch.setProjectId(1L); - launch.setUserId(1L); - - when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.IN_PROGRESS, 1L, "test"))); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals( - "Unable to perform operation for non-finished launch. Unable to delete test item ['1'] under launch ['null'] with 'In progress' state", - exception.getMessage() - ); - } - - @Test - void deleteTestItemFromAnotherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.PASSED); - launch.setProjectId(2L); - launch.setUserId(1L); - - when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.FAILED, 2L, "test"))); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Forbidden operation. Deleting testItem '1' is not under specified project '1'", exception.getMessage()); - } - - @Test - void deleteNotOwnTestItem() { - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - rpUser.setUserId(2L); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.PASSED); - launch.setProjectId(1L); - launch.setUserId(1L); - - when(testItemRepository.findById(1L)).thenReturn(Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.FAILED, 1L, "owner"))); - when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("You do not have enough permissions. You are not a launch owner.", exception.getMessage()); - } - - @Test - void deleteTestItemWithParent() { - ReportPortalUser rpUser = getRpUser("owner", UserRole.ADMINISTRATOR, ProjectRole.MEMBER, 1L); - - TestItem item = getTestItem(StatusEnum.PASSED, StatusEnum.PASSED, 1L, "owner"); - item.setItemId(123123L); - TestItem parent = new TestItem(); - long parentId = 35L; - parent.setItemId(parentId); - String path = "1.2.3"; - parent.setPath(path); - item.setParentId(parent.getItemId()); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.PASSED); - launch.setProjectId(1L); - launch.setUserId(1L); - - item.setLaunchId(launch.getId()); - when(launchRepository.findById(item.getLaunchId())).thenReturn(Optional.of(launch)); - when(testItemRepository.findById(1L)).thenReturn(Optional.of(item)); - when(testItemRepository.findById(parentId)).thenReturn(Optional.of(parent)); - when(testItemRepository.hasChildren(parent.getItemId(), parent.getPath())).thenReturn(false); - when(launchRepository.hasRetries(any())).thenReturn(false); - when(attachmentRepository.moveForDeletionByItems(any(Collection.class))).thenReturn(1); - handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser); - - verify(itemContentRemover,times(1)).remove(anyLong()); - assertFalse(parent.isHasChildren()); - } - - @Test - void deleteItemPositive() { - ReportPortalUser rpUser = getRpUser("owner", UserRole.ADMINISTRATOR, ProjectRole.MEMBER, 1L); - TestItem item = getTestItem(StatusEnum.FAILED, StatusEnum.FAILED, 1L, "owner"); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.FAILED); - launch.setProjectId(1L); - launch.setUserId(1L); - - when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); - when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); - - OperationCompletionRS response = handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser); - - verify(itemContentRemover,times(1)).remove(anyLong()); - assertEquals("Test Item with ID = '1' has been successfully deleted.", response.getResultMessage()); - - } - - private TestItem getTestItem(StatusEnum itemStatus, StatusEnum launchStatus, Long projectId, String owner) { - TestItem item = new TestItem(); - item.setItemId(1L); - TestItemResults results = new TestItemResults(); - results.setStatus(itemStatus); - item.setItemResults(results); - Launch launch = new Launch(); - launch.setId(1L); - launch.setStatus(launchStatus); - launch.setProjectId(projectId); - User user = new User(); - user.setId(1L); - user.setLogin(owner); - launch.setUserId(user.getId()); - item.setLaunchId(launch.getId()); - return item; - } + @Mock + private TestItemRepository testItemRepository; + + @Mock + private ContentRemover<Long> itemContentRemover; + + @Mock + private LogIndexer logIndexer; + + @Mock + private ElementsCounterService elementsCounterService; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @Mock + private LaunchRepository launchRepository; + + @Mock + private AttachmentRepository attachmentRepository; + + @Mock + private LogService logService; + + @InjectMocks + private DeleteTestItemHandlerImpl handler; + + @Test + void testItemNotFound() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(testItemRepository.findById(1L)).thenReturn(Optional.empty()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", + exception.getMessage()); + } + + @Test + void deleteInProgressItem() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.PASSED); + launch.setProjectId(1L); + launch.setUserId(1L); + + when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(getTestItem(StatusEnum.IN_PROGRESS, + StatusEnum.IN_PROGRESS, + 1L, + "test" + ))); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals( + "Unable to perform operation for non-finished test item. Unable to delete test item ['1'] in progress state", + exception.getMessage() + ); + } + + @Test + void deleteTestItemWithInProgressLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.IN_PROGRESS); + launch.setProjectId(1L); + launch.setUserId(1L); + + when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); + when(testItemRepository.findById(1L)).thenReturn( + Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.IN_PROGRESS, 1L, "test"))); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals( + "Unable to perform operation for non-finished launch. Unable to delete test item ['1'] under launch ['null'] with 'In progress' state", + exception.getMessage() + ); + } + + @Test + void deleteTestItemFromAnotherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.PASSED); + launch.setProjectId(2L); + launch.setUserId(1L); + + when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); + when(testItemRepository.findById(1L)).thenReturn( + Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.FAILED, 2L, "test"))); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("Forbidden operation. Deleting testItem '1' is not under specified project '1'", + exception.getMessage()); + } + + @Test + void deleteNotOwnTestItem() { + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + rpUser.setUserId(2L); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.PASSED); + launch.setProjectId(1L); + launch.setUserId(1L); + + when(testItemRepository.findById(1L)).thenReturn( + Optional.of(getTestItem(StatusEnum.PASSED, StatusEnum.FAILED, 1L, "owner"))); + when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("You do not have enough permissions. You are not a launch owner.", + exception.getMessage()); + } + + @Test + void deleteTestItemWithParent() { + ReportPortalUser rpUser = getRpUser("owner", UserRole.ADMINISTRATOR, ProjectRole.MEMBER, 1L); + + TestItem item = getTestItem(StatusEnum.PASSED, StatusEnum.PASSED, 1L, "owner"); + item.setItemId(123123L); + TestItem parent = new TestItem(); + long parentId = 35L; + parent.setItemId(parentId); + String path = "1.2.3"; + parent.setPath(path); + item.setParentId(parent.getItemId()); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.PASSED); + launch.setProjectId(1L); + launch.setUserId(1L); + + item.setLaunchId(launch.getId()); + when(launchRepository.findById(item.getLaunchId())).thenReturn(Optional.of(launch)); + when(testItemRepository.findById(1L)).thenReturn(Optional.of(item)); + when(testItemRepository.findById(parentId)).thenReturn(Optional.of(parent)); + when(testItemRepository.hasChildren(parent.getItemId(), parent.getPath())).thenReturn(false); + when(launchRepository.hasRetries(any())).thenReturn(false); + when(attachmentRepository.moveForDeletionByItems(any(Collection.class))).thenReturn(1); + handler.deleteTestItem(1L, extractProjectDetails(rpUser, "test_project"), rpUser); + + verify(itemContentRemover, times(1)).remove(anyLong()); + assertFalse(parent.isHasChildren()); + } + + @Test + void deleteItemPositive() { + ReportPortalUser rpUser = getRpUser("owner", UserRole.ADMINISTRATOR, ProjectRole.MEMBER, 1L); + TestItem item = getTestItem(StatusEnum.FAILED, StatusEnum.FAILED, 1L, "owner"); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.FAILED); + launch.setProjectId(1L); + launch.setUserId(1L); + + when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); + when(launchRepository.findById(any(Long.class))).thenReturn(Optional.of(launch)); + + OperationCompletionRS response = handler.deleteTestItem(1L, + extractProjectDetails(rpUser, "test_project"), rpUser); + + verify(itemContentRemover, times(1)).remove(anyLong()); + assertEquals("Test Item with ID = '1' has been successfully deleted.", + response.getResultMessage()); + + } + + private TestItem getTestItem(StatusEnum itemStatus, StatusEnum launchStatus, Long projectId, + String owner) { + TestItem item = new TestItem(); + item.setItemId(1L); + TestItemResults results = new TestItemResults(); + results.setStatus(itemStatus); + item.setItemResults(results); + Launch launch = new Launch(); + launch.setId(1L); + launch.setStatus(launchStatus); + launch.setProjectId(projectId); + User user = new User(); + user.setId(1L); + user.setLogin(owner); + launch.setUserId(user.getId()); + item.setLaunchId(launch.getId()); + return item; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImplTest.java index cd84ff52d7..33f8e82dc5 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerAsyncImplTest.java @@ -16,12 +16,19 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ReportingQueueService; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -29,14 +36,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.amqp.core.AmqpTemplate; -import java.util.UUID; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - /** * @author Konstantin Antipin */ @@ -44,38 +43,42 @@ @ExtendWith(MockitoExtension.class) class FinishTestItemHandlerAsyncImplTest { - @Mock - AmqpTemplate amqpTemplate; + @Mock + AmqpTemplate amqpTemplate; - @Mock - ReportingQueueService reportingQueueService; + @Mock + ReportingQueueService reportingQueueService; - @InjectMocks - FinishTestItemHandlerAsyncImpl finishTestItemHandlerAsync; + @InjectMocks + FinishTestItemHandlerAsyncImpl finishTestItemHandlerAsync; - @Test - void finishTestItem() { - FinishTestItemRQ request = new FinishTestItemRQ(); - request.setLaunchUuid(UUID.randomUUID().toString()); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void finishTestItem() { + FinishTestItemRQ request = new FinishTestItemRQ(); + request.setLaunchUuid(UUID.randomUUID().toString()); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - finishTestItemHandlerAsync.finishTestItem(user, user.getProjectDetails().get("test_project"), "123", request); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + finishTestItemHandlerAsync.finishTestItem(user, user.getProjectDetails().get("test_project"), + "123", request); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } - @Test - void finishTestItemWithoutLaunchUuid() { - FinishTestItemRQ request = new FinishTestItemRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void finishTestItemWithoutLaunchUuid() { + FinishTestItemRQ request = new FinishTestItemRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> finishTestItemHandlerAsync.finishTestItem(user, user.getProjectDetails().get("test_project"), "123", request) - ); - assertEquals( - "Error in handled Request. Please, check specified parameters: 'Launch UUID should not be null or empty.'", - exception.getMessage() - ); - } + ReportPortalException exception = assertThrows( + ReportPortalException.class, + () -> finishTestItemHandlerAsync.finishTestItem(user, + user.getProjectDetails().get("test_project"), "123", request) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Launch UUID should not be null or empty.'", + exception.getMessage() + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImplTest.java index 7384da4ea3..6f7c209483 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/FinishTestItemHandlerImplTest.java @@ -16,9 +16,19 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; -import com.epam.ta.reportportal.core.events.activity.item.ItemFinishedEvent; +import com.epam.ta.reportportal.core.events.activity.item.IssueResolvedEvent; import com.epam.ta.reportportal.core.item.impl.status.StatusChangingStrategy; import com.epam.ta.reportportal.dao.IssueEntityRepository; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -36,6 +46,10 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -43,180 +57,175 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.ApplicationEventPublisher; -import java.time.LocalDateTime; -import java.util.Date; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class FinishTestItemHandlerImplTest { - @Mock - private TestItemRepository repository; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private IssueTypeHandler issueTypeHandler; - - @Mock - private Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; - - @Mock - private StatusChangingStrategy statusChangingStrategy; - - @Mock - private IssueEntityRepository issueEntityRepository; - - @Mock - private MessageBus messageBus; - - @Mock - private ApplicationEventPublisher eventPublisher; - - @InjectMocks - private FinishTestItemHandlerImpl handler; - - @Test - void finishNotExistedTestItem() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - when(repository.findByUuid("1")).thenReturn(Optional.empty()); - final ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", new FinishTestItemRQ()) - ); - assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", exception.getMessage()); - } - - @Test - void finishTestItemUnderNotExistedLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem item = new TestItem(); - TestItemResults results = new TestItemResults(); - results.setStatus(StatusEnum.IN_PROGRESS); - item.setItemResults(results); - item.setItemId(1L); - when(repository.findByUuid("1")).thenReturn(Optional.of(item)); - - final ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", new FinishTestItemRQ()) - ); - assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void finishTestItemByNotLaunchOwner() { - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem item = new TestItem(); - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(1L); - User user = new User(); - user.setId(2L); - user.setLogin("owner"); - launch.setUserId(user.getId()); - item.setItemId(1L); - item.setLaunchId(launch.getId()); - item.setHasChildren(false); - when(repository.findByUuid("1")).thenReturn(Optional.of(item)); - TestItemResults results = new TestItemResults(); - results.setStatus(StatusEnum.IN_PROGRESS); - item.setItemResults(results); - item.setItemId(1L); - when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); - - - final ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", new FinishTestItemRQ()) - ); - assertEquals("Finish test item is not allowed. You are not a launch owner.", exception.getMessage()); - } - - @Test - void finishStepItemWithoutProvidedStatus() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem item = new TestItem(); - item.setItemId(1L); - TestItemResults results = new TestItemResults(); - results.setStatus(StatusEnum.IN_PROGRESS); - item.setItemResults(results); - Launch launch = new Launch(); - launch.setId(1L); - launch.setUserId(1L); - launch.setProjectId(1L); - item.setLaunchId(launch.getId()); - item.setHasChildren(false); - when(repository.findByUuid("1")).thenReturn(Optional.of(item)); - when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); - - final ReportPortalException exception = assertThrows( - ReportPortalException.class, - () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", new FinishTestItemRQ()) - ); - assertEquals( - "Test item status is ambiguous. There is no status provided from request and there are no descendants to check statistics for test item id '1'", - exception.getMessage() - ); - } - - @Test - void updateFinishedItemTest() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem item = new TestItem(); - item.setItemId(1L); - TestItemResults results = new TestItemResults(); - results.setStatus(StatusEnum.PASSED); - item.setItemResults(results); - Launch launch = new Launch(); - launch.setId(1L); - launch.setUserId(1L); - launch.setProjectId(1L); - item.setStartTime(LocalDateTime.now().minusSeconds(5L)); - item.setLaunchId(launch.getId()); - item.setType(TestItemTypeEnum.STEP); - item.setHasStats(true); - item.setHasChildren(false); - when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); - when(repository.findByUuid("1")).thenReturn(Optional.of(item)); - when(repository.findIdByUuidForUpdate(any())).thenReturn(Optional.of(item.getItemId())); - when(repository.findById(item.getItemId())).thenReturn(Optional.of(item)); - - IssueType issueType = new IssueType(); - issueType.setLocator("123"); - issueType.setIssueGroup(new IssueGroup()); - issueType.setLongName("123123"); - issueType.setHexColor("#1232asd"); - issueType.setShortName("short"); - - when(issueTypeHandler.defineIssueType(any(), any())).thenReturn(issueType); - when(statusChangingStrategyMapping.get(any(StatusEnum.class))).thenReturn(statusChangingStrategy); - - FinishTestItemRQ finishExecutionRQ = new FinishTestItemRQ(); - finishExecutionRQ.setStatus("FAILED"); - finishExecutionRQ.setEndTime(new Date()); - - OperationCompletionRS operationCompletionRS = handler.finishTestItem(rpUser, - extractProjectDetails(rpUser, "test_project"), - "1", - finishExecutionRQ - ); - - verify(statusChangingStrategy, times(1)).changeStatus(any(), any(), any()); - verify(issueEntityRepository, times(1)).save(any()); - verify(messageBus, times(1)).publishActivity(any()); - verify(eventPublisher, times(1)).publishEvent(any(ItemFinishedEvent.class)); - } + @Mock + private TestItemRepository repository; + + @Mock + private LaunchRepository launchRepository; + + @Mock + private IssueTypeHandler issueTypeHandler; + + @Mock + private Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; + + @Mock + private StatusChangingStrategy statusChangingStrategy; + + @Mock + private IssueEntityRepository issueEntityRepository; + + @Mock + private MessageBus messageBus; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @InjectMocks + private FinishTestItemHandlerImpl handler; + + @Test + void finishNotExistedTestItem() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + when(repository.findByUuid("1")).thenReturn(Optional.empty()); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", + new FinishTestItemRQ() + ) + ); + assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", + exception.getMessage() + ); + } + + @Test + void finishTestItemUnderNotExistedLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + TestItem item = new TestItem(); + TestItemResults results = new TestItemResults(); + results.setStatus(StatusEnum.IN_PROGRESS); + item.setItemResults(results); + item.setItemId(1L); + when(repository.findByUuid("1")).thenReturn(Optional.of(item)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", + new FinishTestItemRQ() + ) + ); + assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void finishTestItemByNotLaunchOwner() { + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + TestItem item = new TestItem(); + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(1L); + User user = new User(); + user.setId(2L); + user.setLogin("owner"); + launch.setUserId(user.getId()); + item.setItemId(1L); + item.setLaunchId(launch.getId()); + item.setHasChildren(false); + when(repository.findByUuid("1")).thenReturn(Optional.of(item)); + TestItemResults results = new TestItemResults(); + results.setStatus(StatusEnum.IN_PROGRESS); + item.setItemResults(results); + item.setItemId(1L); + when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", + new FinishTestItemRQ() + ) + ); + assertEquals("Finish test item is not allowed. You are not a launch owner.", + exception.getMessage() + ); + } + + @Test + void finishStepItemWithoutProvidedStatus() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + TestItem item = new TestItem(); + item.setItemId(1L); + TestItemResults results = new TestItemResults(); + results.setStatus(StatusEnum.IN_PROGRESS); + item.setItemResults(results); + Launch launch = new Launch(); + launch.setId(1L); + launch.setUserId(1L); + launch.setProjectId(1L); + item.setLaunchId(launch.getId()); + item.setHasChildren(false); + when(repository.findByUuid("1")).thenReturn(Optional.of(item)); + when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", + new FinishTestItemRQ() + ) + ); + assertEquals( + "Test item status is ambiguous. There is no status provided from request and there are no descendants to check statistics for test item id '1'", + exception.getMessage() + ); + } + + @Test + void updateFinishedItemTest() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + TestItem item = new TestItem(); + item.setItemId(1L); + TestItemResults results = new TestItemResults(); + results.setStatus(StatusEnum.PASSED); + item.setItemResults(results); + Launch launch = new Launch(); + launch.setId(1L); + launch.setUserId(1L); + launch.setProjectId(1L); + item.setStartTime(LocalDateTime.now().minusSeconds(5L)); + item.setLaunchId(launch.getId()); + item.setType(TestItemTypeEnum.STEP); + item.setHasStats(true); + item.setHasChildren(false); + when(launchRepository.findById(any())).thenReturn(Optional.of(launch)); + when(repository.findByUuid("1")).thenReturn(Optional.of(item)); + when(repository.findIdByUuidForUpdate(any())).thenReturn(Optional.of(item.getItemId())); + when(repository.findById(item.getItemId())).thenReturn(Optional.of(item)); + + IssueType issueType = new IssueType(); + issueType.setLocator("123"); + issueType.setIssueGroup(new IssueGroup()); + issueType.setLongName("123123"); + issueType.setHexColor("#1232asd"); + issueType.setShortName("short"); + + when(issueTypeHandler.defineIssueType(any(), any())).thenReturn(issueType); + when(statusChangingStrategyMapping.get(any(StatusEnum.class))).thenReturn( + statusChangingStrategy); + + FinishTestItemRQ finishExecutionRQ = new FinishTestItemRQ(); + finishExecutionRQ.setStatus("FAILED"); + finishExecutionRQ.setEndTime(new Date()); + + OperationCompletionRS operationCompletionRS = + handler.finishTestItem(rpUser, extractProjectDetails(rpUser, "test_project"), "1", + finishExecutionRQ + ); + + verify(statusChangingStrategy, times(1)).changeStatus(any(), any(), any(), eq(false)); + verify(issueEntityRepository, times(1)).save(any()); + verify(messageBus, times(1)).publishActivity(any()); + verify(eventPublisher, times(1)).publishEvent(any(IssueResolvedEvent.class)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandlerTest.java index 3e3495d63a..70ea7275b1 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/IssueTypeHandlerTest.java @@ -16,53 +16,54 @@ package com.epam.ta.reportportal.core.item.impl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.issue.IssueType; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class IssueTypeHandlerTest { - @Mock - private TestItemRepository testItemRepository; + @Mock + private TestItemRepository testItemRepository; - @InjectMocks - private IssueTypeHandler issueTypeHandler; + @InjectMocks + private IssueTypeHandler issueTypeHandler; - @Test - void defineIssueTypeWithNullLocator() { - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> issueTypeHandler.defineIssueType(1L, null)); - assertEquals("Locator should not be null", exception.getMessage()); - } + @Test + void defineIssueTypeWithNullLocator() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> issueTypeHandler.defineIssueType(1L, null)); + assertEquals("Locator should not be null", exception.getMessage()); + } - @Test - void defineNotExistIssueType() { - when(testItemRepository.selectIssueTypeByLocator(2L, "not_exist")).thenReturn(Optional.empty()); - IssueType issueType = new IssueType(); - issueType.setLocator("exists"); - when(testItemRepository.selectIssueLocatorsByProject(2L)).thenReturn(Collections.singletonList(issueType)); + @Test + void defineNotExistIssueType() { + when(testItemRepository.selectIssueTypeByLocator(2L, "not_exist")).thenReturn(Optional.empty()); + IssueType issueType = new IssueType(); + issueType.setLocator("exists"); + when(testItemRepository.selectIssueLocatorsByProject(2L)).thenReturn( + Collections.singletonList(issueType)); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> issueTypeHandler.defineIssueType(2L, "not_exist") - ); - assertEquals( - "Test items issue type cannot be resolved. Invalid test item issue type definition 'not_exist' is requested. Valid issue types' locators are: [exists]", - exception.getMessage() - ); - } + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> issueTypeHandler.defineIssueType(2L, "not_exist") + ); + assertEquals( + "Test items issue type cannot be resolved. Invalid test item issue type definition 'not_exist' is requested. Valid issue types' locators are: [exists]", + exception.getMessage() + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImplTest.java index a19a809773..429b0271d9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/LaunchAccessValidatorImplTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; @@ -24,6 +30,7 @@ import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.function.Executable; @@ -31,73 +38,69 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @ExtendWith(MockitoExtension.class) class LaunchAccessValidatorImplTest { - @Mock - private LaunchRepository launchRepository; - - @InjectMocks - private LaunchAccessValidatorImpl launchAccessValidator; - - @Test - void validateNotExistingLaunch() { - - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - Launch launch = new Launch(); - launch.setId(1L); - when(launchRepository.findById(1L)).thenReturn(Optional.empty()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> launchAccessValidator.validate(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void validateLaunchUnderAnotherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - TestItem item = new TestItem(); - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(2L); - item.setLaunchId(launch.getId()); - when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); - - final Executable executable = () -> launchAccessValidator.validate(1L, extractProjectDetails(rpUser, "test_project"), rpUser); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, executable); - assertEquals("Forbidden operation. Specified launch with id '1' not referenced to specified project with id '1'", - exception.getMessage() - ); - } - - @Test - void validateLaunchWithOperatorRole() { - ReportPortalUser operator = getRpUser("operator", UserRole.USER, ProjectRole.OPERATOR, 1L); - - Launch launch = new Launch(); - launch.setId(1L); - launch.setMode(LaunchModeEnum.DEBUG); - launch.setProjectId(1L); - - when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> launchAccessValidator.validate(1L, extractProjectDetails(operator, "test_project"), operator) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } + @Mock + private LaunchRepository launchRepository; + + @InjectMocks + private LaunchAccessValidatorImpl launchAccessValidator; + + @Test + void validateNotExistingLaunch() { + + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + Launch launch = new Launch(); + launch.setId(1L); + when(launchRepository.findById(1L)).thenReturn(Optional.empty()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> launchAccessValidator.validate(1L, extractProjectDetails(rpUser, "test_project"), + rpUser) + ); + assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void validateLaunchUnderAnotherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + TestItem item = new TestItem(); + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(2L); + item.setLaunchId(launch.getId()); + when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); + + final Executable executable = () -> launchAccessValidator.validate(1L, + extractProjectDetails(rpUser, "test_project"), rpUser); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, executable); + assertEquals( + "Forbidden operation. Specified launch with id '1' not referenced to specified project with id '1'", + exception.getMessage() + ); + } + + @Test + void validateLaunchWithOperatorRole() { + ReportPortalUser operator = getRpUser("operator", UserRole.USER, ProjectRole.OPERATOR, 1L); + + Launch launch = new Launch(); + launch.setId(1L); + launch.setMode(LaunchModeEnum.DEBUG); + launch.setProjectId(1L); + + when(launchRepository.findById(1L)).thenReturn(Optional.of(launch)); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> launchAccessValidator.validate(1L, extractProjectDetails(operator, "test_project"), + operator) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImplTest.java index 1418221198..b1264242fb 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerAsyncImplTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; @@ -28,10 +32,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.amqp.core.AmqpTemplate; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - /** * @author Konstantin Antipin */ @@ -39,32 +39,36 @@ @ExtendWith(MockitoExtension.class) class StartTestItemHandlerAsyncImplTest { - @Mock - AmqpTemplate amqpTemplate; + @Mock + AmqpTemplate amqpTemplate; - @Mock - ReportingQueueService reportingQueueService; + @Mock + ReportingQueueService reportingQueueService; - @InjectMocks - StartTestItemHandlerAsyncImpl startTestItemHandlerAsync; + @InjectMocks + StartTestItemHandlerAsyncImpl startTestItemHandlerAsync; - @Test - void startRootItem() { - StartTestItemRQ request = new StartTestItemRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void startRootItem() { + StartTestItemRQ request = new StartTestItemRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - startTestItemHandlerAsync.startRootItem(user, user.getProjectDetails().get("test_project"), request); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + startTestItemHandlerAsync.startRootItem(user, user.getProjectDetails().get("test_project"), + request); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } - @Test - void startChildItem() { - StartTestItemRQ request = new StartTestItemRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void startChildItem() { + StartTestItemRQ request = new StartTestItemRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - startTestItemHandlerAsync.startChildItem(user, user.getProjectDetails().get("test_project"), request, "123"); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + startTestItemHandlerAsync.startChildItem(user, user.getProjectDetails().get("test_project"), + request, "123"); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImplTest.java index 797e826f8d..4db2058cdc 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/StartTestItemHandlerImplTest.java @@ -16,6 +16,15 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.core.item.validator.parent.ParentItemValidator; @@ -30,6 +39,11 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -39,191 +53,198 @@ import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Date; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class StartTestItemHandlerImplTest { - private final ParentItemValidator validator = mock(ParentItemValidator.class); - - @Mock - private LaunchRepository launchRepository; - - @Mock - private TestItemRepository testItemRepository; - - @InjectMocks - private StartTestItemHandlerImpl handler; - - @Spy - private ArrayList<ParentItemValidator> parentItemValidators = new ArrayList<>(); - - @BeforeEach - public void setup() throws Exception { - parentItemValidators.clear(); - parentItemValidators.add(validator); - } - - @Test - void startRootItemUnderNotExistedLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(launchRepository.findByUuid("1")).thenReturn(Optional.empty()); - final StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("1"); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), rq) - ); - assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void startRootItemUnderLaunchFromAnotherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - final Launch launch = getLaunch(2L, StatusEnum.IN_PROGRESS); - launch.setStartTime(LocalDateTime.now().minusHours(1)); - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(launch)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - @Disabled - void startRootItemUnderFinishedLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(getLaunch(1L, StatusEnum.PASSED))); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ) - ); - assertEquals("Start test item is not allowed. Launch '1' is not in progress", exception.getMessage()); - } - - @Test - void startRootItemEarlierThanLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - final Launch launch = getLaunch(1L, StatusEnum.IN_PROGRESS); - launch.setStartTime(LocalDateTime.now().plusHours(1)); - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(launch)); - - assertThrows(ReportPortalException.class, - () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ) - ); - } - - @Test - void startChildItemUnderNotExistedParent() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("1"); - - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); - when(testItemRepository.findByUuid("1")).thenReturn(Optional.empty()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), rq, "1") - ); - assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", exception.getMessage()); - } - - @Test - void startChildItemEarlierThanParent() { - - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - TestItem item = new TestItem(); - item.setStartTime(LocalDateTime.now().plusHours(1)); - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); - when(testItemRepository.findByUuid("1")).thenReturn(Optional.of(item)); - doThrow(new ReportPortalException(ErrorType.BAD_REQUEST_ERROR)).when(validator) - .validate(any(StartTestItemRQ.class), any(TestItem.class)); - - assertThrows(ReportPortalException.class, - () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ, "1") - ); - } - - @Test - void startChildItemUnderFinishedParent() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - TestItem item = new TestItem(); - item.setItemId(1L); - TestItemResults results = new TestItemResults(); - results.setStatus(StatusEnum.FAILED); - item.setItemResults(results); - item.setStartTime(LocalDateTime.now().minusHours(1)); - when(launchRepository.findByUuid("1")).thenReturn(Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); - when(testItemRepository.findByUuid("1")).thenReturn(Optional.of(item)); - doThrow(new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, - Suppliers.formattedSupplier("Unable to add a not nested step item, because parent item with ID = '{}' is a nested step", 1L) - .get() - )).when(validator).validate(any(StartTestItemRQ.class), any(TestItem.class)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ, "1") - ); - assertEquals("Error in handled Request. Please, check specified parameters: " - + "'Unable to add a not nested step item, because parent item with ID = '1' is a nested step'", exception.getMessage()); - } - - @Test - void startChildItemWithNotExistedLaunch() { - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("1"); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - startTestItemRQ.setLaunchUuid("1"); - - when(launchRepository.findByUuid("1")).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), startTestItemRQ, "1") - ); - - assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - private Launch getLaunch(Long projectId, StatusEnum status) { - Launch launch = new Launch(); - launch.setProjectId(projectId); - launch.setStatus(status); - return launch; - } + private final ParentItemValidator validator = mock(ParentItemValidator.class); + + @Mock + private LaunchRepository launchRepository; + + @Mock + private TestItemRepository testItemRepository; + + @InjectMocks + private StartTestItemHandlerImpl handler; + + @Spy + private ArrayList<ParentItemValidator> parentItemValidators = new ArrayList<>(); + + @BeforeEach + public void setup() throws Exception { + parentItemValidators.clear(); + parentItemValidators.add(validator); + } + + @Test + void startRootItemUnderNotExistedLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(launchRepository.findByUuid("1")).thenReturn(Optional.empty()); + final StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("1"); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), rq) + ); + assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void startRootItemUnderLaunchFromAnotherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + final Launch launch = getLaunch(2L, StatusEnum.IN_PROGRESS); + launch.setStartTime(LocalDateTime.now().minusHours(1)); + when(launchRepository.findByUuid("1")).thenReturn(Optional.of(launch)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + @Disabled + void startRootItemUnderFinishedLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + + when(launchRepository.findByUuid("1")).thenReturn( + Optional.of(getLaunch(1L, StatusEnum.PASSED))); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ) + ); + assertEquals("Start test item is not allowed. Launch '1' is not in progress", + exception.getMessage()); + } + + @Test + void startRootItemEarlierThanLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + final Launch launch = getLaunch(1L, StatusEnum.IN_PROGRESS); + launch.setStartTime(LocalDateTime.now().plusHours(1)); + when(launchRepository.findByUuid("1")).thenReturn(Optional.of(launch)); + + assertThrows(ReportPortalException.class, + () -> handler.startRootItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ) + ); + } + + @Test + void startChildItemUnderNotExistedParent() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("1"); + + when(launchRepository.findByUuid("1")).thenReturn( + Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); + when(testItemRepository.findByUuid("1")).thenReturn(Optional.empty()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), rq, "1") + ); + assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", + exception.getMessage()); + } + + @Test + void startChildItemEarlierThanParent() { + + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + TestItem item = new TestItem(); + item.setStartTime(LocalDateTime.now().plusHours(1)); + when(launchRepository.findByUuid("1")).thenReturn( + Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); + when(testItemRepository.findByUuid("1")).thenReturn(Optional.of(item)); + doThrow(new ReportPortalException(ErrorType.BAD_REQUEST_ERROR)).when(validator) + .validate(any(StartTestItemRQ.class), any(TestItem.class)); + + assertThrows(ReportPortalException.class, + () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ, "1") + ); + } + + @Test + void startChildItemUnderFinishedParent() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + TestItem item = new TestItem(); + item.setItemId(1L); + TestItemResults results = new TestItemResults(); + results.setStatus(StatusEnum.FAILED); + item.setItemResults(results); + item.setStartTime(LocalDateTime.now().minusHours(1)); + when(launchRepository.findByUuid("1")).thenReturn( + Optional.of(getLaunch(1L, StatusEnum.IN_PROGRESS))); + when(testItemRepository.findByUuid("1")).thenReturn(Optional.of(item)); + doThrow(new ReportPortalException(ErrorType.BAD_REQUEST_ERROR, + Suppliers.formattedSupplier( + "Unable to add a not nested step item, because parent item with ID = '{}' is a nested step", + 1L) + .get() + )).when(validator).validate(any(StartTestItemRQ.class), any(TestItem.class)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ, "1") + ); + assertEquals("Error in handled Request. Please, check specified parameters: " + + "'Unable to add a not nested step item, because parent item with ID = '1' is a nested step'", + exception.getMessage()); + } + + @Test + void startChildItemWithNotExistedLaunch() { + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("1"); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + startTestItemRQ.setLaunchUuid("1"); + + when(launchRepository.findByUuid("1")).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.startChildItem(rpUser, extractProjectDetails(rpUser, "test_project"), + startTestItemRQ, "1") + ); + + assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + private Launch getLaunch(Long projectId, StatusEnum status) { + Launch launch = new Launch(); + launch.setProjectId(projectId); + launch.setStatus(status); + return launch; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/TestCaseHashGeneratorImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/TestCaseHashGeneratorImplTest.java index a5b7eb3ac9..050052ef95 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/TestCaseHashGeneratorImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/TestCaseHashGeneratorImplTest.java @@ -16,26 +16,25 @@ package com.epam.ta.reportportal.core.item.impl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.item.identity.IdentityUtil; import com.epam.ta.reportportal.core.item.identity.TestCaseHashGeneratorImpl; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.Parameter; import com.epam.ta.reportportal.entity.item.TestItem; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -43,52 +42,52 @@ @ExtendWith(MockitoExtension.class) class TestCaseHashGeneratorImplTest { - @Mock - private TestItemRepository testItemRepository; + @Mock + private TestItemRepository testItemRepository; - @InjectMocks - private TestCaseHashGeneratorImpl testCaseHashGenerator; + @InjectMocks + private TestCaseHashGeneratorImpl testCaseHashGenerator; - @Test - void sameHashesForSameObjectsTest() { - TestItem item = getItem(); - item.setItemId(3L); - item.setPath("1.2.3"); + @Test + void sameHashesForSameObjectsTest() { + TestItem item = getItem(); + item.setItemId(3L); + item.setPath("1.2.3"); - Map<Long, String> pathNames = new LinkedHashMap<>(); - pathNames.put(1L, "suite"); - pathNames.put(2L, "test"); + Map<Long, String> pathNames = new LinkedHashMap<>(); + pathNames.put(1L, "suite"); + pathNames.put(2L, "test"); - List<TestItem> parents = pathNames.entrySet().stream().map(entry -> { - TestItem parent = new TestItem(); - parent.setItemId(entry.getKey()); - parent.setName(entry.getValue()); - return parent; - }).collect(Collectors.toList()); + List<TestItem> parents = pathNames.entrySet().stream().map(entry -> { + TestItem parent = new TestItem(); + parent.setItemId(entry.getKey()); + parent.setName(entry.getValue()); + return parent; + }).collect(Collectors.toList()); - final List<Long> parentIds = IdentityUtil.getParentIds(item); + final List<Long> parentIds = IdentityUtil.getParentIds(item); - when(testItemRepository.findAllById(parentIds)).thenReturn(parents); + when(testItemRepository.findAllById(parentIds)).thenReturn(parents); - Integer first = testCaseHashGenerator.generate(item, parentIds, 100L); - Integer second = testCaseHashGenerator.generate(item, parentIds, 100L); + Integer first = testCaseHashGenerator.generate(item, parentIds, 100L); + Integer second = testCaseHashGenerator.generate(item, parentIds, 100L); - assertNotNull(first); - assertNotNull(second); - assertEquals(first, second); - } + assertNotNull(first); + assertNotNull(second); + assertEquals(first, second); + } - private TestItem getItem() { - TestItem item = new TestItem(); - item.setName("item"); - HashSet<Parameter> parameters = new HashSet<>(); - Parameter parameter = new Parameter(); - parameter.setKey("key"); - parameter.setValue("value"); - parameters.add(parameter); - item.setParameters(parameters); - item.setPath("1.2.3"); - item.setLaunchId(1L); - return item; - } + private TestItem getItem() { + TestItem item = new TestItem(); + item.setName("item"); + HashSet<Parameter> parameters = new HashSet<>(); + Parameter parameter = new Parameter(); + parameter.setKey("key"); + parameter.setValue("value"); + parameters.add(parameter); + item.setParameters(parameters); + item.setPath("1.2.3"); + item.setLaunchId(1L); + return item; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/TestItemUniqueIdGeneratorTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/TestItemUniqueIdGeneratorTest.java index 8dc97e0c35..00fe84fb72 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/TestItemUniqueIdGeneratorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/TestItemUniqueIdGeneratorTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.item.impl; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.item.identity.IdentityUtil; import com.epam.ta.reportportal.core.item.identity.TestItemUniqueIdGenerator; import com.epam.ta.reportportal.dao.TestItemRepository; @@ -23,20 +28,16 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -44,63 +45,63 @@ @ExtendWith(MockitoExtension.class) class TestItemUniqueIdGeneratorTest { - @Mock - private TestItemRepository testItemRepository; - - @InjectMocks - private TestItemUniqueIdGenerator uniqueIdGenerator; - - @Test - void validateTest() { - assertFalse(uniqueIdGenerator.validate("")); - assertFalse(uniqueIdGenerator.validate(null)); - assertFalse(uniqueIdGenerator.validate("qwerty")); - assertTrue(uniqueIdGenerator.validate("auto: 123456789")); - } - - @Test - void generateTest() { - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(1L); - launch.setName("launchName"); - - TestItem testItem = new TestItem(); - testItem.setItemId(3L); - testItem.setName("itemName"); - testItem.setPath("1.2.3"); - - HashMap<Long, String> pathNamesMap = new HashMap<>(); - pathNamesMap.put(1L, "first"); - pathNamesMap.put(2L, "second"); - pathNamesMap.put(3L, "third"); - - Parameter param1 = new Parameter(); - param1.setKey("key1"); - param1.setValue("val1"); - Parameter param2 = new Parameter(); - param1.setKey("key2"); - param1.setValue("val2"); - testItem.setParameters(Sets.newHashSet(param1, param2)); - testItem.setLaunchId(1L); - - Map<Long, String> pathNames = new LinkedHashMap<>(); - pathNames.put(1L, "suite"); - pathNames.put(2L, "test"); - - List<TestItem> parents = pathNames.entrySet().stream().map(entry -> { - TestItem parent = new TestItem(); - parent.setItemId(entry.getKey()); - parent.setName(entry.getValue()); - return parent; - }).collect(Collectors.toList()); - - final List<Long> parentIds = IdentityUtil.getParentIds(testItem); - - when(testItemRepository.findAllById(parentIds)).thenReturn(parents); - String generated = uniqueIdGenerator.generate(testItem, parentIds, launch); - - assertNotNull(generated); - assertTrue(generated.startsWith("auto:")); - } + @Mock + private TestItemRepository testItemRepository; + + @InjectMocks + private TestItemUniqueIdGenerator uniqueIdGenerator; + + @Test + void validateTest() { + assertFalse(uniqueIdGenerator.validate("")); + assertFalse(uniqueIdGenerator.validate(null)); + assertFalse(uniqueIdGenerator.validate("qwerty")); + assertTrue(uniqueIdGenerator.validate("auto: 123456789")); + } + + @Test + void generateTest() { + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(1L); + launch.setName("launchName"); + + TestItem testItem = new TestItem(); + testItem.setItemId(3L); + testItem.setName("itemName"); + testItem.setPath("1.2.3"); + + HashMap<Long, String> pathNamesMap = new HashMap<>(); + pathNamesMap.put(1L, "first"); + pathNamesMap.put(2L, "second"); + pathNamesMap.put(3L, "third"); + + Parameter param1 = new Parameter(); + param1.setKey("key1"); + param1.setValue("val1"); + Parameter param2 = new Parameter(); + param1.setKey("key2"); + param1.setValue("val2"); + testItem.setParameters(Sets.newHashSet(param1, param2)); + testItem.setLaunchId(1L); + + Map<Long, String> pathNames = new LinkedHashMap<>(); + pathNames.put(1L, "suite"); + pathNames.put(2L, "test"); + + List<TestItem> parents = pathNames.entrySet().stream().map(entry -> { + TestItem parent = new TestItem(); + parent.setItemId(entry.getKey()); + parent.setName(entry.getValue()); + return parent; + }).collect(Collectors.toList()); + + final List<Long> parentIds = IdentityUtil.getParentIds(testItem); + + when(testItemRepository.findAllById(parentIds)).thenReturn(parents); + String generated = uniqueIdGenerator.generate(testItem, parentIds, launch); + + assertNotNull(generated); + assertTrue(generated.startsWith("auto:")); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImplTest.java index d3886c4962..d7b4a69dba 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/UpdateTestItemHandlerImplTest.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.item.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.item.impl.UpdateTestItemHandlerImpl.INITIAL_STATUS_ATTRIBUTE_KEY; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.item.TestItemService; @@ -37,248 +48,267 @@ import com.epam.ta.reportportal.ws.model.issue.DefineIssueRQ; import com.epam.ta.reportportal.ws.model.item.UpdateTestItemRQ; import com.google.common.collect.Sets; +import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Map; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.core.item.impl.UpdateTestItemHandlerImpl.INITIAL_STATUS_ATTRIBUTE_KEY; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class UpdateTestItemHandlerImplTest { - private final StatusChangingStrategy statusChangingStrategy = mock(StatusChangingStrategy.class); - - @Mock - private Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; - - @Mock - private TestItemRepository itemRepository; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private TestItemService testItemService; - - @Mock - private MessageBus messageBus; - - @InjectMocks - private UpdateTestItemHandlerImpl handler; - - @Test - void updateNotExistedTestItem() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); - when(itemRepository.findById(1L)).thenReturn(Optional.empty()); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, new UpdateTestItemRQ(), rpUser) - ); - assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", exception.getMessage()); - } - - @Test - void updateTestItemUnderNotExistedLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); - - TestItem testItem = new TestItem(); - testItem.setLaunchId(2L); - when(itemRepository.findById(1L)).thenReturn(Optional.of(testItem)); - when(testItemService.getEffectiveLaunch(testItem)).thenThrow(new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, new UpdateTestItemRQ(), rpUser) - ); - assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void updateTestItemUnderNotOwnLaunch() { - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - - TestItem item = new TestItem(); - Launch launch = new Launch(); - launch.setId(1L); - User user = new User(); - user.setId(1L); - user.setLogin("owner"); - launch.setUserId(2L); - launch.setProjectId(1L); - item.setLaunchId(launch.getId()); - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(1L)).thenReturn(Optional.of(item)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, new UpdateTestItemRQ(), rpUser) - ); - assertEquals("You do not have enough permissions. You are not a launch owner.", exception.getMessage()); - } - - @Test - void updateTestItemFromAnotherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - TestItem item = new TestItem(); - Launch launch = new Launch(); - launch.setId(1L); - User user = new User(); - user.setId(1L); - user.setLogin("owner"); - launch.setUserId(user.getId()); - launch.setProjectId(2L); - item.setLaunchId(launch.getId()); - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(1L)).thenReturn(Optional.of(item)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, new UpdateTestItemRQ(), rpUser) - ); - assertEquals("You do not have enough permissions. Launch is not under the specified project.", exception.getMessage()); - } - - @Test - void defineIssuesOnNotExistProject() { - ReportPortalUser rpUser = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(projectRepository.findById(1L)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.defineTestItemsIssues(extractProjectDetails(rpUser, "test_project"), new DefineIssueRQ(), rpUser) - ); - - assertEquals("Project '1' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void changeNotStepItemStatus() { - ReportPortalUser user = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - UpdateTestItemRQ rq = new UpdateTestItemRQ(); - rq.setStatus("FAILED"); - - long itemId = 1L; - TestItem item = new TestItem(); - item.setItemId(itemId); - item.setHasChildren(true); - item.setType(TestItemTypeEnum.TEST); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.PASSED); - item.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(2L); - item.setLaunchId(launch.getId()); - - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user) - ); - assertEquals("Incorrect Request. Unable to change status on test item with children", exception.getMessage()); - } - - @Test - void shouldCreateInitialStatusAttribute() { - ReportPortalUser user = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - UpdateTestItemRQ rq = new UpdateTestItemRQ(); - rq.setStatus("PASSED"); - - long itemId = 1L; - TestItem item = new TestItem(); - item.setItemId(itemId); - item.setHasChildren(false); - item.setType(TestItemTypeEnum.STEP); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.FAILED); - item.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(2L); - item.setLaunchId(launch.getId()); - - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); - doNothing().when(messageBus).publishActivity(any()); - when(statusChangingStrategyMapping.get(StatusEnum.PASSED)).thenReturn(statusChangingStrategy); - doNothing().when(statusChangingStrategy).changeStatus(item, StatusEnum.PASSED, user); - - handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); - assertTrue(item.getAttributes() - .stream() - .anyMatch(attribute -> INITIAL_STATUS_ATTRIBUTE_KEY.equalsIgnoreCase(attribute.getKey()) - && StatusEnum.FAILED.getExecutionCounterField().equalsIgnoreCase("failed"))); - } - - @Test - void shouldNotCreateInitialStatusAttribute() { - ReportPortalUser user = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - UpdateTestItemRQ rq = new UpdateTestItemRQ(); - rq.setStatus("PASSED"); - - long itemId = 1L; - TestItem item = new TestItem(); - item.setItemId(itemId); - item.setHasChildren(false); - item.setType(TestItemTypeEnum.STEP); - item.setAttributes(Sets.newHashSet(new ItemAttribute(INITIAL_STATUS_ATTRIBUTE_KEY, "passed", true))); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.FAILED); - item.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(2L); - item.setLaunchId(launch.getId()); - - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); - doNothing().when(messageBus).publishActivity(any()); - when(statusChangingStrategyMapping.get(StatusEnum.PASSED)).thenReturn(statusChangingStrategy); - doNothing().when(statusChangingStrategy).changeStatus(item, StatusEnum.PASSED, user); - - handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); - assertTrue(item.getAttributes() - .stream() - .anyMatch(attribute -> INITIAL_STATUS_ATTRIBUTE_KEY.equalsIgnoreCase(attribute.getKey()) - && StatusEnum.PASSED.getExecutionCounterField().equalsIgnoreCase("passed"))); - } - - @Test - void updateItemPositive() { - ReportPortalUser user = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - UpdateTestItemRQ rq = new UpdateTestItemRQ(); - rq.setDescription("new description"); - - long itemId = 1L; - TestItem item = new TestItem(); - item.setItemId(itemId); - item.setDescription("old description"); - item.setHasChildren(false); - item.setType(TestItemTypeEnum.STEP); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.FAILED); - item.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(2L); - item.setLaunchId(launch.getId()); - - when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); - when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); - - OperationCompletionRS response = handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); - - assertEquals("TestItem with ID = '1' successfully updated.", response.getResultMessage()); - assertEquals(rq.getDescription(), item.getDescription()); - } + private final StatusChangingStrategy statusChangingStrategy = mock(StatusChangingStrategy.class); + + @Mock + private Map<StatusEnum, StatusChangingStrategy> statusChangingStrategyMapping; + + @Mock + private TestItemRepository itemRepository; + + @Mock + private ProjectRepository projectRepository; + + @Mock + private TestItemService testItemService; + + @Mock + private MessageBus messageBus; + + @InjectMocks + private UpdateTestItemHandlerImpl handler; + + @Test + void updateNotExistedTestItem() { + final ReportPortalUser rpUser = + getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); + when(itemRepository.findById(1L)).thenReturn(Optional.empty()); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, + new UpdateTestItemRQ(), rpUser + ) + ); + assertEquals("Test Item '1' not found. Did you use correct Test Item ID?", + exception.getMessage() + ); + } + + @Test + void updateTestItemUnderNotExistedLaunch() { + final ReportPortalUser rpUser = + getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); + + TestItem testItem = new TestItem(); + testItem.setLaunchId(2L); + when(itemRepository.findById(1L)).thenReturn(Optional.of(testItem)); + when(testItemService.getEffectiveLaunch(testItem)).thenThrow( + new ReportPortalException(ErrorType.LAUNCH_NOT_FOUND)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, + new UpdateTestItemRQ(), rpUser + ) + ); + assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void updateTestItemUnderNotOwnLaunch() { + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + + TestItem item = new TestItem(); + Launch launch = new Launch(); + launch.setId(1L); + User user = new User(); + user.setId(1L); + user.setLogin("owner"); + launch.setUserId(2L); + launch.setProjectId(1L); + item.setLaunchId(launch.getId()); + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(1L)).thenReturn(Optional.of(item)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, + new UpdateTestItemRQ(), rpUser + ) + ); + assertEquals("You do not have enough permissions. You are not a launch owner.", + exception.getMessage() + ); + } + + @Test + void updateTestItemFromAnotherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + TestItem item = new TestItem(); + Launch launch = new Launch(); + launch.setId(1L); + User user = new User(); + user.setId(1L); + user.setLogin("owner"); + launch.setUserId(user.getId()); + launch.setProjectId(2L); + item.setLaunchId(launch.getId()); + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(1L)).thenReturn(Optional.of(item)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateTestItem(extractProjectDetails(rpUser, "test_project"), 1L, + new UpdateTestItemRQ(), rpUser + ) + ); + assertEquals("You do not have enough permissions. Launch is not under the specified project.", + exception.getMessage() + ); + } + + @Test + void defineIssuesOnNotExistProject() { + ReportPortalUser rpUser = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(projectRepository.findById(1L)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.defineTestItemsIssues(extractProjectDetails(rpUser, "test_project"), + new DefineIssueRQ(), rpUser + ) + ); + + assertEquals("Project '1' not found. Did you use correct project name?", + exception.getMessage() + ); + } + + @Test + void changeNotStepItemStatus() { + ReportPortalUser user = + getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + + UpdateTestItemRQ rq = new UpdateTestItemRQ(); + rq.setStatus("FAILED"); + + long itemId = 1L; + TestItem item = new TestItem(); + item.setItemId(itemId); + item.setHasChildren(true); + item.setType(TestItemTypeEnum.TEST); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.PASSED); + item.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(2L); + item.setLaunchId(launch.getId()); + + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user) + ); + assertEquals("Incorrect Request. Unable to change status on test item with children", + exception.getMessage() + ); + } + + @Test + void shouldCreateInitialStatusAttribute() { + ReportPortalUser user = + getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + + UpdateTestItemRQ rq = new UpdateTestItemRQ(); + rq.setStatus("PASSED"); + + long itemId = 1L; + TestItem item = new TestItem(); + item.setItemId(itemId); + item.setHasChildren(false); + item.setType(TestItemTypeEnum.STEP); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.FAILED); + item.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(2L); + item.setLaunchId(launch.getId()); + + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); + doNothing().when(messageBus).publishActivity(any()); + when(statusChangingStrategyMapping.get(StatusEnum.PASSED)).thenReturn(statusChangingStrategy); + doNothing().when(statusChangingStrategy).changeStatus(item, StatusEnum.PASSED, user, true); + + handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); + assertTrue(item.getAttributes().stream().anyMatch( + attribute -> INITIAL_STATUS_ATTRIBUTE_KEY.equalsIgnoreCase(attribute.getKey()) + && StatusEnum.FAILED.getExecutionCounterField().equalsIgnoreCase("failed"))); + } + + @Test + void shouldNotCreateInitialStatusAttribute() { + ReportPortalUser user = + getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + + UpdateTestItemRQ rq = new UpdateTestItemRQ(); + rq.setStatus("PASSED"); + + long itemId = 1L; + TestItem item = new TestItem(); + item.setItemId(itemId); + item.setHasChildren(false); + item.setType(TestItemTypeEnum.STEP); + item.setAttributes( + Sets.newHashSet(new ItemAttribute(INITIAL_STATUS_ATTRIBUTE_KEY, "passed", true))); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.FAILED); + item.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(2L); + item.setLaunchId(launch.getId()); + + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); + doNothing().when(messageBus).publishActivity(any()); + when(statusChangingStrategyMapping.get(StatusEnum.PASSED)).thenReturn(statusChangingStrategy); + doNothing().when(statusChangingStrategy).changeStatus(item, StatusEnum.PASSED, user, true); + + handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); + assertTrue(item.getAttributes().stream().anyMatch( + attribute -> INITIAL_STATUS_ATTRIBUTE_KEY.equalsIgnoreCase(attribute.getKey()) + && StatusEnum.PASSED.getExecutionCounterField().equalsIgnoreCase("passed"))); + } + + @Test + void updateItemPositive() { + ReportPortalUser user = + getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + + UpdateTestItemRQ rq = new UpdateTestItemRQ(); + rq.setDescription("new description"); + + long itemId = 1L; + TestItem item = new TestItem(); + item.setItemId(itemId); + item.setDescription("old description"); + item.setHasChildren(false); + item.setType(TestItemTypeEnum.STEP); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.FAILED); + item.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(2L); + item.setLaunchId(launch.getId()); + + when(testItemService.getEffectiveLaunch(item)).thenReturn(launch); + when(itemRepository.findById(itemId)).thenReturn(Optional.of(item)); + + OperationCompletionRS response = + handler.updateTestItem(extractProjectDetails(user, "test_project"), itemId, rq, user); + + assertEquals("TestItem with ID = '1' successfully updated.", response.getResultMessage()); + assertEquals(rq.getDescription(), item.getDescription()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacerTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacerTest.java index ac1268f6a3..260b912260 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/filter/updater/IssueTypeConditionReplacerTest.java @@ -16,58 +16,59 @@ package com.epam.ta.reportportal.core.item.impl.filter.updater; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE_ID; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.querygen.Condition; import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.dao.IssueTypeRepository; import com.epam.ta.reportportal.entity.item.TestItem; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.List; - -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_ISSUE_TYPE_ID; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class IssueTypeConditionReplacerTest { - private final IssueTypeRepository issueTypeRepository = mock(IssueTypeRepository.class); - private final IssueTypeConditionReplacer replacer = new IssueTypeConditionReplacer(issueTypeRepository); + private final IssueTypeRepository issueTypeRepository = mock(IssueTypeRepository.class); + private final IssueTypeConditionReplacer replacer = new IssueTypeConditionReplacer( + issueTypeRepository); - @Test - void shouldReplace() { + @Test + void shouldReplace() { - final Filter filter = Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder() - .withCondition(Condition.IN) - .withSearchCriteria(CRITERIA_ISSUE_TYPE) - .withValue("ab001,pb001,ti001") - .build()) - .build(); + final Filter filter = Filter.builder() + .withTarget(TestItem.class) + .withCondition(FilterCondition.builder() + .withCondition(Condition.IN) + .withSearchCriteria(CRITERIA_ISSUE_TYPE) + .withValue("ab001,pb001,ti001") + .build()) + .build(); - final List<Long> ids = List.of(1L, 2L, 3L); - when(issueTypeRepository.getIssueTypeIdsByLocators(List.of("ab001", "pb001", "ti001"))).thenReturn(ids); + final List<Long> ids = List.of(1L, 2L, 3L); + when(issueTypeRepository.getIssueTypeIdsByLocators( + List.of("ab001", "pb001", "ti001"))).thenReturn(ids); - replacer.update(filter); + replacer.update(filter); - final List<ConvertibleCondition> rootConditions = filter.getFilterConditions(); - final List<FilterCondition> nestedConditions = rootConditions.get(0).getAllConditions(); - Assertions.assertEquals(1, rootConditions.size()); - Assertions.assertEquals(1, nestedConditions.size()); + final List<ConvertibleCondition> rootConditions = filter.getFilterConditions(); + final List<FilterCondition> nestedConditions = rootConditions.get(0).getAllConditions(); + Assertions.assertEquals(1, rootConditions.size()); + Assertions.assertEquals(1, nestedConditions.size()); - final FilterCondition filterCondition = nestedConditions.get(0); + final FilterCondition filterCondition = nestedConditions.get(0); - Assertions.assertEquals(CRITERIA_ISSUE_TYPE_ID, filterCondition.getSearchCriteria()); - Assertions.assertEquals(Condition.IN, filterCondition.getCondition()); - Assertions.assertEquals("1,2,3", filterCondition.getValue()); + Assertions.assertEquals(CRITERIA_ISSUE_TYPE_ID, filterCondition.getSearchCriteria()); + Assertions.assertEquals(Condition.IN, filterCondition.getCondition()); + Assertions.assertEquals("1,2,3", filterCondition.getValue()); - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImplTest.java index 990b45a344..d1d8f8023d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/history/TestItemsHistoryHandlerImplTest.java @@ -16,16 +16,20 @@ package com.epam.ta.reportportal.core.item.impl.history; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.ReportPortalUserUtil; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.core.item.impl.history.param.HistoryRequestParams; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -33,53 +37,51 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.PageRequest; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertThrows; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class TestItemsHistoryHandlerImplTest { - @Mock - private TestItemRepository testItemRepository; + @Mock + private TestItemRepository testItemRepository; - @InjectMocks - private TestItemsHistoryHandlerImpl handler; + @InjectMocks + private TestItemsHistoryHandlerImpl handler; - @Test - void historyDepthLowerThanBoundTest() { - ReportPortalUser rpUser = ReportPortalUserUtil.getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + @Test + void historyDepthLowerThanBoundTest() { + ReportPortalUser rpUser = ReportPortalUserUtil.getRpUser("test", UserRole.USER, + ProjectRole.MEMBER, 1L); - assertThrows(ReportPortalException.class, - () -> handler.getItemsHistory(extractProjectDetails(rpUser, "test_project"), - Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "1").build()) - .build(), - PageRequest.of(0, 10), - HistoryRequestParams.of(0, 1L, 1L, 1L, null, 1L, 1, false), - rpUser - ) - ); - } + assertThrows(ReportPortalException.class, + () -> handler.getItemsHistory(extractProjectDetails(rpUser, "test_project"), + Filter.builder() + .withTarget(TestItem.class) + .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "1").build()) + .build(), + PageRequest.of(0, 10), + HistoryRequestParams.of(0, 1L, 1L, 1L, null, 1L, 1, false), + rpUser + ) + ); + } - @Test - void historyDepthGreaterThanBoundTest() { - ReportPortalUser rpUser = ReportPortalUserUtil.getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + @Test + void historyDepthGreaterThanBoundTest() { + ReportPortalUser rpUser = ReportPortalUserUtil.getRpUser("test", UserRole.USER, + ProjectRole.MEMBER, 1L); - assertThrows(ReportPortalException.class, - () -> handler.getItemsHistory(extractProjectDetails(rpUser, "test_project"), - Filter.builder() - .withTarget(TestItem.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "1").build()) - .build(), - PageRequest.of(0, 10), - HistoryRequestParams.of(31, 1L, 1L, 1L, "table", 1L, 1, false), - rpUser - ) - ); - } + assertThrows(ReportPortalException.class, + () -> handler.getItemsHistory(extractProjectDetails(rpUser, "test_project"), + Filter.builder() + .withTarget(TestItem.class) + .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "1").build()) + .build(), + PageRequest.of(0, 10), + HistoryRequestParams.of(31, 1L, 1L, 1L, "table", 1L, 1, false), + rpUser + ) + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/impl/provider/impl/mock/ClusterItemDataProviderMockTest.java b/src/test/java/com/epam/ta/reportportal/core/item/impl/provider/impl/mock/ClusterItemDataProviderMockTest.java index 65172d8301..c2d9f53c99 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/impl/provider/impl/mock/ClusterItemDataProviderMockTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/impl/provider/impl/mock/ClusterItemDataProviderMockTest.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.core.item.impl.provider.impl.mock; +import static java.util.stream.Collectors.groupingBy; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.entity.ItemAttribute; @@ -31,167 +33,170 @@ import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.entity.statistics.StatisticsField; import com.google.common.base.Suppliers; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; - import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.*; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; - -import static java.util.stream.Collectors.groupingBy; -import static org.junit.jupiter.api.Assertions.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ClusterItemDataProviderMockTest { - private final Supplier<List<TestItem>> itemSupplier = Suppliers.memoize(this::getItems); - - public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, ReportPortalUser.ProjectDetails projectDetails, - ReportPortalUser user, Map<String, String> params) { - final List<TestItem> testItems = itemSupplier.get(); - final List<TestItem> content = testItems.stream() - .skip(pageable.getOffset()) - .limit(pageable.getPageSize()) - .collect(Collectors.toList()); - return new PageImpl<>(content, pageable, testItems.size()); - } - - public Set<Statistics> accumulateStatistics(Queryable filter, ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, - Map<String, String> params) { - final List<TestItem> testItems = itemSupplier.get(); - - return testItems.stream() - .map(TestItem::getItemResults) - .flatMap(r -> r.getStatistics().stream()) - .collect(groupingBy(Statistics::getStatisticsField, LinkedHashMap::new, Collectors.summingInt(Statistics::getCounter))) - .entrySet() - .stream() - .map(entry -> new Statistics(entry.getKey(), entry.getValue())) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - private List<TestItem> getItems() { - return IntStream.range(1, 21).mapToObj(this::getTestItem).collect(Collectors.toList()); - } - - private TestItem getTestItem(int index) { - final TestItem testItem = new TestItem(); - testItem.setItemId((long) index); - testItem.setUuid(String.valueOf(index)); - testItem.setUniqueId(String.valueOf(index)); - testItem.setTestCaseId(String.valueOf(index)); - testItem.setTestCaseHash(index); - testItem.setName("name " + index); - testItem.setCodeRef("ref" + index); - testItem.setDescription("description " + index); - testItem.setHasChildren(false); - testItem.setType(TestItemTypeEnum.STEP); - testItem.setHasRetries(false); - testItem.setHasStats(true); - testItem.setLastModified(LocalDateTime.now(ZoneOffset.UTC)); - testItem.setPath(String.valueOf(index)); - testItem.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); - - final Set<Parameter> parameters = getParameters(index); - testItem.setParameters(parameters); - - final Set<ItemAttribute> attributes = getItemAttributes(index); - testItem.setAttributes(attributes); - - final TestItemResults testItemResults = getTestItemResults((long) index); - - testItem.setItemResults(testItemResults); - - return testItem; - } - - private Set<Parameter> getParameters(int index) { - final Parameter parameter = new Parameter(); - parameter.setKey("param key " + index); - parameter.setValue("param value " + index); - return Set.of(parameter); - } - - private Set<ItemAttribute> getItemAttributes(int index) { - final ItemAttribute itemAttribute = new ItemAttribute(); - itemAttribute.setKey("key" + index); - itemAttribute.setValue("value" + index); - itemAttribute.setSystem(false); - - return Set.of(itemAttribute); - } - - private TestItemResults getTestItemResults(Long index) { - final TestItemResults testItemResults = new TestItemResults(); - testItemResults.setDuration(0.01); - testItemResults.setEndTime(LocalDateTime.now(ZoneOffset.UTC)); - testItemResults.setStatus(StatusEnum.FAILED); - - final IssueEntity issueEntity = getIssueEntity(index); - - testItemResults.setIssue(issueEntity); - - final LinkedHashSet<Statistics> statistics = getStatistics(); - - testItemResults.setStatistics(statistics); - return testItemResults; - } - - private IssueEntity getIssueEntity(Long index) { - final IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIssueId(index); - issueEntity.setIssueDescription("description " + index); - issueEntity.setAutoAnalyzed(false); - issueEntity.setIgnoreAnalyzer(false); - - final IssueType issueType = getIssueType(); - - issueEntity.setIssueType(issueType); - return issueEntity; - } - - private IssueType getIssueType() { - final IssueType issueType = new IssueType(); - issueType.setId(1L); - issueType.setLocator("ti001"); - issueType.setHexColor("#ffb743"); - issueType.setLongName("To Investigate"); - issueType.setShortName("TI"); - - final IssueGroup issueGroup = getIssueGroup(); - issueType.setIssueGroup(issueGroup); - return issueType; - } - - private IssueGroup getIssueGroup() { - final IssueGroup issueGroup = new IssueGroup(); - issueGroup.setId(1); - issueGroup.setTestItemIssueGroup(TestItemIssueGroup.TO_INVESTIGATE); - return issueGroup; - } - - private LinkedHashSet<Statistics> getStatistics() { - return Map.of(1L, - "statistics$executions$total", - 2L, - "statistics$executions$passed", - 3L, - "statistics$executions$skipped", - 4L, - "statistics$executions$failed", - 12L, - "statistics$defects$to_investigate$ti001" - ).entrySet().stream().map(entry -> { - final StatisticsField sf = new StatisticsField(entry.getValue()); - sf.setId(entry.getKey()); - return new Statistics(sf, 1); - }).collect(Collectors.toCollection(LinkedHashSet::new)); - } + private final Supplier<List<TestItem>> itemSupplier = Suppliers.memoize(this::getItems); + + public Page<TestItem> getTestItems(Queryable filter, Pageable pageable, + ReportPortalUser.ProjectDetails projectDetails, + ReportPortalUser user, Map<String, String> params) { + final List<TestItem> testItems = itemSupplier.get(); + final List<TestItem> content = testItems.stream() + .skip(pageable.getOffset()) + .limit(pageable.getPageSize()) + .collect(Collectors.toList()); + return new PageImpl<>(content, pageable, testItems.size()); + } + + public Set<Statistics> accumulateStatistics(Queryable filter, + ReportPortalUser.ProjectDetails projectDetails, ReportPortalUser user, + Map<String, String> params) { + final List<TestItem> testItems = itemSupplier.get(); + + return testItems.stream() + .map(TestItem::getItemResults) + .flatMap(r -> r.getStatistics().stream()) + .collect(groupingBy(Statistics::getStatisticsField, LinkedHashMap::new, + Collectors.summingInt(Statistics::getCounter))) + .entrySet() + .stream() + .map(entry -> new Statistics(entry.getKey(), entry.getValue())) + .collect(Collectors.toCollection(LinkedHashSet::new)); + } + + private List<TestItem> getItems() { + return IntStream.range(1, 21).mapToObj(this::getTestItem).collect(Collectors.toList()); + } + + private TestItem getTestItem(int index) { + final TestItem testItem = new TestItem(); + testItem.setItemId((long) index); + testItem.setUuid(String.valueOf(index)); + testItem.setUniqueId(String.valueOf(index)); + testItem.setTestCaseId(String.valueOf(index)); + testItem.setTestCaseHash(index); + testItem.setName("name " + index); + testItem.setCodeRef("ref" + index); + testItem.setDescription("description " + index); + testItem.setHasChildren(false); + testItem.setType(TestItemTypeEnum.STEP); + testItem.setHasRetries(false); + testItem.setHasStats(true); + testItem.setLastModified(LocalDateTime.now(ZoneOffset.UTC)); + testItem.setPath(String.valueOf(index)); + testItem.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); + + final Set<Parameter> parameters = getParameters(index); + testItem.setParameters(parameters); + + final Set<ItemAttribute> attributes = getItemAttributes(index); + testItem.setAttributes(attributes); + + final TestItemResults testItemResults = getTestItemResults((long) index); + + testItem.setItemResults(testItemResults); + + return testItem; + } + + private Set<Parameter> getParameters(int index) { + final Parameter parameter = new Parameter(); + parameter.setKey("param key " + index); + parameter.setValue("param value " + index); + return Set.of(parameter); + } + + private Set<ItemAttribute> getItemAttributes(int index) { + final ItemAttribute itemAttribute = new ItemAttribute(); + itemAttribute.setKey("key" + index); + itemAttribute.setValue("value" + index); + itemAttribute.setSystem(false); + + return Set.of(itemAttribute); + } + + private TestItemResults getTestItemResults(Long index) { + final TestItemResults testItemResults = new TestItemResults(); + testItemResults.setDuration(0.01); + testItemResults.setEndTime(LocalDateTime.now(ZoneOffset.UTC)); + testItemResults.setStatus(StatusEnum.FAILED); + + final IssueEntity issueEntity = getIssueEntity(index); + + testItemResults.setIssue(issueEntity); + + final LinkedHashSet<Statistics> statistics = getStatistics(); + + testItemResults.setStatistics(statistics); + return testItemResults; + } + + private IssueEntity getIssueEntity(Long index) { + final IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIssueId(index); + issueEntity.setIssueDescription("description " + index); + issueEntity.setAutoAnalyzed(false); + issueEntity.setIgnoreAnalyzer(false); + + final IssueType issueType = getIssueType(); + + issueEntity.setIssueType(issueType); + return issueEntity; + } + + private IssueType getIssueType() { + final IssueType issueType = new IssueType(); + issueType.setId(1L); + issueType.setLocator("ti001"); + issueType.setHexColor("#ffb743"); + issueType.setLongName("To Investigate"); + issueType.setShortName("TI"); + + final IssueGroup issueGroup = getIssueGroup(); + issueType.setIssueGroup(issueGroup); + return issueType; + } + + private IssueGroup getIssueGroup() { + final IssueGroup issueGroup = new IssueGroup(); + issueGroup.setId(1); + issueGroup.setTestItemIssueGroup(TestItemIssueGroup.TO_INVESTIGATE); + return issueGroup; + } + + private LinkedHashSet<Statistics> getStatistics() { + return Map.of(1L, + "statistics$executions$total", + 2L, + "statistics$executions$passed", + 3L, + "statistics$executions$skipped", + 4L, + "statistics$executions$failed", + 12L, + "statistics$defects$to_investigate$ti001" + ).entrySet().stream().map(entry -> { + final StatisticsField sf = new StatisticsField(entry.getValue()); + sf.setId(entry.getKey()); + return new Statistics(sf, 1); + }).collect(Collectors.toCollection(LinkedHashSet::new)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidatorTest.java index ebb4c1de3f..479297051c 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotNestedStepValidatorTest.java @@ -20,27 +20,25 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class NotNestedStepValidatorTest { - private final NotNestedStepValidator validator = new NotNestedStepValidator(); - - @Test - void shouldReturnTrueWhenHasStats() { - final TestItem testItem = new TestItem(); - testItem.setHasStats(true); - Assertions.assertTrue(validator.validate(testItem)); - } - - @Test - void shouldReturnFalseWhenNotHasStats() { - final TestItem testItem = new TestItem(); - testItem.setHasStats(false); - Assertions.assertFalse(validator.validate(testItem)); - } + private final NotNestedStepValidator validator = new NotNestedStepValidator(); + + @Test + void shouldReturnTrueWhenHasStats() { + final TestItem testItem = new TestItem(); + testItem.setHasStats(true); + Assertions.assertTrue(validator.validate(testItem)); + } + + @Test + void shouldReturnFalseWhenNotHasStats() { + final TestItem testItem = new TestItem(); + testItem.setHasStats(false); + Assertions.assertFalse(validator.validate(testItem)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidatorTest.java index 75729a10c0..363ed3a0c2 100644 --- a/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/item/validator/state/NotRetryValidatorTest.java @@ -20,33 +20,31 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class NotRetryValidatorTest { - private final NotRetryValidator validator = new NotRetryValidator(); - - @Test - void shouldReturnTrueWhenRetryOfIsNullAndLaunchIdIsNotNull() { - final TestItem testItem = new TestItem(); - testItem.setLaunchId(1L); - Assertions.assertTrue(validator.validate(testItem)); - } - - @Test - void shouldReturnFalseWhenRetryOfIsNotNull() { - final TestItem testItem = new TestItem(); - testItem.setRetryOf(1L); - Assertions.assertFalse(validator.validate(testItem)); - } - - @Test - void shouldReturnFalseWhenLaunchIdIsNull() { - final TestItem testItem = new TestItem(); - Assertions.assertFalse(validator.validate(testItem)); - } + private final NotRetryValidator validator = new NotRetryValidator(); + + @Test + void shouldReturnTrueWhenRetryOfIsNullAndLaunchIdIsNotNull() { + final TestItem testItem = new TestItem(); + testItem.setLaunchId(1L); + Assertions.assertTrue(validator.validate(testItem)); + } + + @Test + void shouldReturnFalseWhenRetryOfIsNotNull() { + final TestItem testItem = new TestItem(); + testItem.setRetryOf(1L); + Assertions.assertFalse(validator.validate(testItem)); + } + + @Test + void shouldReturnFalseWhenLaunchIdIsNull() { + final TestItem testItem = new TestItem(); + Assertions.assertFalse(validator.validate(testItem)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImplTest.java index 7f4c3c900f..1c274d8eb0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/CreateClusterHandlerImplTest.java @@ -16,116 +16,124 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anySet; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterInfoRs; import com.epam.ta.reportportal.dao.ClusterRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.entity.cluster.Cluster; +import java.util.List; +import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @ExtendWith(MockitoExtension.class) class CreateClusterHandlerImplTest { - @Mock - private ClusterRepository clusterRepository; - - @Mock - private LogRepository logRepository; - - @InjectMocks - private CreateClusterHandlerImpl createClusterHandler; - - @Test - void updateCluster() { - - final ClusterData clusterData = new ClusterData(); - clusterData.setProject(1L); - clusterData.setLaunchId(1L); - - final ClusterInfoRs first = new ClusterInfoRs(); - first.setClusterId(1L); - first.setClusterMessage("first"); - first.setLogIds(Set.of(1L, 2L)); - first.setItemIds(Set.of(1L, 2L)); - - final ClusterInfoRs second = new ClusterInfoRs(); - second.setClusterId(2L); - second.setClusterMessage("second"); - second.setLogIds(Set.of(3L, 4L)); - second.setItemIds(Set.of(3L, 4L)); - - clusterData.setClusters(List.of(first, second)); - - final Cluster firstCluster = new Cluster(); - firstCluster.setIndexId(1L); - final Cluster secondCluster = new Cluster(); - secondCluster.setIndexId(2L); - when(clusterRepository.findByIndexIdAndLaunchId(1L, clusterData.getLaunchId())).thenReturn(Optional.of(firstCluster)); - when(clusterRepository.findByIndexIdAndLaunchId(2L, clusterData.getLaunchId())).thenReturn(Optional.of(secondCluster)); - - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Cluster cluster = ((Cluster) args[0]); - cluster.setId(cluster.getIndexId()); - return cluster; - }).when(clusterRepository).save(any(Cluster.class)); - - createClusterHandler.create(clusterData); - - verify(clusterRepository, times(2)).save(any(Cluster.class)); - verify(clusterRepository, times(2)).saveClusterTestItems(any(Cluster.class), anySet()); - verify(logRepository, times(2)).updateClusterIdByIdIn(any(Long.class), anySet()); - } - - @Test - void saveCluster() { - - final ClusterData clusterData = new ClusterData(); - clusterData.setProject(1L); - clusterData.setLaunchId(1L); - - final ClusterInfoRs first = new ClusterInfoRs(); - first.setClusterId(1L); - first.setClusterMessage("first"); - first.setLogIds(Set.of(1L, 2L)); - first.setItemIds(Set.of(1L, 2L)); - - final ClusterInfoRs second = new ClusterInfoRs(); - second.setClusterId(2L); - second.setClusterMessage("second"); - second.setLogIds(Set.of(3L, 4L)); - second.setItemIds(Set.of(3L, 4L)); - - clusterData.setClusters(List.of(first, second)); - - when(clusterRepository.findByIndexIdAndLaunchId(anyLong(), eq(clusterData.getLaunchId()))).thenReturn(Optional.empty()); - - doAnswer(invocation -> { - Object[] args = invocation.getArguments(); - Cluster cluster = ((Cluster) args[0]); - cluster.setId(cluster.getIndexId()); - return cluster; - }).when(clusterRepository).save(any(Cluster.class)); - - createClusterHandler.create(clusterData); - - verify(clusterRepository, times(2)).save(any(Cluster.class)); - verify(clusterRepository, times(2)).saveClusterTestItems(any(Cluster.class), anySet()); - verify(logRepository, times(2)).updateClusterIdByIdIn(any(Long.class), anySet()); - } + @Mock + private ClusterRepository clusterRepository; + + @Mock + private LogRepository logRepository; + + @InjectMocks + private CreateClusterHandlerImpl createClusterHandler; + + @Test + void updateCluster() { + + final ClusterData clusterData = new ClusterData(); + clusterData.setProject(1L); + clusterData.setLaunchId(1L); + + final ClusterInfoRs first = new ClusterInfoRs(); + first.setClusterId(1L); + first.setClusterMessage("first"); + first.setLogIds(Set.of(1L, 2L)); + first.setItemIds(Set.of(1L, 2L)); + + final ClusterInfoRs second = new ClusterInfoRs(); + second.setClusterId(2L); + second.setClusterMessage("second"); + second.setLogIds(Set.of(3L, 4L)); + second.setItemIds(Set.of(3L, 4L)); + + clusterData.setClusters(List.of(first, second)); + + final Cluster firstCluster = new Cluster(); + firstCluster.setIndexId(1L); + final Cluster secondCluster = new Cluster(); + secondCluster.setIndexId(2L); + when(clusterRepository.findByIndexIdAndLaunchId(1L, clusterData.getLaunchId())).thenReturn( + Optional.of(firstCluster)); + when(clusterRepository.findByIndexIdAndLaunchId(2L, clusterData.getLaunchId())).thenReturn( + Optional.of(secondCluster)); + + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + Cluster cluster = ((Cluster) args[0]); + cluster.setId(cluster.getIndexId()); + return cluster; + }).when(clusterRepository).save(any(Cluster.class)); + + createClusterHandler.create(clusterData); + + verify(clusterRepository, times(2)).save(any(Cluster.class)); + verify(clusterRepository, times(2)).saveClusterTestItems(any(Cluster.class), anySet()); + verify(logRepository, times(2)).updateClusterIdByIdIn(any(Long.class), anySet()); + } + + @Test + void saveCluster() { + + final ClusterData clusterData = new ClusterData(); + clusterData.setProject(1L); + clusterData.setLaunchId(1L); + + final ClusterInfoRs first = new ClusterInfoRs(); + first.setClusterId(1L); + first.setClusterMessage("first"); + first.setLogIds(Set.of(1L, 2L)); + first.setItemIds(Set.of(1L, 2L)); + + final ClusterInfoRs second = new ClusterInfoRs(); + second.setClusterId(2L); + second.setClusterMessage("second"); + second.setLogIds(Set.of(3L, 4L)); + second.setItemIds(Set.of(3L, 4L)); + + clusterData.setClusters(List.of(first, second)); + + when(clusterRepository.findByIndexIdAndLaunchId(anyLong(), + eq(clusterData.getLaunchId()))).thenReturn(Optional.empty()); + + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + Cluster cluster = ((Cluster) args[0]); + cluster.setId(cluster.getIndexId()); + return cluster; + }).when(clusterRepository).save(any(Cluster.class)); + + createClusterHandler.create(clusterData); + + verify(clusterRepository, times(2)).save(any(Cluster.class)); + verify(clusterRepository, times(2)).saveClusterTestItems(any(Cluster.class), anySet()); + verify(logRepository, times(2)).updateClusterIdByIdIn(any(Long.class), anySet()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarterTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarterTest.java index 49140f3501..9bc2eca9da 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorAnalysisStarterTest.java @@ -1,58 +1,70 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; - import java.util.HashMap; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class UniqueErrorAnalysisStarterTest { - private final ClusterGenerator clusterGenerator = mock(ClusterGenerator.class); + private final ClusterGenerator clusterGenerator = mock(ClusterGenerator.class); - private final UniqueErrorAnalysisStarter starter = new UniqueErrorAnalysisStarter(clusterGenerator); + private final UniqueErrorAnalysisStarter starter = new UniqueErrorAnalysisStarter( + clusterGenerator); - @Test - void shouldGenerateNotForUpdateWhenNoItemIds() { + @Test + void shouldGenerateNotForUpdateWhenNoItemIds() { - final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L); + final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L); - starter.start(entityContext, new HashMap<>()); + starter.start(entityContext, new HashMap<>()); - final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass(GenerateClustersConfig.class); - verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); + final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass( + GenerateClustersConfig.class); + verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); - final GenerateClustersConfig generateClustersConfig = configArgumentCaptor.getValue(); + final GenerateClustersConfig generateClustersConfig = configArgumentCaptor.getValue(); - assertFalse(generateClustersConfig.isForUpdate()); - assertEquals(entityContext.getLaunchId(), generateClustersConfig.getEntityContext().getLaunchId()); - assertEquals(entityContext.getProjectId(), generateClustersConfig.getEntityContext().getProjectId()); - assertEquals(entityContext.getItemIds(), generateClustersConfig.getEntityContext().getItemIds()); - } + assertFalse(generateClustersConfig.isForUpdate()); + assertEquals(entityContext.getLaunchId(), + generateClustersConfig.getEntityContext().getLaunchId()); + assertEquals(entityContext.getProjectId(), + generateClustersConfig.getEntityContext().getProjectId()); + assertEquals(entityContext.getItemIds(), + generateClustersConfig.getEntityContext().getItemIds()); + } - @Test - void shouldGenerateForUpdateWhenItemIdsExist() { - final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L, List.of(1L, 2L)); + @Test + void shouldGenerateForUpdateWhenItemIdsExist() { + final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L, List.of(1L, 2L)); - starter.start(entityContext, new HashMap<>()); + starter.start(entityContext, new HashMap<>()); - final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass(GenerateClustersConfig.class); - verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); + final ArgumentCaptor<GenerateClustersConfig> configArgumentCaptor = ArgumentCaptor.forClass( + GenerateClustersConfig.class); + verify(clusterGenerator, times(1)).generate(configArgumentCaptor.capture()); - final GenerateClustersConfig generateClustersConfig = configArgumentCaptor.getValue(); + final GenerateClustersConfig generateClustersConfig = configArgumentCaptor.getValue(); - assertTrue(generateClustersConfig.isForUpdate()); - assertEquals(entityContext.getLaunchId(), generateClustersConfig.getEntityContext().getLaunchId()); - assertEquals(entityContext.getProjectId(), generateClustersConfig.getEntityContext().getProjectId()); - assertEquals(entityContext.getItemIds(), generateClustersConfig.getEntityContext().getItemIds()); - } + assertTrue(generateClustersConfig.isForUpdate()); + assertEquals(entityContext.getLaunchId(), + generateClustersConfig.getEntityContext().getLaunchId()); + assertEquals(entityContext.getProjectId(), + generateClustersConfig.getEntityContext().getProjectId()); + assertEquals(entityContext.getItemIds(), + generateClustersConfig.getEntityContext().getItemIds()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsyncTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsyncTest.java index f014db5ce7..682b4d7ebd 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsyncTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorAsyncTest.java @@ -16,6 +16,20 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; @@ -25,107 +39,108 @@ import org.junit.jupiter.api.Test; import org.springframework.core.task.SyncTaskExecutor; -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class UniqueErrorGeneratorAsyncTest { - private final SyncTaskExecutor logClusterExecutor = mock(SyncTaskExecutor.class); - - private final AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); - - private final PipelineConstructor<GenerateClustersConfig> pipelineConstructor = (PipelineConstructor<GenerateClustersConfig>) mock( - PipelineConstructor.class); - - private final TransactionalPipeline transactionalPipeline = mock(TransactionalPipeline.class); - - private final UniqueErrorGeneratorAsync clusterGenerator = new UniqueErrorGeneratorAsync(analyzerStatusCache, - pipelineConstructor, - transactionalPipeline, - logClusterExecutor - ); - - @Test - void shouldFailWhenCacheContainsLaunchId() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(true); - - final GenerateClustersConfig config = getConfig(false); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> clusterGenerator.generate(config)); - assertEquals("Impossible interact with integration. Clusters creation is in progress.", exception.getMessage()); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(0)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - } - - @Test - void shouldGenerate() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); - doCallRealMethod().when(logClusterExecutor).execute(any(Runnable.class)); - - final GenerateClustersConfig config = getConfig(false); - - clusterGenerator.generate(config); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - verify(pipelineConstructor, times(1)).construct(config); - verify(transactionalPipeline, times(1)).run(anyList()); - verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } - - @Test - void shouldCleanCacheWhenExceptionThrown() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); - doCallRealMethod().when(logClusterExecutor).execute(any(Runnable.class)); - - final GenerateClustersConfig config = getConfig(false); - - doThrow(new RuntimeException("Exception during generation")).when(transactionalPipeline).run(anyList()); - - clusterGenerator.generate(config); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - verify(pipelineConstructor, times(1)).construct(config); - verify(transactionalPipeline, times(1)).run(anyList()); - verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } - - @Test - void shouldCleanCacheWhenExceptionThrownDuringTaskSubmit() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); - - final GenerateClustersConfig config = getConfig(false); - - doThrow(new RuntimeException("Exception during generation")).when(logClusterExecutor).execute(any(Runnable.class)); - - clusterGenerator.generate(config); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - verify(pipelineConstructor, times(0)).construct(any(GenerateClustersConfig.class)); - verify(transactionalPipeline, times(0)).run(anyList()); - verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } + private final SyncTaskExecutor logClusterExecutor = mock(SyncTaskExecutor.class); + + private final AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); + + private final PipelineConstructor<GenerateClustersConfig> pipelineConstructor = (PipelineConstructor<GenerateClustersConfig>) mock( + PipelineConstructor.class); + + private final TransactionalPipeline transactionalPipeline = mock(TransactionalPipeline.class); + + private final UniqueErrorGeneratorAsync clusterGenerator = new UniqueErrorGeneratorAsync( + analyzerStatusCache, + pipelineConstructor, + transactionalPipeline, + logClusterExecutor + ); + + @Test + void shouldFailWhenCacheContainsLaunchId() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(true); + + final GenerateClustersConfig config = getConfig(false); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> clusterGenerator.generate(config)); + assertEquals("Impossible interact with integration. Clusters creation is in progress.", + exception.getMessage()); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(0)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + } + + @Test + void shouldGenerate() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); + doCallRealMethod().when(logClusterExecutor).execute(any(Runnable.class)); + + final GenerateClustersConfig config = getConfig(false); + + clusterGenerator.generate(config); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + verify(pipelineConstructor, times(1)).construct(config); + verify(transactionalPipeline, times(1)).run(anyList()); + verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } + + @Test + void shouldCleanCacheWhenExceptionThrown() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); + doCallRealMethod().when(logClusterExecutor).execute(any(Runnable.class)); + + final GenerateClustersConfig config = getConfig(false); + + doThrow(new RuntimeException("Exception during generation")).when(transactionalPipeline) + .run(anyList()); + + clusterGenerator.generate(config); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + verify(pipelineConstructor, times(1)).construct(config); + verify(transactionalPipeline, times(1)).run(anyList()); + verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } + + @Test + void shouldCleanCacheWhenExceptionThrownDuringTaskSubmit() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); + + final GenerateClustersConfig config = getConfig(false); + + doThrow(new RuntimeException("Exception during generation")).when(logClusterExecutor) + .execute(any(Runnable.class)); + + clusterGenerator.generate(config); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + verify(pipelineConstructor, times(0)).construct(any(GenerateClustersConfig.class)); + verify(transactionalPipeline, times(0)).run(anyList()); + verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorTest.java index fb189153d5..dc5c5911d0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/UniqueErrorGeneratorTest.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.core.launch.cluster; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.impl.AnalyzerStatusCache; import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; @@ -24,82 +36,81 @@ import com.epam.ta.reportportal.pipeline.TransactionalPipeline; import org.junit.jupiter.api.Test; -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class UniqueErrorGeneratorTest { - private final AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); - - private final PipelineConstructor<GenerateClustersConfig> pipelineConstructor = (PipelineConstructor<GenerateClustersConfig>) mock( - PipelineConstructor.class); - - private final TransactionalPipeline transactionalPipeline = mock(TransactionalPipeline.class); - - private final UniqueErrorGenerator clusterGenerator = new UniqueErrorGenerator(analyzerStatusCache, - pipelineConstructor, - transactionalPipeline - ); - - @Test - void shouldFailWhenCacheContainsLaunchId() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(true); - - final GenerateClustersConfig config = getConfig(false); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> clusterGenerator.generate(config)); - assertEquals("Impossible interact with integration. Clusters creation is in progress.", exception.getMessage()); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(0)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - } - - @Test - void shouldGenerate() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); - - final GenerateClustersConfig config = getConfig(false); - - clusterGenerator.generate(config); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - verify(pipelineConstructor, times(1)).construct(config); - verify(transactionalPipeline, times(1)).run(anyList()); - verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } - - @Test - void shouldCleanCacheWhenExceptionThrown() { - when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); - - final GenerateClustersConfig config = getConfig(false); - - doThrow(new RuntimeException("Exception during generation")).when(transactionalPipeline).run(anyList()); - - clusterGenerator.generate(config); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, - entityContext.getLaunchId(), - entityContext.getProjectId() - ); - verify(pipelineConstructor, times(1)).construct(config); - verify(transactionalPipeline, times(1)).run(anyList()); - verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, entityContext.getLaunchId()); - } + private final AnalyzerStatusCache analyzerStatusCache = mock(AnalyzerStatusCache.class); + + private final PipelineConstructor<GenerateClustersConfig> pipelineConstructor = (PipelineConstructor<GenerateClustersConfig>) mock( + PipelineConstructor.class); + + private final TransactionalPipeline transactionalPipeline = mock(TransactionalPipeline.class); + + private final UniqueErrorGenerator clusterGenerator = new UniqueErrorGenerator( + analyzerStatusCache, + pipelineConstructor, + transactionalPipeline + ); + + @Test + void shouldFailWhenCacheContainsLaunchId() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(true); + + final GenerateClustersConfig config = getConfig(false); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> clusterGenerator.generate(config)); + assertEquals("Impossible interact with integration. Clusters creation is in progress.", + exception.getMessage()); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(0)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + } + + @Test + void shouldGenerate() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); + + final GenerateClustersConfig config = getConfig(false); + + clusterGenerator.generate(config); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + verify(pipelineConstructor, times(1)).construct(config); + verify(transactionalPipeline, times(1)).run(anyList()); + verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } + + @Test + void shouldCleanCacheWhenExceptionThrown() { + when(analyzerStatusCache.containsLaunchId(anyString(), anyLong())).thenReturn(false); + + final GenerateClustersConfig config = getConfig(false); + + doThrow(new RuntimeException("Exception during generation")).when(transactionalPipeline) + .run(anyList()); + + clusterGenerator.generate(config); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(analyzerStatusCache, times(1)).analyzeStarted(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId(), + entityContext.getProjectId() + ); + verify(pipelineConstructor, times(1)).construct(config); + verify(transactionalPipeline, times(1)).run(anyList()); + verify(analyzerStatusCache, times(1)).analyzeFinished(AnalyzerStatusCache.CLUSTER_KEY, + entityContext.getLaunchId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProviderTest.java index ff921016a6..a1246f1cdc 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/DeleteClustersPartProviderTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.core.launch.cluster.config.ClusterEntityContext; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.dao.ClusterRepository; @@ -23,41 +28,41 @@ import com.epam.ta.reportportal.pipeline.PipelinePart; import org.junit.jupiter.api.Test; -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class DeleteClustersPartProviderTest { - private final ClusterRepository clusterRepository = mock(ClusterRepository.class); - private final LogRepository logRepository = mock(LogRepository.class); - - private final DeleteClustersPartProvider provider = new DeleteClustersPartProvider(clusterRepository, logRepository); - - @Test - void shouldDeleteWhenNotForUpdate() { - final GenerateClustersConfig config = getConfig(false); - final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(logRepository, times(1)).updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); - verify(clusterRepository, times(1)).deleteClusterTestItemsByLaunchId(entityContext.getLaunchId()); - verify(clusterRepository, times(1)).deleteAllByLaunchId(entityContext.getLaunchId()); - } - - @Test - void shouldNotDeleteWhenForUpdate() { - final GenerateClustersConfig config = getConfig(true); - final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); - - final ClusterEntityContext entityContext = config.getEntityContext(); - verify(logRepository, times(0)).updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); - verify(clusterRepository, times(0)).deleteClusterTestItemsByLaunchId(entityContext.getLaunchId()); - verify(clusterRepository, times(0)).deleteAllByLaunchId(entityContext.getLaunchId()); - } + private final ClusterRepository clusterRepository = mock(ClusterRepository.class); + private final LogRepository logRepository = mock(LogRepository.class); + + private final DeleteClustersPartProvider provider = new DeleteClustersPartProvider( + clusterRepository, logRepository); + + @Test + void shouldDeleteWhenNotForUpdate() { + final GenerateClustersConfig config = getConfig(false); + final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(logRepository, times(1)).updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); + verify(clusterRepository, times(1)).deleteClusterTestItemsByLaunchId( + entityContext.getLaunchId()); + verify(clusterRepository, times(1)).deleteAllByLaunchId(entityContext.getLaunchId()); + } + + @Test + void shouldNotDeleteWhenForUpdate() { + final GenerateClustersConfig config = getConfig(true); + final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); + + final ClusterEntityContext entityContext = config.getEntityContext(); + verify(logRepository, times(0)).updateClusterIdSetNullByLaunchId(entityContext.getLaunchId()); + verify(clusterRepository, times(0)).deleteClusterTestItemsByLaunchId( + entityContext.getLaunchId()); + verify(clusterRepository, times(0)).deleteAllByLaunchId(entityContext.getLaunchId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProviderTest.java index 73ac9d4731..6ebe945af5 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveClusterDataPartProviderTest.java @@ -16,69 +16,72 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.launch.cluster.CreateClusterHandler; import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.ClusterDataProviderResolver; import com.epam.ta.reportportal.pipeline.PipelinePart; -import org.junit.jupiter.api.Test; - import java.util.Optional; - -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class SaveClusterDataPartProviderTest { - private final ClusterDataProvider dataProvider = mock(ClusterDataProvider.class); - private final ClusterDataProviderResolver resolver = mock(ClusterDataProviderResolver.class); - private final CreateClusterHandler createClusterHandler = mock(CreateClusterHandler.class); + private final ClusterDataProvider dataProvider = mock(ClusterDataProvider.class); + private final ClusterDataProviderResolver resolver = mock(ClusterDataProviderResolver.class); + private final CreateClusterHandler createClusterHandler = mock(CreateClusterHandler.class); - private final SaveClusterDataPartProvider provider = new SaveClusterDataPartProvider(resolver, createClusterHandler); + private final SaveClusterDataPartProvider provider = new SaveClusterDataPartProvider(resolver, + createClusterHandler); - @Test - void shouldSaveWhenProviderAndDataExists() { - final GenerateClustersConfig config = getConfig(false); + @Test + void shouldSaveWhenProviderAndDataExists() { + final GenerateClustersConfig config = getConfig(false); - final ClusterData clusterData = new ClusterData(); - when(dataProvider.provide(config)).thenReturn(Optional.of(clusterData)); - when(resolver.resolve(config)).thenReturn(Optional.of(dataProvider)); + final ClusterData clusterData = new ClusterData(); + when(dataProvider.provide(config)).thenReturn(Optional.of(clusterData)); + when(resolver.resolve(config)).thenReturn(Optional.of(dataProvider)); - final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); + final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); - verify(createClusterHandler, times(1)).create(clusterData); - } + verify(createClusterHandler, times(1)).create(clusterData); + } - @Test - void shouldSaveWhenProviderNotExists() { - final GenerateClustersConfig config = getConfig(false); + @Test + void shouldSaveWhenProviderNotExists() { + final GenerateClustersConfig config = getConfig(false); - final ClusterData clusterData = new ClusterData(); - when(resolver.resolve(config)).thenReturn(Optional.empty()); + final ClusterData clusterData = new ClusterData(); + when(resolver.resolve(config)).thenReturn(Optional.empty()); - final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); + final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); - verify(createClusterHandler, times(0)).create(clusterData); - } + verify(createClusterHandler, times(0)).create(clusterData); + } - @Test - void shouldNotSaveWhenProviderExistsAndNoDataExists() { - final GenerateClustersConfig config = getConfig(false); + @Test + void shouldNotSaveWhenProviderExistsAndNoDataExists() { + final GenerateClustersConfig config = getConfig(false); - final ClusterData clusterData = new ClusterData(); - when(dataProvider.provide(config)).thenReturn(Optional.of(clusterData)); - when(resolver.resolve(config)).thenReturn(Optional.empty()); + final ClusterData clusterData = new ClusterData(); + when(dataProvider.provide(config)).thenReturn(Optional.of(clusterData)); + when(resolver.resolve(config)).thenReturn(Optional.empty()); - final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); + final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); - verify(createClusterHandler, times(0)).create(clusterData); - } + verify(createClusterHandler, times(0)).create(clusterData); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProviderTest.java index 66713afdc1..4c1c230c70 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/SaveLastRunAttributePartProviderTest.java @@ -16,60 +16,71 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline; +import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.dao.ItemAttributeRepository; -import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.pipeline.PipelinePart; import org.junit.jupiter.api.Test; -import java.util.Optional; - -import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class SaveLastRunAttributePartProviderTest { - private final ItemAttributeRepository itemAttributeRepository = mock(ItemAttributeRepository.class); + private final ItemAttributeRepository itemAttributeRepository = mock( + ItemAttributeRepository.class); + + private final SaveLastRunAttributePartProvider provider = new SaveLastRunAttributePartProvider( + itemAttributeRepository); - private final SaveLastRunAttributePartProvider provider = new SaveLastRunAttributePartProvider(itemAttributeRepository); + @Test + void shouldDeletePreviousAndSaveNew() { + final GenerateClustersConfig config = getConfig(false); - @Test - void shouldSaveWhenNotExists() { - final GenerateClustersConfig config = getConfig(false); - when(itemAttributeRepository.findByLaunchIdAndKeyAndSystem(config.getEntityContext().getLaunchId(), - RP_CLUSTER_LAST_RUN_KEY, - true - )).thenReturn(Optional.empty()); + final PipelinePart pipelinePart = provider.provide(config); - final PipelinePart pipelinePart = provider.provide(config); + pipelinePart.handle(); - pipelinePart.handle(); + verify(itemAttributeRepository, times(1)).deleteAllByLaunchIdAndKeyAndSystem( + eq(config.getEntityContext().getLaunchId()), + eq(RP_CLUSTER_LAST_RUN_KEY), + eq(true) + ); - verify(itemAttributeRepository, times(1)).saveByLaunchId(eq(config.getEntityContext().getLaunchId()), - eq(RP_CLUSTER_LAST_RUN_KEY), - anyString(), - eq(true) - ); - } + verify(itemAttributeRepository, times(1)).saveByLaunchId( + eq(config.getEntityContext().getLaunchId()), + eq(RP_CLUSTER_LAST_RUN_KEY), + anyString(), + eq(true) + ); + } - @Test - void shouldUpdateWhenExists() { - final GenerateClustersConfig config = getConfig(false); - final ItemAttribute itemAttribute = new ItemAttribute(); - when(itemAttributeRepository.findByLaunchIdAndKeyAndSystem(config.getEntityContext().getLaunchId(), - RP_CLUSTER_LAST_RUN_KEY, - true - )).thenReturn(Optional.of(itemAttribute)); + @Test + void shouldNotSaveLastRunWhenForUpdate() { + final GenerateClustersConfig config = getConfig(true); - final PipelinePart pipelinePart = provider.provide(config); + final PipelinePart pipelinePart = provider.provide(config); - pipelinePart.handle(); + pipelinePart.handle(); - verify(itemAttributeRepository, times(1)).save(itemAttribute); - } + verify(itemAttributeRepository, times(0)).deleteAllByLaunchIdAndKeyAndSystem( + eq(config.getEntityContext().getLaunchId()), + eq(RP_CLUSTER_LAST_RUN_KEY), + eq(true) + ); + verify(itemAttributeRepository, times(0)).saveByLaunchId( + eq(config.getEntityContext().getLaunchId()), + eq(RP_CLUSTER_LAST_RUN_KEY), + anyString(), + eq(true) + ); + } -} \ No newline at end of file +} diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProviderTest.java index 22e272327d..4be7ffe95a 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerItemClusterDataProviderTest.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline.data; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyList; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; @@ -29,96 +41,102 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; import com.epam.ta.reportportal.ws.model.project.AnalyzerConfig; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Optional; - -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class AnalyzerItemClusterDataProviderTest { - private final LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); - private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); - - private final AnalyzerItemClusterDataProvider provider = new AnalyzerItemClusterDataProvider(analyzerServiceClient, - getLaunchHandler, - testItemRepository, - launchPreparerService - ); - - @Test - void shouldFailWhenNoAnalyzer() { - when(analyzerServiceClient.hasClients()).thenReturn(false); - - final GenerateClustersConfig config = getConfig(false); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> provider.provide(config)); - assertEquals("Impossible interact with integration. There are no analyzer services are deployed.", exception.getMessage()); - } - - @Test - void shouldReturnDataWhenIndexLaunchExists() { - when(analyzerServiceClient.hasClients()).thenReturn(true); - - final GenerateClustersConfig config = getConfig(false); - addItemIds(config); - - final Launch launch = new Launch(); - when(getLaunchHandler.get(config.getEntityContext().getLaunchId())).thenReturn(launch); - - final List<TestItem> testItems = List.of(new TestItem(), new TestItem()); - when(testItemRepository.findAllById(config.getEntityContext().getItemIds())).thenReturn(testItems); - - when(launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig())).thenReturn(Optional.of(new IndexLaunch())); - when(analyzerServiceClient.generateClusters(any(GenerateClustersRq.class))).thenReturn(new ClusterData()); - final Optional<ClusterData> data = provider.provide(config); - assertTrue(data.isPresent()); - } - - @Test - void shouldNotReturnDataWhenNoItemIds() { - when(analyzerServiceClient.hasClients()).thenReturn(true); - - final GenerateClustersConfig config = getConfig(false); - - final Optional<ClusterData> data = provider.provide(config); - assertTrue(data.isEmpty()); - - verify(getLaunchHandler, times(0)).get(anyLong()); - verify(testItemRepository, times(0)).findAllById(anyList()); - verify(launchPreparerService, times(0)).prepare(any(Launch.class), anyList(), any(AnalyzerConfig.class)); - } - - @Test - void shouldNotReturnDataWhenNoIndexLaunch() { - when(analyzerServiceClient.hasClients()).thenReturn(true); - - final GenerateClustersConfig config = getConfig(false); - addItemIds(config); - - final Launch launch = new Launch(); - when(getLaunchHandler.get(config.getEntityContext().getLaunchId())).thenReturn(launch); - - final List<TestItem> testItems = List.of(new TestItem(), new TestItem()); - when(testItemRepository.findAllById(config.getEntityContext().getItemIds())).thenReturn(testItems); - - when(launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig())).thenReturn(Optional.of(new IndexLaunch())); - - final Optional<ClusterData> data = provider.provide(config); - assertTrue(data.isEmpty()); - } - - private void addItemIds(GenerateClustersConfig config) { - final ClusterEntityContext entityContext = config.getEntityContext(); - config.setEntityContext(ClusterEntityContext.of(entityContext.getLaunchId(), entityContext.getProjectId(), List.of(1L, 2L))); - } + private final LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + private final GetLaunchHandler getLaunchHandler = mock(GetLaunchHandler.class); + private final TestItemRepository testItemRepository = mock(TestItemRepository.class); + private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); + + private final AnalyzerItemClusterDataProvider provider = new AnalyzerItemClusterDataProvider( + analyzerServiceClient, + getLaunchHandler, + testItemRepository, + launchPreparerService + ); + + @Test + void shouldFailWhenNoAnalyzer() { + when(analyzerServiceClient.hasClients()).thenReturn(false); + + final GenerateClustersConfig config = getConfig(false); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> provider.provide(config)); + assertEquals( + "Impossible interact with integration. There are no analyzer services are deployed.", + exception.getMessage()); + } + + @Test + void shouldReturnDataWhenIndexLaunchExists() { + when(analyzerServiceClient.hasClients()).thenReturn(true); + + final GenerateClustersConfig config = getConfig(false); + addItemIds(config); + + final Launch launch = new Launch(); + when(getLaunchHandler.get(config.getEntityContext().getLaunchId())).thenReturn(launch); + + final List<TestItem> testItems = List.of(new TestItem(), new TestItem()); + when(testItemRepository.findAllById(config.getEntityContext().getItemIds())).thenReturn( + testItems); + + when(launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig())).thenReturn( + Optional.of(new IndexLaunch())); + when(analyzerServiceClient.generateClusters(any(GenerateClustersRq.class))).thenReturn( + new ClusterData()); + final Optional<ClusterData> data = provider.provide(config); + assertTrue(data.isPresent()); + } + + @Test + void shouldNotReturnDataWhenNoItemIds() { + when(analyzerServiceClient.hasClients()).thenReturn(true); + + final GenerateClustersConfig config = getConfig(false); + + final Optional<ClusterData> data = provider.provide(config); + assertTrue(data.isEmpty()); + + verify(getLaunchHandler, times(0)).get(anyLong()); + verify(testItemRepository, times(0)).findAllById(anyList()); + verify(launchPreparerService, times(0)).prepare(any(Launch.class), anyList(), + any(AnalyzerConfig.class)); + } + + @Test + void shouldNotReturnDataWhenNoIndexLaunch() { + when(analyzerServiceClient.hasClients()).thenReturn(true); + + final GenerateClustersConfig config = getConfig(false); + addItemIds(config); + + final Launch launch = new Launch(); + when(getLaunchHandler.get(config.getEntityContext().getLaunchId())).thenReturn(launch); + + final List<TestItem> testItems = List.of(new TestItem(), new TestItem()); + when(testItemRepository.findAllById(config.getEntityContext().getItemIds())).thenReturn( + testItems); + + when(launchPreparerService.prepare(launch, testItems, config.getAnalyzerConfig())).thenReturn( + Optional.of(new IndexLaunch())); + + final Optional<ClusterData> data = provider.provide(config); + assertTrue(data.isEmpty()); + } + + private void addItemIds(GenerateClustersConfig config) { + final ClusterEntityContext entityContext = config.getEntityContext(); + config.setEntityContext( + ClusterEntityContext.of(entityContext.getLaunchId(), entityContext.getProjectId(), + List.of(1L, 2L))); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProviderTest.java index 0dd5527263..fd71e278c7 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/AnalyzerLaunchClusterDataProviderTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline.data; +import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.ClusterData; import com.epam.ta.reportportal.core.analyzer.auto.client.model.cluster.GenerateClustersRq; @@ -23,60 +31,59 @@ import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.analyzer.IndexLaunch; -import org.junit.jupiter.api.Test; - import java.util.Optional; - -import static com.epam.ta.reportportal.core.launch.cluster.utils.ConfigProvider.getConfig; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class AnalyzerLaunchClusterDataProviderTest { - private final LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); - private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); - private final AnalyzerLaunchClusterDataProvider provider = new AnalyzerLaunchClusterDataProvider(analyzerServiceClient, - launchPreparerService - ); + private final LaunchPreparerService launchPreparerService = mock(LaunchPreparerService.class); + private final AnalyzerServiceClient analyzerServiceClient = mock(AnalyzerServiceClient.class); + + private final AnalyzerLaunchClusterDataProvider provider = new AnalyzerLaunchClusterDataProvider( + analyzerServiceClient, + launchPreparerService + ); - @Test - void shouldFailWhenNoAnalyzer() { - when(analyzerServiceClient.hasClients()).thenReturn(false); + @Test + void shouldFailWhenNoAnalyzer() { + when(analyzerServiceClient.hasClients()).thenReturn(false); - final GenerateClustersConfig config = getConfig(false); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> provider.provide(config)); - assertEquals("Impossible interact with integration. There are no analyzer services are deployed.", exception.getMessage()); - } + final GenerateClustersConfig config = getConfig(false); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> provider.provide(config)); + assertEquals( + "Impossible interact with integration. There are no analyzer services are deployed.", + exception.getMessage()); + } - @Test - void shouldReturnDataWhenIndexLaunchExists() { - when(analyzerServiceClient.hasClients()).thenReturn(true); + @Test + void shouldReturnDataWhenIndexLaunchExists() { + when(analyzerServiceClient.hasClients()).thenReturn(true); - final GenerateClustersConfig config = getConfig(false); + final GenerateClustersConfig config = getConfig(false); - when(launchPreparerService.prepare(config.getEntityContext().getLaunchId(), - config.getAnalyzerConfig() - )).thenReturn(Optional.of(new IndexLaunch())); - when(analyzerServiceClient.generateClusters(any(GenerateClustersRq.class))).thenReturn(new ClusterData()); - final Optional<ClusterData> data = provider.provide(config); - assertTrue(data.isPresent()); - } + when(launchPreparerService.prepare(config.getEntityContext().getLaunchId(), + config.getAnalyzerConfig() + )).thenReturn(Optional.of(new IndexLaunch())); + when(analyzerServiceClient.generateClusters(any(GenerateClustersRq.class))).thenReturn( + new ClusterData()); + final Optional<ClusterData> data = provider.provide(config); + assertTrue(data.isPresent()); + } - @Test - void shouldNotReturnDataWhenNoIndexLaunch() { - when(analyzerServiceClient.hasClients()).thenReturn(true); + @Test + void shouldNotReturnDataWhenNoIndexLaunch() { + when(analyzerServiceClient.hasClients()).thenReturn(true); - final GenerateClustersConfig config = getConfig(false); + final GenerateClustersConfig config = getConfig(false); - when(launchPreparerService.prepare(config.getEntityContext().getLaunchId(), - config.getAnalyzerConfig() - )).thenReturn(Optional.empty()); - final Optional<ClusterData> data = provider.provide(config); - assertTrue(data.isEmpty()); - } + when(launchPreparerService.prepare(config.getEntityContext().getLaunchId(), + config.getAnalyzerConfig() + )).thenReturn(Optional.empty()); + final Optional<ClusterData> data = provider.provide(config); + assertTrue(data.isEmpty()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolverTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolverTest.java index 64d1b35071..48f46d26ad 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolverTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/ClusterDataProviderResolverTest.java @@ -16,45 +16,45 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver; -import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; -import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; -import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator.ClusterDataProviderEvaluator; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; +import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; +import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator.ClusterDataProviderEvaluator; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; + /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ClusterDataProviderResolverTest { - private final ClusterDataProvider dataProvider = mock(ClusterDataProvider.class); - private final ClusterDataProviderEvaluator evaluator = mock(ClusterDataProviderEvaluator.class); - private final ClusterDataProviderResolver resolver = new ClusterDataProviderResolver(List.of(evaluator)); + private final ClusterDataProvider dataProvider = mock(ClusterDataProvider.class); + private final ClusterDataProviderEvaluator evaluator = mock(ClusterDataProviderEvaluator.class); + private final ClusterDataProviderResolver resolver = new ClusterDataProviderResolver( + List.of(evaluator)); - @Test - void shouldReturnProviderWhenSupports() { - when(evaluator.supports(any(GenerateClustersConfig.class))).thenReturn(true); - when(evaluator.getProvider()).thenReturn(dataProvider); + @Test + void shouldReturnProviderWhenSupports() { + when(evaluator.supports(any(GenerateClustersConfig.class))).thenReturn(true); + when(evaluator.getProvider()).thenReturn(dataProvider); - final Optional<ClusterDataProvider> provider = resolver.resolve(new GenerateClustersConfig()); + final Optional<ClusterDataProvider> provider = resolver.resolve(new GenerateClustersConfig()); - assertTrue(provider.isPresent()); - assertEquals(dataProvider, provider.get()); - } + assertTrue(provider.isPresent()); + assertEquals(dataProvider, provider.get()); + } - @Test - void shouldNotReturnProviderWhenSupports() { - when(evaluator.supports(any(GenerateClustersConfig.class))).thenReturn(false); - final Optional<ClusterDataProvider> provider = resolver.resolve(new GenerateClustersConfig()); - assertTrue(provider.isEmpty()); - } + @Test + void shouldNotReturnProviderWhenSupports() { + when(evaluator.supports(any(GenerateClustersConfig.class))).thenReturn(false); + final Optional<ClusterDataProvider> provider = resolver.resolve(new GenerateClustersConfig()); + assertTrue(provider.isEmpty()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluatorTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluatorTest.java index 8223f18b83..d83c2a4eda 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/pipeline/data/resolver/evaluator/ClusterDataProviderEvaluatorTest.java @@ -16,42 +16,45 @@ package com.epam.ta.reportportal.core.launch.cluster.pipeline.data.resolver.evaluator; -import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; -import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; -import org.junit.jupiter.api.Test; - -import java.util.function.Predicate; - -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.epam.ta.reportportal.core.launch.cluster.config.GenerateClustersConfig; +import com.epam.ta.reportportal.core.launch.cluster.pipeline.data.ClusterDataProvider; +import java.util.function.Predicate; +import org.junit.jupiter.api.Test; + /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ClusterDataProviderEvaluatorTest { - private final Predicate<GenerateClustersConfig> predicate = (Predicate<GenerateClustersConfig>) mock(Predicate.class); - private final ClusterDataProvider clusterDataProvider = mock(ClusterDataProvider.class); - - private final ClusterDataProviderEvaluator evaluator = new ClusterDataProviderEvaluator(predicate, clusterDataProvider); - - @Test - void shouldReturnTrueWhenPredicateIsTrue() { - when(predicate.test(any(GenerateClustersConfig.class))).thenReturn(true); - assertTrue(evaluator.supports(new GenerateClustersConfig())); - } - - @Test - void shouldReturnFalseWhenPredicateIsFalse() { - when(predicate.test(any(GenerateClustersConfig.class))).thenReturn(false); - assertFalse(evaluator.supports(new GenerateClustersConfig())); - } - - @Test - void providerShouldBeEqual() { - assertEquals(clusterDataProvider, evaluator.getProvider()); - } + private final Predicate<GenerateClustersConfig> predicate = (Predicate<GenerateClustersConfig>) mock( + Predicate.class); + private final ClusterDataProvider clusterDataProvider = mock(ClusterDataProvider.class); + + private final ClusterDataProviderEvaluator evaluator = new ClusterDataProviderEvaluator(predicate, + clusterDataProvider); + + @Test + void shouldReturnTrueWhenPredicateIsTrue() { + when(predicate.test(any(GenerateClustersConfig.class))).thenReturn(true); + assertTrue(evaluator.supports(new GenerateClustersConfig())); + } + + @Test + void shouldReturnFalseWhenPredicateIsFalse() { + when(predicate.test(any(GenerateClustersConfig.class))).thenReturn(false); + assertFalse(evaluator.supports(new GenerateClustersConfig())); + } + + @Test + void providerShouldBeEqual() { + assertEquals(clusterDataProvider, evaluator.getProvider()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/utils/ConfigProvider.java b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/utils/ConfigProvider.java index 507f9fbe7e..a0ccd90536 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/cluster/utils/ConfigProvider.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/cluster/utils/ConfigProvider.java @@ -25,19 +25,19 @@ */ public class ConfigProvider { - private ConfigProvider() { + private ConfigProvider() { - } + } - public static final GenerateClustersConfig getConfig(boolean forUpdate) { - final GenerateClustersConfig config = new GenerateClustersConfig(); - final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); - analyzerConfig.setNumberOfLogLines(1); - config.setAnalyzerConfig(analyzerConfig); - final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L); - config.setEntityContext(entityContext); - config.setForUpdate(forUpdate); - config.setCleanNumbers(false); - return config; - } + public static final GenerateClustersConfig getConfig(boolean forUpdate) { + final GenerateClustersConfig config = new GenerateClustersConfig(); + final AnalyzerConfig analyzerConfig = new AnalyzerConfig(); + analyzerConfig.setNumberOfLogLines(1); + config.setAnalyzerConfig(analyzerConfig); + final ClusterEntityContext entityContext = ClusterEntityContext.of(1L, 1L); + config.setEntityContext(entityContext); + config.setForUpdate(forUpdate); + config.setCleanNumbers(false); + return config; + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImplTest.java index f097a089dc..9d0d6c8172 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/DeleteLaunchHandlerImplTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -30,58 +37,57 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class DeleteLaunchHandlerImplTest { - @Mock - private LaunchRepository launchRepository; + @Mock + private LaunchRepository launchRepository; - @Mock - private AttachmentRepository attachmentRepository; + @Mock + private AttachmentRepository attachmentRepository; - @InjectMocks - private DeleteLaunchHandlerImpl handler; + @InjectMocks + private DeleteLaunchHandlerImpl handler; - @Test - void deleteNotOwnLaunch() { - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - rpUser.setUserId(2L); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + @Test + void deleteNotOwnLaunch() { + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + rpUser.setUserId(2L); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("You do not have enough permissions. You are not launch owner.", exception.getMessage()); - } + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("You do not have enough permissions. You are not launch owner.", + exception.getMessage()); + } - @Test - void deleteLaunchFromAnotherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 2L); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + @Test + void deleteLaunchFromAnotherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 2L); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Forbidden operation. Target launch '1' not under specified project '2'", exception.getMessage()); - } + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("Forbidden operation. Target launch '1' not under specified project '2'", + exception.getMessage()); + } - @Test - void deleteLaunchInProgressStatus() { + @Test + void deleteLaunchInProgressStatus() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); - assertThrows(ReportPortalException.class, () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser)); - } + assertThrows(ReportPortalException.class, + () -> handler.deleteLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImplTest.java index 4a3f793c78..7a76a64e33 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerAsyncImplTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; @@ -28,10 +32,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.amqp.core.AmqpTemplate; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - /** * @author Konstantin Antipin */ @@ -39,22 +39,24 @@ @ExtendWith(MockitoExtension.class) class FinishLaunchHandlerAsyncImplTest { - @Mock - AmqpTemplate amqpTemplate; + @Mock + AmqpTemplate amqpTemplate; - @Mock - ReportingQueueService reportingQueueService; + @Mock + ReportingQueueService reportingQueueService; - @InjectMocks - FinishLaunchHandlerAsyncImpl finishLaunchHandlerAsync; + @InjectMocks + FinishLaunchHandlerAsyncImpl finishLaunchHandlerAsync; - @Test - void finishLaunch() { - FinishExecutionRQ request = new FinishExecutionRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void finishLaunch() { + FinishExecutionRQ request = new FinishExecutionRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - finishLaunchHandlerAsync.finishLaunch("0", request, user.getProjectDetails().get("test_project"), user, "http://base"); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + finishLaunchHandlerAsync.finishLaunch("0", request, + user.getProjectDetails().get("test_project"), user, "http://base"); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImplTest.java index 86d7ee3be4..bc93573082 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/FinishLaunchHandlerImplTest.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.hierarchy.FinishHierarchyHandler; @@ -31,25 +42,18 @@ import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.OperationCompletionRS; import com.epam.ta.reportportal.ws.model.launch.FinishLaunchRS; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.context.ApplicationEventPublisher; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -57,147 +61,172 @@ @ExtendWith(MockitoExtension.class) class FinishLaunchHandlerImplTest { - @Mock - private LaunchRepository launchRepository; - - @Mock - private FinishHierarchyHandler<Launch> finishHierarchyHandler; - - @Mock - private TestItemRepository testItemRepository; - - @Mock - private MessageBus messageBus; - - @Mock - private ApplicationEventPublisher publisher; - - @InjectMocks - private FinishLaunchHandlerImpl handler; - - @InjectMocks - private StopLaunchHandlerImpl stopLaunchHandler; - - @Test - void finishLaunch() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - when(launchRepository.findByUuid("1")).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); - - FinishLaunchRS response = handler.finishLaunch("1", finishExecutionRQ, extractProjectDetails(rpUser, "test_project"), rpUser, null); - - verify(finishHierarchyHandler,times(1)).finishDescendants(any(), any(),any(),any(),any()); - - assertNotNull(response); - } - - @Test - void finishLaunchWithLink() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - when(launchRepository.findByUuid("1")).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); - - final FinishLaunchRS finishLaunchRS = handler.finishLaunch("1", - finishExecutionRQ, - extractProjectDetails(rpUser, "test_project"), - rpUser, - "http://example.com" - ); - - verify(finishHierarchyHandler,times(1)).finishDescendants(any(), any(),any(),any(),any()); - - assertNotNull(finishLaunchRS); - assertEquals("http://example.com/ui/#test_project/launches/all/1", finishLaunchRS.getLink()); - } - - @Test - void stopLaunch() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - - ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + @Mock + private LaunchRepository launchRepository; - final OperationCompletionRS response = stopLaunchHandler.stopLaunch(1L, - finishExecutionRQ, - extractProjectDetails(rpUser, "test_project"), - rpUser - ); - assertNotNull(response); - assertEquals("Launch with ID = '1' successfully stopped.", response.getResultMessage()); - } + @Mock + private FinishHierarchyHandler<Launch> finishHierarchyHandler; - @Test - void bulkStopLaunch() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + @Mock + private TestItemRepository testItemRepository; - Map<Long, FinishExecutionRQ> entities = new HashMap<>(); - entities.put(1L, finishExecutionRQ); + @Mock + private MessageBus messageBus; - BulkRQ<Long, FinishExecutionRQ> bulkRq = new BulkRQ<>(); - bulkRq.setEntities(entities); + @Mock + private ApplicationEventPublisher publisher; - ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @InjectMocks + private FinishLaunchHandlerImpl handler; - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + @InjectMocks + private StopLaunchHandlerImpl stopLaunchHandler; - final List<OperationCompletionRS> response = stopLaunchHandler.stopLaunch(bulkRq, - extractProjectDetails(rpUser, "test_project"), - rpUser - ); - assertNotNull(response); - assertEquals(1, response.size()); - } + @Test + void finishLaunch() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - @Test - void finishWithIncorrectStatus() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + when(launchRepository.findByUuid("1")).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); - when(launchRepository.findByUuid("1")).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + FinishLaunchRS response = handler.finishLaunch("1", finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), rpUser, null); - assertThrows(ReportPortalException.class, - () -> handler.finishLaunch("1", finishExecutionRQ, extractProjectDetails(rpUser, "test_project"), rpUser, null) - ); - } + verify(finishHierarchyHandler, times(1)).finishDescendants(any(), any(), any(), any(), any()); - @Test - void finishWithIncorrectEndTime() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().minusHours(5).atZone(ZoneId.of("UTC")).toInstant())); + assertNotNull(response); + } - final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void finishLaunchWithLink() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - when(launchRepository.findByUuid("1")).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - assertThrows(ReportPortalException.class, - () -> handler.finishLaunch("1", finishExecutionRQ, extractProjectDetails(rpUser, "test_project"), rpUser, null) - ); - } + when(launchRepository.findByUuid("1")).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); - @Test - void finishNotOwnLaunch() { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + final FinishLaunchRS finishLaunchRS = handler.finishLaunch("1", + finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), + rpUser, + "http://example.com" + ); - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - rpUser.setUserId(2L); + verify(finishHierarchyHandler, times(1)).finishDescendants(any(), any(), any(), any(), any()); - when(launchRepository.findByUuid("1")).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + assertNotNull(finishLaunchRS); + assertEquals("http://example.com/ui/#test_project/launches/all/1", finishLaunchRS.getLink()); + } - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.finishLaunch("1", finishExecutionRQ, extractProjectDetails(rpUser, "test_project"), rpUser, null) - ); - assertEquals("You do not have enough permissions. You are not launch owner.", exception.getMessage()); - } + @Test + void stopLaunch() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + + final OperationCompletionRS response = stopLaunchHandler.stopLaunch(1L, + finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), + rpUser + ); + assertNotNull(response); + assertEquals("Launch with ID = '1' successfully stopped.", response.getResultMessage()); + } + + @Test + void bulkStopLaunch() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + Map<Long, FinishExecutionRQ> entities = new HashMap<>(); + entities.put(1L, finishExecutionRQ); + + BulkRQ<Long, FinishExecutionRQ> bulkRq = new BulkRQ<>(); + bulkRq.setEntities(entities); + + ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + + final List<OperationCompletionRS> response = stopLaunchHandler.stopLaunch(bulkRq, + extractProjectDetails(rpUser, "test_project"), + rpUser + ); + assertNotNull(response); + assertEquals(1, response.size()); + } + + @Test + void finishWithIncorrectStatus() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + + when(launchRepository.findByUuid("1")).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + + assertThrows(ReportPortalException.class, + () -> handler.finishLaunch("1", finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), rpUser, null) + ); + } + + @Test + void finishWithIncorrectEndTime() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().minusHours(5).atZone(ZoneId.of("UTC")).toInstant())); + + final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + + when(launchRepository.findByUuid("1")).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + + assertThrows(ReportPortalException.class, + () -> handler.finishLaunch("1", finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), rpUser, null) + ); + } + + @Test + void finishNotOwnLaunch() { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + rpUser.setUserId(2L); + + when(launchRepository.findByUuid("1")).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.finishLaunch("1", finishExecutionRQ, + extractProjectDetails(rpUser, "test_project"), rpUser, null) + ); + assertEquals("You do not have enough permissions. You are not launch owner.", + exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImplTest.java index 255265e96f..ecb75b6190 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/GetLaunchHandlerImplTest.java @@ -16,13 +16,26 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; +import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.core.jasper.GetJasperReportHandler; import com.epam.ta.reportportal.core.jasper.util.JasperDataProvider; import com.epam.ta.reportportal.core.launch.cluster.GetClusterHandler; -import com.epam.ta.reportportal.dao.*; +import com.epam.ta.reportportal.dao.ItemAttributeRepository; +import com.epam.ta.reportportal.dao.LaunchRepository; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.dao.UserRepository; +import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.jasper.ReportFormat; @@ -34,6 +47,8 @@ import com.epam.ta.reportportal.ws.converter.converters.LaunchConverter; import com.epam.ta.reportportal.ws.model.Page; import com.epam.ta.reportportal.ws.model.launch.cluster.ClusterInfoResource; +import java.util.List; +import java.util.Optional; import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -43,258 +58,265 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import java.util.List; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.commons.querygen.constant.LaunchCriteriaConstant.CRITERIA_LAUNCH_STATUS; -import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class GetLaunchHandlerImplTest { - @Mock - private GetClusterHandler getClusterHandler; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private ItemAttributeRepository itemAttributeRepository; - - @Mock - private ProjectRepository projectRepository; - - @Mock - private WidgetContentRepository widgetContentRepository; - - @Mock - private UserRepository userRepository; - - @Mock - private JasperDataProvider jasperDataProvider; - - @Mock - private GetJasperReportHandler<Launch> getJasperReportHandler; - - @Mock - private LaunchConverter launchConverter; - - @InjectMocks - private GetLaunchHandlerImpl handler; + @Mock + private GetClusterHandler getClusterHandler; + + @Mock + private LaunchRepository launchRepository; - @Test - void getLaunchFromOtherProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 2L); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunch("1", extractProjectDetails(rpUser, "test_project")) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void getDebugLaunchWithCustomerRole() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEBUG)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunch("1", extractProjectDetails(rpUser, "test_project")) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void getLaunchNamesIncorrectInput() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - assertThrows(ReportPortalException.class, () -> handler.getLaunchNames(extractProjectDetails(rpUser, "test_project"), "")); - assertThrows(ReportPortalException.class, - () -> handler.getLaunchNames(extractProjectDetails(rpUser, "test_project"), RandomStringUtils.random(257)) - ); - } - - @Test - void getNotExistLaunch() { - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - String launchId = "1"; - - when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunch(launchId, extractProjectDetails(user, "test_project")) - ); - assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void getLaunchByNotExistProjectName() { - String projectName = "not_exist"; - - when(projectRepository.findByName(projectName)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunchByProjectName(projectName, PageRequest.of(0, 10), getDefaultFilter(), "user") - ); - assertEquals("Project 'not_exist' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void getLaunchByProjectNameNotFound() { - String projectName = "not_exist"; - - when(projectRepository.findByName(projectName)).thenReturn(Optional.of(new Project())); - when(launchRepository.findByFilter(any(), any())).thenReturn(null); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunchByProjectName(projectName, PageRequest.of(0, 10), getDefaultFilter(), "user") - ); - assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void getLaunchesByNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getProjectLaunches(extractProjectDetails(user, "test_project"), - getDefaultFilter(), - PageRequest.of(0, 10), - "user" - ) - ); - assertEquals("Project '1' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void getLatestLaunchesOnNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLatestLaunches(extractProjectDetails(user, "test_project"), getDefaultFilter(), PageRequest.of(0, 10)) - ); - assertEquals("Project '1' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void getOwnersWrongTerm() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getOwners(extractProjectDetails(user, "test_project"), "qw", LaunchModeEnum.DEFAULT.name()) - ); - assertEquals("Incorrect filtering parameters. Length of the filtering string 'qw' is less than 3 symbols", exception.getMessage()); - } - - @Test - void getOwnersWrongMode() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getOwners(extractProjectDetails(user, "test_project"), "qwe", "incorrectMode") - ); - assertEquals("Incorrect filtering parameters. Mode - incorrectMode doesn't exist.", exception.getMessage()); - } - - @Test - void exportLaunchNotFound() { - long launchId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(launchRepository.findById(launchId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.exportLaunch(launchId, ReportFormat.PDF, null, user) - ); - assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void exportLaunchUserNotFound() { - long launchId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); - - Launch launch = new Launch(); - launch.setStatus(StatusEnum.FAILED); - when(launchRepository.findById(launchId)).thenReturn(Optional.of(launch)); - when(userRepository.findById(1L)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.exportLaunch(launchId, ReportFormat.PDF, null, user) - ); - assertEquals("User '1' not found.", exception.getMessage()); - } - - @Test - void getLaunchInDebugModeByCustomer() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.CUSTOMER, projectId); - String launchId = "1"; - - Launch launch = new Launch(); - launch.setProjectId(projectId); - launch.setMode(LaunchModeEnum.DEBUG); - when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.of(launch)); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getLaunch(launchId, extractProjectDetails(user, "test_project")) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void getClusterInfo() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); - String launchId = "1"; - - Launch launch = new Launch(); - launch.setProjectId(projectId); - launch.setMode(LaunchModeEnum.DEBUG); - when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.of(launch)); - - final Pageable pageable = PageRequest.of(1, 2); - - final Page<ClusterInfoResource> expected = new Page<>(List.of(new ClusterInfoResource(), new ClusterInfoResource()), 2, 1, 10); - - when(getClusterHandler.getResources(launch, pageable)).thenReturn(expected); - - final Iterable<ClusterInfoResource> result = handler.getClusters(launchId, extractProjectDetails(user, "test_project"), pageable); - - final Page<ClusterInfoResource> castedResult = (Page<ClusterInfoResource>) result; - - assertEquals(expected.getPage().getNumber(), castedResult.getPage().getNumber()); - assertEquals(expected.getPage().getSize(), castedResult.getPage().getSize()); - assertEquals(expected.getPage().getTotalElements(), castedResult.getPage().getTotalElements()); - - assertEquals(10, castedResult.getPage().getTotalElements()); - assertEquals(1, castedResult.getPage().getNumber()); - assertEquals(2, castedResult.getPage().getSize()); - - assertEquals(2, castedResult.getContent().size()); - } - - private Filter getDefaultFilter() { - return Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_STATUS, "PASSED").build()) - .build(); - } + @Mock + private ItemAttributeRepository itemAttributeRepository; + + @Mock + private ProjectRepository projectRepository; + + @Mock + private WidgetContentRepository widgetContentRepository; + + @Mock + private UserRepository userRepository; + + @Mock + private JasperDataProvider jasperDataProvider; + + @Mock + private GetJasperReportHandler<Launch> getJasperReportHandler; + + @Mock + private LaunchConverter launchConverter; + + @InjectMocks + private GetLaunchHandlerImpl handler; + + @Test + void getLaunchFromOtherProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 2L); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.FAILED, LaunchModeEnum.DEFAULT)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunch("1", extractProjectDetails(rpUser, "test_project")) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void getDebugLaunchWithCustomerRole() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEBUG)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunch("1", extractProjectDetails(rpUser, "test_project")) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void getLaunchNamesIncorrectInput() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + assertThrows(ReportPortalException.class, + () -> handler.getLaunchNames(extractProjectDetails(rpUser, "test_project"), + RandomStringUtils.random(257)) + ); + } + + @Test + void getNotExistLaunch() { + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + String launchId = "1"; + + when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunch(launchId, extractProjectDetails(user, "test_project")) + ); + assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void getLaunchByNotExistProjectName() { + String projectName = "not_exist"; + + when(projectRepository.findByName(projectName)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunchByProjectName(projectName, PageRequest.of(0, 10), getDefaultFilter(), + "user") + ); + assertEquals("Project 'not_exist' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void getLaunchByProjectNameNotFound() { + String projectName = "not_exist"; + + when(projectRepository.findByName(projectName)).thenReturn(Optional.of(new Project())); + when(launchRepository.findByFilter(any(), any())).thenReturn(null); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunchByProjectName(projectName, PageRequest.of(0, 10), getDefaultFilter(), + "user") + ); + assertEquals("Launch '' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void getLaunchesByNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getProjectLaunches(extractProjectDetails(user, "test_project"), + getDefaultFilter(), + PageRequest.of(0, 10), + "user" + ) + ); + assertEquals("Project '1' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void getLatestLaunchesOnNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLatestLaunches(extractProjectDetails(user, "test_project"), + getDefaultFilter(), PageRequest.of(0, 10)) + ); + assertEquals("Project '1' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void getOwnersWrongTerm() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getOwners(extractProjectDetails(user, "test_project"), "qw", + LaunchModeEnum.DEFAULT.name()) + ); + assertEquals( + "Incorrect filtering parameters. Length of the filtering string 'qw' is less than 3 symbols", + exception.getMessage()); + } + + @Test + void getOwnersWrongMode() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getOwners(extractProjectDetails(user, "test_project"), "qwe", "incorrectMode") + ); + assertEquals("Incorrect filtering parameters. Mode - incorrectMode doesn't exist.", + exception.getMessage()); + } + + @Test + void exportLaunchNotFound() { + long launchId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(launchRepository.findById(launchId)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.exportLaunch(launchId, ReportFormat.PDF, null, user) + ); + assertEquals("Launch '1' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void exportLaunchUserNotFound() { + long launchId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, 1L); + + Launch launch = new Launch(); + launch.setStatus(StatusEnum.FAILED); + when(launchRepository.findById(launchId)).thenReturn(Optional.of(launch)); + when(userRepository.findById(1L)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.exportLaunch(launchId, ReportFormat.PDF, null, user) + ); + assertEquals("User '1' not found.", exception.getMessage()); + } + + @Test + void getLaunchInDebugModeByCustomer() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.CUSTOMER, projectId); + String launchId = "1"; + + Launch launch = new Launch(); + launch.setProjectId(projectId); + launch.setMode(LaunchModeEnum.DEBUG); + when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.of(launch)); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getLaunch(launchId, extractProjectDetails(user, "test_project")) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void getClusterInfo() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); + String launchId = "1"; + + Launch launch = new Launch(); + launch.setProjectId(projectId); + launch.setMode(LaunchModeEnum.DEBUG); + when(launchRepository.findById(Long.parseLong(launchId))).thenReturn(Optional.of(launch)); + + final Pageable pageable = PageRequest.of(1, 2); + + final Page<ClusterInfoResource> expected = new Page<>( + List.of(new ClusterInfoResource(), new ClusterInfoResource()), 2, 1, 10); + + when(getClusterHandler.getResources(launch, pageable)).thenReturn(expected); + + final Iterable<ClusterInfoResource> result = handler.getClusters(launchId, + extractProjectDetails(user, "test_project"), pageable); + + final Page<ClusterInfoResource> castedResult = (Page<ClusterInfoResource>) result; + + assertEquals(expected.getPage().getNumber(), castedResult.getPage().getNumber()); + assertEquals(expected.getPage().getSize(), castedResult.getPage().getSize()); + assertEquals(expected.getPage().getTotalElements(), castedResult.getPage().getTotalElements()); + + assertEquals(10, castedResult.getPage().getTotalElements()); + assertEquals(1, castedResult.getPage().getNumber()); + assertEquals(2, castedResult.getPage().getSize()); + + assertEquals(2, castedResult.getContent().size()); + } + + private Filter getDefaultFilter() { + return Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq(CRITERIA_LAUNCH_STATUS, "PASSED").build()) + .build(); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/LaunchTestUtil.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/LaunchTestUtil.java index 47102da1c1..cb4fe5a08d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/LaunchTestUtil.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/LaunchTestUtil.java @@ -20,7 +20,6 @@ import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.user.User; - import java.time.LocalDateTime; import java.util.Optional; @@ -29,25 +28,25 @@ */ public class LaunchTestUtil { - private LaunchTestUtil() { - //static only - } + private LaunchTestUtil() { + //static only + } - public static Optional<Launch> getLaunch(StatusEnum status, LaunchModeEnum mode) { - Launch launch = new Launch(); - launch.setId(1L); - launch.setNumber(1L); - launch.setProjectId(1L); - launch.setStatus(status); - launch.setStartTime(LocalDateTime.now().minusHours(3)); - User user = new User(); - user.setId(1L); - user.setLogin("owner"); - launch.setUserId(user.getId()); - launch.setMode(mode); - launch.setUuid("uuid"); - launch.setDescription("description"); - launch.setName("launch name"); - return Optional.of(launch); - } + public static Optional<Launch> getLaunch(StatusEnum status, LaunchModeEnum mode) { + Launch launch = new Launch(); + launch.setId(1L); + launch.setNumber(1L); + launch.setProjectId(1L); + launch.setStatus(status); + launch.setStartTime(LocalDateTime.now().minusHours(3)); + User user = new User(); + user.setId(1L); + user.setLogin("owner"); + launch.setUserId(user.getId()); + launch.setMode(mode); + launch.setUuid("uuid"); + launch.setDescription("description"); + launch.setName("launch name"); + return Optional.of(launch); + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImplTest.java index 2a053b10a8..ca463f709d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerAsyncImplTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; @@ -28,10 +32,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.amqp.core.AmqpTemplate; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; - /** * @author Konstantin Antipin */ @@ -39,22 +39,24 @@ @ExtendWith(MockitoExtension.class) class StartLaunchHandlerAsyncImplTest { - @Mock - AmqpTemplate amqpTemplate; + @Mock + AmqpTemplate amqpTemplate; - @Mock - ReportingQueueService reportingQueueService; + @Mock + ReportingQueueService reportingQueueService; - @InjectMocks - StartLaunchHandlerAsyncImpl startLaunchHandlerAsync; + @InjectMocks + StartLaunchHandlerAsyncImpl startLaunchHandlerAsync; - @Test - void starLaunch() { - StartLaunchRQ request = new StartLaunchRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void starLaunch() { + StartLaunchRQ request = new StartLaunchRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - startLaunchHandlerAsync.startLaunch(user, user.getProjectDetails().get("test_project"), request); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + startLaunchHandlerAsync.startLaunch(user, user.getProjectDetails().get("test_project"), + request); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImplTest.java index 95caae5bc4..8d074cf6cb 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/StartLaunchHandlerImplTest.java @@ -16,6 +16,16 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.events.MessageBus; import com.epam.ta.reportportal.core.launch.rerun.RerunHandler; @@ -28,6 +38,7 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRS; +import java.util.Date; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -35,75 +46,70 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.ApplicationEventPublisher; -import java.util.Date; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class StartLaunchHandlerImplTest { - @Mock - private UserRepository userRepository; + @Mock + private UserRepository userRepository; - @Mock - private LaunchRepository launchRepository; + @Mock + private LaunchRepository launchRepository; - @Mock - private MessageBus messageBus; + @Mock + private MessageBus messageBus; - @Mock - private RerunHandler rerunHandler; + @Mock + private RerunHandler rerunHandler; - @Mock - private ApplicationEventPublisher eventPublisher; + @Mock + private ApplicationEventPublisher eventPublisher; - @InjectMocks - private StartLaunchHandlerImpl startLaunchHandlerImpl; + @InjectMocks + private StartLaunchHandlerImpl startLaunchHandlerImpl; - @Test - void startLaunch() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void startLaunch() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setStartTime(new Date()); - startLaunchRQ.setName("test"); + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + startLaunchRQ.setStartTime(new Date()); + startLaunchRQ.setName("test"); - Launch launch = new Launch(); - launch.setId(1L); + Launch launch = new Launch(); + launch.setId(1L); - when(launchRepository.save(any(Launch.class))).then(a -> { - Launch l = a.getArgument(0); - l.setId(1L); - return l; - }).thenReturn(launch); + when(launchRepository.save(any(Launch.class))).then(a -> { + Launch l = a.getArgument(0); + l.setId(1L); + return l; + }).thenReturn(launch); - final StartLaunchRS startLaunchRS = startLaunchHandlerImpl.startLaunch(rpUser, - extractProjectDetails(rpUser, "test_project"), - startLaunchRQ - ); + final StartLaunchRS startLaunchRS = startLaunchHandlerImpl.startLaunch(rpUser, + extractProjectDetails(rpUser, "test_project"), + startLaunchRQ + ); - verify(launchRepository, times(1)).refresh(any(Launch.class)); - verify(eventPublisher, times(1)).publishEvent(any()); - assertNotNull(startLaunchRS); - } + verify(launchRepository, times(1)).refresh(any(Launch.class)); + verify(eventPublisher, times(1)).publishEvent(any()); + assertNotNull(startLaunchRS); + } - @Test - void accessDeniedForCustomerRoleAndDebugMode() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); + @Test + void accessDeniedForCustomerRoleAndDebugMode() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setStartTime(new Date()); - startLaunchRQ.setMode(Mode.DEBUG); + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + startLaunchRQ.setStartTime(new Date()); + startLaunchRQ.setMode(Mode.DEBUG); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> startLaunchHandlerImpl.startLaunch(rpUser, extractProjectDetails(rpUser, "test_project"), startLaunchRQ) - ); - assertEquals("Forbidden operation.", exception.getMessage()); - } + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> startLaunchHandlerImpl.startLaunch(rpUser, + extractProjectDetails(rpUser, "test_project"), startLaunchRQ) + ); + assertEquals("Forbidden operation.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImplTest.java index 39c06f0ccf..e6ee281289 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/impl/UpdateLaunchHandlerImplTest.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.core.launch.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.impl.LaunchAccessValidator; import com.epam.ta.reportportal.core.launch.GetLaunchHandler; @@ -35,6 +47,7 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.UpdateLaunchRQ; import com.epam.ta.reportportal.ws.model.launch.cluster.CreateClustersRQ; +import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -42,120 +55,124 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Map; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.core.launch.impl.LaunchTestUtil.getLaunch; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class UpdateLaunchHandlerImplTest { - @Mock - private LaunchAccessValidator launchAccessValidator; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private GetProjectHandler getProjectHandler; - - @Mock - private GetLaunchHandler getLaunchHandler; - - @Mock - private TestItemRepository testItemRepository; - - @Mock - private UniqueErrorAnalysisStarter starter; - - @InjectMocks - private UpdateLaunchHandlerImpl handler; - - @Test - void updateNotOwnLaunch() { - final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); - rpUser.setUserId(2L); - when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(new Project()); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser, new UpdateLaunchRQ()) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void updateDebugLaunchByCustomer() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); - - when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn(new Project()); - when(launchRepository.findById(1L)).thenReturn(getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); - final UpdateLaunchRQ updateLaunchRQ = new UpdateLaunchRQ(); - updateLaunchRQ.setMode(Mode.DEBUG); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser, updateLaunchRQ) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void createClustersLaunchInProgress() { - - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); - - when(getLaunchHandler.get(1L)).thenReturn(getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT).get()); - final CreateClustersRQ createClustersRQ = new CreateClustersRQ(); - createClustersRQ.setLaunchId(1L); - createClustersRQ.setRemoveNumbers(false); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createClusters(createClustersRQ, extractProjectDetails(rpUser, "test_project"), rpUser) - ); - assertEquals("Incorrect Request. Cannot analyze launch in progress.", exception.getMessage()); - verify(launchAccessValidator, times(1)).validate(any(Launch.class), any(ReportPortalUser.ProjectDetails.class), eq(rpUser)); - } - - @Test - void createClusters() { - - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); - - final Project project = new Project(); - project.setId(1L); - - final Launch launch = getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT).get(); - when(getLaunchHandler.get(1L)).thenReturn(launch); - when(getProjectHandler.get(launch.getProjectId())).thenReturn(project); - - final CreateClustersRQ createClustersRQ = new CreateClustersRQ(); - createClustersRQ.setLaunchId(1L); - final boolean defaultRemoveNumbers = Boolean.parseBoolean(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getDefaultValue()); - createClustersRQ.setRemoveNumbers(!defaultRemoveNumbers); - - handler.createClusters(createClustersRQ, extractProjectDetails(rpUser, "test_project"), rpUser); - - verify(launchAccessValidator, times(1)).validate(any(Launch.class), any(ReportPortalUser.ProjectDetails.class), eq(rpUser)); - - final ArgumentCaptor<ClusterEntityContext> contextCaptor = ArgumentCaptor.forClass(ClusterEntityContext.class); - final ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(Map.class); - verify(starter, times(1)).start(contextCaptor.capture(), mapCaptor.capture()); - - final ClusterEntityContext entityContext = contextCaptor.getValue(); - - assertEquals(1L, entityContext.getProjectId().longValue()); - assertEquals(1L, entityContext.getLaunchId().longValue()); - - final Map<String, String> providedConfig = mapCaptor.getValue(); + @Mock + private LaunchAccessValidator launchAccessValidator; + + @Mock + private LaunchRepository launchRepository; + + @Mock + private GetProjectHandler getProjectHandler; - final boolean providedRemoveNumbers = Boolean.parseBoolean(providedConfig.get(ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute())); - assertNotEquals(providedRemoveNumbers, defaultRemoveNumbers); - assertEquals(createClustersRQ.isRemoveNumbers(), providedRemoveNumbers); - } + @Mock + private GetLaunchHandler getLaunchHandler; + + @Mock + private TestItemRepository testItemRepository; + + @Mock + private UniqueErrorAnalysisStarter starter; + + @InjectMocks + private UpdateLaunchHandlerImpl handler; + + @Test + void updateNotOwnLaunch() { + final ReportPortalUser rpUser = getRpUser("not owner", UserRole.USER, ProjectRole.MEMBER, 1L); + rpUser.setUserId(2L); + when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn( + new Project()); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser, + new UpdateLaunchRQ()) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void updateDebugLaunchByCustomer() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); + + when(getProjectHandler.get(any(ReportPortalUser.ProjectDetails.class))).thenReturn( + new Project()); + when(launchRepository.findById(1L)).thenReturn( + getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT)); + final UpdateLaunchRQ updateLaunchRQ = new UpdateLaunchRQ(); + updateLaunchRQ.setMode(Mode.DEBUG); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateLaunch(1L, extractProjectDetails(rpUser, "test_project"), rpUser, + updateLaunchRQ) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void createClustersLaunchInProgress() { + + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); + + when(getLaunchHandler.get(1L)).thenReturn( + getLaunch(StatusEnum.IN_PROGRESS, LaunchModeEnum.DEFAULT).get()); + final CreateClustersRQ createClustersRQ = new CreateClustersRQ(); + createClustersRQ.setLaunchId(1L); + createClustersRQ.setRemoveNumbers(false); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createClusters(createClustersRQ, + extractProjectDetails(rpUser, "test_project"), rpUser) + ); + assertEquals("Incorrect Request. Cannot analyze launch in progress.", exception.getMessage()); + verify(launchAccessValidator, times(1)).validate(any(Launch.class), + any(ReportPortalUser.ProjectDetails.class), eq(rpUser)); + } + + @Test + void createClusters() { + + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.CUSTOMER, 1L); + + final Project project = new Project(); + project.setId(1L); + + final Launch launch = getLaunch(StatusEnum.PASSED, LaunchModeEnum.DEFAULT).get(); + when(getLaunchHandler.get(1L)).thenReturn(launch); + when(getProjectHandler.get(launch.getProjectId())).thenReturn(project); + + final CreateClustersRQ createClustersRQ = new CreateClustersRQ(); + createClustersRQ.setLaunchId(1L); + final boolean defaultRemoveNumbers = Boolean.parseBoolean( + ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getDefaultValue()); + createClustersRQ.setRemoveNumbers(!defaultRemoveNumbers); + + handler.createClusters(createClustersRQ, extractProjectDetails(rpUser, "test_project"), rpUser); + + verify(launchAccessValidator, times(1)).validate(any(Launch.class), + any(ReportPortalUser.ProjectDetails.class), eq(rpUser)); + + final ArgumentCaptor<ClusterEntityContext> contextCaptor = ArgumentCaptor.forClass( + ClusterEntityContext.class); + final ArgumentCaptor<Map<String, String>> mapCaptor = ArgumentCaptor.forClass(Map.class); + verify(starter, times(1)).start(contextCaptor.capture(), mapCaptor.capture()); + + final ClusterEntityContext entityContext = contextCaptor.getValue(); + + assertEquals(1L, entityContext.getProjectId().longValue()); + assertEquals(1L, entityContext.getLaunchId().longValue()); + + final Map<String, String> providedConfig = mapCaptor.getValue(); + + final boolean providedRemoveNumbers = Boolean.parseBoolean(providedConfig.get( + ProjectAttributeEnum.UNIQUE_ERROR_ANALYZER_REMOVE_NUMBERS.getAttribute())); + assertNotEquals(providedRemoveNumbers, defaultRemoveNumbers); + assertEquals(createClustersRQ.isRemoveNumbers(), providedRemoveNumbers); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImplTest.java index 4d21f94642..3baeffaca3 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/rerun/RerunHandlerImplTest.java @@ -16,6 +16,17 @@ package com.epam.ta.reportportal.core.launch.rerun; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.item.identity.TestCaseHashGenerator; @@ -39,6 +50,8 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -48,209 +61,211 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.util.Pair; -import java.util.ArrayList; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class RerunHandlerImplTest { - @Spy - private ArrayList<ParentItemValidator> parentItemValidators; - - @Mock - private TestItemRepository testItemRepository; - - @Mock - private LaunchRepository launchRepository; - - @Mock - private UniqueIdGenerator uniqueIdGenerator; - - @Mock - private TestCaseHashGenerator testCaseHashGenerator; - - @Mock - private ApplicationEventPublisher eventPublisher; - - @Mock - private RerunSearcher rerunSearcher; - - @Mock - private RetryHandler retryHandler; - - @InjectMocks - private RerunHandlerImpl rerunHandler; - - @Test - void exceptionWhenLaunchIsNotStoredInDbByName() { - StartLaunchRQ request = new StartLaunchRQ(); - String launchName = "launch"; - long projectId = 1L; - request.setRerun(true); - request.setName(launchName); - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(launchRepository.findLatestByNameAndProjectId(launchName, projectId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> rerunHandler.handleLaunch(request, projectId, rpUser) - ); - assertEquals("Launch 'launch' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void exceptionWhenLaunchIsNotStoredInDbByUuid() { - StartLaunchRQ request = new StartLaunchRQ(); - String launchName = "launch"; - String uuid = "uuid"; - long projectId = 1L; - request.setRerun(true); - request.setRerunOf(uuid); - request.setName(launchName); - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(launchRepository.findByUuid(uuid)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> rerunHandler.handleLaunch(request, projectId, rpUser) - ); - assertEquals("Launch 'uuid' not found. Did you use correct Launch ID?", exception.getMessage()); - } - - @Test - void happyRerunLaunch() { - StartLaunchRQ request = new StartLaunchRQ(); - String launchName = "launch"; - long projectId = 1L; - request.setRerun(true); - request.setName(launchName); - request.setMode(Mode.DEFAULT); - request.setDescription("desc"); - request.setAttributes(Sets.newHashSet(new ItemAttributesRQ("test", "test"))); - ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(launchRepository.findLatestByNameAndProjectId("launch", projectId)).thenReturn(Optional.of(getLaunch("uuid"))); - - final Launch launch = rerunHandler.handleLaunch(request, projectId, rpUser); - - assertNotNull(launch.getNumber()); - assertNotNull(launch.getId()); - - } - - @Test - void returnEmptyOptionalWhenRootItemNotFound() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setLaunchUuid("launch_uuid"); - request.setType("STEP"); - String itemName = "name"; - request.setName(itemName); - final String testCaseId = "caseId"; - request.setTestCaseId(testCaseId); - Launch launch = getLaunch("uuid"); - - when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.empty()); - - Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleRootItem(request, launch); - - assertFalse(rerunCreatedRS.isPresent()); - } - - @Test - void happyRerunRootItem() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setLaunchUuid("launch_uuid"); - request.setType("STEP"); - String itemName = "name"; - request.setName(itemName); - final String testCaseId = "caseId"; - request.setTestCaseId(testCaseId); - Launch launch = getLaunch("uuid"); - - final TestItem item = getItem(itemName, launch); - when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.of(item.getItemId())); - when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); - - Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleRootItem(request, launch); - - assertTrue(rerunCreatedRS.isPresent()); - } - - @Test - void returnEmptyOptionalWhenChildItemNotFound() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setLaunchUuid("launch_uuid"); - request.setType("STEP"); - String itemName = "name"; - request.setName(itemName); - final String testCaseId = "caseId"; - request.setTestCaseId(testCaseId); - Launch launch = getLaunch("uuid"); - TestItem parent = new TestItem(); - parent.setItemId(2L); - parent.setPath("1.2"); - - when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.empty()); - when(testItemRepository.selectPath("uuid")).thenReturn(Optional.of(Pair.of(parent.getItemId(), parent.getPath()))); - - Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleChildItem(request, launch, "uuid"); - - assertFalse(rerunCreatedRS.isPresent()); - } - - @Test - void happyRerunChildItem() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setLaunchUuid("launch_uuid"); - request.setType("STEP"); - String itemName = "name"; - request.setName(itemName); - final String testCaseId = "caseId"; - request.setTestCaseId(testCaseId); - Launch launch = getLaunch("uuid"); - TestItem parent = new TestItem(); - parent.setItemId(2L); - parent.setPath("1.2"); - - final TestItem item = getItem(itemName, launch); - when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.of(item.getItemId())); - when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); - when(testItemRepository.selectPath("uuid")).thenReturn(Optional.of(Pair.of(parent.getItemId(), parent.getPath()))); - when(testItemRepository.findIdByUuidForUpdate("uuid")).thenReturn(Optional.of(parent.getItemId())); - when(testItemRepository.getOne(parent.getItemId())).thenReturn(parent); - - Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleChildItem(request, launch, "uuid"); - - verify(retryHandler, times(1)).handleRetries(any(), any(), any()); - - assertTrue(rerunCreatedRS.isPresent()); - } - - private TestItem getItem(String name, Launch launch) { - TestItem item = new TestItem(); - item.setItemId(1L); - item.setName(name); - item.setLaunchId(launch.getId()); - item.setDescription("desc"); - item.setType(TestItemTypeEnum.STEP); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.PASSED); - item.setItemResults(itemResults); - return item; - } - - private Launch getLaunch(String uuid) { - Launch launch = new Launch(); - launch.setUuid(uuid); - launch.setNumber(1L); - launch.setId(1L); - return launch; - } + @Spy + private ArrayList<ParentItemValidator> parentItemValidators; + + @Mock + private TestItemRepository testItemRepository; + + @Mock + private LaunchRepository launchRepository; + + @Mock + private UniqueIdGenerator uniqueIdGenerator; + + @Mock + private TestCaseHashGenerator testCaseHashGenerator; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @Mock + private RerunSearcher rerunSearcher; + + @Mock + private RetryHandler retryHandler; + + @InjectMocks + private RerunHandlerImpl rerunHandler; + + @Test + void exceptionWhenLaunchIsNotStoredInDbByName() { + StartLaunchRQ request = new StartLaunchRQ(); + String launchName = "launch"; + long projectId = 1L; + request.setRerun(true); + request.setName(launchName); + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(launchRepository.findLatestByNameAndProjectId(launchName, projectId)).thenReturn( + Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> rerunHandler.handleLaunch(request, projectId, rpUser) + ); + assertEquals("Launch 'launch' not found. Did you use correct Launch ID?", + exception.getMessage()); + } + + @Test + void exceptionWhenLaunchIsNotStoredInDbByUuid() { + StartLaunchRQ request = new StartLaunchRQ(); + String launchName = "launch"; + String uuid = "uuid"; + long projectId = 1L; + request.setRerun(true); + request.setRerunOf(uuid); + request.setName(launchName); + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(launchRepository.findByUuid(uuid)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> rerunHandler.handleLaunch(request, projectId, rpUser) + ); + assertEquals("Launch 'uuid' not found. Did you use correct Launch ID?", exception.getMessage()); + } + + @Test + void happyRerunLaunch() { + StartLaunchRQ request = new StartLaunchRQ(); + String launchName = "launch"; + long projectId = 1L; + request.setRerun(true); + request.setName(launchName); + request.setMode(Mode.DEFAULT); + request.setDescription("desc"); + request.setAttributes(Sets.newHashSet(new ItemAttributesRQ("test", "test"))); + ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(launchRepository.findLatestByNameAndProjectId("launch", projectId)).thenReturn( + Optional.of(getLaunch("uuid"))); + + final Launch launch = rerunHandler.handleLaunch(request, projectId, rpUser); + + assertNotNull(launch.getNumber()); + assertNotNull(launch.getId()); + + } + + @Test + void returnEmptyOptionalWhenRootItemNotFound() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setLaunchUuid("launch_uuid"); + request.setType("STEP"); + String itemName = "name"; + request.setName(itemName); + final String testCaseId = "caseId"; + request.setTestCaseId(testCaseId); + Launch launch = getLaunch("uuid"); + + when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.empty()); + + Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleRootItem(request, launch); + + assertFalse(rerunCreatedRS.isPresent()); + } + + @Test + void happyRerunRootItem() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setLaunchUuid("launch_uuid"); + request.setType("STEP"); + String itemName = "name"; + request.setName(itemName); + final String testCaseId = "caseId"; + request.setTestCaseId(testCaseId); + Launch launch = getLaunch("uuid"); + + final TestItem item = getItem(itemName, launch); + when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.of(item.getItemId())); + when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); + + Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleRootItem(request, launch); + + assertTrue(rerunCreatedRS.isPresent()); + } + + @Test + void returnEmptyOptionalWhenChildItemNotFound() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setLaunchUuid("launch_uuid"); + request.setType("STEP"); + String itemName = "name"; + request.setName(itemName); + final String testCaseId = "caseId"; + request.setTestCaseId(testCaseId); + Launch launch = getLaunch("uuid"); + TestItem parent = new TestItem(); + parent.setItemId(2L); + parent.setPath("1.2"); + + when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.empty()); + when(testItemRepository.selectPath("uuid")).thenReturn( + Optional.of(Pair.of(parent.getItemId(), parent.getPath()))); + + Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleChildItem(request, launch, "uuid"); + + assertFalse(rerunCreatedRS.isPresent()); + } + + @Test + void happyRerunChildItem() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setLaunchUuid("launch_uuid"); + request.setType("STEP"); + String itemName = "name"; + request.setName(itemName); + final String testCaseId = "caseId"; + request.setTestCaseId(testCaseId); + Launch launch = getLaunch("uuid"); + TestItem parent = new TestItem(); + parent.setItemId(2L); + parent.setPath("1.2"); + + final TestItem item = getItem(itemName, launch); + when(rerunSearcher.findItem(any(Queryable.class))).thenReturn(Optional.of(item.getItemId())); + when(testItemRepository.findById(item.getItemId())).thenReturn(Optional.of(item)); + when(testItemRepository.selectPath("uuid")).thenReturn( + Optional.of(Pair.of(parent.getItemId(), parent.getPath()))); + when(testItemRepository.findIdByUuidForUpdate("uuid")).thenReturn( + Optional.of(parent.getItemId())); + when(testItemRepository.getOne(parent.getItemId())).thenReturn(parent); + + Optional<ItemCreatedRS> rerunCreatedRS = rerunHandler.handleChildItem(request, launch, "uuid"); + + verify(retryHandler, times(1)).handleRetries(any(), any(), any()); + + assertTrue(rerunCreatedRS.isPresent()); + } + + private TestItem getItem(String name, Launch launch) { + TestItem item = new TestItem(); + item.setItemId(1L); + item.setName(name); + item.setLaunchId(launch.getId()); + item.setDescription("desc"); + item.setType(TestItemTypeEnum.STEP); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.PASSED); + item.setItemResults(itemResults); + return item; + } + + private Launch getLaunch(String uuid) { + Launch launch = new Launch(); + launch.setUuid(uuid); + launch.setNumber(1L); + launch.setId(1L); + return launch; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/launch/util/LaunchValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/launch/util/LaunchValidatorTest.java index e0934c711a..02ad7ed9e3 100644 --- a/src/test/java/com/epam/ta/reportportal/core/launch/util/LaunchValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/launch/util/LaunchValidatorTest.java @@ -16,46 +16,47 @@ package com.epam.ta.reportportal.core.launch.util; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; +import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.commons.validation.Suppliers; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; -import org.junit.jupiter.api.Test; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; -import static com.epam.ta.reportportal.commons.EntityUtils.TO_LOCAL_DATE_TIME; -import static com.epam.ta.reportportal.ws.model.ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class LaunchValidatorTest { - @Test - void validate() { - Launch launch = new Launch(); - launch.setStatus(StatusEnum.IN_PROGRESS); - launch.setStartTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(1575551458336L), ZoneOffset.UTC)); - - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(TO_DATE.apply(LocalDateTime.ofInstant(Instant.ofEpochMilli(1575551458334L), ZoneOffset.UTC))); - - ReportPortalException reportPortalException = assertThrows(ReportPortalException.class, - () -> LaunchValidator.validate(launch, finishExecutionRQ) - ); - - assertEquals(Suppliers.formattedSupplier(FINISH_TIME_EARLIER_THAN_START_TIME.getDescription(), - TO_LOCAL_DATE_TIME.apply(finishExecutionRQ.getEndTime()), - launch.getStartTime(), - launch.getId() - ).get(), reportPortalException.getMessage()); - } + @Test + void validate() { + Launch launch = new Launch(); + launch.setStatus(StatusEnum.IN_PROGRESS); + launch.setStartTime( + LocalDateTime.ofInstant(Instant.ofEpochMilli(1575551458336L), ZoneOffset.UTC)); + + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime(TO_DATE.apply( + LocalDateTime.ofInstant(Instant.ofEpochMilli(1575551458334L), ZoneOffset.UTC))); + + ReportPortalException reportPortalException = assertThrows(ReportPortalException.class, + () -> LaunchValidator.validate(launch, finishExecutionRQ) + ); + + assertEquals(Suppliers.formattedSupplier(FINISH_TIME_EARLIER_THAN_START_TIME.getDescription(), + TO_LOCAL_DATE_TIME.apply(finishExecutionRQ.getEndTime()), + launch.getStartTime(), + launch.getId() + ).get(), reportPortalException.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/log/ElasticLogServiceTest.java b/src/test/java/com/epam/ta/reportportal/core/log/ElasticLogServiceTest.java new file mode 100644 index 0000000000..ea6bc7cbaf --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/log/ElasticLogServiceTest.java @@ -0,0 +1,62 @@ +package com.epam.ta.reportportal.core.log; + +import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.LOG_MESSAGE_SAVING_ROUTING_KEY; +import static com.epam.ta.reportportal.core.configs.rabbit.BackgroundProcessingConfiguration.PROCESSING_EXCHANGE_NAME; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.epam.ta.reportportal.entity.item.TestItem; +import com.epam.ta.reportportal.entity.launch.Launch; +import com.epam.ta.reportportal.entity.log.LogFull; +import com.epam.ta.reportportal.entity.log.LogMessage; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.amqp.core.AmqpTemplate; + +@ExtendWith(MockitoExtension.class) +class ElasticLogServiceTest { + + @Mock + private AmqpTemplate amqpTemplate; + + @InjectMocks + private ElasticLogService elasticLogService; + + private LogFull logFull; + + private LogMessage logMessage; + + @BeforeEach + public void setUp() { + Long itemId = 1L; + Long launchId = 1L; + logFull = new LogFull(); + logFull.setTestItem(new TestItem(itemId)); + logFull.setLaunch(new Launch(launchId)); + + logMessage = new LogMessage(logFull.getId(), logFull.getLogTime(), logFull.getLogMessage(), + itemId, launchId, logFull.getProjectId()); + } + + @Test + void saveLogMessage() { + elasticLogService.saveLogMessage(logFull, logFull.getLaunch().getId()); + + verify(amqpTemplate, times(1)).convertAndSend(eq(PROCESSING_EXCHANGE_NAME), + eq(LOG_MESSAGE_SAVING_ROUTING_KEY), eq(logMessage)); + } + + @Test + void saveLogMessageList() { + elasticLogService.saveLogMessageList(List.of(logFull), logFull.getLaunch().getId()); + + verify(amqpTemplate, times(1)).convertAndSend(eq(PROCESSING_EXCHANGE_NAME), + eq(LOG_MESSAGE_SAVING_ROUTING_KEY), eq(logMessage)); + } +} \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImplTest.java b/src/test/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImplTest.java index 822a09e880..bcf4eb3512 100644 --- a/src/test/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/log/impl/CreateLogHandlerAsyncImplTest.java @@ -16,12 +16,18 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.BinaryDataMetaInfo; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.util.ReportingQueueService; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import javax.inject.Provider; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -31,13 +37,6 @@ import org.springframework.core.task.TaskExecutor; import org.springframework.web.multipart.MultipartFile; -import javax.inject.Provider; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - /** * @author Konstantin Antipin */ @@ -45,55 +44,58 @@ @ExtendWith(MockitoExtension.class) class CreateLogHandlerAsyncImplTest { - @Mock - Provider<SaveLogBinaryDataTaskAsync> provider; + @Mock + Provider<SaveLogBinaryDataTaskAsync> provider; - @Mock - ReportingQueueService reportingQueueService; + @Mock + ReportingQueueService reportingQueueService; - @Mock - AmqpTemplate amqpTemplate; + @Mock + AmqpTemplate amqpTemplate; - @Mock - TaskExecutor taskExecutor; + @Mock + TaskExecutor taskExecutor; - @InjectMocks - CreateLogHandlerAsyncImpl createLogHandlerAsync; + @InjectMocks + CreateLogHandlerAsyncImpl createLogHandlerAsync; - @Mock - MultipartFile multipartFile; + @Mock + MultipartFile multipartFile; - @Mock - SaveLogBinaryDataTaskAsync saveLogBinaryDataTask; + @Mock + SaveLogBinaryDataTaskAsync saveLogBinaryDataTask; - @Mock - BinaryDataMetaInfo binaryDataMetaInfo; + @Mock + BinaryDataMetaInfo binaryDataMetaInfo; - @Test - void createLog() { - SaveLogRQ request = new SaveLogRQ(); - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void createLog() { + SaveLogRQ request = new SaveLogRQ(); + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - when(provider.get()).thenReturn(saveLogBinaryDataTask); - when(saveLogBinaryDataTask.withRequest(any())).thenReturn(saveLogBinaryDataTask); - when(saveLogBinaryDataTask.withFile(any())).thenReturn(saveLogBinaryDataTask); - when(saveLogBinaryDataTask.withProjectId(any())).thenReturn(saveLogBinaryDataTask); + when(provider.get()).thenReturn(saveLogBinaryDataTask); + when(saveLogBinaryDataTask.withRequest(any())).thenReturn(saveLogBinaryDataTask); + when(saveLogBinaryDataTask.withFile(any())).thenReturn(saveLogBinaryDataTask); + when(saveLogBinaryDataTask.withProjectId(any())).thenReturn(saveLogBinaryDataTask); - createLogHandlerAsync.createLog(request, multipartFile, user.getProjectDetails().get("test_project")); + createLogHandlerAsync.createLog(request, multipartFile, + user.getProjectDetails().get("test_project")); - verify(provider).get(); - verify(saveLogBinaryDataTask).withRequest(request); - verify(saveLogBinaryDataTask).withFile(multipartFile); - verify(saveLogBinaryDataTask).withProjectId(user.getProjectDetails().get("test_project").getProjectId()); - } + verify(provider).get(); + verify(saveLogBinaryDataTask).withRequest(request); + verify(saveLogBinaryDataTask).withFile(multipartFile); + verify(saveLogBinaryDataTask).withProjectId( + user.getProjectDetails().get("test_project").getProjectId()); + } - @Test - void sendMessage() { - SaveLogRQ request = new SaveLogRQ(); + @Test + void sendMessage() { + SaveLogRQ request = new SaveLogRQ(); - createLogHandlerAsync.sendMessage(request, binaryDataMetaInfo, 0L); - verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); - verify(reportingQueueService).getReportingQueueKey(any()); - } + createLogHandlerAsync.sendMessage(request, binaryDataMetaInfo, 0L); + verify(amqpTemplate).convertAndSend(any(), any(), any(), any()); + verify(reportingQueueService).getReportingQueueKey(any()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerTest.java b/src/test/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerTest.java index 963d1fe88a..61018dfb9f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/log/impl/DeleteLogHandlerTest.java @@ -16,9 +16,20 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.item.TestItemService; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.AttachmentRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.ProjectRepository; @@ -33,175 +44,174 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class DeleteLogHandlerTest { - @Mock - private ProjectRepository projectRepository; - - @Mock - private LogRepository logRepository; - - @Mock - private AttachmentRepository attachmentRepository; - - @Mock - private TestItemService testItemService; - - @Mock - private LogIndexer logIndexer; - - @InjectMocks - private DeleteLogHandlerImpl handler; - - @Test - void deleteLogOnNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.existsById(projectId)).thenReturn(false); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLog(1L, extractProjectDetails(user, "test_project"), user) - ); - assertEquals("Project '1' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void deleteNotExistLog() { - long projectId = 1L; - long logId = 2L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.existsById(projectId)).thenReturn(true); - when(logRepository.findById(logId)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) - ); - assertEquals("Log '2' not found. Did you use correct Log ID?", exception.getMessage()); - } - - @Test - void deleteLogByNotOwner() { - long projectId = 1L; - long logId = 2L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); - - Log log = new Log(); - TestItem testItem = new TestItem(); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatistics(Sets.newHashSet(new Statistics())); - testItem.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(projectId); - User user1 = new User(); - user1.setId(1L); - user1.setLogin("owner"); - launch.setUserId(2L); - testItem.setLaunchId(launch.getId()); - log.setTestItem(testItem); - - when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); - when(projectRepository.existsById(projectId)).thenReturn(true); - when(logRepository.findById(logId)).thenReturn(Optional.of(log)); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) - ); - assertEquals("You do not have enough permissions.", exception.getMessage()); - } - - @Test - void cleanUpLogDataTest() { - long projectId = 1L; - long logId = 2L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); - - Log log = new Log(); - TestItem testItem = new TestItem(); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatistics(Sets.newHashSet(new Statistics())); - testItem.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(projectId); - User user1 = new User(); - user1.setId(1L); - user1.setLogin("owner"); - launch.setUserId(user1.getId()); - testItem.setLaunchId(launch.getId()); - log.setTestItem(testItem); - Attachment attachment = new Attachment(); - String attachmentPath = "attachmentPath"; - attachment.setFileId(attachmentPath); - String attachmentThumbnailPath = "attachmentThumbnail"; - attachment.setThumbnailId(attachmentThumbnailPath); - log.setAttachment(attachment); - - when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); - when(projectRepository.existsById(projectId)).thenReturn(true); - when(logRepository.findById(logId)).thenReturn(Optional.of(log)); - - handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user); - - verify(logRepository, times(1)).delete(log); - verify(logIndexer, times(1)).cleanIndex(projectId, Collections.singletonList(logId)); - } - - @Test - void cleanUpLogDataNegative() { - long projectId = 1L; - long logId = 2L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); - - Log log = new Log(); - TestItem testItem = new TestItem(); - TestItemResults itemResults = new TestItemResults(); - itemResults.setStatistics(Sets.newHashSet(new Statistics())); - testItem.setItemResults(itemResults); - Launch launch = new Launch(); - launch.setId(1L); - launch.setProjectId(projectId); - User user1 = new User(); - user1.setId(1L); - user1.setLogin("owner"); - launch.setUserId(user1.getId()); - testItem.setLaunchId(launch.getId()); - log.setTestItem(testItem); - Attachment attachment = new Attachment(); - String attachmentPath = "attachmentPath"; - attachment.setFileId(attachmentPath); - String attachmentThumbnailPath = "attachmentThumbnail"; - attachment.setThumbnailId(attachmentThumbnailPath); - log.setAttachment(attachment); - when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); - when(projectRepository.existsById(projectId)).thenReturn(true); - when(logRepository.findById(logId)).thenReturn(Optional.of(log)); - doThrow(IllegalArgumentException.class).when(logRepository).delete(log); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) - ); - assertEquals("Error while Log instance deleting.", exception.getMessage()); - } + @Mock + private ProjectRepository projectRepository; + + @Mock + private LogRepository logRepository; + + @Mock + private AttachmentRepository attachmentRepository; + + @Mock + private TestItemService testItemService; + + @Mock + private LogIndexer logIndexer; + + @Mock + private LogService logService; + + @InjectMocks + private DeleteLogHandlerImpl handler; + + @Test + void deleteLogOnNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.existsById(projectId)).thenReturn(false); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLog(1L, extractProjectDetails(user, "test_project"), user) + ); + assertEquals("Project '1' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void deleteNotExistLog() { + long projectId = 1L; + long logId = 2L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.existsById(projectId)).thenReturn(true); + when(logRepository.findById(logId)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) + ); + assertEquals("Log '2' not found. Did you use correct Log ID?", exception.getMessage()); + } + + @Test + void deleteLogByNotOwner() { + long projectId = 1L; + long logId = 2L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); + + Log log = new Log(); + TestItem testItem = new TestItem(); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatistics(Sets.newHashSet(new Statistics())); + testItem.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(projectId); + User user1 = new User(); + user1.setId(1L); + user1.setLogin("owner"); + launch.setUserId(2L); + testItem.setLaunchId(launch.getId()); + log.setTestItem(testItem); + + when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); + when(projectRepository.existsById(projectId)).thenReturn(true); + when(logRepository.findById(logId)).thenReturn(Optional.of(log)); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) + ); + assertEquals("You do not have enough permissions.", exception.getMessage()); + } + + @Test + void cleanUpLogDataTest() { + long projectId = 1L; + long logId = 2L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); + + Log log = new Log(); + TestItem testItem = new TestItem(); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatistics(Sets.newHashSet(new Statistics())); + testItem.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(projectId); + User user1 = new User(); + user1.setId(1L); + user1.setLogin("owner"); + launch.setUserId(user1.getId()); + testItem.setLaunchId(launch.getId()); + log.setTestItem(testItem); + Attachment attachment = new Attachment(); + String attachmentPath = "attachmentPath"; + attachment.setFileId(attachmentPath); + String attachmentThumbnailPath = "attachmentThumbnail"; + attachment.setThumbnailId(attachmentThumbnailPath); + log.setAttachment(attachment); + + when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); + when(projectRepository.existsById(projectId)).thenReturn(true); + when(logRepository.findById(logId)).thenReturn(Optional.of(log)); + + handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user); + + verify(logRepository, times(1)).delete(log); + verify(logIndexer, times(1)).cleanIndex(projectId, Collections.singletonList(logId)); + } + + @Test + void cleanUpLogDataNegative() { + long projectId = 1L; + long logId = 2L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.MEMBER, projectId); + + Log log = new Log(); + TestItem testItem = new TestItem(); + TestItemResults itemResults = new TestItemResults(); + itemResults.setStatistics(Sets.newHashSet(new Statistics())); + testItem.setItemResults(itemResults); + Launch launch = new Launch(); + launch.setId(1L); + launch.setProjectId(projectId); + User user1 = new User(); + user1.setId(1L); + user1.setLogin("owner"); + launch.setUserId(user1.getId()); + testItem.setLaunchId(launch.getId()); + log.setTestItem(testItem); + Attachment attachment = new Attachment(); + String attachmentPath = "attachmentPath"; + attachment.setFileId(attachmentPath); + String attachmentThumbnailPath = "attachmentThumbnail"; + attachment.setThumbnailId(attachmentThumbnailPath); + log.setAttachment(attachment); + when(testItemService.getEffectiveLaunch(any(TestItem.class))).thenReturn(launch); + when(projectRepository.existsById(projectId)).thenReturn(true); + when(logRepository.findById(logId)).thenReturn(Optional.of(log)); + doThrow(IllegalArgumentException.class).when(logRepository).delete(log); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteLog(logId, extractProjectDetails(user, "test_project"), user) + ); + assertEquals("Error while Log instance deleting.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImplTest.java index 10e04185b8..22994eb417 100644 --- a/src/test/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/log/impl/GetLogHandlerImplTest.java @@ -1,9 +1,22 @@ package com.epam.ta.reportportal.core.log.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.commons.querygen.constant.LogCriteriaConstant.CRITERIA_ITEM_LAUNCH_ID; +import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; +import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.commons.querygen.*; +import com.epam.ta.reportportal.commons.querygen.Condition; +import com.epam.ta.reportportal.commons.querygen.ConvertibleCondition; +import com.epam.ta.reportportal.commons.querygen.Filter; +import com.epam.ta.reportportal.commons.querygen.FilterCondition; +import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.core.item.TestItemService; import com.epam.ta.reportportal.core.log.GetLogHandler; +import com.epam.ta.reportportal.core.log.LogService; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.TestItemRepository; import com.epam.ta.reportportal.entity.item.TestItem; @@ -11,6 +24,8 @@ import com.epam.ta.reportportal.entity.log.Log; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; +import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -18,83 +33,80 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import java.util.List; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static com.epam.ta.reportportal.commons.querygen.constant.LogCriteriaConstant.CRITERIA_ITEM_LAUNCH_ID; -import static com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant.CRITERIA_PATH; -import static com.epam.ta.reportportal.util.TestProjectExtractor.extractProjectDetails; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class GetLogHandlerTest { - private final LogRepository logRepository = mock(LogRepository.class); + private final LogRepository logRepository = mock(LogRepository.class); + + private final LogService logService = mock(LogService.class); - private final TestItemRepository testItemRepository = mock(TestItemRepository.class); + private final TestItemRepository testItemRepository = mock(TestItemRepository.class); - private final TestItemService testItemService = mock(TestItemService.class); + private final TestItemService testItemService = mock(TestItemService.class); - private final GetLogHandler getLogHandler = new GetLogHandlerImpl(logRepository, testItemRepository, testItemService); + private final GetLogHandler getLogHandler = new GetLogHandlerImpl(logRepository, logService, + testItemRepository, testItemService); - @Test - void getLogs() { + @Test + void getLogs() { - Long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); + Long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); - String wrongPath = "1"; - Filter idFilter = Filter.builder() - .withTarget(Log.class) - .withCondition(FilterCondition.builder() - .withSearchCriteria(CRITERIA_PATH) - .withValue(wrongPath) - .withCondition(Condition.UNDER) - .build()) - .build(); - Pageable pageable = PageRequest.of(1, 5); + String wrongPath = "1"; + Filter idFilter = Filter.builder() + .withTarget(Log.class) + .withCondition(FilterCondition.builder() + .withSearchCriteria(CRITERIA_PATH) + .withValue(wrongPath) + .withCondition(Condition.UNDER) + .build()) + .build(); + Pageable pageable = PageRequest.of(1, 5); - TestItem testItem = new TestItem(); - testItem.setItemId(3L); - String correctPath = "1.2.3"; - testItem.setPath(correctPath); - testItem.setLaunchId(1L); + TestItem testItem = new TestItem(); + testItem.setItemId(3L); + String correctPath = "1.2.3"; + testItem.setPath(correctPath); + testItem.setLaunchId(1L); - Launch launch = new Launch(); - launch.setId(1L); + Launch launch = new Launch(); + launch.setId(1L); - when(testItemRepository.findByPath(correctPath)).thenReturn(Optional.of(testItem)); - when(testItemService.getEffectiveLaunch(testItem)).thenReturn(launch); + when(testItemRepository.findByPath(correctPath)).thenReturn(Optional.of(testItem)); + when(testItemService.getEffectiveLaunch(testItem)).thenReturn(launch); - ArgumentCaptor<Queryable> queryableArgumentCaptor = ArgumentCaptor.forClass(Queryable.class); - when(logRepository.findByFilter(queryableArgumentCaptor.capture(), any(Pageable.class))).thenReturn(Page.empty(pageable)); + ArgumentCaptor<Queryable> queryableArgumentCaptor = ArgumentCaptor.forClass(Queryable.class); + when( + logService.findByFilter(queryableArgumentCaptor.capture(), any(Pageable.class))).thenReturn( + Page.empty(pageable)); - getLogHandler.getLogs(correctPath, extractProjectDetails(user, "test_project"), idFilter, pageable); + getLogHandler.getLogs(correctPath, extractProjectDetails(user, "test_project"), idFilter, + pageable); - Queryable updatedFilter = queryableArgumentCaptor.getValue(); + Queryable updatedFilter = queryableArgumentCaptor.getValue(); - List<ConvertibleCondition> filterConditions = updatedFilter.getFilterConditions(); + List<ConvertibleCondition> filterConditions = updatedFilter.getFilterConditions(); - Optional<FilterCondition> launchIdCondition = filterConditions.stream() - .flatMap(convertibleCondition -> convertibleCondition.getAllConditions().stream()) - .filter(c -> CRITERIA_ITEM_LAUNCH_ID.equals(c.getSearchCriteria())) - .findFirst(); + Optional<FilterCondition> launchIdCondition = filterConditions.stream() + .flatMap(convertibleCondition -> convertibleCondition.getAllConditions().stream()) + .filter(c -> CRITERIA_ITEM_LAUNCH_ID.equals(c.getSearchCriteria())) + .findFirst(); - Assertions.assertTrue(launchIdCondition.isPresent()); - Assertions.assertEquals(String.valueOf(launch.getId()), launchIdCondition.get().getValue()); + Assertions.assertTrue(launchIdCondition.isPresent()); + Assertions.assertEquals(String.valueOf(launch.getId()), launchIdCondition.get().getValue()); - Optional<FilterCondition> underPathCondition = filterConditions.stream() - .flatMap(convertibleCondition -> convertibleCondition.getAllConditions().stream()) - .filter(c -> CRITERIA_PATH.equals(c.getSearchCriteria()) && Condition.UNDER.equals(c.getCondition())) - .findFirst(); + Optional<FilterCondition> underPathCondition = filterConditions.stream() + .flatMap(convertibleCondition -> convertibleCondition.getAllConditions().stream()) + .filter(c -> CRITERIA_PATH.equals(c.getSearchCriteria()) && Condition.UNDER.equals( + c.getCondition())) + .findFirst(); - Assertions.assertTrue(underPathCondition.isPresent()); - Assertions.assertNotEquals(wrongPath, underPathCondition.get().getValue()); - Assertions.assertEquals(correctPath, underPathCondition.get().getValue()); - } + Assertions.assertTrue(underPathCondition.isPresent()); + Assertions.assertNotEquals(wrongPath, underPathCondition.get().getValue()); + Assertions.assertEquals(correctPath, underPathCondition.get().getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/logging/HelperController.java b/src/test/java/com/epam/ta/reportportal/core/logging/HelperController.java index f28caa9604..c3a275b97d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/logging/HelperController.java +++ b/src/test/java/com/epam/ta/reportportal/core/logging/HelperController.java @@ -16,37 +16,38 @@ package com.epam.ta.reportportal.core.logging; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; -import java.util.Map; public class HelperController { - private static final Logger logger = LoggerFactory.getLogger(HelperController.class); - - private static final HttpHeaders responseHeaders; - - static { - responseHeaders = new HttpHeaders(); - responseHeaders.set("Cotent-Type", "text/plain"); - responseHeaders.set("Server", "Apache"); - } - - @HttpLogging(logExecutionTime = false) - public ResponseEntity<Map<String, Object>> logFull(@RequestBody Object payload) { - return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); - } - - @HttpLogging(logExecutionTime = false, logHeaders = false) - public ResponseEntity<Map<String, Object>> logWithoutHeaders(@RequestBody Object payload) { - return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); - } - - @HttpLogging(logExecutionTime = false, logResponseBody = false, logRequestBody = false) - public ResponseEntity<Map<String, Object>> logWithoutBody(@RequestBody Object payload) { - return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); - } + + private static final Logger logger = LoggerFactory.getLogger(HelperController.class); + + private static final HttpHeaders responseHeaders; + + static { + responseHeaders = new HttpHeaders(); + responseHeaders.set("Cotent-Type", "text/plain"); + responseHeaders.set("Server", "Apache"); + } + + @HttpLogging(logExecutionTime = false) + public ResponseEntity<Map<String, Object>> logFull(@RequestBody Object payload) { + return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); + } + + @HttpLogging(logExecutionTime = false, logHeaders = false) + public ResponseEntity<Map<String, Object>> logWithoutHeaders(@RequestBody Object payload) { + return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); + } + + @HttpLogging(logExecutionTime = false, logResponseBody = false, logRequestBody = false) + public ResponseEntity<Map<String, Object>> logWithoutBody(@RequestBody Object payload) { + return new ResponseEntity(payload, responseHeaders, HttpStatus.OK); + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/logging/HelperListener.java b/src/test/java/com/epam/ta/reportportal/core/logging/HelperListener.java index 8bce4ce462..6d2ebba4d0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/logging/HelperListener.java +++ b/src/test/java/com/epam/ta/reportportal/core/logging/HelperListener.java @@ -20,15 +20,15 @@ public class HelperListener { - @RabbitMessageLogging - public void onMessageFull(Message message) { - } + @RabbitMessageLogging + public void onMessageFull(Message message) { + } - @RabbitMessageLogging(logHeaders = false) - public void onMessageWithoutHeaders(Message message) { - } + @RabbitMessageLogging(logHeaders = false) + public void onMessageWithoutHeaders(Message message) { + } - @RabbitMessageLogging(logBody = false) - public void onMessageWithoutBody(Message message) { - } + @RabbitMessageLogging(logBody = false) + public void onMessageWithoutBody(Message message) { + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/logging/HelperUtil.java b/src/test/java/com/epam/ta/reportportal/core/logging/HelperUtil.java index 0f482f434f..45c1afb771 100644 --- a/src/test/java/com/epam/ta/reportportal/core/logging/HelperUtil.java +++ b/src/test/java/com/epam/ta/reportportal/core/logging/HelperUtil.java @@ -16,37 +16,38 @@ package com.epam.ta.reportportal.core.logging; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.core.Appender; -import org.mockito.ArgumentCaptor; - import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.verify; -import static org.mockito.internal.verification.VerificationModeFactory.times; +import org.mockito.ArgumentCaptor; public class HelperUtil { - public static void checkLoggingRecords(Appender<ILoggingEvent> appender, int numberOfRecords, Level[] levels, String ... records) { - ArgumentCaptor<LoggingEvent> argument = ArgumentCaptor.forClass(LoggingEvent.class); - verify(appender, times(numberOfRecords)).doAppend(argument.capture()); - - List<LoggingEvent> events = argument.getAllValues(); - for (int i = 0; i < events.size(); i++) { - assertEquals(levels[i], events.get(i).getLevel()); - assertEquals(orderedMultilineString(records[i]), orderedMultilineString(events.get(i).getMessage())); - } - } - - public static String orderedMultilineString(String input) { - String[] lines = input.split("\n"); - Arrays.sort(lines); - return Stream.of(lines).collect(Collectors.joining("\n")); - } + public static void checkLoggingRecords(Appender<ILoggingEvent> appender, int numberOfRecords, + Level[] levels, String... records) { + ArgumentCaptor<LoggingEvent> argument = ArgumentCaptor.forClass(LoggingEvent.class); + verify(appender, times(numberOfRecords)).doAppend(argument.capture()); + + List<LoggingEvent> events = argument.getAllValues(); + for (int i = 0; i < events.size(); i++) { + assertEquals(levels[i], events.get(i).getLevel()); + assertEquals(orderedMultilineString(records[i]), + orderedMultilineString(events.get(i).getMessage())); + } + } + + public static String orderedMultilineString(String input) { + String[] lines = input.split("\n"); + Arrays.sort(lines); + return Stream.of(lines).collect(Collectors.joining("\n")); + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspectTest.java b/src/test/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspectTest.java index 331f466798..3556c67911 100644 --- a/src/test/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspectTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/logging/HttpLoggingAspectTest.java @@ -16,11 +16,18 @@ package com.epam.ta.reportportal.core.logging; +import static com.epam.ta.reportportal.core.logging.HelperUtil.checkLoggingRecords; +import static org.mockito.Mockito.when; + import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,121 +42,118 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -import static com.epam.ta.reportportal.core.logging.HelperUtil.checkLoggingRecords; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class HttpLoggingAspectTest { - private static HelperController proxy; - private static HttpLoggingAspect aspect; + private static HelperController proxy; + + private static HttpLoggingAspect aspect; - private static MockHttpServletRequest request; + private static MockHttpServletRequest request; - private static Map<Object, Object> payload; + private static Map<Object, Object> payload; - private static Logger logger; + private static Logger logger; - @Mock - private static Appender<ILoggingEvent> appender; + @Mock + private static Appender<ILoggingEvent> appender; - @Mock - private static HttpLogging annotation; + @Mock + private static HttpLogging annotation; - private static String requestLog; + private static String requestLog; - private static String responseLog; + private static String responseLog; - private static AtomicLong COUNT = new AtomicLong(); + private static AtomicLong COUNT = new AtomicLong(); - @BeforeAll - static void beforeAll() { - aspect = new HttpLoggingAspect(); - ReflectionTestUtils.setField(aspect, "objectMapper", new ObjectMapper()); + @BeforeAll + static void beforeAll() { + aspect = new HttpLoggingAspect(); + ReflectionTestUtils.setField(aspect, "objectMapper", new ObjectMapper()); - HelperController controller = new HelperController(); - AspectJProxyFactory factory = new AspectJProxyFactory(controller); - factory.addAspect(aspect); - proxy = factory.getProxy(); + HelperController controller = new HelperController(); + AspectJProxyFactory factory = new AspectJProxyFactory(controller); + factory.addAspect(aspect); + proxy = factory.getProxy(); - request = new MockHttpServletRequest("GET", "/request/path/is/here"); - request.setQueryString("ddd=qwerty"); - request.addHeader("Content-Type", "application/json"); - request.addHeader("Host", "localhost"); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + request = new MockHttpServletRequest("GET", "/request/path/is/here"); + request.setQueryString("ddd=qwerty"); + request.addHeader("Content-Type", "application/json"); + request.addHeader("Host", "localhost"); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); - payload = new HashMap<>(); - payload.put("key1", "one"); - payload.put("key2", "two"); - payload.put("key3", "three"); + payload = new HashMap<>(); + payload.put("key1", "one"); + payload.put("key2", "two"); + payload.put("key3", "three"); - logger = (Logger) LoggerFactory.getLogger(HelperController.class); - logger.setLevel(Level.DEBUG); - logger.setAdditive(false); - } + logger = (Logger) LoggerFactory.getLogger(HelperController.class); + logger.setLevel(Level.DEBUG); + logger.setAdditive(false); + } - @BeforeEach - void setup() { - logger.detachAndStopAllAppenders(); - logger.addAppender(appender); - } + @BeforeEach + void setup() { + logger.detachAndStopAllAppenders(); + logger.addAppender(appender); + } - @Test - void testFull() throws Exception { + @Test + void testFull() throws Exception { - when(annotation.logHeaders()).thenReturn(true); - when(annotation.logRequestBody()).thenReturn(true); - when(annotation.logResponseBody()).thenReturn(true); - when(annotation.logExecutionTime()).thenReturn(false); + when(annotation.logHeaders()).thenReturn(true); + when(annotation.logRequestBody()).thenReturn(true); + when(annotation.logResponseBody()).thenReturn(true); + when(annotation.logExecutionTime()).thenReturn(false); - long count = COUNT.incrementAndGet(); - ResponseEntity<Map<String, Object>> response = proxy.logFull(payload); - formatRequestResponseAndPrint(count, "logFull", request, response); + long count = COUNT.incrementAndGet(); + ResponseEntity<Map<String, Object>> response = proxy.logFull(payload); + formatRequestResponseAndPrint(count, "logFull", request, response); - checkLoggingRecords(appender, 2, new Level[] { Level.DEBUG, Level.DEBUG }, requestLog, responseLog); - } + checkLoggingRecords(appender, 2, new Level[]{Level.DEBUG, Level.DEBUG}, requestLog, + responseLog); + } - @Test - void testWithoutHeaders() throws Exception { + @Test + void testWithoutHeaders() throws Exception { - when(annotation.logHeaders()).thenReturn(false); - when(annotation.logRequestBody()).thenReturn(true); - when(annotation.logResponseBody()).thenReturn(true); - when(annotation.logExecutionTime()).thenReturn(false); + when(annotation.logHeaders()).thenReturn(false); + when(annotation.logRequestBody()).thenReturn(true); + when(annotation.logResponseBody()).thenReturn(true); + when(annotation.logExecutionTime()).thenReturn(false); - long count = COUNT.incrementAndGet(); - ResponseEntity<Map<String, Object>> response = proxy.logWithoutHeaders(payload); - formatRequestResponseAndPrint(count, "logWithoutHeaders", request, response); + long count = COUNT.incrementAndGet(); + ResponseEntity<Map<String, Object>> response = proxy.logWithoutHeaders(payload); + formatRequestResponseAndPrint(count, "logWithoutHeaders", request, response); - checkLoggingRecords(appender, 2, new Level[] { Level.DEBUG, Level.DEBUG }, requestLog, responseLog); - } + checkLoggingRecords(appender, 2, new Level[]{Level.DEBUG, Level.DEBUG}, requestLog, + responseLog); + } - @Test - void testWithoutBody() throws Exception { + @Test + void testWithoutBody() throws Exception { - when(annotation.logHeaders()).thenReturn(true); - when(annotation.logRequestBody()).thenReturn(false); - when(annotation.logResponseBody()).thenReturn(false); - when(annotation.logExecutionTime()).thenReturn(false); + when(annotation.logHeaders()).thenReturn(true); + when(annotation.logRequestBody()).thenReturn(false); + when(annotation.logResponseBody()).thenReturn(false); + when(annotation.logExecutionTime()).thenReturn(false); - long count = COUNT.incrementAndGet(); - ResponseEntity<Map<String, Object>> response = proxy.logWithoutBody(payload); - formatRequestResponseAndPrint(count, "logWithoutBody", request, response); + long count = COUNT.incrementAndGet(); + ResponseEntity<Map<String, Object>> response = proxy.logWithoutBody(payload); + formatRequestResponseAndPrint(count, "logWithoutBody", request, response); - checkLoggingRecords(appender, 2, new Level[] { Level.DEBUG, Level.DEBUG }, requestLog, responseLog); - } + checkLoggingRecords(appender, 2, new Level[]{Level.DEBUG, Level.DEBUG}, requestLog, + responseLog); + } - private void formatRequestResponseAndPrint(long count, String prefix, HttpServletRequest request, ResponseEntity response) - throws Exception { - requestLog = aspect.formatRequestRecord(count, prefix, request, payload, annotation); - responseLog = aspect.formatResponseRecord(count, prefix, response, annotation, 0L); - System.out.println(requestLog); - System.out.println(responseLog); - } + private void formatRequestResponseAndPrint(long count, String prefix, HttpServletRequest request, + ResponseEntity response) + throws Exception { + requestLog = aspect.formatRequestRecord(count, prefix, request, payload, annotation); + responseLog = aspect.formatResponseRecord(count, prefix, response, annotation, 0L); + System.out.println(requestLog); + System.out.println(responseLog); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspectTest.java b/src/test/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspectTest.java index 5b3e09be79..85e09069a6 100644 --- a/src/test/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspectTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/logging/RabbitMessageLoggingAspectTest.java @@ -16,11 +16,18 @@ package com.epam.ta.reportportal.core.logging; +import static com.epam.ta.reportportal.core.logging.HelperUtil.checkLoggingRecords; +import static org.mockito.Mockito.when; + import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,122 +42,114 @@ import org.springframework.aop.aspectj.annotation.AspectJProxyFactory; import org.springframework.test.util.ReflectionTestUtils; -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; -import java.util.UUID; - -import static com.epam.ta.reportportal.core.logging.HelperUtil.checkLoggingRecords; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class RabbitMessageLoggingAspectTest { - private static HelperListener proxy; + private static HelperListener proxy; - private static RabbitMessageLoggingAspect aspect; + private static RabbitMessageLoggingAspect aspect; - private static Message message; + private static Message message; - private static Map<Object, Object> payload; + private static Map<Object, Object> payload; - private static Logger logger; + private static Logger logger; - @Mock - private static Appender<ILoggingEvent> appender; + @Mock + private static Appender<ILoggingEvent> appender; - @Mock - private static RabbitMessageLogging annotation; + @Mock + private static RabbitMessageLogging annotation; - private String log; + private String log; - private static ObjectMapper objectMapper; + private static ObjectMapper objectMapper; - private static MessageConverter messageConverter; + private static MessageConverter messageConverter; - private static Map<String, Object> headers; + private static Map<String, Object> headers; - @BeforeAll - static void beforeAll() throws Exception { - aspect = new RabbitMessageLoggingAspect(); + @BeforeAll + static void beforeAll() throws Exception { + aspect = new RabbitMessageLoggingAspect(); - objectMapper = new ObjectMapper(); - messageConverter = new Jackson2JsonMessageConverter(); + objectMapper = new ObjectMapper(); + messageConverter = new Jackson2JsonMessageConverter(); - ReflectionTestUtils.setField(aspect, "objectMapper", objectMapper); - ReflectionTestUtils.setField(aspect, "messageConverter", messageConverter); + ReflectionTestUtils.setField(aspect, "objectMapper", objectMapper); + ReflectionTestUtils.setField(aspect, "messageConverter", messageConverter); - HelperListener listener = new HelperListener(); - AspectJProxyFactory factory = new AspectJProxyFactory(listener); - factory.addAspect(aspect); - proxy = factory.getProxy(); + HelperListener listener = new HelperListener(); + AspectJProxyFactory factory = new AspectJProxyFactory(listener); + factory.addAspect(aspect); + proxy = factory.getProxy(); - payload = new HashMap<>(); - payload.put("key1", "one"); - payload.put("key2", "two"); - payload.put("key3", "three"); + payload = new HashMap<>(); + payload.put("key1", "one"); + payload.put("key2", "two"); + payload.put("key3", "three"); - headers = new TreeMap<>(); - headers.put("header1", "one"); - headers.put("header2", UUID.randomUUID()); - headers.put("__ContentTypeId__", "java.lang.Object"); - headers.put("__TypeId__", "java.util.HashMap"); - headers.put("__KeyTypeId__", "java.lang.Object"); + headers = new TreeMap<>(); + headers.put("header1", "one"); + headers.put("header2", UUID.randomUUID()); + headers.put("__ContentTypeId__", "java.lang.Object"); + headers.put("__TypeId__", "java.util.HashMap"); + headers.put("__KeyTypeId__", "java.lang.Object"); - MessagePropertiesBuilder properties = MessagePropertiesBuilder.newInstance(); - for (Map.Entry<String, Object> entry : headers.entrySet()) { - properties.setHeader(entry.getKey(), entry.getValue()); - } - message = messageConverter.toMessage(payload, properties.build()); + MessagePropertiesBuilder properties = MessagePropertiesBuilder.newInstance(); + for (Map.Entry<String, Object> entry : headers.entrySet()) { + properties.setHeader(entry.getKey(), entry.getValue()); + } + message = messageConverter.toMessage(payload, properties.build()); - logger = (Logger) LoggerFactory.getLogger(HelperListener.class); - logger.setLevel(Level.DEBUG); - logger.setAdditive(false); - } + logger = (Logger) LoggerFactory.getLogger(HelperListener.class); + logger.setLevel(Level.DEBUG); + logger.setAdditive(false); + } - @BeforeEach - void setup() { - logger.detachAndStopAllAppenders(); - logger.addAppender(appender); - } + @BeforeEach + void setup() { + logger.detachAndStopAllAppenders(); + logger.addAppender(appender); + } - @Test - void testMessageFull() throws Exception { + @Test + void testMessageFull() throws Exception { - when(annotation.logHeaders()).thenReturn(true); - when(annotation.logBody()).thenReturn(true); + when(annotation.logHeaders()).thenReturn(true); + when(annotation.logBody()).thenReturn(true); - proxy.onMessageFull(message); - log = aspect.formatMessageRecord("onMessageFull", headers, payload, annotation); - System.out.println(log); + proxy.onMessageFull(message); + log = aspect.formatMessageRecord("onMessageFull", headers, payload, annotation); + System.out.println(log); - checkLoggingRecords(appender, 1, new Level[] { Level.DEBUG }, log); - } + checkLoggingRecords(appender, 1, new Level[]{Level.DEBUG}, log); + } - @Test - void testMessageWithoutHeader() throws Exception { + @Test + void testMessageWithoutHeader() throws Exception { - when(annotation.logHeaders()).thenReturn(false); - when(annotation.logBody()).thenReturn(true); + when(annotation.logHeaders()).thenReturn(false); + when(annotation.logBody()).thenReturn(true); - proxy.onMessageWithoutHeaders(message); - log = aspect.formatMessageRecord("onMessageWithoutHeaders", headers, payload, annotation); - System.out.println(log); + proxy.onMessageWithoutHeaders(message); + log = aspect.formatMessageRecord("onMessageWithoutHeaders", headers, payload, annotation); + System.out.println(log); - checkLoggingRecords(appender, 1, new Level[] { Level.DEBUG }, log); - } + checkLoggingRecords(appender, 1, new Level[]{Level.DEBUG}, log); + } - @Test - void testMessageWithoutBody() throws Exception { + @Test + void testMessageWithoutBody() throws Exception { - when(annotation.logHeaders()).thenReturn(true); - when(annotation.logBody()).thenReturn(false); + when(annotation.logHeaders()).thenReturn(true); + when(annotation.logBody()).thenReturn(false); - proxy.onMessageWithoutBody(message); - log = aspect.formatMessageRecord("onMessageWithoutBody", headers, payload, annotation); - System.out.println(log); + proxy.onMessageWithoutBody(message); + log = aspect.formatMessageRecord("onMessageWithoutBody", headers, payload, annotation); + System.out.println(log); - checkLoggingRecords(appender, 1, new Level[] { Level.DEBUG }, log); - } + checkLoggingRecords(appender, 1, new Level[]{Level.DEBUG}, log); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProviderTest.java b/src/test/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProviderTest.java index 0e61724e30..601e4a87c8 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProviderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/config/ProjectConfigProviderTest.java @@ -16,50 +16,49 @@ package com.epam.ta.reportportal.core.project.config; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.project.GetProjectHandler; import com.epam.ta.reportportal.entity.attribute.Attribute; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectAttribute; -import org.junit.jupiter.api.Test; - import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.LongStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ProjectConfigProviderTest { - private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); - private final ProjectConfigProvider provider = new ProjectConfigProvider(getProjectHandler); + private final GetProjectHandler getProjectHandler = mock(GetProjectHandler.class); + private final ProjectConfigProvider provider = new ProjectConfigProvider(getProjectHandler); - @Test - void shouldReturnConfig() { + @Test + void shouldReturnConfig() { - final long projectId = 1L; - final Project project = new Project(); - project.setId(projectId); - final Set<ProjectAttribute> projectAttributes = LongStream.range(1, 10).mapToObj(it -> { - final Attribute attribute = new Attribute(it, String.valueOf(it)); - return new ProjectAttribute(attribute, "Value " + it, project); - }).collect(Collectors.toSet()); - project.setProjectAttributes(projectAttributes); + final long projectId = 1L; + final Project project = new Project(); + project.setId(projectId); + final Set<ProjectAttribute> projectAttributes = LongStream.range(1, 10).mapToObj(it -> { + final Attribute attribute = new Attribute(it, String.valueOf(it)); + return new ProjectAttribute(attribute, "Value " + it, project); + }).collect(Collectors.toSet()); + project.setProjectAttributes(projectAttributes); - when(getProjectHandler.get(projectId)).thenReturn(project); + when(getProjectHandler.get(projectId)).thenReturn(project); - final Map<String, String> attributesMapping = provider.provide(projectId); + final Map<String, String> attributesMapping = provider.provide(projectId); - assertEquals(projectAttributes.size(), attributesMapping.size()); - projectAttributes.forEach(a -> { - final String value = attributesMapping.get(a.getAttribute().getName()); - assertEquals(a.getValue(), value); - }); - } + assertEquals(projectAttributes.size(), attributesMapping.size()); + projectAttributes.forEach(a -> { + final String value = attributesMapping.get(a.getAttribute().getName()); + assertEquals(a.getValue(), value); + }); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImplTest.java index ce79e09b07..2dd97504e0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/impl/CreateProjectHandlerImplTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.project.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.dao.UserRepository; @@ -23,64 +28,65 @@ import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.project.CreateProjectRQ; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class CreateProjectHandlerImplTest { - @Mock - private ProjectRepository projectRepository; + @Mock + private ProjectRepository projectRepository; - @Mock - private UserRepository userRepository; + @Mock + private UserRepository userRepository; - @InjectMocks - private CreateProjectHandlerImpl handler; + @InjectMocks + private CreateProjectHandlerImpl handler; - @Test - void createProjectWithWrongType() { - ReportPortalUser rpUser = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void createProjectWithWrongType() { + ReportPortalUser rpUser = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - CreateProjectRQ createProjectRQ = new CreateProjectRQ(); - String projectName = "projectName"; - createProjectRQ.setProjectName(projectName); - createProjectRQ.setEntryType("wrongType"); + CreateProjectRQ createProjectRQ = new CreateProjectRQ(); + String projectName = "projectName"; + createProjectRQ.setProjectName(projectName); + createProjectRQ.setEntryType("wrongType"); - when(projectRepository.findByName(projectName.toLowerCase().trim())).thenReturn(Optional.empty()); + when(projectRepository.findByName(projectName.toLowerCase().trim())).thenReturn( + Optional.empty()); - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createProject(createProjectRQ, rpUser)); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createProject(createProjectRQ, rpUser)); - assertEquals("Error in handled Request. Please, check specified parameters: 'wrongType'", exception.getMessage()); - } + assertEquals("Error in handled Request. Please, check specified parameters: 'wrongType'", + exception.getMessage()); + } - @Test - void createProjectByNotExistUser() { - ReportPortalUser rpUser = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); + @Test + void createProjectByNotExistUser() { + ReportPortalUser rpUser = getRpUser("user", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); - CreateProjectRQ createProjectRQ = new CreateProjectRQ(); - String projectName = "projectName"; - createProjectRQ.setProjectName(projectName); - createProjectRQ.setEntryType("internal"); + CreateProjectRQ createProjectRQ = new CreateProjectRQ(); + String projectName = "projectName"; + createProjectRQ.setProjectName(projectName); + createProjectRQ.setEntryType("internal"); - when(projectRepository.findByName(projectName.toLowerCase().trim())).thenReturn(Optional.empty()); - when(userRepository.findRawById(rpUser.getUserId())).thenReturn(Optional.empty()); + when(projectRepository.findByName(projectName.toLowerCase().trim())).thenReturn( + Optional.empty()); + when(userRepository.findRawById(rpUser.getUserId())).thenReturn(Optional.empty()); - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createProject(createProjectRQ, rpUser)); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createProject(createProjectRQ, rpUser)); - assertEquals("User 'user' not found.", exception.getMessage()); - } + assertEquals("User 'user' not found.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImplTest.java index 8af4ab38d7..54ed8ef79c 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/impl/DeleteProjectHandlerImplTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.analyzer.auto.LogIndexer; import com.epam.ta.reportportal.core.analyzer.auto.client.AnalyzerServiceClient; @@ -67,9 +68,6 @@ class DeleteProjectHandlerImplTest { @Mock private UserRepository userRepository; - @Mock - private AttachmentRepository attachmentRepository; - @Mock private LogIndexer logIndexer; @@ -91,6 +89,9 @@ class DeleteProjectHandlerImplTest { @Mock private LogRepository logRepository; + @Mock + private AttachmentBinaryDataService attachmentBinaryDataService; + @InjectMocks private DeleteProjectHandlerImpl handler; diff --git a/src/test/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverterTest.java b/src/test/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverterTest.java index 0a2191c967..71e7b91f3b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/impl/ProjectInfoWidgetDataConverterTest.java @@ -16,6 +16,16 @@ package com.epam.ta.reportportal.core.project.impl; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_AUTOMATION_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_PRODUCT_BUG_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_SYSTEM_ISSUE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.DEFECTS_TO_INVESTIGATE_TOTAL; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_FAILED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_SKIPPED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.InfoInterval; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.statistics.Statistics; @@ -23,10 +33,11 @@ import com.epam.ta.reportportal.ws.model.widget.ChartObject; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.time.*; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.IsoFields; @@ -34,164 +45,185 @@ import java.util.Collections; import java.util.List; import java.util.Map; - -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.*; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class ProjectInfoWidgetDataConverterTest { - private ProjectInfoWidgetDataConverter converter; - - private String thisWeekFormattedDate; - - private LocalDate today; - private LocalDate yesterday; - - private String todayString; - private String yesterdayString; - - @BeforeEach - void setUp() { - converter = new ProjectInfoWidgetDataConverter(ImmutableMap.<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup>builder() - .put(InfoInterval.ONE_MONTH, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY) - .put(InfoInterval.THREE_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) - .put(InfoInterval.SIX_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) - .build()); - - thisWeekFormattedDate = LocalDate.now(ZoneOffset.UTC) - .format(new DateTimeFormatterBuilder().appendValue(IsoFields.WEEK_BASED_YEAR, 4) - .appendLiteral("-W") - .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) - .toFormatter()); - - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - - LocalDate now = LocalDate.now(ZoneOffset.UTC); - today = now.getDayOfWeek().equals(DayOfWeek.MONDAY) ? now.plusDays(2) : now; - yesterday = today.minusDays(1); - - todayString = today.format(formatter); - yesterdayString = yesterday.format(formatter); - } - - @Test - void getInvestigatedProjectInfo() { - Map<String, List<ChartObject>> investigatedProjectInfo = converter.getInvestigatedProjectInfo(getTestData(), - InfoInterval.ONE_MONTH - ); - - assertEquals("33.33", investigatedProjectInfo.get(yesterdayString).get(0).getValues().get("toInvestigate")); - assertEquals("66.67", investigatedProjectInfo.get(yesterdayString).get(0).getValues().get("investigated")); - - assertEquals("38.46", investigatedProjectInfo.get(todayString).get(0).getValues().get("toInvestigate")); - assertEquals("61.54", investigatedProjectInfo.get(todayString).get(0).getValues().get("investigated")); - } - - @Test - void getInvestigatedProjectInfoWithoutDefectsStatistics() { - Launch launch = new Launch(); - launch.setName("test_launch"); - launch.setId(1L); - launch.setNumber(1L); - launch.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); - launch.setStatistics(Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 5), getStatistics(EXECUTIONS_PASSED, 5))); - - Map<String, List<ChartObject>> investigatedProjectInfo = converter.getInvestigatedProjectInfo(Collections.singletonList(launch), - InfoInterval.THREE_MONTHS - ); - - assertEquals("0", investigatedProjectInfo.get(thisWeekFormattedDate).get(0).getValues().get("toInvestigate")); - assertEquals("0", investigatedProjectInfo.get(thisWeekFormattedDate).get(0).getValues().get("investigated")); - } - - @Test - void getTestCasesStatisticsProjectInfo() { - Map<String, List<ChartObject>> testCasesStatisticsProjectInfo = converter.getTestCasesStatisticsProjectInfo(getTestData()); - - assertEquals("18.0", testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("min")); - assertEquals("19.5", testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("avg")); - assertEquals("21.0", testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("max")); - } - - @Test - void getLaunchesQuantity() { - Map<String, List<ChartObject>> launchesQuantity = converter.getLaunchesQuantity(getTestData(), InfoInterval.ONE_MONTH); - - assertEquals("1", launchesQuantity.get(yesterdayString).get(0).getValues().get("count")); - assertEquals("1", launchesQuantity.get(todayString).get(0).getValues().get("count")); - } - - @Test - void getLaunchesQuantityByWeek() { - Map<String, List<ChartObject>> launchesQuantity = converter.getLaunchesQuantity(getTestData(), InfoInterval.THREE_MONTHS); - - assertEquals("2", launchesQuantity.get(thisWeekFormattedDate).get(0).getValues().get("count")); - } - - @Test - void getLaunchesIssues() { - Map<String, List<ChartObject>> launchesIssues = converter.getLaunchesIssues(getTestData(), InfoInterval.ONE_MONTH); - - assertEquals("3", launchesIssues.get(yesterdayString).get(0).getValues().get("systemIssue")); - assertEquals("4", launchesIssues.get(yesterdayString).get(0).getValues().get("toInvestigate")); - assertEquals("2", launchesIssues.get(yesterdayString).get(0).getValues().get("productBug")); - assertEquals("3", launchesIssues.get(yesterdayString).get(0).getValues().get("automationBug")); - - assertEquals("3", launchesIssues.get(todayString).get(0).getValues().get("systemIssue")); - assertEquals("5", launchesIssues.get(todayString).get(0).getValues().get("toInvestigate")); - assertEquals("1", launchesIssues.get(todayString).get(0).getValues().get("productBug")); - assertEquals("4", launchesIssues.get(todayString).get(0).getValues().get("automationBug")); - } - - @Test - void getLaunchesIssuesByWeek() { - Map<String, List<ChartObject>> launchesIssues = converter.getLaunchesIssues(getTestData(), InfoInterval.THREE_MONTHS); - - assertEquals("6", launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("systemIssue")); - assertEquals("9", launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("toInvestigate")); - assertEquals("3", launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("productBug")); - assertEquals("7", launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("automationBug")); - } - - private List<Launch> getTestData() { - Launch launch1 = new Launch(); - launch1.setName("test_launch"); - launch1.setId(1L); - launch1.setNumber(1L); - launch1.setStartTime(LocalDateTime.of(yesterday, LocalTime.now(ZoneOffset.UTC))); - launch1.setStatistics(Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 18), - getStatistics(EXECUTIONS_PASSED, 5), - getStatistics(EXECUTIONS_SKIPPED, 1), - getStatistics(EXECUTIONS_FAILED, 12), - getStatistics(DEFECTS_AUTOMATION_BUG_TOTAL, 3), - getStatistics(DEFECTS_PRODUCT_BUG_TOTAL, 2), - getStatistics(DEFECTS_SYSTEM_ISSUE_TOTAL, 3), - getStatistics(DEFECTS_TO_INVESTIGATE_TOTAL, 4) - )); - Launch launch2 = new Launch(); - launch2.setName("test_launch"); - launch2.setId(2L); - launch2.setNumber(2L); - launch2.setStartTime(LocalDateTime.of(today, LocalTime.now(ZoneOffset.UTC))); - launch2.setStatistics(Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 21), - getStatistics(EXECUTIONS_PASSED, 6), - getStatistics(EXECUTIONS_SKIPPED, 2), - getStatistics(EXECUTIONS_FAILED, 13), - getStatistics(DEFECTS_AUTOMATION_BUG_TOTAL, 4), - getStatistics(DEFECTS_PRODUCT_BUG_TOTAL, 1), - getStatistics(DEFECTS_SYSTEM_ISSUE_TOTAL, 3), - getStatistics(DEFECTS_TO_INVESTIGATE_TOTAL, 5) - )); - return Arrays.asList(launch1, launch2); - } - - private Statistics getStatistics(String statisticsFieldName, int counter) { - Statistics statistics = new Statistics(); - statistics.setStatisticsField(new StatisticsField(statisticsFieldName)); - statistics.setCounter(counter); - return statistics; - } + private ProjectInfoWidgetDataConverter converter; + + private String thisWeekFormattedDate; + + private LocalDate today; + private LocalDate yesterday; + + private String todayString; + private String yesterdayString; + + @BeforeEach + void setUp() { + converter = new ProjectInfoWidgetDataConverter( + ImmutableMap.<InfoInterval, ProjectInfoWidgetDataConverter.ProjectInfoGroup>builder() + .put(InfoInterval.ONE_MONTH, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_DAY) + .put(InfoInterval.THREE_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) + .put(InfoInterval.SIX_MONTHS, ProjectInfoWidgetDataConverter.ProjectInfoGroup.BY_WEEK) + .build()); + + thisWeekFormattedDate = LocalDate.now(ZoneOffset.UTC) + .format(new DateTimeFormatterBuilder().appendValue(IsoFields.WEEK_BASED_YEAR, 4) + .appendLiteral("-W") + .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) + .toFormatter()); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + LocalDate now = LocalDate.now(ZoneOffset.UTC); + today = now.getDayOfWeek().equals(DayOfWeek.MONDAY) ? now.plusDays(2) : now; + yesterday = today.minusDays(1); + + todayString = today.format(formatter); + yesterdayString = yesterday.format(formatter); + } + + @Test + void getInvestigatedProjectInfo() { + Map<String, List<ChartObject>> investigatedProjectInfo = converter.getInvestigatedProjectInfo( + getTestData(), + InfoInterval.ONE_MONTH + ); + + assertEquals("33.33", + investigatedProjectInfo.get(yesterdayString).get(0).getValues().get("toInvestigate")); + assertEquals("66.67", + investigatedProjectInfo.get(yesterdayString).get(0).getValues().get("investigated")); + + assertEquals("38.46", + investigatedProjectInfo.get(todayString).get(0).getValues().get("toInvestigate")); + assertEquals("61.54", + investigatedProjectInfo.get(todayString).get(0).getValues().get("investigated")); + } + + @Test + void getInvestigatedProjectInfoWithoutDefectsStatistics() { + Launch launch = new Launch(); + launch.setName("test_launch"); + launch.setId(1L); + launch.setNumber(1L); + launch.setStartTime(LocalDateTime.now(ZoneOffset.UTC)); + launch.setStatistics( + Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 5), getStatistics(EXECUTIONS_PASSED, 5))); + + Map<String, List<ChartObject>> investigatedProjectInfo = converter.getInvestigatedProjectInfo( + Collections.singletonList(launch), + InfoInterval.THREE_MONTHS + ); + + assertEquals("0", + investigatedProjectInfo.get(thisWeekFormattedDate).get(0).getValues().get("toInvestigate")); + assertEquals("0", + investigatedProjectInfo.get(thisWeekFormattedDate).get(0).getValues().get("investigated")); + } + + @Test + void getTestCasesStatisticsProjectInfo() { + Map<String, List<ChartObject>> testCasesStatisticsProjectInfo = converter.getTestCasesStatisticsProjectInfo( + getTestData()); + + assertEquals("18.0", + testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("min")); + assertEquals("19.5", + testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("avg")); + assertEquals("21.0", + testCasesStatisticsProjectInfo.get("test_launch").get(0).getValues().get("max")); + } + + @Test + void getLaunchesQuantity() { + Map<String, List<ChartObject>> launchesQuantity = converter.getLaunchesQuantity(getTestData(), + InfoInterval.ONE_MONTH); + + assertEquals("1", launchesQuantity.get(yesterdayString).get(0).getValues().get("count")); + assertEquals("1", launchesQuantity.get(todayString).get(0).getValues().get("count")); + } + + @Test + void getLaunchesQuantityByWeek() { + Map<String, List<ChartObject>> launchesQuantity = converter.getLaunchesQuantity(getTestData(), + InfoInterval.THREE_MONTHS); + + assertEquals("2", launchesQuantity.get(thisWeekFormattedDate).get(0).getValues().get("count")); + } + + @Test + void getLaunchesIssues() { + Map<String, List<ChartObject>> launchesIssues = converter.getLaunchesIssues(getTestData(), + InfoInterval.ONE_MONTH); + + assertEquals("3", launchesIssues.get(yesterdayString).get(0).getValues().get("systemIssue")); + assertEquals("4", launchesIssues.get(yesterdayString).get(0).getValues().get("toInvestigate")); + assertEquals("2", launchesIssues.get(yesterdayString).get(0).getValues().get("productBug")); + assertEquals("3", launchesIssues.get(yesterdayString).get(0).getValues().get("automationBug")); + + assertEquals("3", launchesIssues.get(todayString).get(0).getValues().get("systemIssue")); + assertEquals("5", launchesIssues.get(todayString).get(0).getValues().get("toInvestigate")); + assertEquals("1", launchesIssues.get(todayString).get(0).getValues().get("productBug")); + assertEquals("4", launchesIssues.get(todayString).get(0).getValues().get("automationBug")); + } + + @Test + void getLaunchesIssuesByWeek() { + Map<String, List<ChartObject>> launchesIssues = converter.getLaunchesIssues(getTestData(), + InfoInterval.THREE_MONTHS); + + assertEquals("6", + launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("systemIssue")); + assertEquals("9", + launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("toInvestigate")); + assertEquals("3", + launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("productBug")); + assertEquals("7", + launchesIssues.get(thisWeekFormattedDate).get(0).getValues().get("automationBug")); + } + + private List<Launch> getTestData() { + Launch launch1 = new Launch(); + launch1.setName("test_launch"); + launch1.setId(1L); + launch1.setNumber(1L); + launch1.setStartTime(LocalDateTime.of(yesterday, LocalTime.now(ZoneOffset.UTC))); + launch1.setStatistics(Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 18), + getStatistics(EXECUTIONS_PASSED, 5), + getStatistics(EXECUTIONS_SKIPPED, 1), + getStatistics(EXECUTIONS_FAILED, 12), + getStatistics(DEFECTS_AUTOMATION_BUG_TOTAL, 3), + getStatistics(DEFECTS_PRODUCT_BUG_TOTAL, 2), + getStatistics(DEFECTS_SYSTEM_ISSUE_TOTAL, 3), + getStatistics(DEFECTS_TO_INVESTIGATE_TOTAL, 4) + )); + Launch launch2 = new Launch(); + launch2.setName("test_launch"); + launch2.setId(2L); + launch2.setNumber(2L); + launch2.setStartTime(LocalDateTime.of(today, LocalTime.now(ZoneOffset.UTC))); + launch2.setStatistics(Sets.newHashSet(getStatistics(EXECUTIONS_TOTAL, 21), + getStatistics(EXECUTIONS_PASSED, 6), + getStatistics(EXECUTIONS_SKIPPED, 2), + getStatistics(EXECUTIONS_FAILED, 13), + getStatistics(DEFECTS_AUTOMATION_BUG_TOTAL, 4), + getStatistics(DEFECTS_PRODUCT_BUG_TOTAL, 1), + getStatistics(DEFECTS_SYSTEM_ISSUE_TOTAL, 3), + getStatistics(DEFECTS_TO_INVESTIGATE_TOTAL, 5) + )); + return Arrays.asList(launch1, launch2); + } + + private Statistics getStatistics(String statisticsFieldName, int counter) { + Statistics statistics = new Statistics(); + statistics.setStatisticsField(new StatisticsField(statisticsFieldName)); + statistics.setCounter(counter); + return statistics; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImplTest.java index 47e24bb867..efa9b5b70c 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/CreateProjectSettingsHandlerImplTest.java @@ -1,121 +1,127 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.core.project.settings.impl; - -import com.epam.ta.reportportal.commons.ReportPortalUser; -import com.epam.ta.reportportal.dao.ProjectRepository; -import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; -import com.epam.ta.reportportal.entity.item.issue.IssueGroup; -import com.epam.ta.reportportal.entity.item.issue.IssueType; -import com.epam.ta.reportportal.entity.project.Project; -import com.epam.ta.reportportal.entity.project.ProjectIssueType; -import com.epam.ta.reportportal.entity.project.ProjectRole; -import com.epam.ta.reportportal.entity.user.UserRole; -import com.epam.ta.reportportal.exception.ReportPortalException; -import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - -/** - * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> - */ -@ExtendWith(MockitoExtension.class) -class CreateProjectSettingsHandlerImplTest { - - @Mock - private ProjectRepository projectRepository; - - @InjectMocks - private CreateProjectSettingsHandlerImpl handler; - - @Test - void createSubtypeOnNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, new CreateIssueSubTypeRQ()) - ); - - assertEquals("Project 'test_project' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void createSubtypeWithWrongGroup() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); - - CreateIssueSubTypeRQ createIssueSubTypeRQ = new CreateIssueSubTypeRQ(); - createIssueSubTypeRQ.setTypeRef("wrongType"); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, createIssueSubTypeRQ) - ); - - assertEquals("Error in handled Request. Please, check specified parameters: 'wrongType'", exception.getMessage()); - } - - @Test - void maxSubtypesCount() { - Project project = new Project(); - project.setProjectIssueTypes(getSubTypes()); - - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(project)); - - CreateIssueSubTypeRQ createIssueSubTypeRQ = new CreateIssueSubTypeRQ(); - createIssueSubTypeRQ.setTypeRef("product_bug"); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, createIssueSubTypeRQ) - ); - - assertEquals("Incorrect Request. Sub Issues count is bound of size limit", exception.getMessage()); - } - - private Set<ProjectIssueType> getSubTypes() { - HashSet<ProjectIssueType> subTypes = new HashSet<>(); - for (int i = 1; i < 16; i++) { - IssueType issueType = new IssueType(); - issueType.setId((long) i); - issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); - ProjectIssueType projectIssueType = new ProjectIssueType(); - projectIssueType.setIssueType(issueType); - subTypes.add(projectIssueType); - } - return subTypes; - } +/* + * Copyright 2019 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.impl; + +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.dao.ProjectRepository; +import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; +import com.epam.ta.reportportal.entity.item.issue.IssueGroup; +import com.epam.ta.reportportal.entity.item.issue.IssueType; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.ProjectIssueType; +import com.epam.ta.reportportal.entity.project.ProjectRole; +import com.epam.ta.reportportal.entity.user.UserRole; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.model.ValidationConstraints; +import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> + */ +@ExtendWith(MockitoExtension.class) +class CreateProjectSettingsHandlerImplTest { + + @Mock + private ProjectRepository projectRepository; + + @InjectMocks + private CreateProjectSettingsHandlerImpl handler; + + @Test + void createSubtypeOnNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, new CreateIssueSubTypeRQ()) + ); + + assertEquals("Project 'test_project' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void createSubtypeWithWrongGroup() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); + + CreateIssueSubTypeRQ createIssueSubTypeRQ = new CreateIssueSubTypeRQ(); + createIssueSubTypeRQ.setTypeRef("wrongType"); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, createIssueSubTypeRQ) + ); + + assertEquals("Error in handled Request. Please, check specified parameters: 'wrongType'", + exception.getMessage()); + } + + @Test + void maxSubtypesCount() { + Project project = new Project(); + project.setProjectIssueTypes(getSubTypes()); + + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(project)); + + CreateIssueSubTypeRQ createIssueSubTypeRQ = new CreateIssueSubTypeRQ(); + createIssueSubTypeRQ.setTypeRef("product_bug"); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createProjectIssueSubType(TEST_PROJECT_NAME, user, createIssueSubTypeRQ) + ); + + assertEquals("Incorrect Request. Sub Issues count is bound of size limit", + exception.getMessage()); + } + + private Set<ProjectIssueType> getSubTypes() { + HashSet<ProjectIssueType> subTypes = new HashSet<>(); + for (int i = 1; i < ValidationConstraints.MAX_ISSUE_TYPES_AND_SUBTYPES + 1; i++) { + IssueType issueType = new IssueType(); + issueType.setId((long) i); + issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); + ProjectIssueType projectIssueType = new ProjectIssueType(); + projectIssueType.setIssueType(issueType); + subTypes.add(projectIssueType); + } + return subTypes; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/DeleteProjectSettingsHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/DeleteProjectSettingsHandlerImplTest.java index 3a317a1ab9..1a1b02a4bc 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/DeleteProjectSettingsHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/DeleteProjectSettingsHandlerImplTest.java @@ -16,64 +16,66 @@ package com.epam.ta.reportportal.core.project.settings.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class DeleteProjectSettingsHandlerImplTest { - @Mock - private ProjectRepository projectRepository; + @Mock + private ProjectRepository projectRepository; - @InjectMocks - private DeleteProjectSettingsHandlerImpl handler; + @InjectMocks + private DeleteProjectSettingsHandlerImpl handler; - @Test - void deleteSubtypeOnNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); + @Test + void deleteSubtypeOnNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteProjectIssueSubType(TEST_PROJECT_NAME, user, 1L) - ); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteProjectIssueSubType(TEST_PROJECT_NAME, user, 1L) + ); - assertEquals("Project 'test_project' not found. Did you use correct project name?", exception.getMessage()); - } + assertEquals("Project 'test_project' not found. Did you use correct project name?", + exception.getMessage()); + } - @Test - void deleteNotExistSubtype() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); + @Test + void deleteNotExistSubtype() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.deleteProjectIssueSubType(TEST_PROJECT_NAME, user, 1L) - ); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.deleteProjectIssueSubType(TEST_PROJECT_NAME, user, 1L) + ); - assertEquals("Issue Type '1' not found.", exception.getMessage()); - } + assertEquals("Issue Type '1' not found.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImplTest.java index 7d06b5312a..8ad3cb5261 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/GetProjectSettingsHandlerImplTest.java @@ -16,44 +16,41 @@ package com.epam.ta.reportportal.core.project.settings.impl; -import com.epam.ta.reportportal.commons.ReportPortalUser; +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.ProjectRepository; -import com.epam.ta.reportportal.entity.project.ProjectRole; -import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class GetProjectSettingsHandlerImplTest { - @Mock - private ProjectRepository repository; + @Mock + private ProjectRepository repository; - @InjectMocks - private GetProjectSettingsHandlerImpl handler; + @InjectMocks + private GetProjectSettingsHandlerImpl handler; - @Test - void getProjectSettingOnNotExistProject() { + @Test + void getProjectSettingOnNotExistProject() { - when(repository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); + when(repository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.getProjectSettings(TEST_PROJECT_NAME)); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getProjectSettings(TEST_PROJECT_NAME)); - assertEquals("Project 'test_project' not found. Did you use correct project name?", exception.getMessage()); - } + assertEquals("Project 'test_project' not found. Did you use correct project name?", + exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImplTest.java index d674ad2094..1fc6cc5d61 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/impl/UpdateProjectSettingsHandlerImplTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.project.settings.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.dao.ProjectRepository; import com.epam.ta.reportportal.entity.project.Project; @@ -24,96 +30,94 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.project.config.UpdateIssueSubTypeRQ; import com.epam.ta.reportportal.ws.model.project.config.UpdateOneIssueSubTypeRQ; +import java.util.Collections; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.TEST_PROJECT_NAME; -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class UpdateProjectSettingsHandlerImplTest { - @Mock - private ProjectRepository projectRepository; - - @InjectMocks - private UpdateProjectSettingsHandlerImpl handler; - - @Test - void emptyRequest() { - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); - - UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); - updateIssueSubTypeRQ.setIds(Collections.emptyList()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateProjectIssueSubType("test_project", user, updateIssueSubTypeRQ) - ); - assertEquals("Forbidden operation. Please specify at least one item data for update.", exception.getMessage()); - } - - @Test - void updateSubtypeOnNotExistProject() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); - updateIssueSubTypeRQ.setIds(Collections.singletonList(new UpdateOneIssueSubTypeRQ())); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) - ); - assertEquals("Project 'test_project' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void updateSubtypeWithIncorrectGroup() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); - UpdateOneIssueSubTypeRQ oneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); - oneIssueSubTypeRQ.setTypeRef("wrongType"); - updateIssueSubTypeRQ.setIds(Collections.singletonList(oneIssueSubTypeRQ)); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) - ); - assertEquals("Issue Type 'wrongType' not found.", exception.getMessage()); - } - - @Test - void updateNotExistSubtype() { - long projectId = 1L; - ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, projectId); - - UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); - UpdateOneIssueSubTypeRQ oneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); - oneIssueSubTypeRQ.setTypeRef("product_bug"); - oneIssueSubTypeRQ.setLocator("locator"); - updateIssueSubTypeRQ.setIds(Collections.singletonList(oneIssueSubTypeRQ)); - - when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); - - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) - ); - assertEquals("Issue Type 'locator' not found.", exception.getMessage()); - } + @Mock + private ProjectRepository projectRepository; + + @InjectMocks + private UpdateProjectSettingsHandlerImpl handler; + + @Test + void emptyRequest() { + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, 1L); + + UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); + updateIssueSubTypeRQ.setIds(Collections.emptyList()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateProjectIssueSubType("test_project", user, updateIssueSubTypeRQ) + ); + assertEquals("Forbidden operation. Please specify at least one item data for update.", + exception.getMessage()); + } + + @Test + void updateSubtypeOnNotExistProject() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); + updateIssueSubTypeRQ.setIds(Collections.singletonList(new UpdateOneIssueSubTypeRQ())); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.empty()); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) + ); + assertEquals("Project 'test_project' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void updateSubtypeWithIncorrectGroup() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); + UpdateOneIssueSubTypeRQ oneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); + oneIssueSubTypeRQ.setTypeRef("wrongType"); + updateIssueSubTypeRQ.setIds(Collections.singletonList(oneIssueSubTypeRQ)); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) + ); + assertEquals("Issue Type 'wrongType' not found.", exception.getMessage()); + } + + @Test + void updateNotExistSubtype() { + long projectId = 1L; + ReportPortalUser user = getRpUser("user", UserRole.USER, ProjectRole.PROJECT_MANAGER, + projectId); + + UpdateIssueSubTypeRQ updateIssueSubTypeRQ = new UpdateIssueSubTypeRQ(); + UpdateOneIssueSubTypeRQ oneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); + oneIssueSubTypeRQ.setTypeRef("product_bug"); + oneIssueSubTypeRQ.setLocator("locator"); + updateIssueSubTypeRQ.setIds(Collections.singletonList(oneIssueSubTypeRQ)); + + when(projectRepository.findByName(TEST_PROJECT_NAME)).thenReturn(Optional.of(new Project())); + + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.updateProjectIssueSubType(TEST_PROJECT_NAME, user, updateIssueSubTypeRQ) + ); + assertEquals("Issue Type 'locator' not found.", exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImplTest.java new file mode 100644 index 0000000000..d9ef4bc959 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/CreateProjectNotificationHandlerImplTest.java @@ -0,0 +1,166 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static com.epam.ta.reportportal.commons.validation.Suppliers.formattedSupplier; +import static com.epam.ta.reportportal.ws.model.ErrorType.BAD_REQUEST_ERROR; +import static com.epam.ta.reportportal.ws.model.ErrorType.RESOURCE_ALREADY_EXISTS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.project.validator.notification.ProjectNotificationValidator; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.enums.LogicalOperator; +import com.epam.ta.reportportal.entity.enums.SendCase; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.LaunchAttributeRule; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class CreateProjectNotificationHandlerImplTest { + + private static final long DEFAULT_PROJECT_ID = 1L; + private static final String DEFAULT_RULE_NAME = "Rule1"; + + private final SenderCaseRepository senderCaseRepository = mock(SenderCaseRepository.class); + private final MessageBus messageBus = mock(MessageBus.class); + private final ProjectConverter projectConverter = mock(ProjectConverter.class); + private final ProjectNotificationValidator projectNotificationValidator = new ProjectNotificationValidator( + senderCaseRepository); + + private final CreateProjectNotificationHandlerImpl service = new CreateProjectNotificationHandlerImpl( + senderCaseRepository, messageBus, + projectConverter, projectNotificationValidator); + + private SenderCaseDTO createNotificationRQ; + private Project project; + private ReportPortalUser rpUser; + + @BeforeEach + public void beforeEach() { + createNotificationRQ = new SenderCaseDTO(); + createNotificationRQ.setSendCase("always"); + createNotificationRQ.setRuleName(DEFAULT_RULE_NAME); + createNotificationRQ.setAttributesOperator(LogicalOperator.AND.getOperator()); + createNotificationRQ.setRecipients(Collections.singletonList("OWNER")); + createNotificationRQ.setLaunchNames(Collections.singletonList("test launch")); + createNotificationRQ.setEnabled(true); + ItemAttributeResource launchAttribute = new ItemAttributeResource(); + launchAttribute.setKey("key"); + launchAttribute.setValue("val"); + createNotificationRQ.setAttributes(Sets.newHashSet(launchAttribute)); + + project = mock(Project.class); + when(project.getId()).thenReturn(DEFAULT_PROJECT_ID); + + rpUser = mock(ReportPortalUser.class); + } + + @Test + public void createNotificationWithExistingRuleNameTest() { + SenderCase existingSenderCase = mock(SenderCase.class); + + when(senderCaseRepository.findByProjectIdAndRuleNameIgnoreCase(DEFAULT_PROJECT_ID, + DEFAULT_RULE_NAME)) + .thenReturn(Optional.of(existingSenderCase)); + + assertEquals( + assertThrows(ReportPortalException.class, + () -> service.createNotification(project, createNotificationRQ, rpUser) + ).getMessage(), + formattedSupplier(RESOURCE_ALREADY_EXISTS.getDescription(), + createNotificationRQ.getRuleName()).get() + ); + } + + @Test + public void createNotificationWithNonExistingSendCaseTest() { + createNotificationRQ.setSendCase("NonExistingSendCase"); + + assertEquals( + assertThrows(ReportPortalException.class, + () -> service.createNotification(project, createNotificationRQ, rpUser) + ).getMessage(), + formattedSupplier(BAD_REQUEST_ERROR.getDescription(), + createNotificationRQ.getSendCase()).get() + ); + } + + @Test + public void createNotificationWithNullOrEmptyRecipientsTest() { + createNotificationRQ.setRecipients(null); + + assertTrue( + assertThrows(ReportPortalException.class, + () -> service.createNotification(project, createNotificationRQ, rpUser)) + .getMessage().contains("Recipients list should not be null") + ); + + createNotificationRQ.setRecipients(Collections.emptyList()); + + assertTrue( + assertThrows(ReportPortalException.class, + () -> service.createNotification(project, createNotificationRQ, rpUser)) + .getMessage().contains("Empty recipients list for email case") + ); + } + + @Test + public void createNotificationWithDuplicateContentButWithDifferentRuleNameTest() { + SenderCase dupeCreateNotificationRQ = mock(SenderCase.class); + when(dupeCreateNotificationRQ.getSendCase()).thenReturn(SendCase.ALWAYS); + when(dupeCreateNotificationRQ.getRuleName()).thenReturn("Rule2"); + when(dupeCreateNotificationRQ.getAttributesOperator()).thenReturn(LogicalOperator.AND); + when(dupeCreateNotificationRQ.getRecipients()).thenReturn(Collections.singleton("OWNER")); + when(dupeCreateNotificationRQ.getLaunchNames()).thenReturn( + Collections.singleton("test launch")); + when(dupeCreateNotificationRQ.isEnabled()).thenReturn(true); + when(dupeCreateNotificationRQ.getProject()).thenReturn(project); + + LaunchAttributeRule launchAttribute = mock(LaunchAttributeRule.class); + when(launchAttribute.getKey()).thenReturn("key"); + when(launchAttribute.getValue()).thenReturn("val"); + when(dupeCreateNotificationRQ.getLaunchAttributeRules()).thenReturn( + Collections.singleton(launchAttribute)); + + when(senderCaseRepository.findAllByProjectId(DEFAULT_PROJECT_ID)).thenReturn( + Collections.singletonList(dupeCreateNotificationRQ)); + + assertTrue( + assertThrows(ReportPortalException.class, + () -> service.createNotification(project, createNotificationRQ, rpUser)) + .getMessage().contains("Project email settings contain duplicate cases") + ); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImplTest.java new file mode 100644 index 0000000000..36c1ca6eb8 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/DeleteProjectNotificationHandlerImplTest.java @@ -0,0 +1,87 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class DeleteProjectNotificationHandlerImplTest { + + private final SenderCaseRepository senderCaseRepository = mock(SenderCaseRepository.class); + private final MessageBus messageBus = mock(MessageBus.class); + private final ProjectConverter projectConverter = mock(ProjectConverter.class); + + private final DeleteProjectNotificationHandlerImpl service = new DeleteProjectNotificationHandlerImpl( + senderCaseRepository, messageBus, + projectConverter); + + private Project project; + private ReportPortalUser rpUser; + + @BeforeEach + public void beforeEach() { + project = mock(Project.class); + when(project.getId()).thenReturn(1L); + + rpUser = mock(ReportPortalUser.class); + } + + @Test + public void deleteNonExistingNotificationTest() { + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.deleteNotification(project, 1L, rpUser)) + .getMessage().contains("Did you use correct Notification ID?") + ); + } + + @Test + public void deleteNotificationButWithDifferentProjectTest() { + SenderCase sc = mock(SenderCase.class); + Project scProject = mock(Project.class); + + when(scProject.getId()).thenReturn(2L); + when(sc.getProject()).thenReturn(scProject); + when(senderCaseRepository.findById(any())).thenReturn(Optional.of(sc)); + + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.deleteNotification(project, 1L, rpUser)) + .getMessage().contains("Did you use correct Notification ID?") + ); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImplTest.java new file mode 100644 index 0000000000..053a78687a --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/GetProjectNotificationsHandlerImplTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static com.epam.ta.reportportal.entity.enums.SendCase.ALWAYS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.enums.LogicalOperator; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class GetProjectNotificationsHandlerImplTest { + + private static final Long DEFAULT_PROJECT_ID = 1L; + private static final Long DEFAULT_SENDER_CASE_1_ID = 1L; + private static final Long DEFAULT_SENDER_CASE_2_ID = 2L; + private static final String DEFAULT_SENDER_CASE_1_RULE_NAME = "rule #" + DEFAULT_SENDER_CASE_1_ID; + private static final String DEFAULT_SENDER_CASE_2_RULE_NAME = "rule #" + DEFAULT_SENDER_CASE_2_ID; + + private final SenderCaseRepository senderCaseRepository = mock(SenderCaseRepository.class); + private final GetProjectNotificationsHandlerImpl getProjectNotificationsHandler = + new GetProjectNotificationsHandlerImpl(senderCaseRepository); + + @Test + public void getProjectNotificationsTest() { + SenderCase senderCase1 = mock(SenderCase.class); + SenderCase senderCase2 = mock(SenderCase.class); + + when(senderCase1.getId()).thenReturn(DEFAULT_SENDER_CASE_1_ID); + when(senderCase1.getRuleName()).thenReturn(DEFAULT_SENDER_CASE_1_RULE_NAME); + when(senderCase1.getSendCase()).thenReturn(ALWAYS); + when(senderCase2.getId()).thenReturn(DEFAULT_SENDER_CASE_2_ID); + when(senderCase2.getRuleName()).thenReturn(DEFAULT_SENDER_CASE_2_RULE_NAME); + when(senderCase2.getSendCase()).thenReturn(ALWAYS); + when(senderCase1.getAttributesOperator()).thenReturn(LogicalOperator.AND); + when(senderCase2.getAttributesOperator()).thenReturn(LogicalOperator.AND); + + when(senderCaseRepository.findAllByProjectId(DEFAULT_PROJECT_ID)).thenReturn( + List.of(senderCase1, senderCase2)); + + List<SenderCaseDTO> result = getProjectNotificationsHandler.getProjectNotifications( + DEFAULT_PROJECT_ID); + assertEquals(2, result.size()); + } +} diff --git a/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImplTest.java new file mode 100644 index 0000000000..6dc76d2921 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/project/settings/notification/UpdateProjectNotificationHandlerImplTest.java @@ -0,0 +1,202 @@ +/* + * + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + * + */ + +package com.epam.ta.reportportal.core.project.settings.notification; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.project.validator.notification.ProjectNotificationValidator; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.enums.LogicalOperator; +import com.epam.ta.reportportal.entity.enums.SendCase; +import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.project.email.LaunchAttributeRule; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.exception.ReportPortalException; +import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; +import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class UpdateProjectNotificationHandlerImplTest { + + private static final long DEFAULT_PROJECT_ID = 1L; + private static final String DEFAULT_RULE_NAME = "Rule1"; + + private final SenderCaseRepository senderCaseRepository = mock(SenderCaseRepository.class); + private final MessageBus messageBus = mock(MessageBus.class); + private final ProjectConverter projectConverter = mock(ProjectConverter.class); + private final ProjectNotificationValidator projectNotificationValidator = new ProjectNotificationValidator( + senderCaseRepository); + + private final UpdateProjectNotificationHandlerImpl service = new UpdateProjectNotificationHandlerImpl( + senderCaseRepository, messageBus, + projectConverter, projectNotificationValidator); + + private SenderCaseDTO updateNotificationRQ; + private Project project; + private ReportPortalUser rpUser; + + @BeforeEach + public void beforeEach() { + updateNotificationRQ = new SenderCaseDTO(); + updateNotificationRQ.setId(1L); + updateNotificationRQ.setSendCase("always"); + updateNotificationRQ.setAttributesOperator(LogicalOperator.AND.getOperator()); + updateNotificationRQ.setRuleName(DEFAULT_RULE_NAME); + updateNotificationRQ.setRecipients(Collections.singletonList("OWNER")); + updateNotificationRQ.setLaunchNames(Collections.singletonList("test launch")); + updateNotificationRQ.setEnabled(true); + ItemAttributeResource launchAttribute = new ItemAttributeResource(); + launchAttribute.setKey("key"); + launchAttribute.setValue("val"); + updateNotificationRQ.setAttributes(Sets.newHashSet(launchAttribute)); + + project = mock(Project.class); + when(project.getId()).thenReturn(DEFAULT_PROJECT_ID); + + rpUser = mock(ReportPortalUser.class); + } + + @Test + public void updateNonExistingNotificationTest() { + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage().contains("Did you use correct Notification ID?") + ); + } + + @Test + public void updateNotificationButWithDifferentProjectTest() { + SenderCase sc = mock(SenderCase.class); + Project scProject = mock(Project.class); + + when(scProject.getId()).thenReturn(2L); + when(sc.getProject()).thenReturn(scProject); + when(senderCaseRepository.findById(any())).thenReturn(Optional.of(sc)); + + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage().contains("Did you use correct Notification ID?") + ); + } + + @Test + public void updateNotificationWithNonExistingSendCaseTest() { + SenderCase sc = mock(SenderCase.class); + Project project = mock(Project.class); + + when(project.getId()).thenReturn(1L); + when(sc.getProject()).thenReturn(project); + when(senderCaseRepository.findById(any())).thenReturn(Optional.of(sc)); + + updateNotificationRQ.setSendCase("NonExistingSendCase"); + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage().contains(updateNotificationRQ.getSendCase()) + ); + } + + @Test + public void updateNotificationWithNullOrEmptyRecipientsTest() { + SenderCase sc = mock(SenderCase.class); + Project project = mock(Project.class); + + when(project.getId()).thenReturn(DEFAULT_PROJECT_ID); + when(sc.getProject()).thenReturn(project); + when(senderCaseRepository.findById(any())).thenReturn(Optional.of(sc)); + + updateNotificationRQ.setRecipients(null); + String s = assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage(); + Assertions.assertTrue(s.contains("Recipients list should not be null")); + + updateNotificationRQ.setRecipients(Collections.emptyList()); + + Assertions.assertTrue( + assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage().contains("Empty recipients list for email case") + ); + } + + @Test + public void updateNotificationWithDuplicateContentButWithDifferentRuleNameTest() { + SenderCase sc = mock(SenderCase.class); + Project project = mock(Project.class); + + when(project.getId()).thenReturn(DEFAULT_PROJECT_ID); + when(sc.getProject()).thenReturn(project); + when(senderCaseRepository.findById(any())).thenReturn(Optional.of(sc)); + + SenderCase modelForUpdate = mock(SenderCase.class); + when(modelForUpdate.getId()).thenReturn(1L); + when(modelForUpdate.getSendCase()).thenReturn(SendCase.ALWAYS); + when(modelForUpdate.getRuleName()).thenReturn("Rule2"); + when(modelForUpdate.getAttributesOperator()).thenReturn(LogicalOperator.AND); + when(modelForUpdate.getRecipients()).thenReturn(Collections.singleton("OWNER")); + when(modelForUpdate.getLaunchNames()).thenReturn(Collections.singleton("test launch1")); + when(modelForUpdate.isEnabled()).thenReturn(true); + when(modelForUpdate.getProject()).thenReturn(project); + + SenderCase dupeUpdateNotification = mock(SenderCase.class); + when(dupeUpdateNotification.getId()).thenReturn(2L); + when(dupeUpdateNotification.getSendCase()).thenReturn(SendCase.ALWAYS); + when(dupeUpdateNotification.getRuleName()).thenReturn("Rule3"); + when(dupeUpdateNotification.getAttributesOperator()).thenReturn(LogicalOperator.AND); + when(dupeUpdateNotification.getRecipients()).thenReturn(Collections.singleton("OWNER")); + when(dupeUpdateNotification.getLaunchNames()).thenReturn(Collections.singleton("test launch")); + when(dupeUpdateNotification.isEnabled()).thenReturn(true); + when(dupeUpdateNotification.getProject()).thenReturn(project); + + LaunchAttributeRule launchAttribute = mock(LaunchAttributeRule.class); + when(launchAttribute.getKey()).thenReturn("key"); + when(launchAttribute.getValue()).thenReturn("val"); + when(dupeUpdateNotification.getLaunchAttributeRules()).thenReturn( + Collections.singleton(launchAttribute)); + + when(senderCaseRepository.findAllByProjectId(DEFAULT_PROJECT_ID)).thenReturn( + List.of(modelForUpdate, dupeUpdateNotification)); + + assertTrue( + assertThrows(ReportPortalException.class, + () -> service.updateNotification(project, updateNotificationRQ, rpUser)) + .getMessage().contains("Project email settings contain duplicate cases") + ); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/remover/user/UserContentRemoverTest.java b/src/test/java/com/epam/ta/reportportal/core/remover/user/UserContentRemoverTest.java new file mode 100644 index 0000000000..b870c5b6dc --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/remover/user/UserContentRemoverTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.remover.user; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +import com.epam.ta.reportportal.core.remover.ContentRemover; +import com.epam.ta.reportportal.entity.user.User; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class UserContentRemoverTest { + + private final UserPhotoRemover userPhotoRemover = mock(UserPhotoRemover.class); + private final UserWidgetRemover userWidgetRemover = mock(UserWidgetRemover.class); + private final ContentRemover<User> userContentRemover = new UserContentRemover( + List.of(userWidgetRemover, userPhotoRemover)); + + @Test + public void removeTest() { + User user = mock(User.class); + + userContentRemover.remove(user); + + verify(userWidgetRemover, times(1)).remove(eq(user)); + verify(userPhotoRemover, times(1)).remove(eq(user)); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemoverTest.java b/src/test/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemoverTest.java new file mode 100644 index 0000000000..4081ae4ff1 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/core/remover/user/UserPhotoRemoverTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.core.remover.user; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import com.epam.ta.reportportal.dao.AttachmentRepository; +import com.epam.ta.reportportal.entity.attachment.Attachment; +import com.epam.ta.reportportal.entity.user.User; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * @author <a href="mailto:chingiskhan_kalanov@epam.com">Chingiskhan Kalanov</a> + */ +class UserPhotoRemoverTest { + + private static final String USER_PHOTO_ID = "SOME_PHOTO_ID"; + private static final String USER_THUMBNAIL_ID = "SOME_THUMBNAIL_ID"; + private static final Long ATTACHMENT_PHOTO_ID = 1L; + private static final Long ATTACHMENT_THUMBNAIL_ID = 2L; + + private final AttachmentRepository attachmentRepository = mock(AttachmentRepository.class); + private final UserPhotoRemover userPhotoRemover = new UserPhotoRemover(attachmentRepository); + + @Test + public void removePhotoWithoutPhotoAttachmentTest() { + final User user = mock(User.class); + + userPhotoRemover.remove(user); + + verifyNoInteractions(attachmentRepository); + } + + @Test + public void removePhotoWithoutThumbnailAttachmentTest() { + final User user = mock(User.class); + final Attachment userPhoto = mock(Attachment.class); + + when(user.getAttachment()).thenReturn(USER_PHOTO_ID); + + when(userPhoto.getId()).thenReturn(ATTACHMENT_PHOTO_ID); + when(userPhoto.getFileId()).thenReturn(USER_PHOTO_ID); + + doReturn(userPhoto).when(attachmentRepository) + .save(argThat(argument -> argument.getFileId().equals(USER_PHOTO_ID))); + + userPhotoRemover.remove(user); + + verify(attachmentRepository, times(1)).save(any(Attachment.class)); + verify(attachmentRepository, times(1)).moveForDeletion(eq(List.of(ATTACHMENT_PHOTO_ID))); + } + + @Test + public void removePhotoTest() { + final User user = mock(User.class); + final Attachment userPhoto = mock(Attachment.class); + final Attachment userThumbnail = mock(Attachment.class); + + when(user.getAttachment()).thenReturn(USER_PHOTO_ID); + when(user.getAttachmentThumbnail()).thenReturn(USER_THUMBNAIL_ID); + + when(userPhoto.getId()).thenReturn(ATTACHMENT_PHOTO_ID); + when(userPhoto.getFileId()).thenReturn(USER_PHOTO_ID); + when(userThumbnail.getId()).thenReturn(ATTACHMENT_THUMBNAIL_ID); + when(userThumbnail.getFileId()).thenReturn(USER_THUMBNAIL_ID); + + doReturn(userPhoto).when(attachmentRepository) + .save(argThat(argument -> argument.getFileId().equals(USER_PHOTO_ID))); + doReturn(userThumbnail).when(attachmentRepository) + .save(argThat(argument -> argument.getFileId().equals(USER_THUMBNAIL_ID))); + + userPhotoRemover.remove(user); + + verify(attachmentRepository, times(2)).save(any(Attachment.class)); + verify(attachmentRepository, times(1)).moveForDeletion( + eq(List.of(ATTACHMENT_PHOTO_ID, ATTACHMENT_THUMBNAIL_ID))); + } +} diff --git a/src/test/java/com/epam/ta/reportportal/core/statistics/StatisticsHelperTest.java b/src/test/java/com/epam/ta/reportportal/core/statistics/StatisticsHelperTest.java index 22f3ce33fd..4001bdc333 100644 --- a/src/test/java/com/epam/ta/reportportal/core/statistics/StatisticsHelperTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/statistics/StatisticsHelperTest.java @@ -16,97 +16,102 @@ package com.epam.ta.reportportal.core.statistics; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.entity.statistics.StatisticsField; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class StatisticsHelperTest { - @Test - void emptyStatisticsTest() { - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(new Statistics())) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'Statistics should contain a name field.'", - exception.getMessage() - ); - } + @Test + void emptyStatisticsTest() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(new Statistics())) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Statistics should contain a name field.'", + exception.getMessage() + ); + } - @Test - void passedTest() { - StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(getStatistics("statistics$executions$passed", - 4 - ), - getStatistics("statistics$executions$total", 4), - getStatistics("statistics$executions$failed", 0), - getStatistics("statistics$executions$skipped", 0) - )); - assertEquals(StatusEnum.PASSED, statusFromStatistics); - } + @Test + void passedTest() { + StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics( + Sets.newHashSet(getStatistics("statistics$executions$passed", + 4 + ), + getStatistics("statistics$executions$total", 4), + getStatistics("statistics$executions$failed", 0), + getStatistics("statistics$executions$skipped", 0) + )); + assertEquals(StatusEnum.PASSED, statusFromStatistics); + } - @Test - void failedTest() { - StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(getStatistics("statistics$executions$passed", - 4 - ), - getStatistics("statistics$executions$failed", 2), - getStatistics("statistics$executions$total", 6) - )); - assertEquals(StatusEnum.FAILED, statusFromStatistics); - } + @Test + void failedTest() { + StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics( + Sets.newHashSet(getStatistics("statistics$executions$passed", + 4 + ), + getStatistics("statistics$executions$failed", 2), + getStatistics("statistics$executions$total", 6) + )); + assertEquals(StatusEnum.FAILED, statusFromStatistics); + } - @Test - void skippedTest() { - StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(getStatistics("statistics$executions$passed", - 4 - ), - getStatistics("statistics$executions$skipped", 1), - getStatistics("statistics$executions$total", 5) - )); - assertEquals(StatusEnum.FAILED, statusFromStatistics); - } + @Test + void skippedTest() { + StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics( + Sets.newHashSet(getStatistics("statistics$executions$passed", + 4 + ), + getStatistics("statistics$executions$skipped", 1), + getStatistics("statistics$executions$total", 5) + )); + assertEquals(StatusEnum.FAILED, statusFromStatistics); + } - @Test - void toInvestigateTest() { - StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics(Sets.newHashSet(getStatistics("statistics$executions$passed", - 4 - ), - getStatistics("statistics$defects$to_investigate$total", 1), - getStatistics("statistics$executions$total", 5) - )); - assertEquals(StatusEnum.FAILED, statusFromStatistics); - } + @Test + void toInvestigateTest() { + StatusEnum statusFromStatistics = StatisticsHelper.getStatusFromStatistics( + Sets.newHashSet(getStatistics("statistics$executions$passed", + 4 + ), + getStatistics("statistics$defects$to_investigate$total", 1), + getStatistics("statistics$executions$total", 5) + )); + assertEquals(StatusEnum.FAILED, statusFromStatistics); + } - private Statistics getStatistics(String statisticsFieldName, int counter) { - Statistics statistics = new Statistics(); - statistics.setStatisticsField(new StatisticsField(statisticsFieldName)); - statistics.setCounter(counter); - return statistics; - } + private Statistics getStatistics(String statisticsFieldName, int counter) { + Statistics statistics = new Statistics(); + statistics.setStatisticsField(new StatisticsField(statisticsFieldName)); + statistics.setCounter(counter); + return statistics; + } - @Test - void extractStatisticsCount() { - assertEquals(5, (int) StatisticsHelper.extractStatisticsCount( - "statistics$executions$passed", - Sets.newHashSet(getStatistics("statistics$executions$passed", 5), getStatistics("statistics$executions$total", 5)) - )); - } + @Test + void extractStatisticsCount() { + assertEquals(5, (int) StatisticsHelper.extractStatisticsCount( + "statistics$executions$passed", + Sets.newHashSet(getStatistics("statistics$executions$passed", 5), + getStatistics("statistics$executions$total", 5)) + )); + } - @Test - void defaultStatisticsFields() { - List<String> fields = StatisticsHelper.defaultStatisticsFields().collect(Collectors.toList()); - assertEquals(9, fields.size()); - } + @Test + void defaultStatisticsFields() { + List<String> fields = StatisticsHelper.defaultStatisticsFields().collect(Collectors.toList()); + assertEquals(9, fields.size()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImplTest.java index 7a52442d39..0029766b77 100644 --- a/src/test/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/user/impl/CreateUserHandlerImplTest.java @@ -16,10 +16,29 @@ package com.epam.ta.reportportal.core.user.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.user.impl.CreateUserHandlerImpl.BID_TYPE; +import static com.epam.ta.reportportal.core.user.impl.CreateUserHandlerImpl.INTERNAL_BID_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; +import com.epam.ta.reportportal.core.events.activity.ChangeUserTypeEvent; +import com.epam.ta.reportportal.core.events.activity.CreateInvitationLinkEvent; +import com.epam.ta.reportportal.core.integration.GetIntegrationHandler; import com.epam.ta.reportportal.core.project.GetProjectHandler; import com.epam.ta.reportportal.dao.UserCreationBidRepository; import com.epam.ta.reportportal.dao.UserRepository; +import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; +import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.User; @@ -30,19 +49,15 @@ import com.epam.ta.reportportal.ws.model.user.CreateUserRQ; import com.epam.ta.reportportal.ws.model.user.CreateUserRQConfirm; import com.epam.ta.reportportal.ws.model.user.CreateUserRQFull; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -50,211 +65,293 @@ @ExtendWith(MockitoExtension.class) class CreateUserHandlerImplTest { - @Mock - private UserRepository userRepository; - - @Mock - private GetProjectHandler getProjectHandler; - - @Mock - private UserCreationBidRepository userCreationBidRepository; - - @InjectMocks - private CreateUserHandlerImpl handler; - - @Test - void createByNotExistedAdmin() { - - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - when(userRepository.findRawById(rpUser.getUserId())).thenReturn(Optional.empty()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(new CreateUserRQFull(), rpUser, "url") - ); - assertEquals("User 'admin' not found.", exception.getMessage()); - } - - @Test - void createByNotAdmin() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User user = new User(); - user.setRole(UserRole.USER); - when(userRepository.findRawById(1L)).thenReturn(Optional.of(user)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(new CreateUserRQFull(), rpUser, "url") - ); - assertEquals("You do not have enough permissions. Only administrator can create new user. Your role is - USER", - exception.getMessage() - ); - } - - @Test - void createByAdminUserAlreadyExists() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User creator = new User(); - creator.setRole(UserRole.ADMINISTRATOR); - - doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); - doReturn(Optional.of(new User())).when(userRepository).findByLogin("new_user"); - - final CreateUserRQFull request = new CreateUserRQFull(); - request.setLogin("new_user"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(request, rpUser, "url") - ); - assertEquals("User with 'login='new_user'' already exists. You couldn't create the duplicate.", exception.getMessage()); - } - - @Test - void createByAdminWithIncorrectName() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User creator = new User(); - creator.setRole(UserRole.ADMINISTRATOR); - doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); - doReturn(Optional.empty()).when(userRepository).findByLogin("#$$/"); - - final CreateUserRQFull request = new CreateUserRQFull(); - request.setLogin("#$$/"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(request, rpUser, "url") - ); - assertEquals("Incorrect Request. Username '#$$/' consists only of special characters", exception.getMessage()); - } - - @Test - void createByAdminWithIncorrectEmail() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User creator = new User(); - creator.setRole(UserRole.ADMINISTRATOR); - doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); - doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); - - final CreateUserRQFull request = new CreateUserRQFull(); - request.setLogin("new_user"); - request.setEmail("incorrect@email"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(request, rpUser, "url") - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'email='incorrect@email''", exception.getMessage()); - } - - @Test - void createByAdminWithExistedEmail() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User creator = new User(); - creator.setRole(UserRole.ADMINISTRATOR); - doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); - doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); - when(userRepository.findByEmail("correct@domain.com")).thenReturn(Optional.of(new User())); - - final CreateUserRQFull request = new CreateUserRQFull(); - request.setLogin("new_user"); - request.setEmail("correct@domain.com"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(request, rpUser, "url") - ); - assertEquals("User with 'email='correct@domain.com'' already exists. You couldn't create the duplicate.", exception.getMessage()); - } - - @Test - void createByAdminWithExistedEmailUppercase() { - final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - User creator = new User(); - creator.setRole(UserRole.ADMINISTRATOR); - doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); - doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); - when(userRepository.findByEmail("correct@domain.com")).thenReturn(Optional.of(new User())); - - final CreateUserRQFull request = new CreateUserRQFull(); - request.setLogin("new_user"); - request.setEmail("CORRECT@domain.com"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserByAdmin(request, rpUser, "url") - ); - assertEquals("User with 'email='CORRECT@domain.com'' already exists. You couldn't create the duplicate.", exception.getMessage()); - } - - @Test - void CreateUserBidOnNotExistedProject() { - final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); - - when(getProjectHandler.get("not_exists")).thenThrow(new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, "not_exists")); - - CreateUserRQ request = new CreateUserRQ(); - request.setDefaultProject("not_exists"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUserBid(request, rpUser, "emailUrl") - ); - assertEquals("Project 'not_exists' not found. Did you use correct project name?", exception.getMessage()); - } - - @Test - void createUserWithoutBid() { - when(userCreationBidRepository.findById("uuid")).thenReturn(Optional.empty()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.createUser(new CreateUserRQConfirm(), "uuid") - ); - assertEquals("Incorrect Request. Impossible to register user. UUID expired or already registered.", exception.getMessage()); - } - - @Test - void createAlreadyExistedUser() { - final UserCreationBid creationBid = new UserCreationBid(); - creationBid.setDefaultProject(new Project()); - when(userCreationBidRepository.findById("uuid")).thenReturn(Optional.of(creationBid)); - when(userRepository.findByLogin("test")).thenReturn(Optional.of(new User())); - - final CreateUserRQConfirm request = new CreateUserRQConfirm(); - request.setLogin("test"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createUser(request, "uuid")); - assertEquals("User with 'login='test'' already exists. You couldn't create the duplicate.", exception.getMessage()); - } - - @Test - public void createUserWithIncorrectLogin() { - final UserCreationBid creationBid = new UserCreationBid(); - creationBid.setDefaultProject(new Project()); - when(userCreationBidRepository.findById("uuid")).thenReturn(Optional.of(creationBid)); - when(userRepository.findByLogin("##$%/")).thenReturn(Optional.empty()); - - final CreateUserRQConfirm request = new CreateUserRQConfirm(); - request.setLogin("##$%/"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createUser(request, "uuid")); - assertEquals("Incorrect Request. Username '##$%/' consists only of special characters", exception.getMessage()); - } - - @Test - void createUserWithIncorrectEmail() { - final UserCreationBid bid = new UserCreationBid(); - Project project = new Project(); - project.setName("test_project"); - bid.setDefaultProject(project); - when(userCreationBidRepository.findById("uuid")).thenReturn(Optional.of(bid)); - when(userRepository.findByLogin("test")).thenReturn(Optional.empty()); - - final CreateUserRQConfirm request = new CreateUserRQConfirm(); - request.setLogin("test"); - request.setEmail("incorrect@domain"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createUser(request, "uuid")); - assertEquals("Error in handled Request. Please, check specified parameters: 'email='incorrect@domain''", exception.getMessage()); - } - - @Test - void createUserWithExistedEmail() { - final UserCreationBid bid = new UserCreationBid(); - Project project = new Project(); - project.setName("test_project"); - bid.setDefaultProject(project); - when(userCreationBidRepository.findById("uuid")).thenReturn(Optional.of(bid)); - when(userRepository.findByLogin("test")).thenReturn(Optional.empty()); - when(userRepository.findByEmail("email@domain.com")).thenReturn(Optional.of(new User())); - - final CreateUserRQConfirm request = new CreateUserRQConfirm(); - request.setLogin("test"); - request.setEmail("email@domain.com"); - final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.createUser(request, "uuid")); - assertEquals("User with 'email='email@domain.com'' already exists. You couldn't create the duplicate.", exception.getMessage()); - } + @Mock + private UserRepository userRepository; + + @Mock + private GetProjectHandler getProjectHandler; + + @Mock + private UserCreationBidRepository userCreationBidRepository; + + @Mock + private GetIntegrationHandler getIntegrationHandler; + + @Mock + private ThreadPoolTaskExecutor emailExecutorService; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @InjectMocks + private CreateUserHandlerImpl handler; + + @Test + void createByNotExistedAdmin() { + + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + when(userRepository.findRawById(rpUser.getUserId())).thenReturn(Optional.empty()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(new CreateUserRQFull(), rpUser, "url") + ); + assertEquals("User 'admin' not found.", exception.getMessage()); + } + + @Test + void createByNotAdmin() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User user = new User(); + user.setRole(UserRole.USER); + when(userRepository.findRawById(1L)).thenReturn(Optional.of(user)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(new CreateUserRQFull(), rpUser, "url") + ); + assertEquals( + "You do not have enough permissions. Only administrator can create new user. Your role is - USER", + exception.getMessage() + ); + } + + @Test + void createByAdminUserAlreadyExists() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User creator = new User(); + creator.setRole(UserRole.ADMINISTRATOR); + + doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); + doReturn(Optional.of(new User())).when(userRepository).findByLogin("new_user"); + + final CreateUserRQFull request = new CreateUserRQFull(); + request.setLogin("new_user"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(request, rpUser, "url") + ); + assertEquals("User with 'login='new_user'' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } + + @Test + void createByAdminWithIncorrectName() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User creator = new User(); + creator.setRole(UserRole.ADMINISTRATOR); + doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); + doReturn(Optional.empty()).when(userRepository).findByLogin("#$$/"); + + final CreateUserRQFull request = new CreateUserRQFull(); + request.setLogin("#$$/"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(request, rpUser, "url") + ); + assertEquals("Incorrect Request. Username '#$$/' consists only of special characters", + exception.getMessage()); + } + + @Test + void createByAdminWithIncorrectEmail() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User creator = new User(); + creator.setRole(UserRole.ADMINISTRATOR); + doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); + doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); + + final CreateUserRQFull request = new CreateUserRQFull(); + request.setLogin("new_user"); + request.setEmail("incorrect@email"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(request, rpUser, "url") + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'email='incorrect@email''", + exception.getMessage()); + } + + @Test + void createByAdminWithExistedEmail() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User creator = new User(); + creator.setRole(UserRole.ADMINISTRATOR); + doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); + doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); + when(userRepository.findByEmail("correct@domain.com")).thenReturn(Optional.of(new User())); + + final CreateUserRQFull request = new CreateUserRQFull(); + request.setLogin("new_user"); + request.setEmail("correct@domain.com"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(request, rpUser, "url") + ); + assertEquals( + "User with 'email='correct@domain.com'' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } + + @Test + void createByAdminWithExistedEmailUppercase() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, + ProjectRole.PROJECT_MANAGER, 1L); + User creator = new User(); + creator.setRole(UserRole.ADMINISTRATOR); + doReturn(Optional.of(creator)).when(userRepository).findRawById(rpUser.getUserId()); + doReturn(Optional.empty()).when(userRepository).findByLogin("new_user"); + when(userRepository.findByEmail("correct@domain.com")).thenReturn(Optional.of(new User())); + + final CreateUserRQFull request = new CreateUserRQFull(); + request.setLogin("new_user"); + request.setEmail("CORRECT@domain.com"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserByAdmin(request, rpUser, "url") + ); + assertEquals( + "User with 'email='CORRECT@domain.com'' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } + + @Test + void createUserBid() { + final ReportPortalUser rpUser = getRpUser("admin", UserRole.ADMINISTRATOR, ProjectRole.MEMBER, + 1L); + final String projectName = "test_project"; + final String email = "email@mail.com"; + final String role = ProjectRole.MEMBER.name(); + + final Project project = new Project(); + project.setId(1L); + project.setName(projectName); + + when(getProjectHandler.get(projectName)).thenReturn(project); + when(userRepository.existsById(rpUser.getUserId())).thenReturn(true); + when(getIntegrationHandler.getEnabledByProjectIdOrGlobalAndIntegrationGroup(project.getId(), + IntegrationGroupEnum.NOTIFICATION + )).thenReturn(Optional.of(new Integration())); + doNothing().when(emailExecutorService).execute(any()); + doNothing().when(eventPublisher).publishEvent(isA(CreateInvitationLinkEvent.class)); + + CreateUserRQ request = new CreateUserRQ(); + request.setDefaultProject(projectName); + request.setEmail(email); + request.setRole(role); + + handler.createUserBid(request, rpUser, "emailUrl"); + + final ArgumentCaptor<UserCreationBid> bidCaptor = ArgumentCaptor.forClass( + UserCreationBid.class); + verify(userCreationBidRepository, times(1)).save(bidCaptor.capture()); + + final UserCreationBid bid = bidCaptor.getValue(); + + assertEquals(projectName, bid.getProjectName()); + assertEquals(email, bid.getEmail()); + assertEquals(role, bid.getRole()); + assertNotNull(bid.getMetadata()); + + assertEquals(INTERNAL_BID_TYPE, String.valueOf(bid.getMetadata().getMetadata().get(BID_TYPE))); + + } + + @Test + void CreateUserBidOnNotExistedProject() { + final ReportPortalUser rpUser = getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L); + + when(getProjectHandler.get("not_exists")).thenThrow( + new ReportPortalException(ErrorType.PROJECT_NOT_FOUND, "not_exists")); + + CreateUserRQ request = new CreateUserRQ(); + request.setDefaultProject("not_exists"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUserBid(request, rpUser, "emailUrl") + ); + assertEquals("Project 'not_exists' not found. Did you use correct project name?", + exception.getMessage()); + } + + @Test + void createUserWithoutBid() { + when(userCreationBidRepository.findByUuidAndType("uuid", INTERNAL_BID_TYPE)).thenReturn( + Optional.empty()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUser(new CreateUserRQConfirm(), "uuid") + ); + assertEquals( + "Incorrect Request. Impossible to register user. UUID expired or already registered.", + exception.getMessage()); + } + + @Test + void createAlreadyExistedUser() { + final UserCreationBid creationBid = new UserCreationBid(); + creationBid.setProjectName("project"); + when(userCreationBidRepository.findByUuidAndType("uuid", INTERNAL_BID_TYPE)).thenReturn( + Optional.of(creationBid)); + when(userRepository.findByLogin("test")).thenReturn(Optional.of(new User())); + + final CreateUserRQConfirm request = new CreateUserRQConfirm(); + request.setLogin("test"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUser(request, "uuid")); + assertEquals("User with 'login='test'' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } + + @Test + public void createUserWithIncorrectLogin() { + final UserCreationBid creationBid = new UserCreationBid(); + creationBid.setProjectName("project"); + when(userCreationBidRepository.findByUuidAndType("uuid", INTERNAL_BID_TYPE)).thenReturn( + Optional.of(creationBid)); + when(userRepository.findByLogin("##$%/")).thenReturn(Optional.empty()); + + final CreateUserRQConfirm request = new CreateUserRQConfirm(); + request.setLogin("##$%/"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUser(request, "uuid")); + assertEquals("Incorrect Request. Username '##$%/' consists only of special characters", + exception.getMessage()); + } + + @Test + void createUserWithIncorrectEmail() { + final UserCreationBid bid = new UserCreationBid(); + bid.setProjectName("test_project"); + when(userCreationBidRepository.findByUuidAndType("uuid", INTERNAL_BID_TYPE)).thenReturn( + Optional.of(bid)); + when(userRepository.findByLogin("test")).thenReturn(Optional.empty()); + + final CreateUserRQConfirm request = new CreateUserRQConfirm(); + request.setLogin("test"); + request.setEmail("incorrect@domain"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUser(request, "uuid")); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'email='incorrect@domain''", + exception.getMessage()); + } + + @Test + void createUserWithExistedEmail() { + final UserCreationBid bid = new UserCreationBid(); + bid.setProjectName("test_project"); + when(userCreationBidRepository.findByUuidAndType("uuid", INTERNAL_BID_TYPE)).thenReturn( + Optional.of(bid)); + when(userRepository.findByLogin("test")).thenReturn(Optional.empty()); + when(userRepository.findByEmail("email@domain.com")).thenReturn(Optional.of(new User())); + + final CreateUserRQConfirm request = new CreateUserRQConfirm(); + request.setLogin("test"); + request.setEmail("email@domain.com"); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.createUser(request, "uuid")); + assertEquals( + "User with 'email='email@domain.com'' already exists. You couldn't create the duplicate.", + exception.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImplTest.java index d354935ad1..ba43a833ee 100644 --- a/src/test/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/user/impl/GetUserHandlerImplTest.java @@ -16,6 +16,15 @@ package com.epam.ta.reportportal.core.user.impl; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static com.epam.ta.reportportal.core.user.impl.CreateUserHandlerImpl.INTERNAL_BID_TYPE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.UserCreationBidRepository; import com.epam.ta.reportportal.dao.UserRepository; import com.epam.ta.reportportal.entity.project.ProjectRole; @@ -24,97 +33,93 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.YesNoRS; import com.epam.ta.reportportal.ws.model.user.UserBidRS; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Optional; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class GetUserHandlerImplTest { - @Mock - private UserRepository userRepository; + @Mock + private UserRepository userRepository; - @Mock - private UserCreationBidRepository userCreationBidRepository; + @Mock + private UserCreationBidRepository userCreationBidRepository; - @InjectMocks - private GetUserHandlerImpl handler; + @InjectMocks + private GetUserHandlerImpl handler; - @Test - void getNotExistedUserByUsername() { - when(userRepository.findByLogin("not_exist")).thenReturn(Optional.empty()); + @Test + void getNotExistedUserByUsername() { + when(userRepository.findByLogin("not_exist")).thenReturn(Optional.empty()); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getUser("not_exist", getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L)) - ); - assertEquals("User 'not_exist' not found.", exception.getMessage()); - } + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getUser("not_exist", getRpUser("test", UserRole.USER, ProjectRole.MEMBER, 1L)) + ); + assertEquals("User 'not_exist' not found.", exception.getMessage()); + } - @Test - void getNotExistedUserByLoggedInUser() { - when(userRepository.findByLogin("not_exist")).thenReturn(Optional.empty()); + @Test + void getNotExistedUserByLoggedInUser() { + when(userRepository.findByLogin("not_exist")).thenReturn(Optional.empty()); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> handler.getUser(getRpUser("not_exist", UserRole.USER, ProjectRole.MEMBER, 1L)) - ); - assertEquals("User 'not_exist' not found.", exception.getMessage()); - } + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> handler.getUser(getRpUser("not_exist", UserRole.USER, ProjectRole.MEMBER, 1L)) + ); + assertEquals("User 'not_exist' not found.", exception.getMessage()); + } - @Test - void getEmptyBidInfo() { - String uuid = "uuid"; + @Test + void getEmptyBidInfo() { + String uuid = "uuid"; - when(userCreationBidRepository.findById(uuid)).thenReturn(Optional.empty()); + when(userCreationBidRepository.findByUuidAndType(uuid, INTERNAL_BID_TYPE)).thenReturn( + Optional.empty()); - UserBidRS bidInformation = handler.getBidInformation(uuid); - assertFalse(bidInformation.getIsActive()); - assertNull(bidInformation.getEmail()); - assertNull(bidInformation.getUuid()); - } + UserBidRS bidInformation = handler.getBidInformation(uuid); + assertFalse(bidInformation.getIsActive()); + assertNull(bidInformation.getEmail()); + assertNull(bidInformation.getUuid()); + } - @Test - void validateInfoByNotExistUsername() { - String username = "not_exist"; - when(userRepository.findByLogin(username)).thenReturn(Optional.empty()); + @Test + void validateInfoByNotExistUsername() { + String username = "not_exist"; + when(userRepository.findByLogin(username)).thenReturn(Optional.empty()); - YesNoRS yesNoRS = handler.validateInfo(username, null); + YesNoRS yesNoRS = handler.validateInfo(username, null); - assertFalse(yesNoRS.getIs()); - } + assertFalse(yesNoRS.getIs()); + } - @Test - void validateInfoByExistEmail() { - String email = "exist@domain.com"; - when(userRepository.findByEmail(email)).thenReturn(Optional.of(new User())); + @Test + void validateInfoByExistEmail() { + String email = "exist@domain.com"; + when(userRepository.findByEmail(email)).thenReturn(Optional.of(new User())); - YesNoRS yesNoRS = handler.validateInfo(null, email); + YesNoRS yesNoRS = handler.validateInfo(null, email); - assertTrue(yesNoRS.getIs()); - } + assertTrue(yesNoRS.getIs()); + } - @Test - void validateInfoByNotExistEmail() { - String email = "not_exist@domain.com"; - when(userRepository.findByEmail(email)).thenReturn(Optional.empty()); + @Test + void validateInfoByNotExistEmail() { + String email = "not_exist@domain.com"; + when(userRepository.findByEmail(email)).thenReturn(Optional.empty()); - YesNoRS yesNoRS = handler.validateInfo(null, email); + YesNoRS yesNoRS = handler.validateInfo(null, email); - assertFalse(yesNoRS.getIs()); - } + assertFalse(yesNoRS.getIs()); + } - @Test - void validateInfoNullRequest() { - assertFalse(handler.validateInfo(null, null).getIs()); - } + @Test + void validateInfoNullRequest() { + assertFalse(handler.validateInfo(null, null).getIs()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGeneratorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGeneratorTest.java index 11aa4964ad..fc3bf86f5b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGeneratorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/materialized/generator/FailedViewStateGeneratorTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.core.widget.content.loader.materialized.generator; +import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.core.widget.util.WidgetOptionUtil; @@ -29,47 +35,49 @@ import org.springframework.data.domain.Sort; import org.springframework.util.LinkedMultiValueMap; -import static com.epam.ta.reportportal.core.widget.content.updater.MaterializedWidgetStateUpdater.STATE; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class FailedViewStateGeneratorTest { - private final ViewGenerator delegate = mock(ViewGenerator.class); - private final WidgetRepository widgetRepository = mock(WidgetRepository.class); + private final ViewGenerator delegate = mock(ViewGenerator.class); + private final WidgetRepository widgetRepository = mock(WidgetRepository.class); - private final FailedViewStateGenerator generator = new FailedViewStateGenerator(delegate, widgetRepository); + private final FailedViewStateGenerator generator = new FailedViewStateGenerator(delegate, + widgetRepository); - @Test - void shouldCatchExceptionAndSetFailedState() { + @Test + void shouldCatchExceptionAndSetFailedState() { - final boolean refresh = false; - final String viewName = "viewName"; - final Widget widget = getWidget(); - Sort sort = Sort.unsorted(); - final LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(); + final boolean refresh = false; + final String viewName = "viewName"; + final Widget widget = getWidget(); + Sort sort = Sort.unsorted(); + final LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(); - Filter filter = Filter.builder().withTarget(Widget.class).withCondition(FilterCondition.builder().eq("id", "1").build()).build(); - doThrow(RuntimeException.class).when(delegate).generate(refresh, viewName, widget, filter, sort, params); + Filter filter = Filter.builder().withTarget(Widget.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()).build(); + doThrow(RuntimeException.class).when(delegate) + .generate(refresh, viewName, widget, filter, sort, params); - generator.generate(refresh, viewName, widget, filter, sort, params); + generator.generate(refresh, viewName, widget, filter, sort, params); - final ArgumentCaptor<Widget> widgetArgumentCaptor = ArgumentCaptor.forClass(Widget.class); - verify(widgetRepository, times(1)).save(widgetArgumentCaptor.capture()); + final ArgumentCaptor<Widget> widgetArgumentCaptor = ArgumentCaptor.forClass(Widget.class); + verify(widgetRepository, times(1)).save(widgetArgumentCaptor.capture()); - final Widget failedWidget = widgetArgumentCaptor.getValue(); - final String failedState = WidgetOptionUtil.getValueByKey(STATE, failedWidget.getWidgetOptions()); + final Widget failedWidget = widgetArgumentCaptor.getValue(); + final String failedState = WidgetOptionUtil.getValueByKey(STATE, + failedWidget.getWidgetOptions()); - Assertions.assertEquals(WidgetState.FAILED.getValue(), failedState); + Assertions.assertEquals(WidgetState.FAILED.getValue(), failedState); - } + } - private Widget getWidget() { - Widget widget = new Widget(); - widget.setId(1L); - widget.setWidgetType("componentHealthCheckTable"); - return new WidgetBuilder(widget).addProject(1L).addOption(STATE, WidgetState.CREATED.getValue()).get(); - } + private Widget getWidget() { + Widget widget = new Widget(); + widget.setId(1L); + widget.setWidgetType("componentHealthCheckTable"); + return new WidgetBuilder(widget).addProject(1L).addOption(STATE, WidgetState.CREATED.getValue()) + .get(); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/util/healthcheck/HealthCheckTableReadyContentResolverTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/util/healthcheck/HealthCheckTableReadyContentResolverTest.java index 1f949fa7f5..0eededc3c2 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/util/healthcheck/HealthCheckTableReadyContentResolverTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/loader/util/healthcheck/HealthCheckTableReadyContentResolverTest.java @@ -1,5 +1,14 @@ package com.epam.ta.reportportal.core.widget.content.loader.util.healthcheck; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; +import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.widget.content.loader.materialized.HealthCheckTableReadyContentLoader; import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.Widget; @@ -10,80 +19,77 @@ import com.epam.ta.reportportal.ws.model.widget.WidgetRQ; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.junit.jupiter.api.Test; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import java.util.*; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTES; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_PASSED; -import static com.epam.ta.reportportal.dao.constant.WidgetContentRepositoryConstants.EXECUTIONS_TOTAL; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ public class HealthCheckTableReadyContentResolverTest { - private final WidgetContentRepository widgetContentRepository = mock(WidgetContentRepository.class); - private final ObjectMapper objectMapper = new ObjectMapper(); + private final WidgetContentRepository widgetContentRepository = mock( + WidgetContentRepository.class); + private final ObjectMapper objectMapper = new ObjectMapper(); - private final HealthCheckTableReadyContentLoader contentResolver = new HealthCheckTableReadyContentLoader(widgetContentRepository, - objectMapper - ); + private final HealthCheckTableReadyContentLoader contentResolver = new HealthCheckTableReadyContentLoader( + widgetContentRepository, + objectMapper + ); - @Test - void getContentTest() { + @Test + void getContentTest() { - WidgetRQ widgetRQ = new WidgetRQ(); - widgetRQ.setName("name"); + WidgetRQ widgetRQ = new WidgetRQ(); + widgetRQ.setName("name"); - widgetRQ.setWidgetType("componentHealthCheckTable"); - ContentParameters contentParameters = new ContentParameters(); - contentParameters.setContentFields(new ArrayList<>()); - contentParameters.setItemsCount(600); + widgetRQ.setWidgetType("componentHealthCheckTable"); + ContentParameters contentParameters = new ContentParameters(); + contentParameters.setContentFields(new ArrayList<>()); + contentParameters.setItemsCount(600); - Map<String, Object> options = new HashMap<>(); + Map<String, Object> options = new HashMap<>(); - contentParameters.setWidgetOptions(options); - widgetRQ.setContentParameters(contentParameters); - widgetRQ.setFilterIds(Collections.singletonList(1L)); - widgetRQ.setDescription("descr"); + contentParameters.setWidgetOptions(options); + widgetRQ.setContentParameters(contentParameters); + widgetRQ.setFilterIds(Collections.singletonList(1L)); + widgetRQ.setDescription("descr"); - SortEntry sortEntry = new SortEntry(); - sortEntry.setSortingColumn("passingRate"); - Widget widget = new WidgetBuilder().addWidgetRq(widgetRQ) - .addOption("viewName", "name") - .addOption("sort", sortEntry) - .addOption(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "k2")) - .get(); + SortEntry sortEntry = new SortEntry(); + sortEntry.setSortingColumn("passingRate"); + Widget widget = new WidgetBuilder().addWidgetRq(widgetRQ) + .addOption("viewName", "name") + .addOption("sort", sortEntry) + .addOption(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "k2")) + .get(); - HealthCheckTableContent content = new HealthCheckTableContent(); - content.setAttributeValue("v2"); - content.setPassingRate(50.00); - HashMap<String, Integer> statistics = new HashMap<>(); - statistics.put(EXECUTIONS_PASSED, 5); - statistics.put(EXECUTIONS_TOTAL, 10); - content.setStatistics(statistics); + HealthCheckTableContent content = new HealthCheckTableContent(); + content.setAttributeValue("v2"); + content.setPassingRate(50.00); + HashMap<String, Integer> statistics = new HashMap<>(); + statistics.put(EXECUTIONS_PASSED, 5); + statistics.put(EXECUTIONS_TOTAL, 10); + content.setStatistics(statistics); - when(widgetContentRepository.componentHealthCheckTable(any())).thenReturn(Lists.newArrayList(content)); + when(widgetContentRepository.componentHealthCheckTable(any())).thenReturn( + Lists.newArrayList(content)); - MultiValueMap<String, String> values = new LinkedMultiValueMap<>(); - values.put(ATTRIBUTES, Lists.newArrayList("v1")); + MultiValueMap<String, String> values = new LinkedMultiValueMap<>(); + values.put(ATTRIBUTES, Lists.newArrayList("v1")); - Map<String, Object> result = contentResolver.loadContent(widget, values); + Map<String, Object> result = contentResolver.loadContent(widget, values); - List<HealthCheckTableContent> resultList = (List<HealthCheckTableContent>) result.get("result"); + List<HealthCheckTableContent> resultList = (List<HealthCheckTableContent>) result.get("result"); - HealthCheckTableContent tableContent = resultList.get(0); + HealthCheckTableContent tableContent = resultList.get(0); - assertEquals(content.getPassingRate(), tableContent.getPassingRate()); - assertEquals(content.getAttributeValue(), tableContent.getAttributeValue()); - } + assertEquals(content.getPassingRate(), tableContent.getPassingRate()); + assertEquals(content.getAttributeValue(), tableContent.getAttributeValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGeneratorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGeneratorTest.java index d5468c9f1e..c4856b336d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGeneratorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/materialized/generator/MaterializedViewNameGeneratorTest.java @@ -18,40 +18,39 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.widget.Widget; +import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class MaterializedViewNameGeneratorTest { - private final MaterializedViewNameGenerator generator = new MaterializedViewNameGenerator(); - - private static Stream<Arguments> provideData() { - return Stream.of(Arguments.of("widget_1_1", getWidget(1L, 1L)), - Arguments.of("widget_1_2", getWidget(2L, 1L)), - Arguments.of("widget_2_1", getWidget(1L, 2L)) - ); - } - - private static Widget getWidget(Long id, Long projectId) { - final Widget widget = new Widget(); - widget.setId(id); - final Project project = new Project(); - project.setId(projectId); - widget.setProject(project); - return widget; - } - - @ParameterizedTest - @MethodSource("provideData") - void generate(String expectedName, Widget widget) { - Assertions.assertEquals(expectedName, generator.generate(widget)); - } + private final MaterializedViewNameGenerator generator = new MaterializedViewNameGenerator(); + + private static Stream<Arguments> provideData() { + return Stream.of(Arguments.of("widget_1_1", getWidget(1L, 1L)), + Arguments.of("widget_1_2", getWidget(2L, 1L)), + Arguments.of("widget_2_1", getWidget(1L, 2L)) + ); + } + + private static Widget getWidget(Long id, Long projectId) { + final Widget widget = new Widget(); + widget.setId(id); + final Project project = new Project(); + project.setId(projectId); + widget.setProject(project); + return widget; + } + + @ParameterizedTest + @MethodSource("provideData") + void generate(String expectedName, Widget widget) { + Assertions.assertEquals(expectedName, generator.generate(widget)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemoverTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemoverTest.java index 4ac37d772a..29fc705a56 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemoverTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/DelegatingStateContentRemoverTest.java @@ -16,50 +16,55 @@ package com.epam.ta.reportportal.core.widget.content.remover; +import static com.epam.ta.reportportal.entity.widget.WidgetType.COMPONENT_HEALTH_CHECK; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.widget.content.materialized.state.WidgetStateResolver; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.entity.widget.WidgetState; +import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.util.Map; - -import static com.epam.ta.reportportal.entity.widget.WidgetType.*; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class DelegatingStateContentRemoverTest { - private final WidgetStateResolver widgetStateResolver = mock(WidgetStateResolver.class); + private final WidgetStateResolver widgetStateResolver = mock(WidgetStateResolver.class); - private final WidgetContentRemover remover = mock(WidgetContentRemover.class); - private final Map<WidgetState, WidgetContentRemover> removerMapping = Map.of(WidgetState.RENDERING, remover); + private final WidgetContentRemover remover = mock(WidgetContentRemover.class); + private final Map<WidgetState, WidgetContentRemover> removerMapping = Map.of( + WidgetState.RENDERING, remover); - private final DelegatingStateContentRemover delegatingStateContentRemover = new DelegatingStateContentRemover(widgetStateResolver, - removerMapping - ); + private final DelegatingStateContentRemover delegatingStateContentRemover = new DelegatingStateContentRemover( + widgetStateResolver, + removerMapping + ); - @ParameterizedTest - @ValueSource(strings = { "cumulative", "componentHealthCheckTable" }) - void supports(String type) { - final Widget widget = new Widget(); - widget.setWidgetType(type); + @ParameterizedTest + @ValueSource(strings = {"cumulative", "componentHealthCheckTable"}) + void supports(String type) { + final Widget widget = new Widget(); + widget.setWidgetType(type); - when(widgetStateResolver.resolve(widget.getWidgetOptions())).thenReturn(WidgetState.RENDERING); + when(widgetStateResolver.resolve(widget.getWidgetOptions())).thenReturn(WidgetState.RENDERING); - delegatingStateContentRemover.removeContent(widget); - verify(remover, times(1)).removeContent(widget); - } + delegatingStateContentRemover.removeContent(widget); + verify(remover, times(1)).removeContent(widget); + } - @Test - void supportsHealthNegative() { - final Widget widget = new Widget(); - widget.setWidgetType(COMPONENT_HEALTH_CHECK.getType()); - delegatingStateContentRemover.removeContent(widget); - verify(widgetStateResolver, times(0)).resolve(any(WidgetOptions.class)); - } + @Test + void supportsHealthNegative() { + final Widget widget = new Widget(); + widget.setWidgetType(COMPONENT_HEALTH_CHECK.getType()); + delegatingStateContentRemover.removeContent(widget); + verify(widgetStateResolver, times(0)).resolve(any(WidgetOptions.class)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemoverTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemoverTest.java index 4c042f5b77..61747243d0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemoverTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/MaterializedViewRemoverTest.java @@ -16,33 +16,36 @@ package com.epam.ta.reportportal.core.widget.content.remover; +import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.dao.WidgetContentRepository; import com.epam.ta.reportportal.entity.widget.Widget; import com.epam.ta.reportportal.entity.widget.WidgetOptions; -import org.junit.jupiter.api.Test; - import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.loader.materialized.handler.MaterializedWidgetStateHandler.VIEW_NAME; -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class MaterializedViewRemoverTest { - private final WidgetContentRepository widgetContentRepository = mock(WidgetContentRepository.class); - private final MaterializedViewRemover materializedViewRemover = new MaterializedViewRemover(widgetContentRepository); + private final WidgetContentRepository widgetContentRepository = mock( + WidgetContentRepository.class); + private final MaterializedViewRemover materializedViewRemover = new MaterializedViewRemover( + widgetContentRepository); - @Test - void shouldRemove() { - final Widget widget = new Widget(); - final String viewName = "name"; - widget.setWidgetOptions(new WidgetOptions(Map.of(VIEW_NAME, viewName))); + @Test + void shouldRemove() { + final Widget widget = new Widget(); + final String viewName = "name"; + widget.setWidgetOptions(new WidgetOptions(Map.of(VIEW_NAME, viewName))); - materializedViewRemover.removeContent(widget); + materializedViewRemover.removeContent(widget); - verify(widgetContentRepository, times(1)).removeWidgetView(viewName); - } + verify(widgetContentRepository, times(1)).removeWidgetView(viewName); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemoverTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemoverTest.java index 722982f284..12550c6e83 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemoverTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/remover/StaleMaterializedViewRemoverTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.core.widget.content.remover; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.widget.content.materialized.generator.MaterializedViewNameGenerator; import com.epam.ta.reportportal.dao.StaleMaterializedViewRepository; import com.epam.ta.reportportal.entity.materialized.StaleMaterializedView; @@ -24,35 +29,37 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class StaleMaterializedViewRemoverTest { - private final MaterializedViewNameGenerator nameGenerator = mock(MaterializedViewNameGenerator.class); - private final StaleMaterializedViewRepository staleMaterializedViewRepository = mock(StaleMaterializedViewRepository.class); - private final StaleMaterializedViewRemover staleMaterializedViewRemover = new StaleMaterializedViewRemover(nameGenerator, - staleMaterializedViewRepository - ); + private final MaterializedViewNameGenerator nameGenerator = mock( + MaterializedViewNameGenerator.class); + private final StaleMaterializedViewRepository staleMaterializedViewRepository = mock( + StaleMaterializedViewRepository.class); + private final StaleMaterializedViewRemover staleMaterializedViewRemover = new StaleMaterializedViewRemover( + nameGenerator, + staleMaterializedViewRepository + ); - @Test - void shouldSaveStaleView() { - final Widget widget = new Widget(); + @Test + void shouldSaveStaleView() { + final Widget widget = new Widget(); - final String viewName = "widget_1_1"; - when(nameGenerator.generate(widget)).thenReturn(viewName); + final String viewName = "widget_1_1"; + when(nameGenerator.generate(widget)).thenReturn(viewName); - staleMaterializedViewRemover.removeContent(widget); + staleMaterializedViewRemover.removeContent(widget); - final ArgumentCaptor<StaleMaterializedView> viewArgumentCaptor = ArgumentCaptor.forClass(StaleMaterializedView.class); - verify(staleMaterializedViewRepository, times(1)).insert(viewArgumentCaptor.capture()); + final ArgumentCaptor<StaleMaterializedView> viewArgumentCaptor = ArgumentCaptor.forClass( + StaleMaterializedView.class); + verify(staleMaterializedViewRepository, times(1)).insert(viewArgumentCaptor.capture()); - final StaleMaterializedView view = viewArgumentCaptor.getValue(); + final StaleMaterializedView view = viewArgumentCaptor.getValue(); - Assertions.assertEquals(viewName, view.getName()); - Assertions.assertNotNull(view.getCreationDate()); - } + Assertions.assertEquals(viewName, view.getName()); + Assertions.assertNotNull(view.getCreationDate()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidatorTest.java index f79ab45cce..850d6443c0 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ActivityContentValidatorTest.java @@ -1,34 +1,34 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class ActivityContentValidatorTest { - private WidgetValidatorStrategy activityContentValidator; + private WidgetValidatorStrategy activityContentValidator; - @BeforeEach - public void setUp() { - activityContentValidator = new ActivityContentValidator(); - } + @BeforeEach + public void setUp() { + activityContentValidator = new ActivityContentValidator(); + } - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - activityContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), new WidgetOptions(), 5); - }); + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + activityContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), + new WidgetOptions(), 5); + }); - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidatorTest.java index be91486589..60c4ed99e9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/BugTrendChartContentValidatorTest.java @@ -1,44 +1,46 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; -import java.util.Collections; -import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class BugTrendChartContentValidatorTest { - private WidgetValidatorStrategy bugTrendChartContentValidator; - - @BeforeEach - public void setUp() { - bugTrendChartContentValidator = new BugTrendChartContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - bugTrendChartContentValidator.validate(Collections.singletonList("statistics$defects$automation_bug$total'"), filterSortMap, new WidgetOptions(), 5); - }); - - String expectedMessage = "Bad content fields format"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy bugTrendChartContentValidator; + + @BeforeEach + public void setUp() { + bugTrendChartContentValidator = new BugTrendChartContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + bugTrendChartContentValidator.validate( + Collections.singletonList("statistics$defects$automation_bug$total'"), filterSortMap, + new WidgetOptions(), 5); + }); + + String expectedMessage = "Bad content fields format"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidatorTest.java index 13d180a7c1..7ccdfd089b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CasesTrendContentValidatorTest.java @@ -1,45 +1,45 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; -import java.util.Collections; -import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class CasesTrendContentValidatorTest { - private WidgetValidatorStrategy casesTrendContentValidator; - - @BeforeEach - public void setUp() { - casesTrendContentValidator = new CasesTrendContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - casesTrendContentValidator.validate(Collections.singletonList("test"), filterSortMap, new WidgetOptions(), 5); - }); - - String expectedMessage = "Bad content fields format"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy casesTrendContentValidator; + + @BeforeEach + public void setUp() { + casesTrendContentValidator = new CasesTrendContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + casesTrendContentValidator.validate(Collections.singletonList("test"), filterSortMap, + new WidgetOptions(), 5); + }); + + String expectedMessage = "Bad content fields format"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidatorTest.java index 2b73b0fb22..b989b56794 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ChartInvestigatedContentValidatorTest.java @@ -1,37 +1,37 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ChartInvestigatedContentValidatorTest { - private WidgetValidatorStrategy chartInvestigatedContentValidator; + private WidgetValidatorStrategy chartInvestigatedContentValidator; - @BeforeEach - public void setUp() { - chartInvestigatedContentValidator = new ChartInvestigatedContentValidator(); - } + @BeforeEach + public void setUp() { + chartInvestigatedContentValidator = new ChartInvestigatedContentValidator(); + } - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - chartInvestigatedContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), new WidgetOptions(), 5); - }); + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + chartInvestigatedContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), + new WidgetOptions(), 5); + }); - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidatorTest.java index 302e099221..6de71ce07f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/ComponentHealthCheckContentValidatorTest.java @@ -1,76 +1,75 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.MIN_PASSING_RATE; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Lists; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.ATTRIBUTE_KEYS; -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.MIN_PASSING_RATE; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class ComponentHealthCheckContentValidatorTest { - private MultilevelValidatorStrategy сomponentHealthCheckContentValidator; + private MultilevelValidatorStrategy сomponentHealthCheckContentValidator; - @BeforeEach - public void setUp() { - сomponentHealthCheckContentValidator = new ComponentHealthCheckContentValidator(); - } + @BeforeEach + public void setUp() { + сomponentHealthCheckContentValidator = new ComponentHealthCheckContentValidator(); + } - @Test - public void testValidateWithException() { - WidgetOptions widgetOptions = new WidgetOptions(getWidgetOptionsContentWithBlankKey()); - Exception exception = assertThrows(ReportPortalException.class, - () -> сomponentHealthCheckContentValidator.validate(Collections.singletonList("test"), - new HashMap<>(), - widgetOptions, - new String[] { "v1" }, - new HashMap<>(), - 100 - ) - ); + @Test + public void testValidateWithException() { + WidgetOptions widgetOptions = new WidgetOptions(getWidgetOptionsContentWithBlankKey()); + Exception exception = assertThrows(ReportPortalException.class, + () -> сomponentHealthCheckContentValidator.validate(Collections.singletonList("test"), + new HashMap<>(), + widgetOptions, + new String[]{"v1"}, + new HashMap<>(), + 100 + ) + ); - String expectedMessage = "Current level key should be not blank"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); + String expectedMessage = "Current level key should be not blank"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); - WidgetOptions wo = new WidgetOptions(getWidgetOptionsContent()); - сomponentHealthCheckContentValidator.validate(Collections.singletonList("test"), - new HashMap<>(), - wo, - new String[] { "v1" }, - new HashMap<>(), - 100 - ); - } + WidgetOptions wo = new WidgetOptions(getWidgetOptionsContent()); + сomponentHealthCheckContentValidator.validate(Collections.singletonList("test"), + new HashMap<>(), + wo, + new String[]{"v1"}, + new HashMap<>(), + 100 + ); + } - private Map<String, Object> getWidgetOptionsContent() { - Map<String, Object> content = new HashMap<>(); + private Map<String, Object> getWidgetOptionsContent() { + Map<String, Object> content = new HashMap<>(); - content.put(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "k2")); - content.put(MIN_PASSING_RATE, 50); + content.put(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "k2")); + content.put(MIN_PASSING_RATE, 50); - return content; + return content; - } + } - private Map<String, Object> getWidgetOptionsContentWithBlankKey() { - Map<String, Object> content = new HashMap<>(); + private Map<String, Object> getWidgetOptionsContentWithBlankKey() { + Map<String, Object> content = new HashMap<>(); - content.put(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "")); - content.put(MIN_PASSING_RATE, 50); + content.put(ATTRIBUTE_KEYS, Lists.newArrayList("k1", "")); + content.put(MIN_PASSING_RATE, 50); - return content; + return content; - } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidatorTest.java index c8eca151e3..41c33277a9 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/CumulativeTrendChartValidatorTest.java @@ -1,7 +1,5 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidatorTest.java index a28705dfd7..c4fc0a9fc2 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/FlakyCasesTableContentValidatorTest.java @@ -4,7 +4,6 @@ import com.epam.ta.reportportal.exception.ReportPortalException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import java.util.HashMap; import java.util.Map; diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidatorTest.java index b4d4bd0dd5..0249e9a58b 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchExecutionAndIssueStatisticsContentValidatorTest.java @@ -1,44 +1,45 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; -import java.util.Collections; -import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchExecutionAndIssueStatisticsContentValidatorTest { - private WidgetValidatorStrategy launchExecutionAndIssueStatisticsContentValidator; - - @BeforeEach - public void setUp() { - launchExecutionAndIssueStatisticsContentValidator = new LaunchExecutionAndIssueStatisticsContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - launchExecutionAndIssueStatisticsContentValidator.validate(Collections.singletonList("test"), filterSortMap, new WidgetOptions(), 5); - }); - - String expectedMessage = "Bad content fields format"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy launchExecutionAndIssueStatisticsContentValidator; + + @BeforeEach + public void setUp() { + launchExecutionAndIssueStatisticsContentValidator = new LaunchExecutionAndIssueStatisticsContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + launchExecutionAndIssueStatisticsContentValidator.validate(Collections.singletonList("test"), + filterSortMap, new WidgetOptions(), 5); + }); + + String expectedMessage = "Bad content fields format"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidatorTest.java index 7dd0f4879c..b3d0ca58e1 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesComparisonContentValidatorTest.java @@ -1,44 +1,45 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.Collections; +import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; -import java.util.Collections; -import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchesComparisonContentValidatorTest { - private WidgetValidatorStrategy launchesComparisonContentValidator; - - @BeforeEach - public void setUp() { - launchesComparisonContentValidator = new LaunchesComparisonContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - launchesComparisonContentValidator.validate(Collections.singletonList("test"), filterSortMap, new WidgetOptions(), 5); - }); - - String expectedMessage = "Bad content fields format"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy launchesComparisonContentValidator; + + @BeforeEach + public void setUp() { + launchesComparisonContentValidator = new LaunchesComparisonContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + launchesComparisonContentValidator.validate(Collections.singletonList("test"), filterSortMap, + new WidgetOptions(), 5); + }); + + String expectedMessage = "Bad content fields format"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidatorTest.java index d505151392..dec6a1a18d 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesDurationContentValidatorTest.java @@ -1,36 +1,36 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchesDurationContentValidatorTest { - private WidgetValidatorStrategy launchesDurationContentValidator; + private WidgetValidatorStrategy launchesDurationContentValidator; - @BeforeEach - public void setUp() { - launchesDurationContentValidator = new LaunchesDurationContentValidator(); - } + @BeforeEach + public void setUp() { + launchesDurationContentValidator = new LaunchesDurationContentValidator(); + } - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - launchesDurationContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), new WidgetOptions(), 5); - }); + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + launchesDurationContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), + new WidgetOptions(), 5); + }); - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidatorTest.java index 5b4f68ab43..f464796a57 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/LaunchesTableContentValidatorTest.java @@ -1,45 +1,45 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; +import java.util.ArrayList; +import java.util.HashMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; -import java.util.ArrayList; -import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchesTableContentValidatorTest { - private WidgetValidatorStrategy launchesTableContentValidator; - - @BeforeEach - public void setUp() { - launchesTableContentValidator = new LaunchesTableContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - launchesTableContentValidator.validate(new ArrayList<>(), filterSortMap, new WidgetOptions(), 5); - }); - - String expectedMessage = "Content fields should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy launchesTableContentValidator; + + @BeforeEach + public void setUp() { + launchesTableContentValidator = new LaunchesTableContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + launchesTableContentValidator.validate(new ArrayList<>(), filterSortMap, new WidgetOptions(), + 5); + }); + + String expectedMessage = "Content fields should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidatorTest.java index 83053d5119..5f349548b3 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/MostTimeConsumingContentValidatorTest.java @@ -1,52 +1,51 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.data.domain.Sort; - import java.util.Collections; import java.util.HashMap; import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Sort; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class MostTimeConsumingContentValidatorTest { - private WidgetValidatorStrategy mostTimeConsumingContentValidator; - - @BeforeEach - public void setUp() { - mostTimeConsumingContentValidator = new MostTimeConsumingContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - Map<String, Object> params = new HashMap<>(); - params.put(LAUNCH_NAME_FIELD, ""); - WidgetOptions widgetOptions = new WidgetOptions(); - mostTimeConsumingContentValidator.validate(Collections.singletonList("test"), filterSortMap, - widgetOptions, 5); - }); - - String expectedMessage = LAUNCH_NAME_FIELD + " should be specified for widget."; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy mostTimeConsumingContentValidator; + + @BeforeEach + public void setUp() { + mostTimeConsumingContentValidator = new MostTimeConsumingContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + Map<String, Object> params = new HashMap<>(); + params.put(LAUNCH_NAME_FIELD, ""); + WidgetOptions widgetOptions = new WidgetOptions(); + mostTimeConsumingContentValidator.validate(Collections.singletonList("test"), filterSortMap, + widgetOptions, 5); + }); + + String expectedMessage = LAUNCH_NAME_FIELD + " should be specified for widget."; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidatorTest.java index d783562439..b712f2cafe 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/NotPassedTestsContentValidatorTest.java @@ -1,36 +1,36 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class NotPassedTestsContentValidatorTest { - private WidgetValidatorStrategy notPassedTestsContentValidator; + private WidgetValidatorStrategy notPassedTestsContentValidator; - @BeforeEach - public void setUp() { - notPassedTestsContentValidator = new NotPassedTestsContentValidator(); - } + @BeforeEach + public void setUp() { + notPassedTestsContentValidator = new NotPassedTestsContentValidator(); + } - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - notPassedTestsContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), new WidgetOptions(), 5); - }); + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + notPassedTestsContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), + new WidgetOptions(), 5); + }); - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidatorTest.java index ddfb84888a..5e2453fb86 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRatePerLaunchContentValidatorTest.java @@ -1,50 +1,50 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.data.domain.Sort; - import java.util.Collections; import java.util.HashMap; import java.util.Map; - -import static com.epam.ta.reportportal.core.widget.content.constant.ContentLoaderConstants.LAUNCH_NAME_FIELD; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Sort; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PassingRatePerLaunchContentValidatorTest { - private WidgetValidatorStrategy passingRatePerLaunchContentValidator; - - @BeforeEach - public void setUp() { - passingRatePerLaunchContentValidator = new PassingRatePerLaunchContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - HashMap<Filter, Sort> filterSortMap = new HashMap<>(); - filterSortMap.put(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq("id", "1").build()) - .build(), Sort.unsorted()); - Map<String, Object> params = new HashMap<>(); - params.put(LAUNCH_NAME_FIELD, ""); - WidgetOptions widgetOptions = new WidgetOptions(); - passingRatePerLaunchContentValidator.validate(Collections.singletonList("test"), filterSortMap, widgetOptions, 5); - }); - - String expectedMessage = LAUNCH_NAME_FIELD + " should be specified for widget."; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy passingRatePerLaunchContentValidator; + + @BeforeEach + public void setUp() { + passingRatePerLaunchContentValidator = new PassingRatePerLaunchContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + HashMap<Filter, Sort> filterSortMap = new HashMap<>(); + filterSortMap.put(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("id", "1").build()) + .build(), Sort.unsorted()); + Map<String, Object> params = new HashMap<>(); + params.put(LAUNCH_NAME_FIELD, ""); + WidgetOptions widgetOptions = new WidgetOptions(); + passingRatePerLaunchContentValidator.validate(Collections.singletonList("test"), + filterSortMap, widgetOptions, 5); + }); + + String expectedMessage = LAUNCH_NAME_FIELD + " should be specified for widget."; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidatorTest.java index cef939e864..628ca15c2f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/PassingRateSummaryContentValidatorTest.java @@ -1,40 +1,39 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PassingRateSummaryContentValidatorTest { - private WidgetValidatorStrategy passingRateSummaryContentValidator; - - @BeforeEach - public void setUp() { - passingRateSummaryContentValidator = new PassingRateSummaryContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, - () -> passingRateSummaryContentValidator.validate(Collections.singletonList("test"), - new HashMap<>(), - new WidgetOptions(), - 5 - ) - ); - - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private WidgetValidatorStrategy passingRateSummaryContentValidator; + + @BeforeEach + public void setUp() { + passingRateSummaryContentValidator = new PassingRateSummaryContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, + () -> passingRateSummaryContentValidator.validate(Collections.singletonList("test"), + new HashMap<>(), + new WidgetOptions(), + 5 + ) + ); + + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidatorTest.java index 386700abc7..280ac05740 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/TopPatternContentValidatorTest.java @@ -1,42 +1,41 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class TopPatternContentValidatorTest { - private MultilevelValidatorStrategy topPatternContentValidator; - - @BeforeEach - public void setUp() { - topPatternContentValidator = new TopPatternContentValidator(); - } - - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - topPatternContentValidator.validate(Collections.singletonList("test"), - new HashMap<>(), - new WidgetOptions(), - new String[] {}, - new HashMap<>(), - 5 - ); - }); - - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + private MultilevelValidatorStrategy topPatternContentValidator; + + @BeforeEach + public void setUp() { + topPatternContentValidator = new TopPatternContentValidator(); + } + + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + topPatternContentValidator.validate(Collections.singletonList("test"), + new HashMap<>(), + new WidgetOptions(), + new String[]{}, + new HashMap<>(), + 5 + ); + }); + + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidatorTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidatorTest.java index de6965f412..34ba8d0df6 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/content/updater/validator/UniqueBugContentValidatorTest.java @@ -1,36 +1,36 @@ package com.epam.ta.reportportal.core.widget.content.updater.validator; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.util.Collections; import java.util.HashMap; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class UniqueBugContentValidatorTest { - private WidgetValidatorStrategy uniqueBugContentValidator; + private WidgetValidatorStrategy uniqueBugContentValidator; - @BeforeEach - public void setUp() { - uniqueBugContentValidator = new UniqueBugContentValidator(); - } + @BeforeEach + public void setUp() { + uniqueBugContentValidator = new UniqueBugContentValidator(); + } - @Test - public void testValidateWithException() { - Exception exception = assertThrows(ReportPortalException.class, () -> { - uniqueBugContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), new WidgetOptions(), 5); - }); + @Test + public void testValidateWithException() { + Exception exception = assertThrows(ReportPortalException.class, () -> { + uniqueBugContentValidator.validate(Collections.singletonList("test"), new HashMap<>(), + new WidgetOptions(), 5); + }); - String expectedMessage = "Filter-Sort mapping should not be empty"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } + String expectedMessage = "Filter-Sort mapping should not be empty"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtilTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtilTest.java index 3cc221f89d..334ed2f79f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtilTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/util/ContentFieldMatcherUtilTest.java @@ -16,15 +16,16 @@ package com.epam.ta.reportportal.core.widget.util; -import com.google.common.collect.Lists; -import org.junit.jupiter.api.Test; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.COMBINED_CONTENT_FIELDS_REGEX; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.DEFECTS_REGEX; +import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.EXECUTIONS_REGEX; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import com.google.common.collect.Lists; import java.util.List; import java.util.Random; - -import static com.epam.ta.reportportal.core.widget.util.ContentFieldPatternConstants.*; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> @@ -32,128 +33,131 @@ //TODO replace random wrong content field generation with the specified loop public class ContentFieldMatcherUtilTest { - @Test - void whenCorrectDefectsContentFieldsFormatThenTrue() { - - boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, buildCorrectDefectContentFields()); + @Test + void whenCorrectDefectsContentFieldsFormatThenTrue() { - assertTrue(match); - } + boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, buildCorrectDefectContentFields()); - @Test - void whenWrongDefectsContentFieldsFormatThenFalse() { + assertTrue(match); + } - boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, buildWrongDefectContentFields()); + @Test + void whenWrongDefectsContentFieldsFormatThenFalse() { - assertFalse(match); - } + boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, buildWrongDefectContentFields()); - @Test - void whenCorrectExecutionsContentFieldsFormatThenTrue() { + assertFalse(match); + } - boolean match = ContentFieldMatcherUtil.match(EXECUTIONS_REGEX, buildCorrectExecutionContentFields()); + @Test + void whenCorrectExecutionsContentFieldsFormatThenTrue() { - assertTrue(match); - } + boolean match = ContentFieldMatcherUtil.match(EXECUTIONS_REGEX, + buildCorrectExecutionContentFields()); - @Test - void whenWrongExecutionsContentFieldsFormatThenFalse() { + assertTrue(match); + } - List<String> contentFields = buildWrongExecutionContentFields(); - boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, contentFields); + @Test + void whenWrongExecutionsContentFieldsFormatThenFalse() { - assertFalse(match); - } + List<String> contentFields = buildWrongExecutionContentFields(); + boolean match = ContentFieldMatcherUtil.match(DEFECTS_REGEX, contentFields); - @Test - void whenCorrectCombinedContentFieldsFormatThenTrue() { + assertFalse(match); + } - boolean match = ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, buildCorrectCombinedContentFields()); + @Test + void whenCorrectCombinedContentFieldsFormatThenTrue() { - assertTrue(match); - } + boolean match = ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, + buildCorrectCombinedContentFields()); - @Test - void whenWrongCombinedContentFieldsFormatThenFalse() { + assertTrue(match); + } - boolean match = ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, buildWrongCombinedContentFields()); + @Test + void whenWrongCombinedContentFieldsFormatThenFalse() { - assertFalse(match); - } + boolean match = ContentFieldMatcherUtil.match(COMBINED_CONTENT_FIELDS_REGEX, + buildWrongCombinedContentFields()); - private List<String> buildCorrectDefectContentFields() { - return Lists.newArrayList( - "statistics$defects$automation_bug$AB001", - "statistics$defects$product_bug$PB001", - "statistics$defects$to_investigate$TI001", - "statistics$defects$system_issue$SI001", - "statistics$defects$no_defect$ND001", - "statistics$defects$no_defect$total", - "statistics$defects$product_bug$total", - "statistics$defects$to_investigate$total", - "statistics$defects$system_issue$total" + assertFalse(match); + } - ); - } + private List<String> buildCorrectDefectContentFields() { + return Lists.newArrayList( + "statistics$defects$automation_bug$AB001", + "statistics$defects$product_bug$PB001", + "statistics$defects$to_investigate$TI001", + "statistics$defects$system_issue$SI001", + "statistics$defects$no_defect$ND001", + "statistics$defects$no_defect$total", + "statistics$defects$product_bug$total", + "statistics$defects$to_investigate$total", + "statistics$defects$system_issue$total" - private List<String> buildWrongDefectContentFields() { - List<String> contentFields = buildCorrectDefectContentFields(); - Random random = new Random(); - int index = random.nextInt(contentFields.size()); + ); + } - contentFields.set(index, "statistics$wrong$format"); + private List<String> buildWrongDefectContentFields() { + List<String> contentFields = buildCorrectDefectContentFields(); + Random random = new Random(); + int index = random.nextInt(contentFields.size()); - return contentFields; - } + contentFields.set(index, "statistics$wrong$format"); - private List<String> buildCorrectExecutionContentFields() { - return Lists.newArrayList( - "statistics$executions$passed", - "statistics$executions$failed", - "statistics$executions$skipped", - "statistics$executions$total" - ); - } + return contentFields; + } - private List<String> buildWrongExecutionContentFields() { - List<String> contentFields = buildCorrectExecutionContentFields(); + private List<String> buildCorrectExecutionContentFields() { + return Lists.newArrayList( + "statistics$executions$passed", + "statistics$executions$failed", + "statistics$executions$skipped", + "statistics$executions$total" + ); + } - Random random = new Random(); - int index = random.nextInt(contentFields.size()); + private List<String> buildWrongExecutionContentFields() { + List<String> contentFields = buildCorrectExecutionContentFields(); - contentFields.set(index, "statistics$wrong$format"); + Random random = new Random(); + int index = random.nextInt(contentFields.size()); - return contentFields; - } + contentFields.set(index, "statistics$wrong$format"); - private List<String> buildCorrectCombinedContentFields() { - return Lists.newArrayList( - "statistics$executions$passed", - "statistics$executions$failed", - "statistics$executions$skipped", - "statistics$executions$total", - "statistics$defects$automation_bug$AB001", - "statistics$defects$product_bug$PB001", - "statistics$defects$to_investigate$TI001", - "statistics$defects$system_issue$SI001", - "statistics$defects$no_defect$ND001", - "statistics$defects$no_defect$total" - ); - } + return contentFields; + } - private List<String> buildWrongCombinedContentFields() { - List<String> contentFields = buildCorrectCombinedContentFields(); + private List<String> buildCorrectCombinedContentFields() { + return Lists.newArrayList( + "statistics$executions$passed", + "statistics$executions$failed", + "statistics$executions$skipped", + "statistics$executions$total", + "statistics$defects$automation_bug$AB001", + "statistics$defects$product_bug$PB001", + "statistics$defects$to_investigate$TI001", + "statistics$defects$system_issue$SI001", + "statistics$defects$no_defect$ND001", + "statistics$defects$no_defect$total" + ); + } - Random random = new Random(); - int index = random.nextInt(contentFields.size()); + private List<String> buildWrongCombinedContentFields() { + List<String> contentFields = buildCorrectCombinedContentFields(); - contentFields.set(index, "statistics$wrong$format"); + Random random = new Random(); + int index = random.nextInt(contentFields.size()); - return contentFields; - } + contentFields.set(index, "statistics$wrong$format"); - public static Object[][] data() { - return new Object[1][0]; - } + return contentFields; + } + + public static Object[][] data() { + return new Object[1][0]; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtilTest.java b/src/test/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtilTest.java index c1a17b52e2..d3531fc486 100644 --- a/src/test/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtilTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/widget/util/WidgetOptionUtilTest.java @@ -16,82 +16,86 @@ package com.epam.ta.reportportal.core.widget.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.entity.widget.WidgetOptions; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; -import org.junit.jupiter.api.Test; - import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class WidgetOptionUtilTest { - private static final String FIRST_KEY = "KEY1"; - private static final String SECOND_KEY = "KEY2"; - private static final String FIRST_STRING_VALUE = "VALUE1"; - private static final String SECOND_STRING_VALUE = "VALUE2"; + private static final String FIRST_KEY = "KEY1"; + private static final String SECOND_KEY = "KEY2"; + private static final String FIRST_STRING_VALUE = "VALUE1"; + private static final String SECOND_STRING_VALUE = "VALUE2"; - @Test - void getStringValueWhenCorrectTypeTest() { + @Test + void getStringValueWhenCorrectTypeTest() { - //given - WidgetOptions widgetOptions = new WidgetOptions(getMapWithStringValues()); + //given + WidgetOptions widgetOptions = new WidgetOptions(getMapWithStringValues()); - //when - String value = WidgetOptionUtil.getValueByKey(FIRST_KEY, widgetOptions); + //when + String value = WidgetOptionUtil.getValueByKey(FIRST_KEY, widgetOptions); - //then - assertNotNull(value); - assertEquals(FIRST_STRING_VALUE, value); - } + //then + assertNotNull(value); + assertEquals(FIRST_STRING_VALUE, value); + } - @Test - void throwExceptionWhenGetStringValueWithInCorrectTypeTest() { + @Test + void throwExceptionWhenGetStringValueWithInCorrectTypeTest() { - //given - WidgetOptions widgetOptions = new WidgetOptions(getMapWithNonStringValues()); + //given + WidgetOptions widgetOptions = new WidgetOptions(getMapWithNonStringValues()); - //when //then throw exception - assertThrows(ReportPortalException.class, () -> WidgetOptionUtil.getValueByKey(FIRST_KEY, widgetOptions)); - } + //when //then throw exception + assertThrows(ReportPortalException.class, + () -> WidgetOptionUtil.getValueByKey(FIRST_KEY, widgetOptions)); + } - @Test - void getMapValueWhenCorrectTypeTest() { + @Test + void getMapValueWhenCorrectTypeTest() { - //given - WidgetOptions widgetOptions = new WidgetOptions(getMapWithNonStringValues()); + //given + WidgetOptions widgetOptions = new WidgetOptions(getMapWithNonStringValues()); - //when - Map<String, String> mapByKey = WidgetOptionUtil.getMapByKey(FIRST_KEY, widgetOptions); + //when + Map<String, String> mapByKey = WidgetOptionUtil.getMapByKey(FIRST_KEY, widgetOptions); - //then - assertNotNull(mapByKey); - } + //then + assertNotNull(mapByKey); + } - @Test - void throwExceptionWhenGetMapValueWithInCorrectTypeTest() { + @Test + void throwExceptionWhenGetMapValueWithInCorrectTypeTest() { - //given - WidgetOptions widgetOptions = new WidgetOptions(getMapWithStringValues()); + //given + WidgetOptions widgetOptions = new WidgetOptions(getMapWithStringValues()); - //when //then throw exception - assertThrows(ReportPortalException.class, () -> WidgetOptionUtil.getMapByKey(FIRST_KEY, widgetOptions)); - } + //when //then throw exception + assertThrows(ReportPortalException.class, + () -> WidgetOptionUtil.getMapByKey(FIRST_KEY, widgetOptions)); + } - private Map<String, Object> getMapWithStringValues() { - return ImmutableMap.<String, Object>builder().put(FIRST_KEY, FIRST_STRING_VALUE).put(SECOND_KEY, SECOND_STRING_VALUE).build(); - } + private Map<String, Object> getMapWithStringValues() { + return ImmutableMap.<String, Object>builder().put(FIRST_KEY, FIRST_STRING_VALUE) + .put(SECOND_KEY, SECOND_STRING_VALUE).build(); + } - private Map<String, Object> getMapWithNonStringValues() { - Map<String, Object> mapValue = Maps.newHashMap(); - mapValue.put(FIRST_KEY, ImmutableList.<String>builder().add(FIRST_STRING_VALUE).build()); + private Map<String, Object> getMapWithNonStringValues() { + Map<String, Object> mapValue = Maps.newHashMap(); + mapValue.put(FIRST_KEY, ImmutableList.<String>builder().add(FIRST_STRING_VALUE).build()); - return ImmutableMap.<String, Object>builder().put(FIRST_KEY, mapValue).build(); - } + return ImmutableMap.<String, Object>builder().put(FIRST_KEY, mapValue).build(); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJobTest.java b/src/test/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJobTest.java index 8d5dcaa3a7..d478b9f6e3 100644 --- a/src/test/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJobTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/CleanOutdatedPluginsJobTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.job; +import static java.util.Optional.ofNullable; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; + import com.epam.reportportal.extension.common.ExtensionPoint; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; import com.epam.ta.reportportal.core.plugin.Plugin; @@ -24,129 +32,129 @@ import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; import com.epam.ta.reportportal.job.service.PluginLoaderService; import com.google.common.collect.Lists; -import org.junit.jupiter.api.Test; -import org.pf4j.PluginWrapper; - import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.Optional; - -import static java.util.Optional.ofNullable; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.mockito.internal.verification.VerificationModeFactory.times; +import org.junit.jupiter.api.Test; +import org.pf4j.PluginWrapper; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> **/ class CleanOutdatedPluginsJobTest { - private static final String PLUGIN_TEMP_DIRECTORY = "/temp/"; + private static final String PLUGIN_TEMP_DIRECTORY = "/temp/"; - private String pluginsRootPath = System.getProperty("java.io.tmpdir") + "/plugins"; + private String pluginsRootPath = System.getProperty("java.io.tmpdir") + "/plugins"; - private IntegrationTypeRepository integrationTypeRepository = mock(IntegrationTypeRepository.class); + private IntegrationTypeRepository integrationTypeRepository = mock( + IntegrationTypeRepository.class); - private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); + private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); - private PluginLoaderService pluginLoaderService = mock(PluginLoaderService.class); + private PluginLoaderService pluginLoaderService = mock(PluginLoaderService.class); - private PluginWrapper jiraPlugin = mock(PluginWrapper.class); - private IntegrationType jiraIntegrationType = mock(IntegrationType.class); - private PluginWrapper rallyPlugin = mock(PluginWrapper.class); - private IntegrationType rallyIntegrationType = mock(IntegrationType.class); + private PluginWrapper jiraPlugin = mock(PluginWrapper.class); + private IntegrationType jiraIntegrationType = mock(IntegrationType.class); + private PluginWrapper rallyPlugin = mock(PluginWrapper.class); + private IntegrationType rallyIntegrationType = mock(IntegrationType.class); - private CleanOutdatedPluginsJob cleanOutdatedPluginsJob = new CleanOutdatedPluginsJob(pluginsRootPath + PLUGIN_TEMP_DIRECTORY, - integrationTypeRepository, - pluginBox, - pluginLoaderService - ); + private CleanOutdatedPluginsJob cleanOutdatedPluginsJob = new CleanOutdatedPluginsJob( + pluginsRootPath + PLUGIN_TEMP_DIRECTORY, + integrationTypeRepository, + pluginBox, + pluginLoaderService + ); - @Test - void testExecutionWithoutPluginInCache() throws IOException { + @Test + void testExecutionWithoutPluginInCache() throws IOException { - File dir = new File(pluginsRootPath + PLUGIN_TEMP_DIRECTORY); - if (!dir.exists()) { - assertTrue(dir.mkdirs()); - } + File dir = new File(pluginsRootPath + PLUGIN_TEMP_DIRECTORY); + if (!dir.exists()) { + assertTrue(dir.mkdirs()); + } - File file = new File(dir, "qwe.jar"); + File file = new File(dir, "qwe.jar"); - assertTrue(file.createNewFile()); + assertTrue(file.createNewFile()); - when(pluginBox.isInUploadingState(any(String.class))).thenReturn(false); + when(pluginBox.isInUploadingState(any(String.class))).thenReturn(false); - cleanOutdatedPluginsJob.execute(); - } + cleanOutdatedPluginsJob.execute(); + } - @Test - void testExecutionWithPluginInCache() throws IOException { + @Test + void testExecutionWithPluginInCache() throws IOException { - File dir = new File(pluginsRootPath + PLUGIN_TEMP_DIRECTORY); - if (!dir.exists()) { - assertTrue(dir.mkdirs()); - } + File dir = new File(pluginsRootPath + PLUGIN_TEMP_DIRECTORY); + if (!dir.exists()) { + assertTrue(dir.mkdirs()); + } - File file = File.createTempFile("test", ".jar", dir); + File file = File.createTempFile("test", ".jar", dir); - file.deleteOnExit(); + file.deleteOnExit(); - when(pluginBox.isInUploadingState(any(String.class))).thenReturn(true); + when(pluginBox.isInUploadingState(any(String.class))).thenReturn(true); - cleanOutdatedPluginsJob.execute(); - } + cleanOutdatedPluginsJob.execute(); + } - @Test - void testBrokenIntegrationTypeRemoving() { + @Test + void testBrokenIntegrationTypeRemoving() { - when(integrationTypeRepository.findAll()).thenReturn(getBrokenIntegrationType()); + when(integrationTypeRepository.findAll()).thenReturn(getBrokenIntegrationType()); - cleanOutdatedPluginsJob.execute(); - verify(pluginLoaderService, times(2)).checkAndDeleteIntegrationType(any(IntegrationType.class)); - } + cleanOutdatedPluginsJob.execute(); + verify(pluginLoaderService, times(2)).checkAndDeleteIntegrationType(any(IntegrationType.class)); + } - @Test - void testTemporaryPluginRemoving() { - List<Plugin> plugins = getPlugins(); - when(integrationTypeRepository.findAll()).thenReturn(Collections.emptyList()); + @Test + void testTemporaryPluginRemoving() { + List<Plugin> plugins = getPlugins(); + when(integrationTypeRepository.findAll()).thenReturn(Collections.emptyList()); - when(pluginBox.getPlugins()).thenReturn(plugins); - when(pluginBox.getPluginById(plugins.get(0).getId())).thenReturn(ofNullable(jiraPlugin)); - when(jiraPlugin.getPluginPath()).thenReturn(Paths.get(pluginsRootPath, "qwe.jar")); + when(pluginBox.getPlugins()).thenReturn(plugins); + when(pluginBox.getPluginById(plugins.get(0).getId())).thenReturn(ofNullable(jiraPlugin)); + when(jiraPlugin.getPluginPath()).thenReturn(Paths.get(pluginsRootPath, "qwe.jar")); - when(pluginBox.isInUploadingState(jiraPlugin.getPluginPath().getFileName().toString())).thenReturn(false); - when(integrationTypeRepository.findByName(jiraPlugin.getPluginId())).thenReturn(Optional.of(jiraIntegrationType)); - when(pluginBox.unloadPlugin(jiraIntegrationType)).thenReturn(true); + when(pluginBox.isInUploadingState( + jiraPlugin.getPluginPath().getFileName().toString())).thenReturn(false); + when(integrationTypeRepository.findByName(jiraPlugin.getPluginId())).thenReturn( + Optional.of(jiraIntegrationType)); + when(pluginBox.unloadPlugin(jiraIntegrationType)).thenReturn(true); - when(pluginBox.getPluginById(plugins.get(1).getId())).thenReturn(ofNullable(rallyPlugin)); - when(rallyPlugin.getPluginPath()).thenReturn(Paths.get(pluginsRootPath, "qwe1.jar")); + when(pluginBox.getPluginById(plugins.get(1).getId())).thenReturn(ofNullable(rallyPlugin)); + when(rallyPlugin.getPluginPath()).thenReturn(Paths.get(pluginsRootPath, "qwe1.jar")); - when(pluginBox.isInUploadingState(rallyPlugin.getPluginPath().getFileName().toString())).thenReturn(false); - when(integrationTypeRepository.findByName(rallyPlugin.getPluginId())).thenReturn(Optional.of(rallyIntegrationType)); - when(pluginBox.unloadPlugin(rallyIntegrationType)).thenReturn(false); + when(pluginBox.isInUploadingState( + rallyPlugin.getPluginPath().getFileName().toString())).thenReturn(false); + when(integrationTypeRepository.findByName(rallyPlugin.getPluginId())).thenReturn( + Optional.of(rallyIntegrationType)); + when(pluginBox.unloadPlugin(rallyIntegrationType)).thenReturn(false); - cleanOutdatedPluginsJob.execute(); + cleanOutdatedPluginsJob.execute(); - } + } - private List<IntegrationType> getBrokenIntegrationType() { + private List<IntegrationType> getBrokenIntegrationType() { - IntegrationType jira = new IntegrationType(); - jira.setName("jira"); - jira.setDetails(new IntegrationTypeDetails()); + IntegrationType jira = new IntegrationType(); + jira.setName("jira"); + jira.setDetails(new IntegrationTypeDetails()); - IntegrationType rally = new IntegrationType(); - rally.setName("rally"); + IntegrationType rally = new IntegrationType(); + rally.setName("rally"); - return Lists.newArrayList(jira, rally); - } + return Lists.newArrayList(jira, rally); + } - private List<Plugin> getPlugins() { - return Lists.newArrayList(new Plugin("jira", ExtensionPoint.BTS), new Plugin("rally", ExtensionPoint.BTS)); - } + private List<Plugin> getPlugins() { + return Lists.newArrayList(new Plugin("jira", ExtensionPoint.BTS), + new Plugin("rally", ExtensionPoint.BTS)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJobTest.java b/src/test/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJobTest.java index 699221b806..0096bbae97 100644 --- a/src/test/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJobTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/InterruptBrokenLaunchesJobTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.job; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.LogRepository; import com.epam.ta.reportportal.dao.ProjectRepository; @@ -26,6 +31,10 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectAttribute; import com.google.common.collect.Sets; +import java.time.Duration; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -33,92 +42,93 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.PageImpl; -import java.time.Duration; -import java.util.Collections; -import java.util.Optional; -import java.util.stream.Stream; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class InterruptBrokenLaunchesJobTest { - @Mock - private LaunchRepository launchRepository; - - @Mock - private LogRepository logRepository; - - @Mock - private TestItemRepository testItemRepository; - - @Mock - private ProjectRepository projectRepository; - - @InjectMocks - private InterruptBrokenLaunchesJob interruptBrokenLaunchesJob; - - @Test - void noInProgressItemsTest() { - String name = "name"; - Project project = new Project(); - final ProjectAttribute projectAttribute = new ProjectAttribute(); - final Attribute attribute = new Attribute(); - attribute.setName("job.interruptJobTime"); - projectAttribute.setAttribute(attribute); - - //1 day in seconds - projectAttribute.setValue(String.valueOf(3600 * 24)); - project.setProjectAttributes(Sets.newHashSet(projectAttribute)); - project.setName(name); - - long launchId = 1L; - - when(projectRepository.findAllIdsAndProjectAttributes(any())).thenReturn(new PageImpl<>(Collections.singletonList(project))); - when(launchRepository.streamIdsWithStatusAndStartTimeBefore(any(), any(), any())).thenReturn(Stream.of(launchId)); - when(testItemRepository.hasItemsInStatusByLaunch(launchId, StatusEnum.IN_PROGRESS)).thenReturn(false); - when(launchRepository.findById(launchId)).thenReturn(Optional.of(new Launch())); - - interruptBrokenLaunchesJob.execute(null); - - verify(launchRepository, times(1)).findById(launchId); - verify(launchRepository, times(1)).save(any()); - - } - - @Test - void interruptLaunchWithInProgressItemsTest() { - String name = "name"; - Project project = new Project(); - final ProjectAttribute projectAttribute = new ProjectAttribute(); - final Attribute attribute = new Attribute(); - attribute.setName("job.interruptJobTime"); - projectAttribute.setAttribute(attribute); - - //1 day in seconds - projectAttribute.setValue(String.valueOf(3600 * 24)); - project.setProjectAttributes(Sets.newHashSet(projectAttribute)); - project.setName(name); - - long launchId = 1L; - - when(projectRepository.findAllIdsAndProjectAttributes(any())).thenReturn(new PageImpl<>(Collections.singletonList(project))); - when(launchRepository.streamIdsWithStatusAndStartTimeBefore(any(), any(), any())).thenReturn(Stream.of(launchId)); - when(testItemRepository.hasItemsInStatusByLaunch(launchId, StatusEnum.IN_PROGRESS)).thenReturn(true); - when(testItemRepository.hasItemsInStatusAddedLately(launchId, Duration.ofSeconds(3600 * 24),StatusEnum.IN_PROGRESS)).thenReturn(false); - when(testItemRepository.hasLogs(launchId, Duration.ofSeconds(3600 * 24), StatusEnum.IN_PROGRESS)).thenReturn(true); - when(logRepository.hasLogsAddedLately(Duration.ofSeconds(3600 * 24), launchId, StatusEnum.IN_PROGRESS)).thenReturn(false); - when(launchRepository.findById(launchId)).thenReturn(Optional.of(new Launch())); - - interruptBrokenLaunchesJob.execute(null); - - verify(testItemRepository, times(1)).interruptInProgressItems(launchId); - verify(launchRepository, times(1)).findById(launchId); - verify(launchRepository, times(1)).save(any()); - - } + @Mock + private LaunchRepository launchRepository; + + @Mock + private LogRepository logRepository; + + @Mock + private TestItemRepository testItemRepository; + + @Mock + private ProjectRepository projectRepository; + + @InjectMocks + private InterruptBrokenLaunchesJob interruptBrokenLaunchesJob; + + @Test + void noInProgressItemsTest() { + String name = "name"; + Project project = new Project(); + final ProjectAttribute projectAttribute = new ProjectAttribute(); + final Attribute attribute = new Attribute(); + attribute.setName("job.interruptJobTime"); + projectAttribute.setAttribute(attribute); + + //1 day in seconds + projectAttribute.setValue(String.valueOf(3600 * 24)); + project.setProjectAttributes(Sets.newHashSet(projectAttribute)); + project.setName(name); + + long launchId = 1L; + + when(projectRepository.findAllIdsAndProjectAttributes(any())).thenReturn( + new PageImpl<>(Collections.singletonList(project))); + when(launchRepository.streamIdsWithStatusAndStartTimeBefore(any(), any(), any())).thenReturn( + Stream.of(launchId)); + when(testItemRepository.hasItemsInStatusByLaunch(launchId, StatusEnum.IN_PROGRESS)).thenReturn( + false); + when(launchRepository.findById(launchId)).thenReturn(Optional.of(new Launch())); + + interruptBrokenLaunchesJob.execute(null); + + verify(launchRepository, times(1)).findById(launchId); + verify(launchRepository, times(1)).save(any()); + + } + + @Test + void interruptLaunchWithInProgressItemsTest() { + String name = "name"; + Project project = new Project(); + final ProjectAttribute projectAttribute = new ProjectAttribute(); + final Attribute attribute = new Attribute(); + attribute.setName("job.interruptJobTime"); + projectAttribute.setAttribute(attribute); + + //1 day in seconds + projectAttribute.setValue(String.valueOf(3600 * 24)); + project.setProjectAttributes(Sets.newHashSet(projectAttribute)); + project.setName(name); + + long launchId = 1L; + + when(projectRepository.findAllIdsAndProjectAttributes(any())).thenReturn( + new PageImpl<>(Collections.singletonList(project))); + when(launchRepository.streamIdsWithStatusAndStartTimeBefore(any(), any(), any())).thenReturn( + Stream.of(launchId)); + when(testItemRepository.hasItemsInStatusByLaunch(launchId, StatusEnum.IN_PROGRESS)).thenReturn( + true); + when(testItemRepository.hasItemsInStatusAddedLately(launchId, Duration.ofSeconds(3600 * 24), + StatusEnum.IN_PROGRESS)).thenReturn(false); + when(testItemRepository.hasLogs(launchId, Duration.ofSeconds(3600 * 24), + StatusEnum.IN_PROGRESS)).thenReturn(true); + when(logRepository.hasLogsAddedLately(Duration.ofSeconds(3600 * 24), launchId, + StatusEnum.IN_PROGRESS)).thenReturn(false); + when(launchRepository.findById(launchId)).thenReturn(Optional.of(new Launch())); + + interruptBrokenLaunchesJob.execute(null); + + verify(testItemRepository, times(1)).interruptInProgressItems(launchId); + verify(launchRepository, times(1)).findById(launchId); + verify(launchRepository, times(1)).save(any()); + + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/JobExecutorDelegateTest.java b/src/test/java/com/epam/ta/reportportal/job/JobExecutorDelegateTest.java index 0aab51d2c6..aa47ff9e57 100644 --- a/src/test/java/com/epam/ta/reportportal/job/JobExecutorDelegateTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/JobExecutorDelegateTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.job; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -23,9 +26,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.scheduling.TaskScheduler; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - /** * Created by Andrey_Ivanov1 on 31-May-17. */ @@ -33,17 +33,17 @@ @ExtendWith(MockitoExtension.class) class JobExecutorDelegateTest { - @InjectMocks - private JobExecutorDelegate jobExecutorDelegate = new JobExecutorDelegate(); - @Mock - private SelfCancelableJob selfCancalableJob; - @Mock - private TaskScheduler taskScheduler; - - @Test - void submitJobTest() { - jobExecutorDelegate.submitJob(selfCancalableJob); - verify(taskScheduler, times(1)).schedule(selfCancalableJob, selfCancalableJob); - } + @InjectMocks + private JobExecutorDelegate jobExecutorDelegate = new JobExecutorDelegate(); + @Mock + private SelfCancelableJob selfCancalableJob; + @Mock + private TaskScheduler taskScheduler; + + @Test + void submitJobTest() { + jobExecutorDelegate.submitJob(selfCancalableJob); + verify(taskScheduler, times(1)).schedule(selfCancalableJob, selfCancalableJob); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/LoadPluginsJobTest.java b/src/test/java/com/epam/ta/reportportal/job/LoadPluginsJobTest.java index 5f89408591..099b1d4944 100644 --- a/src/test/java/com/epam/ta/reportportal/job/LoadPluginsJobTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/LoadPluginsJobTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.job; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; import com.epam.ta.reportportal.core.plugin.PluginInfo; import com.epam.ta.reportportal.dao.IntegrationTypeRepository; @@ -24,84 +28,83 @@ import com.epam.ta.reportportal.filesystem.DataStore; import com.epam.ta.reportportal.job.service.PluginLoaderService; import com.google.common.collect.Lists; -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Test; -import org.pf4j.PluginWrapper; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.List; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import org.pf4j.PluginWrapper; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LoadPluginsJobTest { - private IntegrationTypeRepository integrationTypeRepository = mock(IntegrationTypeRepository.class); + private IntegrationTypeRepository integrationTypeRepository = mock( + IntegrationTypeRepository.class); - private PluginLoaderService pluginLoaderService = mock(PluginLoaderService.class); + private PluginLoaderService pluginLoaderService = mock(PluginLoaderService.class); - private String pluginsRootPath = "plugins"; + private String pluginsRootPath = "plugins"; - private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); + private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); - private DataStore dataStore = mock(DataStore.class); + private DataStore dataStore = mock(DataStore.class); - private PluginWrapper rallyPlugin = mock(PluginWrapper.class); - private IntegrationType rally = mock(IntegrationType.class); + private PluginWrapper rallyPlugin = mock(PluginWrapper.class); + private IntegrationType rally = mock(IntegrationType.class); - private LoadPluginsJob loadPluginsJob = new LoadPluginsJob(pluginsRootPath, - integrationTypeRepository, - pluginLoaderService, - pluginBox, - dataStore - ); + private LoadPluginsJob loadPluginsJob = new LoadPluginsJob(pluginsRootPath, + integrationTypeRepository, + pluginLoaderService, + pluginBox, + dataStore + ); - @AfterAll - public static void clearPluginDirectory() throws IOException { - FileUtils.deleteDirectory(new File(System.getProperty("user.dir") + "/plugins")); - } + @AfterAll + public static void clearPluginDirectory() throws IOException { + FileUtils.deleteDirectory(new File(System.getProperty("user.dir") + "/plugins")); + } - @Test - void loadDisabledPluginTest() throws IOException { + @Test + void loadDisabledPluginTest() throws IOException { - List<IntegrationType> integrationTypes = getIntegrationTypes(); - when(integrationTypeRepository.findAll()).thenReturn(integrationTypes); - List<PluginInfo> pluginInfos = getPluginInfos(); + List<IntegrationType> integrationTypes = getIntegrationTypes(); + when(integrationTypeRepository.findAll()).thenReturn(integrationTypes); + List<PluginInfo> pluginInfos = getPluginInfos(); - File tempFile = File.createTempFile("file", ".jar"); - tempFile.deleteOnExit(); + File tempFile = File.createTempFile("file", ".jar"); + tempFile.deleteOnExit(); - when(dataStore.load(any(String.class))).thenReturn(new FileInputStream(tempFile)); - when(pluginBox.loadPlugin(any(String.class), any(IntegrationTypeDetails.class))).thenReturn(true); - when(pluginLoaderService.getNotLoadedPluginsInfo()).thenReturn(pluginInfos); - when(pluginBox.getPluginById(any(String.class))).thenReturn(java.util.Optional.ofNullable(rallyPlugin)); - when(rallyPlugin.getPluginId()).thenReturn("rally"); - when(integrationTypeRepository.findByName(any(String.class))).thenReturn(java.util.Optional.ofNullable(rally)); - when(pluginBox.unloadPlugin(rally)).thenReturn(true); + when(dataStore.load(any(String.class))).thenReturn(new FileInputStream(tempFile)); + when(pluginBox.loadPlugin(any(String.class), any(IntegrationTypeDetails.class))).thenReturn( + true); + when(pluginLoaderService.getNotLoadedPluginsInfo()).thenReturn(pluginInfos); + when(pluginBox.getPluginById(any(String.class))).thenReturn( + java.util.Optional.ofNullable(rallyPlugin)); + when(rallyPlugin.getPluginId()).thenReturn("rally"); + when(integrationTypeRepository.findByName(any(String.class))).thenReturn( + java.util.Optional.ofNullable(rally)); + when(pluginBox.unloadPlugin(rally)).thenReturn(true); - loadPluginsJob.execute(); - } + loadPluginsJob.execute(); + } - private List<IntegrationType> getIntegrationTypes() { - IntegrationType jira = new IntegrationType(); - jira.setName("jira"); - IntegrationType rally = new IntegrationType(); - rally.setName("rally"); - return Lists.newArrayList(jira, rally); - } + private List<IntegrationType> getIntegrationTypes() { + IntegrationType jira = new IntegrationType(); + jira.setName("jira"); + IntegrationType rally = new IntegrationType(); + rally.setName("rally"); + return Lists.newArrayList(jira, rally); + } - private List<PluginInfo> getPluginInfos() { + private List<PluginInfo> getPluginInfos() { - return Lists.newArrayList(new PluginInfo("jira", "v1.0", "file Id", "jira file", true), - new PluginInfo("rally", "v2.0", "file Id", "rally file", false) - ); - } + return Lists.newArrayList(new PluginInfo("jira", "v1.0", "file Id", "jira file", true), + new PluginInfo("rally", "v2.0", "file Id", "rally file", false) + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/PluginLoaderServiceTest.java b/src/test/java/com/epam/ta/reportportal/job/PluginLoaderServiceTest.java index 3bb9244287..fbf4cab757 100644 --- a/src/test/java/com/epam/ta/reportportal/job/PluginLoaderServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/PluginLoaderServiceTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.job; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.reportportal.extension.common.IntegrationTypeProperties; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; import com.epam.ta.reportportal.core.plugin.PluginInfo; @@ -26,128 +31,129 @@ import com.epam.ta.reportportal.job.service.impl.PluginLoaderServiceImpl; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.pf4j.PluginDescriptor; -import org.pf4j.PluginWrapper; - import java.nio.file.Paths; import java.util.List; import java.util.Map; import java.util.Optional; - -import static org.mockito.Mockito.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.pf4j.PluginDescriptor; +import org.pf4j.PluginWrapper; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PluginLoaderServiceTest { - private IntegrationTypeRepository integrationTypeRepository = mock(IntegrationTypeRepository.class); - - private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); - - private PluginLoaderService pluginLoaderService = new PluginLoaderServiceImpl(integrationTypeRepository, pluginBox); - - private PluginWrapper jiraPlugin = mock(PluginWrapper.class); - private PluginWrapper rallyPlugin = mock(PluginWrapper.class); - - private PluginDescriptor jiraPluginDescriptor = mock(PluginDescriptor.class); - private PluginDescriptor rallyPluginDescriptor = mock(PluginDescriptor.class); - - @Test - void getNotLoadedPluginsInfoTest() { - - when(pluginBox.getPluginById("jira")).thenReturn(Optional.ofNullable(jiraPlugin)); - when(pluginBox.getPluginById("rally")).thenReturn(Optional.ofNullable(rallyPlugin)); - when(jiraPlugin.getDescriptor()).thenReturn(jiraPluginDescriptor); - when(jiraPluginDescriptor.getVersion()).thenReturn("v1"); - when(rallyPlugin.getDescriptor()).thenReturn(rallyPluginDescriptor); - when(rallyPluginDescriptor.getVersion()).thenReturn("another version"); - when(integrationTypeRepository.findAll()).thenReturn(getIntegrationTypes()); - List<PluginInfo> notLoadedPluginsInfo = pluginLoaderService.getNotLoadedPluginsInfo(); - - Assertions.assertFalse(notLoadedPluginsInfo.isEmpty()); - Assertions.assertEquals(1, notLoadedPluginsInfo.size()); - Assertions.assertEquals("rally", notLoadedPluginsInfo.get(0).getId()); - } - - @Test - void checkAndDeleteIntegrationTypeWhenPluginPositive() { - IntegrationType integrationType = new IntegrationType(); - integrationType.setId(1L); - integrationType.setName("jira"); - - when(pluginBox.getPluginById(integrationType.getName())).thenReturn(Optional.ofNullable(jiraPlugin)); - when(jiraPlugin.getPluginId()).thenReturn("jira"); - when(jiraPlugin.getPluginPath()).thenReturn(Paths.get("plugins", "file.jar")); - when(pluginBox.unloadPlugin(integrationType)).thenReturn(true); - - pluginLoaderService.checkAndDeleteIntegrationType(integrationType); - - verify(integrationTypeRepository, times(1)).deleteById(integrationType.getId()); - } - - @Test - void checkAndDeleteIntegrationTypeWhenPluginNegative() { - IntegrationType integrationType = new IntegrationType(); - integrationType.setId(1L); - integrationType.setName("jira"); - - when(pluginBox.getPluginById(integrationType.getName())).thenReturn(Optional.ofNullable(jiraPlugin)); - when(jiraPlugin.getPluginId()).thenReturn("jira"); - when(pluginBox.unloadPlugin(integrationType)).thenReturn(false); - - pluginLoaderService.checkAndDeleteIntegrationType(integrationType); - - verify(integrationTypeRepository, times(0)).deleteById(integrationType.getId()); - } - - @Test - void checkAndDeleteIntegrationTypeWhenNotPluginTest() { - IntegrationType integrationType = new IntegrationType(); - integrationType.setId(1L); - integrationType.setName("EMAIL"); - - pluginLoaderService.checkAndDeleteIntegrationType(integrationType); - - verify(integrationTypeRepository, times(0)).deleteById(integrationType.getId()); - } - - private List<IntegrationType> getIntegrationTypes() { - - IntegrationType jira = new IntegrationType(); - jira.setName("jira"); - IntegrationTypeDetails jiraDetails = new IntegrationTypeDetails(); - Map<String, Object> jiraParams = Maps.newHashMap(); - jiraParams.put(IntegrationTypeProperties.FILE_ID.getAttribute(), "f1"); - jiraParams.put(IntegrationTypeProperties.FILE_NAME.getAttribute(), "fname1"); - jiraParams.put(IntegrationTypeProperties.VERSION.getAttribute(), "v1"); - jiraParams.put(IntegrationTypeProperties.COMMANDS.getAttribute(), ""); - jiraDetails.setDetails(jiraParams); - jira.setEnabled(true); - jira.setDetails(jiraDetails); - - IntegrationType rally = new IntegrationType(); - rally.setEnabled(true); - Map<String, Object> rallyParams = Maps.newHashMap(); - rallyParams.put(IntegrationTypeProperties.FILE_ID.getAttribute(), "f2"); - rallyParams.put(IntegrationTypeProperties.FILE_NAME.getAttribute(), "fname2"); - rallyParams.put(IntegrationTypeProperties.VERSION.getAttribute(), "v2"); - rallyParams.put(IntegrationTypeProperties.COMMANDS.getAttribute(), ""); - IntegrationTypeDetails rallyDetails = new IntegrationTypeDetails(); - rallyDetails.setDetails(rallyParams); - rally.setName("rally"); - rally.setDetails(rallyDetails); - - IntegrationType noDetails = new IntegrationType(); - noDetails.setName("NO DETAILS"); - - IntegrationType emptyParams = new IntegrationType(); - emptyParams.setName("EMPTY PARAMS"); - emptyParams.setDetails(new IntegrationTypeDetails()); - - return Lists.newArrayList(jira, rally, noDetails, emptyParams); - } + private IntegrationTypeRepository integrationTypeRepository = mock( + IntegrationTypeRepository.class); + + private Pf4jPluginBox pluginBox = mock(Pf4jPluginBox.class); + + private PluginLoaderService pluginLoaderService = new PluginLoaderServiceImpl( + integrationTypeRepository, pluginBox); + + private PluginWrapper jiraPlugin = mock(PluginWrapper.class); + private PluginWrapper rallyPlugin = mock(PluginWrapper.class); + + private PluginDescriptor jiraPluginDescriptor = mock(PluginDescriptor.class); + private PluginDescriptor rallyPluginDescriptor = mock(PluginDescriptor.class); + + @Test + void getNotLoadedPluginsInfoTest() { + + when(pluginBox.getPluginById("jira")).thenReturn(Optional.ofNullable(jiraPlugin)); + when(pluginBox.getPluginById("rally")).thenReturn(Optional.ofNullable(rallyPlugin)); + when(jiraPlugin.getDescriptor()).thenReturn(jiraPluginDescriptor); + when(jiraPluginDescriptor.getVersion()).thenReturn("v1"); + when(rallyPlugin.getDescriptor()).thenReturn(rallyPluginDescriptor); + when(rallyPluginDescriptor.getVersion()).thenReturn("another version"); + when(integrationTypeRepository.findAll()).thenReturn(getIntegrationTypes()); + List<PluginInfo> notLoadedPluginsInfo = pluginLoaderService.getNotLoadedPluginsInfo(); + + Assertions.assertFalse(notLoadedPluginsInfo.isEmpty()); + Assertions.assertEquals(1, notLoadedPluginsInfo.size()); + Assertions.assertEquals("rally", notLoadedPluginsInfo.get(0).getId()); + } + + @Test + void checkAndDeleteIntegrationTypeWhenPluginPositive() { + IntegrationType integrationType = new IntegrationType(); + integrationType.setId(1L); + integrationType.setName("jira"); + + when(pluginBox.getPluginById(integrationType.getName())).thenReturn( + Optional.ofNullable(jiraPlugin)); + when(jiraPlugin.getPluginId()).thenReturn("jira"); + when(jiraPlugin.getPluginPath()).thenReturn(Paths.get("plugins", "file.jar")); + when(pluginBox.unloadPlugin(integrationType)).thenReturn(true); + + pluginLoaderService.checkAndDeleteIntegrationType(integrationType); + + verify(integrationTypeRepository, times(1)).deleteById(integrationType.getId()); + } + + @Test + void checkAndDeleteIntegrationTypeWhenPluginNegative() { + IntegrationType integrationType = new IntegrationType(); + integrationType.setId(1L); + integrationType.setName("jira"); + + when(pluginBox.getPluginById(integrationType.getName())).thenReturn( + Optional.ofNullable(jiraPlugin)); + when(jiraPlugin.getPluginId()).thenReturn("jira"); + when(pluginBox.unloadPlugin(integrationType)).thenReturn(false); + + pluginLoaderService.checkAndDeleteIntegrationType(integrationType); + + verify(integrationTypeRepository, times(0)).deleteById(integrationType.getId()); + } + + @Test + void checkAndDeleteIntegrationTypeWhenNotPluginTest() { + IntegrationType integrationType = new IntegrationType(); + integrationType.setId(1L); + integrationType.setName("EMAIL"); + + pluginLoaderService.checkAndDeleteIntegrationType(integrationType); + + verify(integrationTypeRepository, times(0)).deleteById(integrationType.getId()); + } + + private List<IntegrationType> getIntegrationTypes() { + + IntegrationType jira = new IntegrationType(); + jira.setName("jira"); + IntegrationTypeDetails jiraDetails = new IntegrationTypeDetails(); + Map<String, Object> jiraParams = Maps.newHashMap(); + jiraParams.put(IntegrationTypeProperties.FILE_ID.getAttribute(), "f1"); + jiraParams.put(IntegrationTypeProperties.FILE_NAME.getAttribute(), "fname1"); + jiraParams.put(IntegrationTypeProperties.VERSION.getAttribute(), "v1"); + jiraParams.put(IntegrationTypeProperties.COMMANDS.getAttribute(), ""); + jiraDetails.setDetails(jiraParams); + jira.setEnabled(true); + jira.setDetails(jiraDetails); + + IntegrationType rally = new IntegrationType(); + rally.setEnabled(true); + Map<String, Object> rallyParams = Maps.newHashMap(); + rallyParams.put(IntegrationTypeProperties.FILE_ID.getAttribute(), "f2"); + rallyParams.put(IntegrationTypeProperties.FILE_NAME.getAttribute(), "fname2"); + rallyParams.put(IntegrationTypeProperties.VERSION.getAttribute(), "v2"); + rallyParams.put(IntegrationTypeProperties.COMMANDS.getAttribute(), ""); + IntegrationTypeDetails rallyDetails = new IntegrationTypeDetails(); + rallyDetails.setDetails(rallyParams); + rally.setName("rally"); + rally.setDetails(rallyDetails); + + IntegrationType noDetails = new IntegrationType(); + noDetails.setName("NO DETAILS"); + + IntegrationType emptyParams = new IntegrationType(); + emptyParams.setName("EMPTY PARAMS"); + emptyParams.setDetails(new IntegrationTypeDetails()); + + return Lists.newArrayList(jira, rally, noDetails, emptyParams); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/SaveLogBinaryDataTaskTest.java b/src/test/java/com/epam/ta/reportportal/job/SaveLogBinaryDataTaskTest.java deleted file mode 100644 index 651eea4482..0000000000 --- a/src/test/java/com/epam/ta/reportportal/job/SaveLogBinaryDataTaskTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.job; - -import com.epam.ta.reportportal.binary.AttachmentBinaryDataService; -import com.epam.ta.reportportal.core.log.impl.SaveLogBinaryDataTask; -import com.epam.ta.reportportal.entity.attachment.AttachmentMetaInfo; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.mock.web.MockMultipartFile; - -import java.nio.charset.StandardCharsets; - -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> - */ -@ExtendWith(MockitoExtension.class) -class SaveLogBinaryDataTaskTest { - - @Mock - private AttachmentBinaryDataService attachmentBinaryDataService; - - @InjectMocks - private SaveLogBinaryDataTask saveLogBinaryDataTask; - - @Test - void saveBinaryDataPositive() { - long logId = 1L; - MockMultipartFile file = new MockMultipartFile("file", "filename", "text/plain", "some data".getBytes(StandardCharsets.UTF_8)); - long projectId = 2L; - AttachmentMetaInfo attachmentMetaInfo = AttachmentMetaInfo.builder().withLogId(logId).withProjectId(projectId).build(); - SaveLogBinaryDataTask saveLogBinaryDataTask = this.saveLogBinaryDataTask.withFile(file).withAttachmentMetaInfo(attachmentMetaInfo); - - saveLogBinaryDataTask.run(); - - verify(attachmentBinaryDataService, times(1)).saveFileAndAttachToLog(file, attachmentMetaInfo); - - } -} \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/job/SelfCancalableJobTest.java b/src/test/java/com/epam/ta/reportportal/job/SelfCancalableJobTest.java index 41ce2498f7..0e9ebbef99 100644 --- a/src/test/java/com/epam/ta/reportportal/job/SelfCancalableJobTest.java +++ b/src/test/java/com/epam/ta/reportportal/job/SelfCancalableJobTest.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.job; +import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -24,8 +26,6 @@ import org.springframework.scheduling.TriggerContext; import org.springframework.test.util.ReflectionTestUtils; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * Created by Andrey_Ivanov1 on 01-Jun-17. */ @@ -33,27 +33,28 @@ @ExtendWith(MockitoExtension.class) class SelfCancelableJobTest { - @Mock - private Trigger triggerDelegate; - @Mock - private TriggerContext triggerContext; - - @Test - void selfCancelableJobTest() { - SelfCancelableJob selfCancelableJob = new SelfCancelableJob(triggerDelegate) { - @Override - public void run() { - } - }; - - assertEquals(true, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); - assertEquals(triggerDelegate, ReflectionTestUtils.getField(selfCancelableJob, "triggerDelegate")); - selfCancelableJob.oneMoreTime(true); - selfCancelableJob.nextExecutionTime(triggerContext); - assertEquals(true, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); - selfCancelableJob.oneMoreTime(false); - selfCancelableJob.nextExecutionTime(triggerContext); - assertEquals(false, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); - } + @Mock + private Trigger triggerDelegate; + @Mock + private TriggerContext triggerContext; + + @Test + void selfCancelableJobTest() { + SelfCancelableJob selfCancelableJob = new SelfCancelableJob(triggerDelegate) { + @Override + public void run() { + } + }; + + assertEquals(true, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); + assertEquals(triggerDelegate, + ReflectionTestUtils.getField(selfCancelableJob, "triggerDelegate")); + selfCancelableJob.oneMoreTime(true); + selfCancelableJob.nextExecutionTime(triggerContext); + assertEquals(true, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); + selfCancelableJob.oneMoreTime(false); + selfCancelableJob.nextExecutionTime(triggerContext); + assertEquals(false, ReflectionTestUtils.getField(selfCancelableJob, "oneMoreTime")); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java b/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java index f8f24e16bd..fd9aeef652 100644 --- a/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java +++ b/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java @@ -16,6 +16,14 @@ package com.epam.ta.reportportal.plugin; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.reportportal.extension.bugtracking.BtsExtension; import com.epam.ta.reportportal.core.integration.impl.util.IntegrationTestUtil; import com.epam.ta.reportportal.core.integration.plugin.PluginLoader; @@ -26,6 +34,13 @@ import com.epam.ta.reportportal.entity.integration.IntegrationTypeDetails; import com.epam.ta.reportportal.exception.ReportPortalException; import com.google.common.collect.Lists; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -36,196 +51,207 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationEventPublisher; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class Pf4jPluginManagerTest { - public static final String PLUGINS_PATH = "plugins"; - public static final String RESOURCES_PATH = "resources"; - public static final String PLUGINS_TEMP_PATH = "plugins/temp"; - public static final String NEW_PLUGIN_FILE_NAME = "plugin.jar"; - - public static final String NEW_JIRA_PLUGIN_ID = "new_jira"; - public static final String NEW_JIRA_PLUGIN_VERSION = "1.0"; - - private final PluginLoader pluginLoader = mock(PluginLoader.class); - private final IntegrationTypeRepository integrationTypeRepository = mock(IntegrationTypeRepository.class); - private final AutowireCapableBeanFactory beanFactory = mock(AutowireCapableBeanFactory.class); - private final PluginManager pluginManager = mock(PluginManager.class); - private final PluginWrapper previousPlugin = mock(PluginWrapper.class); - private final PluginWrapper newPlugin = mock(PluginWrapper.class); - private final ApplicationEventPublisher applicationEventPublisher = mock(ApplicationEventPublisher.class); - - private final Pf4jPluginManager pluginBox = new Pf4jPluginManager(PLUGINS_PATH, - PLUGINS_TEMP_PATH, - RESOURCES_PATH, - pluginLoader, - integrationTypeRepository, - pluginManager, - beanFactory, - applicationEventPublisher - ); - - private final InputStream fileStream = mock(InputStream.class); - - Pf4jPluginManagerTest() throws IOException { - } - - @AfterEach - void cleanUp() throws IOException { - File directory = new File("plugins"); - if (directory.exists()) { - FileUtils.deleteDirectory(directory); - } - } - - @Test - void uploadPlugin() throws PluginException, IOException { - PluginInfo pluginInfo = getPluginInfo(); - - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); - IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); - IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); - when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); - when(pluginManager.getPlugin("old_jira")).then((i) -> { - pluginInfo.setId(NEW_JIRA_PLUGIN_ID); - return null; - }); - when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(NEW_JIRA_PLUGIN_ID); - when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); - when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); - when(pluginLoader.validatePluginExtensionClasses(newPlugin)).thenReturn(true); - doNothing().when(pluginLoader).savePlugin(Paths.get(PLUGINS_PATH, NEW_PLUGIN_FILE_NAME), fileStream); - - String pluginFileName = NEW_JIRA_PLUGIN_ID + "-" + NEW_JIRA_PLUGIN_VERSION + ".jar"; - when(pluginLoader.saveToDataStore(pluginFileName, fileStream)).thenReturn(pluginFileName); - when(pluginManager.loadPlugin(Paths.get(PLUGINS_PATH, pluginFileName))).thenReturn(NEW_JIRA_PLUGIN_ID); - when(integrationTypeRepository.save(any(IntegrationType.class))).thenReturn(jiraIntegrationType); - Files.createFile(Paths.get(PLUGINS_TEMP_PATH, "plugin.jar")); - IntegrationType newIntegrationType = pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream); - assertEquals(1L, newIntegrationType.getId().longValue()); - } - - @Test - void uploadPluginWithExistingFile() throws PluginException, IOException { - File tempFile = File.createTempFile(NEW_PLUGIN_FILE_NAME, ".jar", new File(PLUGINS_TEMP_PATH)); - tempFile.deleteOnExit(); - PluginInfo pluginInfo = getPluginInfo(); - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, tempFile.getName()))).thenReturn(pluginInfo); - IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); - IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); - when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); - when(pluginManager.getPlugin("old_jira")).then((i) -> { - pluginInfo.setId(NEW_JIRA_PLUGIN_ID); - return null; - }); - when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, tempFile.getName()))).thenReturn(NEW_JIRA_PLUGIN_ID); - when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); - when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); - when(pluginLoader.validatePluginExtensionClasses(newPlugin)).thenReturn(true); - String pluginFileName = NEW_JIRA_PLUGIN_ID + "-" + NEW_JIRA_PLUGIN_VERSION + ".jar"; - when(pluginManager.loadPlugin(Paths.get(PLUGINS_PATH, pluginFileName))).thenReturn(NEW_JIRA_PLUGIN_ID); - when(integrationTypeRepository.save(any(IntegrationType.class))).thenReturn(jiraIntegrationType); - IntegrationType newIntegrationType = pluginBox.uploadPlugin(tempFile.getName(), fileStream); - assertEquals(1L, newIntegrationType.getId().longValue()); - } - - @Test - void uploadPluginWithLoadingError() throws PluginException { - - PluginInfo pluginInfo = getPluginInfo(); - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); - IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); - IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); - when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); - when(pluginManager.getPlugin("old_jira")).then((i) -> { - pluginInfo.setId(NEW_JIRA_PLUGIN_ID); - return null; - }); - when(previousPlugin.getPluginState()).thenReturn(PluginState.STARTED); - when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); - when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(null); - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) - ); - assertEquals("Error during plugin uploading: 'Failed to load new plugin from file = 'plugin.jar''", exception.getMessage()); - } - - @Test - void uploadPluginWithoutExtensionClasses() throws PluginException { - - PluginInfo pluginInfo = getPluginInfo(); - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); - IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); - IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); - when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); - when(pluginManager.getPlugin("old_jira")).then((i) -> { - pluginInfo.setId(NEW_JIRA_PLUGIN_ID); - return null; - }); - when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(NEW_JIRA_PLUGIN_ID); - when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); - when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) - ); - assertEquals("Error during plugin uploading: 'New plugin with id = 'new_jira' doesn't have mandatory extension classes.'", - exception.getMessage() - ); - } - - @Test - void uploadPluginWithPluginException() throws PluginException { - - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenThrow(new PluginException( - "Manifest not found")); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) - ); - assertEquals("Error during plugin uploading: 'Manifest not found'", exception.getMessage()); - } - - @Test - void uploadPluginWithoutVersion() throws PluginException { - - when(pluginLoader.extractPluginInfo(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(getPluginInfoWithoutVersion()); - - final ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) - ); - assertEquals("Error during plugin uploading: 'Plugin version should be specified.'", exception.getMessage()); - } - - @Test - void getPlugins() { - when(pluginManager.getPlugins()).thenReturn(Lists.newArrayList(newPlugin)); - when(newPlugin.getPluginId()).thenReturn(NEW_JIRA_PLUGIN_ID); - when(pluginManager.getExtensionClasses(NEW_JIRA_PLUGIN_ID)).thenReturn(Lists.newArrayList(BtsExtension.class)); - List<Plugin> plugins = pluginBox.getPlugins(); - assertNotNull(plugins); - assertEquals(1L, plugins.size()); - } - - private PluginInfo getPluginInfo() { - return new PluginInfo("old_jira", NEW_JIRA_PLUGIN_VERSION); - } - - private PluginInfo getPluginInfoWithoutVersion() { - return new PluginInfo("jira", null); - } + public static final String PLUGINS_PATH = "plugins"; + public static final String RESOURCES_PATH = "resources"; + public static final String PLUGINS_TEMP_PATH = "plugins/temp"; + public static final String NEW_PLUGIN_FILE_NAME = "plugin.jar"; + + public static final String NEW_JIRA_PLUGIN_ID = "new_jira"; + public static final String NEW_JIRA_PLUGIN_VERSION = "1.0"; + + private final PluginLoader pluginLoader = mock(PluginLoader.class); + private final IntegrationTypeRepository integrationTypeRepository = mock( + IntegrationTypeRepository.class); + private final AutowireCapableBeanFactory beanFactory = mock(AutowireCapableBeanFactory.class); + private final PluginManager pluginManager = mock(PluginManager.class); + private final PluginWrapper previousPlugin = mock(PluginWrapper.class); + private final PluginWrapper newPlugin = mock(PluginWrapper.class); + private final ApplicationEventPublisher applicationEventPublisher = mock( + ApplicationEventPublisher.class); + + private final Pf4jPluginManager pluginBox = new Pf4jPluginManager(PLUGINS_PATH, + PLUGINS_TEMP_PATH, + RESOURCES_PATH, + pluginLoader, + integrationTypeRepository, + pluginManager, + beanFactory, + applicationEventPublisher + ); + + private final InputStream fileStream = mock(InputStream.class); + + Pf4jPluginManagerTest() throws IOException { + } + + @AfterEach + void cleanUp() throws IOException { + File directory = new File("plugins"); + if (directory.exists()) { + FileUtils.deleteDirectory(directory); + } + } + + @Test + void uploadPlugin() throws PluginException, IOException { + PluginInfo pluginInfo = getPluginInfo(); + + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); + IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); + IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); + when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); + when(pluginManager.getPlugin("old_jira")).then((i) -> { + pluginInfo.setId(NEW_JIRA_PLUGIN_ID); + return null; + }); + when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn( + NEW_JIRA_PLUGIN_ID); + when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); + when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); + when(pluginLoader.validatePluginExtensionClasses(newPlugin)).thenReturn(true); + doNothing().when(pluginLoader) + .savePlugin(Paths.get(PLUGINS_PATH, NEW_PLUGIN_FILE_NAME), fileStream); + + String pluginFileName = NEW_JIRA_PLUGIN_ID + "-" + NEW_JIRA_PLUGIN_VERSION + ".jar"; + when(pluginLoader.saveToDataStore(pluginFileName, fileStream)).thenReturn(pluginFileName); + when(pluginManager.loadPlugin(Paths.get(PLUGINS_PATH, pluginFileName))).thenReturn( + NEW_JIRA_PLUGIN_ID); + when(integrationTypeRepository.save(any(IntegrationType.class))).thenReturn( + jiraIntegrationType); + Files.createFile(Paths.get(PLUGINS_TEMP_PATH, "plugin.jar")); + IntegrationType newIntegrationType = pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream); + assertEquals(1L, newIntegrationType.getId().longValue()); + } + + @Test + void uploadPluginWithExistingFile() throws PluginException, IOException { + File tempFile = File.createTempFile(NEW_PLUGIN_FILE_NAME, ".jar", new File(PLUGINS_TEMP_PATH)); + tempFile.deleteOnExit(); + PluginInfo pluginInfo = getPluginInfo(); + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, tempFile.getName()))).thenReturn(pluginInfo); + IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); + IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); + when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); + when(pluginManager.getPlugin("old_jira")).then((i) -> { + pluginInfo.setId(NEW_JIRA_PLUGIN_ID); + return null; + }); + when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, tempFile.getName()))).thenReturn( + NEW_JIRA_PLUGIN_ID); + when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); + when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); + when(pluginLoader.validatePluginExtensionClasses(newPlugin)).thenReturn(true); + String pluginFileName = NEW_JIRA_PLUGIN_ID + "-" + NEW_JIRA_PLUGIN_VERSION + ".jar"; + when(pluginManager.loadPlugin(Paths.get(PLUGINS_PATH, pluginFileName))).thenReturn( + NEW_JIRA_PLUGIN_ID); + when(integrationTypeRepository.save(any(IntegrationType.class))).thenReturn( + jiraIntegrationType); + IntegrationType newIntegrationType = pluginBox.uploadPlugin(tempFile.getName(), fileStream); + assertEquals(1L, newIntegrationType.getId().longValue()); + } + + @Test + void uploadPluginWithLoadingError() throws PluginException { + + PluginInfo pluginInfo = getPluginInfo(); + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); + IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); + IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); + when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); + when(pluginManager.getPlugin("old_jira")).then((i) -> { + pluginInfo.setId(NEW_JIRA_PLUGIN_ID); + return null; + }); + when(previousPlugin.getPluginState()).thenReturn(PluginState.STARTED); + when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); + when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn( + null); + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) + ); + assertEquals( + "Error during plugin uploading: 'Failed to load new plugin from file = 'plugin.jar''", + exception.getMessage()); + } + + @Test + void uploadPluginWithoutExtensionClasses() throws PluginException { + + PluginInfo pluginInfo = getPluginInfo(); + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn(pluginInfo); + IntegrationType jiraIntegrationType = IntegrationTestUtil.getJiraIntegrationType(); + IntegrationTypeDetails jiraDetails = jiraIntegrationType.getDetails(); + when(pluginLoader.resolvePluginDetails(pluginInfo)).thenReturn(jiraDetails); + when(pluginManager.getPlugin("old_jira")).then((i) -> { + pluginInfo.setId(NEW_JIRA_PLUGIN_ID); + return null; + }); + when(pluginManager.loadPlugin(Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn( + NEW_JIRA_PLUGIN_ID); + when(pluginManager.getPlugin(NEW_JIRA_PLUGIN_ID)).thenReturn(newPlugin); + when(pluginManager.getPluginsRoot()).thenReturn(FileSystems.getDefault().getPath(PLUGINS_PATH)); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) + ); + assertEquals( + "Error during plugin uploading: 'New plugin with id = 'new_jira' doesn't have mandatory extension classes.'", + exception.getMessage() + ); + } + + @Test + void uploadPluginWithPluginException() throws PluginException { + + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenThrow(new PluginException( + "Manifest not found")); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) + ); + assertEquals("Error during plugin uploading: 'Manifest not found'", exception.getMessage()); + } + + @Test + void uploadPluginWithoutVersion() throws PluginException { + + when(pluginLoader.extractPluginInfo( + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn( + getPluginInfoWithoutVersion()); + + final ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) + ); + assertEquals("Error during plugin uploading: 'Plugin version should be specified.'", + exception.getMessage()); + } + + @Test + void getPlugins() { + when(pluginManager.getPlugins()).thenReturn(Lists.newArrayList(newPlugin)); + when(newPlugin.getPluginId()).thenReturn(NEW_JIRA_PLUGIN_ID); + when(pluginManager.getExtensionClasses(NEW_JIRA_PLUGIN_ID)).thenReturn( + Lists.newArrayList(BtsExtension.class)); + List<Plugin> plugins = pluginBox.getPlugins(); + assertNotNull(plugins); + assertEquals(1L, plugins.size()); + } + + private PluginInfo getPluginInfo() { + return new PluginInfo("old_jira", NEW_JIRA_PLUGIN_VERSION); + } + + private PluginInfo getPluginInfoWithoutVersion() { + return new PluginInfo("jira", null); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/store/service/DataStoreServiceTest.java b/src/test/java/com/epam/ta/reportportal/store/service/DataStoreServiceTest.java index 577e6866da..0c8a49bb3d 100644 --- a/src/test/java/com/epam/ta/reportportal/store/service/DataStoreServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/store/service/DataStoreServiceTest.java @@ -16,10 +16,22 @@ package com.epam.ta.reportportal.store.service; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.reportportal.commons.Thumbnailator; import com.epam.ta.reportportal.binary.impl.AttachmentDataStoreService; import com.epam.ta.reportportal.filesystem.DataEncoder; import com.epam.ta.reportportal.filesystem.DataStore; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -27,84 +39,77 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.io.InputStream; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - /** * @author Dzianis_Shybeka */ @ExtendWith(MockitoExtension.class) class DataStoreServiceTest { - @Mock - private DataStore dataStore; + @Mock + private DataStore dataStore; - @Mock - private Thumbnailator thumbnailator; + @Mock + private Thumbnailator thumbnailator; - @Mock - private DataEncoder dataEncoder; + @Mock + private DataEncoder dataEncoder; - @InjectMocks - private AttachmentDataStoreService dataStoreService; + @InjectMocks + private AttachmentDataStoreService dataStoreService; - @Test - void saveTest() throws Exception { - // given: - MultipartFile file = mock(MultipartFile.class); + @Test + void saveTest() throws Exception { + // given: + MultipartFile file = mock(MultipartFile.class); - // and: setups - when(dataStore.save("fileName", file.getInputStream())).thenReturn("filePath"); - when(dataEncoder.encode("filePath")).thenReturn("fileId"); + // and: setups + when(dataStore.save("fileName", file.getInputStream())).thenReturn("filePath"); + when(dataEncoder.encode("filePath")).thenReturn("fileId"); - // when: - String fileId = dataStoreService.save("fileName", file.getInputStream()); + // when: + String fileId = dataStoreService.save("fileName", file.getInputStream()); - assertEquals("fileId", fileId); - } + assertEquals("fileId", fileId); + } - @Test - void saveThumbnailTest() throws IOException { - MultipartFile file = mock(MultipartFile.class); + @Test + void saveThumbnailTest() throws IOException { + MultipartFile file = mock(MultipartFile.class); - when(dataStore.save("fileName", file.getInputStream())).thenReturn("thumbnailPath"); - when(dataEncoder.encode("thumbnailPath")).thenReturn("thumbnailId"); + when(dataStore.save("fileName", file.getInputStream())).thenReturn("thumbnailPath"); + when(dataEncoder.encode("thumbnailPath")).thenReturn("thumbnailId"); - assertEquals("thumbnailId", dataStoreService.saveThumbnail("fileName", file.getInputStream())); - } + assertEquals("thumbnailId", dataStoreService.saveThumbnail("fileName", file.getInputStream())); + } - @Test - void saveThumbnailWithException() throws IOException { - MultipartFile file = mock(MultipartFile.class); + @Test + void saveThumbnailWithException() throws IOException { + MultipartFile file = mock(MultipartFile.class); - when(thumbnailator.createThumbnail(file.getInputStream())).thenThrow(IOException.class); + when(thumbnailator.createThumbnail(file.getInputStream())).thenThrow(IOException.class); - assertNull(dataStoreService.saveThumbnail("fileName", file.getInputStream())); - } + assertNull(dataStoreService.saveThumbnail("fileName", file.getInputStream())); + } - @Test - void deleteTest() { - when(dataEncoder.decode("fileId")).thenReturn("filePath"); + @Test + void deleteTest() { + when(dataEncoder.decode("fileId")).thenReturn("filePath"); - dataStoreService.delete("fileId"); + dataStoreService.delete("fileId"); - verify(dataStore, times(1)).delete("filePath"); - } + verify(dataStore, times(1)).delete("filePath"); + } - @Test - void loadTest() { - InputStream inputStream = mock(InputStream.class); + @Test + void loadTest() { + InputStream inputStream = mock(InputStream.class); - when(dataEncoder.decode("fileId")).thenReturn("filePath"); - when(dataStore.load("filePath")).thenReturn(inputStream); + when(dataEncoder.decode("fileId")).thenReturn("filePath"); + when(dataStore.load("filePath")).thenReturn(inputStream); - Optional<InputStream> content = dataStoreService.load("fileId"); + Optional<InputStream> content = dataStoreService.load("fileId"); - assertTrue(content.isPresent()); - assertSame(inputStream, content.get()); - } + assertTrue(content.isPresent()); + assertSame(inputStream, content.get()); + } } diff --git a/src/test/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBeanTest.java b/src/test/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBeanTest.java index bbf7cc84a6..afffaf5bfb 100644 --- a/src/test/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBeanTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/ApplicationContextAwareFactoryBeanTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.util; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.FactoryBean; @@ -26,44 +29,41 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = { ApplicationContextAwareFactoryBeanTest.TestConfig.class }) +@ContextConfiguration(classes = {ApplicationContextAwareFactoryBeanTest.TestConfig.class}) public class ApplicationContextAwareFactoryBeanTest { - @Autowired - private ApplicationContextAwareFactoryBeanTest testObject; + @Autowired + private ApplicationContextAwareFactoryBeanTest testObject; - @Autowired - private ApplicationContext context; + @Autowired + private ApplicationContext context; - @Test - void testSingleton() { - assertThat(testObject, is(context.getBean(ApplicationContextAwareFactoryBeanTest.class))); - } + @Test + void testSingleton() { + assertThat(testObject, is(context.getBean(ApplicationContextAwareFactoryBeanTest.class))); + } - @Configuration - public static class TestConfig { + @Configuration + public static class TestConfig { - @Bean - FactoryBean<ApplicationContextAwareFactoryBeanTest> resourceCopier() { - return new ApplicationContextAwareFactoryBean<ApplicationContextAwareFactoryBeanTest>() { + @Bean + FactoryBean<ApplicationContextAwareFactoryBeanTest> resourceCopier() { + return new ApplicationContextAwareFactoryBean<ApplicationContextAwareFactoryBeanTest>() { - @Override - public Class<?> getObjectType() { - return ApplicationContextAwareFactoryBeanTest.class; - } + @Override + public Class<?> getObjectType() { + return ApplicationContextAwareFactoryBeanTest.class; + } - @Override - protected ApplicationContextAwareFactoryBeanTest createInstance() { - return new ApplicationContextAwareFactoryBeanTest(); - } - }; - } - } + @Override + protected ApplicationContextAwareFactoryBeanTest createInstance() { + return new ApplicationContextAwareFactoryBeanTest(); + } + }; + } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/ItemInfoUtilsTest.java b/src/test/java/com/epam/ta/reportportal/util/ItemInfoUtilsTest.java index a62386a949..7efc44eb87 100644 --- a/src/test/java/com/epam/ta/reportportal/util/ItemInfoUtilsTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/ItemInfoUtilsTest.java @@ -16,92 +16,99 @@ package com.epam.ta.reportportal.util; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class ItemInfoUtilsTest { - @Test - void nullAttributesCollectionTest() { - Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(null, "key"); - assertTrue(attribute.isEmpty()); - } - - @Test - void emptyAttributesCollectionTest() { - Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(Collections.emptyList(), "key"); - assertTrue(attribute.isEmpty()); - } - - @Test - void shouldFindNonSystemAttribute() { - String key = "key1"; - Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); - assertTrue(attribute.isPresent()); - assertEquals(key, attribute.get().getKey()); - } - - @Test - void shouldFindSystemAttribute() { - String key = "key3"; - Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); - assertTrue(attribute.isPresent()); - assertEquals(key, attribute.get().getKey()); - } - - @Test - void shouldNotFindAttribute() { - String key = "not-exist"; - Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); - assertTrue(attribute.isEmpty()); - } - - @Test - void nullAttributeResourceCollectionTest() { - Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource(null, "key"); - assertTrue(itemAttributeResource.isEmpty()); - } - - @Test - void emptyAttributeResourcesCollectionTest() { - Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource(Collections.emptyList(), "key"); - assertTrue(itemAttributeResource.isEmpty()); - } - - @Test - void shouldFindAttributeResource() { - String key = "key1"; - Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource(getAttributeResources(), key); - assertTrue(itemAttributeResource.isPresent()); - assertEquals(key, itemAttributeResource.get().getKey()); - } - - @Test - void shouldNotFindAttributeResource() { - String key = "not-exist"; - Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource(getAttributeResources(), key); - assertTrue(itemAttributeResource.isEmpty()); - } - - private List<ItemAttribute> getAttributes() { - return Lists.newArrayList( - new ItemAttribute("key1", "value1", false), - new ItemAttribute("key2", "value2", false), - new ItemAttribute("key3", "value3", true) - ); - } - - private List<ItemAttributeResource> getAttributeResources() { - return Lists.newArrayList(new ItemAttributeResource("key1", "value1"), new ItemAttributeResource("key2", "value2")); - } + @Test + void nullAttributesCollectionTest() { + Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(null, "key"); + assertTrue(attribute.isEmpty()); + } + + @Test + void emptyAttributesCollectionTest() { + Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(Collections.emptyList(), + "key"); + assertTrue(attribute.isEmpty()); + } + + @Test + void shouldFindNonSystemAttribute() { + String key = "key1"; + Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); + assertTrue(attribute.isPresent()); + assertEquals(key, attribute.get().getKey()); + } + + @Test + void shouldFindSystemAttribute() { + String key = "key3"; + Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); + assertTrue(attribute.isPresent()); + assertEquals(key, attribute.get().getKey()); + } + + @Test + void shouldNotFindAttribute() { + String key = "not-exist"; + Optional<ItemAttribute> attribute = ItemInfoUtils.extractAttribute(getAttributes(), key); + assertTrue(attribute.isEmpty()); + } + + @Test + void nullAttributeResourceCollectionTest() { + Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource( + null, "key"); + assertTrue(itemAttributeResource.isEmpty()); + } + + @Test + void emptyAttributeResourcesCollectionTest() { + Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource( + Collections.emptyList(), "key"); + assertTrue(itemAttributeResource.isEmpty()); + } + + @Test + void shouldFindAttributeResource() { + String key = "key1"; + Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource( + getAttributeResources(), key); + assertTrue(itemAttributeResource.isPresent()); + assertEquals(key, itemAttributeResource.get().getKey()); + } + + @Test + void shouldNotFindAttributeResource() { + String key = "not-exist"; + Optional<ItemAttributeResource> itemAttributeResource = ItemInfoUtils.extractAttributeResource( + getAttributeResources(), key); + assertTrue(itemAttributeResource.isEmpty()); + } + + private List<ItemAttribute> getAttributes() { + return Lists.newArrayList( + new ItemAttribute("key1", "value1", false), + new ItemAttribute("key2", "value2", false), + new ItemAttribute("key3", "value3", true) + ); + } + + private List<ItemAttributeResource> getAttributeResources() { + return Lists.newArrayList(new ItemAttributeResource("key1", "value1"), + new ItemAttributeResource("key2", "value2")); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/MultipartFileUtilsTest.java b/src/test/java/com/epam/ta/reportportal/util/MultipartFileUtilsTest.java index 6f50ffa706..db5bf17ea9 100644 --- a/src/test/java/com/epam/ta/reportportal/util/MultipartFileUtilsTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/MultipartFileUtilsTest.java @@ -16,33 +16,32 @@ package com.epam.ta.reportportal.util; -import org.apache.commons.io.IOUtils; -import org.junit.jupiter.api.Test; -import org.springframework.core.io.ClassPathResource; -import org.springframework.web.multipart.commons.CommonsMultipartFile; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; +import org.springframework.web.multipart.commons.CommonsMultipartFile; /** * @author <a href="mailto:pavel_bortnik@epam.com">Pavel Bortnik</a> */ class MultipartFileUtilsTest { - @Test - void getMultipartFile() throws IOException { - String path = "image/image.png"; - File expected = new ClassPathResource(path).getFile(); - CommonsMultipartFile file = MultipartFileUtils.getMultipartFile(path); - assertEquals(expected.length(), file.getSize()); - assertEquals(expected.getName(), file.getFileItem().getName()); - assertEquals("image/png", file.getContentType()); - try (FileInputStream expectedStream = new FileInputStream(expected)) { - assertTrue(IOUtils.contentEquals(expectedStream, file.getInputStream())); - } - } + @Test + void getMultipartFile() throws IOException { + String path = "image/image.png"; + File expected = new ClassPathResource(path).getFile(); + CommonsMultipartFile file = MultipartFileUtils.getMultipartFile(path); + assertEquals(expected.length(), file.getSize()); + assertEquals(expected.getName(), file.getFileItem().getName()); + assertEquals("image/png", file.getContentType()); + try (FileInputStream expectedStream = new FileInputStream(expected)) { + assertTrue(IOUtils.contentEquals(expectedStream, file.getInputStream())); + } + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/PredicatesTest.java b/src/test/java/com/epam/ta/reportportal/util/PredicatesTest.java index 2891fe76c3..fd4108d73f 100644 --- a/src/test/java/com/epam/ta/reportportal/util/PredicatesTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/PredicatesTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.util; +import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; +import static com.epam.ta.reportportal.util.Predicates.LAUNCH_CAN_BE_INDEXED; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; @@ -29,80 +34,80 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import static com.epam.ta.reportportal.util.Predicates.ITEM_CAN_BE_INDEXED; -import static com.epam.ta.reportportal.util.Predicates.LAUNCH_CAN_BE_INDEXED; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - /** * @author Andrei Varabyeu */ class PredicatesTest { - @Test - void checkSpecialCharacters() { - assertTrue(Predicates.SPECIAL_CHARS_ONLY.test("_"), "Incorrect predicate behavior: only spec chars"); - assertFalse(Predicates.SPECIAL_CHARS_ONLY.test("a_"), "Incorrect predicate behavior: spec chars after ASCII"); - assertFalse(Predicates.SPECIAL_CHARS_ONLY.test("_a"), "Incorrect predicate behavior: spec chars before ASCII"); - } + @Test + void checkSpecialCharacters() { + assertTrue(Predicates.SPECIAL_CHARS_ONLY.test("_"), + "Incorrect predicate behavior: only spec chars"); + assertFalse(Predicates.SPECIAL_CHARS_ONLY.test("a_"), + "Incorrect predicate behavior: spec chars after ASCII"); + assertFalse(Predicates.SPECIAL_CHARS_ONLY.test("_a"), + "Incorrect predicate behavior: spec chars before ASCII"); + } - @ParameterizedTest - @ValueSource(strings = { "STEP", "BEFORE_METHOD", "AFTER_METHOD" }) - void checkCanBeIndexed(String type) { - TestItem testItem = new TestItem(); - testItem.setType(TestItemTypeEnum.fromValue(type).get()); - final TestItemResults itemResults = new TestItemResults(); - final IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIgnoreAnalyzer(false); - final IssueType issueType = new IssueType(); - issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); - issueEntity.setIssueType(issueType); - itemResults.setIssue(issueEntity); - testItem.setItemResults(itemResults); - assertTrue(ITEM_CAN_BE_INDEXED.test(testItem), "Item should be available for indexing"); - } + @ParameterizedTest + @ValueSource(strings = {"STEP", "BEFORE_METHOD", "AFTER_METHOD"}) + void checkCanBeIndexed(String type) { + TestItem testItem = new TestItem(); + testItem.setType(TestItemTypeEnum.fromValue(type).get()); + final TestItemResults itemResults = new TestItemResults(); + final IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIgnoreAnalyzer(false); + final IssueType issueType = new IssueType(); + issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); + issueEntity.setIssueType(issueType); + itemResults.setIssue(issueEntity); + testItem.setItemResults(itemResults); + assertTrue(ITEM_CAN_BE_INDEXED.test(testItem), "Item should be available for indexing"); + } - @Test - void checkTIIndexed() { - TestItem testItem = new TestItem(); - final TestItemResults itemResults = new TestItemResults(); - testItem.setType(TestItemTypeEnum.STEP); - final IssueEntity issue = new IssueEntity(); - final IssueType issueType = new IssueType(); - issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.TO_INVESTIGATE)); - issueType.setLocator(TestItemIssueGroup.TO_INVESTIGATE.getLocator()); - issue.setIssueType(issueType); - itemResults.setIssue(issue); - testItem.setItemResults(itemResults); - assertTrue(ITEM_CAN_BE_INDEXED.test(testItem), "Item with TI issue is available for indexing"); - } + @Test + void checkTIIndexed() { + TestItem testItem = new TestItem(); + final TestItemResults itemResults = new TestItemResults(); + testItem.setType(TestItemTypeEnum.STEP); + final IssueEntity issue = new IssueEntity(); + final IssueType issueType = new IssueType(); + issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.TO_INVESTIGATE)); + issueType.setLocator(TestItemIssueGroup.TO_INVESTIGATE.getLocator()); + issue.setIssueType(issueType); + itemResults.setIssue(issue); + testItem.setItemResults(itemResults); + assertTrue(ITEM_CAN_BE_INDEXED.test(testItem), "Item with TI issue is available for indexing"); + } - @Test - void checkIgnoreIndexed() { - TestItem testItem = new TestItem(); - testItem.setType(TestItemTypeEnum.STEP); - final TestItemResults itemResults = new TestItemResults(); - final IssueEntity issueEntity = new IssueEntity(); - issueEntity.setIgnoreAnalyzer(true); - final IssueType issueType = new IssueType(); - issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); - issueEntity.setIssueType(issueType); - itemResults.setIssue(issueEntity); - testItem.setItemResults(itemResults); - assertFalse(ITEM_CAN_BE_INDEXED.test(testItem), "Item with ignore flag shouldn't be available for indexing"); - } + @Test + void checkIgnoreIndexed() { + TestItem testItem = new TestItem(); + testItem.setType(TestItemTypeEnum.STEP); + final TestItemResults itemResults = new TestItemResults(); + final IssueEntity issueEntity = new IssueEntity(); + issueEntity.setIgnoreAnalyzer(true); + final IssueType issueType = new IssueType(); + issueType.setIssueGroup(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG)); + issueEntity.setIssueType(issueType); + itemResults.setIssue(issueEntity); + testItem.setItemResults(itemResults); + assertFalse(ITEM_CAN_BE_INDEXED.test(testItem), + "Item with ignore flag shouldn't be available for indexing"); + } - @Test - void checkLaunchCanBeIndexed() { - Launch launch = new Launch(); - launch.setMode(LaunchModeEnum.DEFAULT); - assertTrue(LAUNCH_CAN_BE_INDEXED.test(launch), "Launch should be available for indexing"); - } + @Test + void checkLaunchCanBeIndexed() { + Launch launch = new Launch(); + launch.setMode(LaunchModeEnum.DEFAULT); + assertTrue(LAUNCH_CAN_BE_INDEXED.test(launch), "Launch should be available for indexing"); + } - @Test - void checkDebugLaunchCanBeIndexed() { - Launch launch = new Launch(); - launch.setMode(LaunchModeEnum.DEFAULT); - assertTrue(LAUNCH_CAN_BE_INDEXED.test(launch), "Launch in debug mode should not be available for indexing"); - } + @Test + void checkDebugLaunchCanBeIndexed() { + Launch launch = new Launch(); + launch.setMode(LaunchModeEnum.DEFAULT); + assertTrue(LAUNCH_CAN_BE_INDEXED.test(launch), + "Launch in debug mode should not be available for indexing"); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/ReportingQueueServiceTest.java b/src/test/java/com/epam/ta/reportportal/util/ReportingQueueServiceTest.java index 2040b2f41f..2f914865da 100755 --- a/src/test/java/com/epam/ta/reportportal/util/ReportingQueueServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/ReportingQueueServiceTest.java @@ -16,38 +16,37 @@ package com.epam.ta.reportportal.util; -import org.junit.jupiter.api.Test; - -import java.util.UUID; - import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -class ReportingQueueServiceTest { - - private ReportingQueueService reportingQueueService = new ReportingQueueService(); +import java.util.UUID; +import org.junit.jupiter.api.Test; - @Test - void getKeyFromUuid() { - String uuid = UUID.randomUUID().toString(); - int queueAmount = 5; - reportingQueueService.setQueueAmount(queueAmount); - String reportingQueueKey = reportingQueueService.getReportingQueueKey(uuid); - System.out.println(reportingQueueKey); - assertNotNull(reportingQueueKey); - int integerKey = Integer.parseInt(reportingQueueKey); - assertTrue(integerKey <= queueAmount); - } +class ReportingQueueServiceTest { - @Test - void getKeyFromCustomString() { - String customUuid = "cutom-uuid-kek"; - int queueAmount = 5; - reportingQueueService.setQueueAmount(queueAmount); - String reportingQueueKey = reportingQueueService.getReportingQueueKey(customUuid); - System.out.println(reportingQueueKey); - assertNotNull(reportingQueueKey); - int integerKey = Integer.parseInt(reportingQueueKey); - assertTrue(integerKey <= queueAmount); - } + private ReportingQueueService reportingQueueService = new ReportingQueueService(); + + @Test + void getKeyFromUuid() { + String uuid = UUID.randomUUID().toString(); + int queueAmount = 5; + reportingQueueService.setQueueAmount(queueAmount); + String reportingQueueKey = reportingQueueService.getReportingQueueKey(uuid); + System.out.println(reportingQueueKey); + assertNotNull(reportingQueueKey); + int integerKey = Integer.parseInt(reportingQueueKey); + assertTrue(integerKey <= queueAmount); + } + + @Test + void getKeyFromCustomString() { + String customUuid = "cutom-uuid-kek"; + int queueAmount = 5; + reportingQueueService.setQueueAmount(queueAmount); + String reportingQueueKey = reportingQueueService.getReportingQueueKey(customUuid); + System.out.println(reportingQueueKey); + assertNotNull(reportingQueueKey); + int integerKey = Integer.parseInt(reportingQueueKey); + assertTrue(integerKey <= queueAmount); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/TestProjectExtractor.java b/src/test/java/com/epam/ta/reportportal/util/TestProjectExtractor.java index ffec9e5bb0..25e803fdd6 100644 --- a/src/test/java/com/epam/ta/reportportal/util/TestProjectExtractor.java +++ b/src/test/java/com/epam/ta/reportportal/util/TestProjectExtractor.java @@ -1,21 +1,21 @@ package com.epam.ta.reportportal.util; +import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.model.ErrorType; - import java.util.Optional; -import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId; - public class TestProjectExtractor { - public static ReportPortalUser.ProjectDetails extractProjectDetails(ReportPortalUser user, String projectName) { - final String normalizedProjectName = normalizeId(projectName); - return Optional.ofNullable(user.getProjectDetails().get(normalizedProjectName)) - .orElseThrow(() -> new ReportPortalException(ErrorType.ACCESS_DENIED, - "Please check the list of your available projects." - )); - } + public static ReportPortalUser.ProjectDetails extractProjectDetails(ReportPortalUser user, + String projectName) { + final String normalizedProjectName = normalizeId(projectName); + return Optional.ofNullable(user.getProjectDetails().get(normalizedProjectName)) + .orElseThrow(() -> new ReportPortalException(ErrorType.ACCESS_DENIED, + "Please check the list of your available projects." + )); + } } diff --git a/src/test/java/com/epam/ta/reportportal/util/email/EmailRulesValidatorTest.java b/src/test/java/com/epam/ta/reportportal/util/email/EmailRulesValidatorTest.java index 33d7923268..1624df0b57 100644 --- a/src/test/java/com/epam/ta/reportportal/util/email/EmailRulesValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/email/EmailRulesValidatorTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.util.email; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.user.ProjectUser; import com.epam.ta.reportportal.entity.user.User; @@ -25,156 +28,162 @@ import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class EmailRulesValidatorTest { - @Test - void validateBlankLaunchName() { - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> EmailRulesValidator.validateLaunchName("")); - assertEquals( - "Error in handled Request. Please, check specified parameters: 'Launch name values cannot be empty. Please specify it or not include in request.'", - exception.getMessage() - ); - } - - @Test - void validateNullLaunchName() { - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> EmailRulesValidator.validateLaunchName(null)); - assertEquals( - "Error in handled Request. Please, check specified parameters: 'Launch name values cannot be empty. Please specify it or not include in request.'", - exception.getMessage() - ); - } - - @Test - void validateLaunchNameLength() { - String largeString = RandomStringUtils.randomAlphabetic(257); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateLaunchName(largeString) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'One of provided launch names '" + largeString + "' is too long. Acceptable name length is [1..256]'", - exception.getMessage() - ); - } - - @Test - void successfullyValidateLaunchName() { - EmailRulesValidator.validateLaunchName("launch_name"); - } - - @Test - void validateEmptyLaunchAttributes() { - ItemAttributeResource attribute = new ItemAttributeResource(); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateLaunchAttribute(attribute) - ); - assertEquals( - "Error in handled Request. Please, check specified parameters: 'Attribute' values cannot be empty. Please specify them or do not include in a request.'", - exception.getMessage() - ); - } - - @Test - void validateNullLaunchAttribute() { - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateLaunchAttribute(null) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'Launch attribute cannot be null.'", - exception.getMessage() - ); - } - - @Test - void successfullyValidateLaunchAttribute() { - ItemAttributeResource attribute = new ItemAttributeResource(); - attribute.setKey("key"); - attribute.setValue("value"); - EmailRulesValidator.validateLaunchAttribute(attribute); - } - - @Test - void validateNullRecipientName() { - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateRecipient(new Project(), null) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'Provided recipient email 'null' is invalid'", - exception.getMessage() - ); - } - - @Test - void validateInvalidRecipientEmail() { - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateRecipient(new Project(), "invalid@domain") - ); - assertEquals( - "Error in handled Request. Please, check specified parameters: 'Provided recipient email 'invalid@domain' is invalid'", - exception.getMessage() - ); - } - - @Test - void successfullyValidateRecipientEmail() { - EmailRulesValidator.validateRecipient(new Project(), "valid.email@domain.com"); - } - - @Test - void successfullyValidateOwnerRecipient() { - EmailRulesValidator.validateRecipient(new Project(), "OWNER"); - } - - @Test - void validateShortLoginRecipient() { - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateRecipient(new Project(), "") - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'Acceptable login length [1..128]'", - exception.getMessage() - ); - } - - @Test - void validateLongLoginRecipient() { - String largeLogin = RandomStringUtils.randomAlphabetic(129); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateRecipient(new Project(), largeLogin) - ); - assertEquals("Error in handled Request. Please, check specified parameters: 'Acceptable login length [1..128]'", - exception.getMessage() - ); - } - - @Test - void validateNotAssignedUserLoginRecipient() { - Project project = new Project(); - project.setId(1L); - ProjectUser projectUser = new ProjectUser(); - projectUser.setProject(project); - User user = new User(); - user.setLogin("exists"); - projectUser.setUser(user); - project.setUsers(Sets.newHashSet(projectUser)); - ReportPortalException exception = assertThrows(ReportPortalException.class, - () -> EmailRulesValidator.validateRecipient(project, "not_exists") - ); - assertEquals("User 'not_exists' not found. User not found in project 1", exception.getMessage()); - } - - @Test - void successfullyValidateLoginRecipient() { - Project project = new Project(); - project.setId(1L); - ProjectUser projectUser = new ProjectUser(); - projectUser.setProject(project); - User user = new User(); - user.setLogin("exists"); - projectUser.setUser(user); - project.setUsers(Sets.newHashSet(projectUser)); - EmailRulesValidator.validateRecipient(project, "exists"); - } + @Test + void validateBlankLaunchName() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateLaunchName("")); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Launch name values cannot be empty. Please specify it or not include in request.'", + exception.getMessage() + ); + } + + @Test + void validateNullLaunchName() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateLaunchName(null)); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Launch name values cannot be empty. Please specify it or not include in request.'", + exception.getMessage() + ); + } + + @Test + void validateLaunchNameLength() { + String largeString = RandomStringUtils.randomAlphabetic(257); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateLaunchName(largeString) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'One of provided launch names '" + + largeString + "' is too long. Acceptable name length is [1..256]'", + exception.getMessage() + ); + } + + @Test + void successfullyValidateLaunchName() { + EmailRulesValidator.validateLaunchName("launch_name"); + } + + @Test + void validateEmptyLaunchAttributes() { + ItemAttributeResource attribute = new ItemAttributeResource(); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateLaunchAttribute(attribute) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Attribute' values cannot be empty. Please specify them or do not include in a request.'", + exception.getMessage() + ); + } + + @Test + void validateNullLaunchAttribute() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateLaunchAttribute(null) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Launch attribute cannot be null.'", + exception.getMessage() + ); + } + + @Test + void successfullyValidateLaunchAttribute() { + ItemAttributeResource attribute = new ItemAttributeResource(); + attribute.setKey("key"); + attribute.setValue("value"); + EmailRulesValidator.validateLaunchAttribute(attribute); + } + + @Test + void validateNullRecipientName() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateRecipient(new Project(), null) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Provided recipient email 'null' is invalid'", + exception.getMessage() + ); + } + + @Test + void validateInvalidRecipientEmail() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateRecipient(new Project(), "invalid@domain") + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Provided recipient email 'invalid@domain' is invalid'", + exception.getMessage() + ); + } + + @Test + void successfullyValidateRecipientEmail() { + EmailRulesValidator.validateRecipient(new Project(), "valid.email@domain.com"); + } + + @Test + void successfullyValidateOwnerRecipient() { + EmailRulesValidator.validateRecipient(new Project(), "OWNER"); + } + + @Test + void validateShortLoginRecipient() { + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateRecipient(new Project(), "") + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Acceptable login length [1..128]'", + exception.getMessage() + ); + } + + @Test + void validateLongLoginRecipient() { + String largeLogin = RandomStringUtils.randomAlphabetic(129); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateRecipient(new Project(), largeLogin) + ); + assertEquals( + "Error in handled Request. Please, check specified parameters: 'Acceptable login length [1..128]'", + exception.getMessage() + ); + } + + @Test + void validateNotAssignedUserLoginRecipient() { + Project project = new Project(); + project.setId(1L); + ProjectUser projectUser = new ProjectUser(); + projectUser.setProject(project); + User user = new User(); + user.setLogin("exists"); + projectUser.setUser(user); + project.setUsers(Sets.newHashSet(projectUser)); + ReportPortalException exception = assertThrows(ReportPortalException.class, + () -> EmailRulesValidator.validateRecipient(project, "not_exists") + ); + assertEquals("User 'not_exists' not found. User not found in project 1", + exception.getMessage()); + } + + @Test + void successfullyValidateLoginRecipient() { + Project project = new Project(); + project.setId(1L); + ProjectUser projectUser = new ProjectUser(); + projectUser.setProject(project); + User user = new User(); + user.setLogin("exists"); + projectUser.setUser(user); + project.setUsers(Sets.newHashSet(projectUser)); + EmailRulesValidator.validateRecipient(project, "exists"); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/email/EmailServiceTest.java b/src/test/java/com/epam/ta/reportportal/util/email/EmailServiceTest.java index f88bd950a8..00ceffb7bb 100644 --- a/src/test/java/com/epam/ta/reportportal/util/email/EmailServiceTest.java +++ b/src/test/java/com/epam/ta/reportportal/util/email/EmailServiceTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.util.email; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.epam.reportportal.commons.template.TemplateEngine; import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; @@ -26,64 +30,60 @@ import com.epam.ta.reportportal.entity.statistics.Statistics; import com.epam.ta.reportportal.entity.statistics.StatisticsField; import com.google.common.collect.Sets; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.util.Map; import java.util.Properties; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class EmailServiceTest { - private TemplateEngine templateEngine = mock(TemplateEngine.class); + private TemplateEngine templateEngine = mock(TemplateEngine.class); - private EmailService emailService = new EmailService(new Properties()); + private EmailService emailService = new EmailService(new Properties()); - @BeforeEach - void setUp() { - emailService.setTemplateEngine(templateEngine); - } + @BeforeEach + void setUp() { + emailService.setTemplateEngine(templateEngine); + } - @Test - void prepareLaunchTest() { + @Test + void prepareLaunchTest() { - when(templateEngine.merge(any(String.class), any(Map.class))).thenReturn("EMAIL MESSAGE"); + when(templateEngine.merge(any(String.class), any(Map.class))).thenReturn("EMAIL MESSAGE"); - ProjectIssueType projectIssueType = new ProjectIssueType(); - IssueType issueType = new IssueType(); - issueType.setLocator("pb001"); - issueType.setLongName("ProductBug"); - projectIssueType.setIssueType(issueType); + ProjectIssueType projectIssueType = new ProjectIssueType(); + IssueType issueType = new IssueType(); + issueType.setLocator("pb001"); + issueType.setLongName("ProductBug"); + projectIssueType.setIssueType(issueType); - String url = emailService.mergeFinishLaunchText("url", getLaunch(), Sets.newHashSet(projectIssueType)); + String url = emailService.mergeFinishLaunchText("url", getLaunch(), + Sets.newHashSet(projectIssueType)); - System.out.println(url); - } + System.out.println(url); + } - private Launch getLaunch() { - Launch launch = new Launch(); - launch.setId(1L); - launch.setHasRetries(false); - launch.setStatus(StatusEnum.PASSED); - launch.setProjectId(1L); - launch.setStartTime(LocalDateTime.now()); - launch.setEndTime(LocalDateTime.now().plusMinutes(5L)); - launch.setName("Launch name"); - launch.setMode(LaunchModeEnum.DEFAULT); - launch.setNumber(1L); - launch.setDescription("description"); - launch.setAttributes(Sets.newHashSet(new ItemAttribute("key", "value", false))); - StatisticsField statisticsField = new StatisticsField("statistics$executions$total"); - Statistics statistics = new Statistics(statisticsField, 1, 1L); - launch.setStatistics(Sets.newHashSet(statistics)); - return launch; - } + private Launch getLaunch() { + Launch launch = new Launch(); + launch.setId(1L); + launch.setHasRetries(false); + launch.setStatus(StatusEnum.PASSED); + launch.setProjectId(1L); + launch.setStartTime(LocalDateTime.now()); + launch.setEndTime(LocalDateTime.now().plusMinutes(5L)); + launch.setName("Launch name"); + launch.setMode(LaunchModeEnum.DEFAULT); + launch.setNumber(1L); + launch.setDescription("description"); + launch.setAttributes(Sets.newHashSet(new ItemAttribute("key", "value", false))); + StatisticsField statisticsField = new StatisticsField("statistics$executions$total"); + Statistics statistics = new Statistics(statisticsField, 1, 1L); + launch.setStatistics(Sets.newHashSet(statistics)); + return launch; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/util/sample/LaunchSampleUtil.java b/src/test/java/com/epam/ta/reportportal/util/sample/LaunchSampleUtil.java new file mode 100644 index 0000000000..9dc2aa2469 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/util/sample/LaunchSampleUtil.java @@ -0,0 +1,51 @@ +/* + * Copyright 2023 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.util.sample; + +import com.epam.ta.reportportal.entity.launch.Launch; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import org.apache.commons.lang3.RandomStringUtils; + +/** + * Utility class for generating {@link Launch } samples. + * + * @author Siarhei Hrabko + */ +public final class LaunchSampleUtil { + + private LaunchSampleUtil() { + } + + /** + * Generates sample launch object for testing purposes. + * + * @param uuid {@link String} uuid of generated launch + * @return {@link Launch } generated launch object + */ + public static Launch getSampleLaunch(String uuid) { + var launch = new Launch(); + launch.setUuid(uuid); + launch.setName(RandomStringUtils.random(10)); + launch.setNumber(ThreadLocalRandom.current().nextLong(100)); + return launch; + } + + public static Launch getSampleLaunch() { + return getSampleLaunch(UUID.randomUUID().toString()); + } +} diff --git a/src/test/java/com/epam/ta/reportportal/ws/BaseMvcTest.java b/src/test/java/com/epam/ta/reportportal/ws/BaseMvcTest.java index 12b0fac4cb..6f51bab15d 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/BaseMvcTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/BaseMvcTest.java @@ -20,7 +20,10 @@ import com.epam.ta.reportportal.TestConfig; import com.epam.ta.reportportal.auth.OAuthHelper; import com.epam.ta.reportportal.core.events.MessageBus; +import com.epam.ta.reportportal.core.integration.ExecuteIntegrationHandler; +import com.epam.ta.reportportal.core.integration.plugin.binary.PluginFilesProvider; import com.epam.ta.reportportal.core.plugin.Pf4jPluginBox; +import com.epam.ta.reportportal.util.BinaryDataResponseWriter; import com.epam.ta.reportportal.util.email.EmailService; import com.epam.ta.reportportal.util.email.MailServiceFactory; import org.flywaydb.test.FlywayTestExecutionListener; @@ -48,44 +51,57 @@ @AutoConfigureMockMvc @ActiveProfiles("unittest") @ContextConfiguration(classes = TestConfig.class) -@TestExecutionListeners(listeners = { FlywayTestExecutionListener.class }, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) +@TestExecutionListeners(listeners = { + FlywayTestExecutionListener.class}, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) @Transactional public abstract class BaseMvcTest { - protected static final String DEFAULT_PROJECT_BASE_URL = "/v1/default_personal"; - protected static final String SUPERADMIN_PROJECT_BASE_URL = "/v1/superadmin_personal"; + protected static final String DEFAULT_PROJECT_BASE_URL = "/v1/default_personal"; + protected static final String SUPERADMIN_PROJECT_BASE_URL = "/v1/superadmin_personal"; - @Autowired - protected OAuthHelper oAuthHelper; + @Autowired + protected OAuthHelper oAuthHelper; - @Autowired - protected MockMvc mockMvc; + @Autowired + protected MockMvc mockMvc; - @MockBean - protected MessageBus messageBus; + @MockBean + protected MessageBus messageBus; - @MockBean - protected MailServiceFactory mailServiceFactory; + @MockBean + protected MailServiceFactory mailServiceFactory; - @MockBean - protected Pf4jPluginBox pluginBox; + @MockBean + protected Pf4jPluginBox pluginBox; - @Mock - protected BtsExtension extension; + @MockBean(name = "pluginFilesProvider") + protected PluginFilesProvider pluginFilesProvider; - @Mock - protected EmailService emailService; + @MockBean(name = "pluginPublicFilesProvider") + protected PluginFilesProvider pluginPublicFilesProvider; - @FlywayTest - @BeforeAll - public static void before() { - } + @MockBean + protected BinaryDataResponseWriter binaryDataResponseWriter; - protected RequestPostProcessor token(String tokenValue) { - return mockRequest -> { - mockRequest.addHeader("Authorization", "Bearer " + tokenValue); - return mockRequest; - }; - } + @MockBean + protected ExecuteIntegrationHandler executeIntegrationHandler; + + @Mock + protected BtsExtension extension; + + @Mock + protected EmailService emailService; + + @FlywayTest + @BeforeAll + public static void before() { + } + + protected RequestPostProcessor token(String tokenValue) { + return mockRequest -> { + mockRequest.addHeader("Authorization", "Bearer " + tokenValue); + return mockRequest; + }; + } } diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemControllerTest.java index d75a2c49d6..b10ae1db6c 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/BugTrackingSystemControllerTest.java @@ -16,15 +16,34 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.reportportal.extension.bugtracking.BtsExtension; import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.ErrorRS; -import com.epam.ta.reportportal.ws.model.externalsystem.*; +import com.epam.ta.reportportal.ws.model.externalsystem.AllowedValue; +import com.epam.ta.reportportal.ws.model.externalsystem.BtsConnectionTestRQ; +import com.epam.ta.reportportal.ws.model.externalsystem.PostFormField; +import com.epam.ta.reportportal.ws.model.externalsystem.PostTicketRQ; +import com.epam.ta.reportportal.ws.model.externalsystem.Ticket; import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.LongStream; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -33,177 +52,179 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.LongStream; - -import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ @Sql("/db/bts/bts-integration-fill.sql") class BugTrackingSystemControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; - - @Test - @Disabled - void updateGlobalBtsIntegration() throws Exception { - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.testConnection(any(Integration.class))).thenReturn(true); - - IntegrationRQ request = getUpdateRQ(); - - mockMvc.perform(put("/v1/integration" + "/9").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - } - - @Test - @Disabled - void updateProjectBtsIntegration() throws Exception { - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.testConnection(any(Integration.class))).thenReturn(true); - - IntegrationRQ request = getUpdateRQ(); - - mockMvc.perform(put("/v1/integration/superadmin_personal/10").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - } - - @Test - @Disabled - void checkConnection() throws Exception { - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.testConnection(any(Integration.class))).thenReturn(true); - - mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/integration/10/connection/test").with(token(oAuthHelper.getSuperadminToken()))); - } - - @Test - void getSetOfIntegrationSystemFields() throws Exception { - - Map<String, List<String>> params = Maps.newHashMap(); - params.put("issueType", Lists.newArrayList("ISSUE01")); - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.getTicketFields(any(String.class), any(Integration.class))).thenReturn(Lists.newArrayList(new PostFormField())); - - mockMvc.perform(get("/v1/bts/superadmin_personal/10/fields-set").params(CollectionUtils.toMultiValueMap(params)) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void getAllowableIssueTypes() throws Exception { - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.getIssueTypes(any(Integration.class))).thenReturn(Lists.newArrayList("type1", "type2")); - - mockMvc.perform(get("/v1/bts/superadmin_personal/10/issue_types").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().isOk()); - } - - @Test - void createIssue() throws Exception { - - PostTicketRQ request = getPostTicketRQ(); - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.submitTicket(any(PostTicketRQ.class), any(Integration.class))).thenReturn(new Ticket()); - - mockMvc.perform(post("/v1/bts/superadmin_personal/10/ticket").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); - } - - @Test - void shouldNotCreateIssueWhenMoreThen300BackLinks() throws Exception { - - final PostTicketRQ request = new PostTicketRQ(); - final Map<Long, String> backLinks = LongStream.range(1, 302).boxed().collect(Collectors.toMap(it -> it, String::valueOf)); - request.setBackLinks(backLinks); - - final MvcResult mvcResult = mockMvc.perform(post("/v1/bts/superadmin_personal/10/ticket").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isBadRequest()).andReturn(); - - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'backLinks' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - @Test - void getTicket() throws Exception { - - final String ticketId = "/ticket_id"; - - Map<String, List<String>> params = Maps.newHashMap(); - params.put("btsUrl", Lists.newArrayList("jira.com")); - params.put("btsProject", Lists.newArrayList("project")); - - when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn(java.util.Optional.ofNullable(extension)); - when(extension.getTicket(any(String.class), any(Integration.class))).thenReturn(java.util.Optional.of(new Ticket())); - - mockMvc.perform(get("/v1/bts/superadmin_personal/ticket" + ticketId).params(CollectionUtils.toMultiValueMap(params)) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - private IntegrationRQ getUpdateRQ() { + @Autowired + private ObjectMapper objectMapper; - IntegrationRQ integrationRQ = new IntegrationRQ(); - integrationRQ.setEnabled(true); - integrationRQ.setName("jira1"); - Map<String, Object> integrationParams = new HashMap<>(); - integrationParams.put("defectFormFields", getPostFormFields()); - integrationRQ.setIntegrationParams(integrationParams); - return integrationRQ; - } + @Test + @Disabled + void updateGlobalBtsIntegration() throws Exception { - private BtsConnectionTestRQ getConnectionRQ() { - BtsConnectionTestRQ connectionTestRQ = new BtsConnectionTestRQ(); - connectionTestRQ.setUrl("url"); - connectionTestRQ.setBtsProject("project"); + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.testConnection(any(Integration.class))).thenReturn(true); + + IntegrationRQ request = getUpdateRQ(); + + mockMvc.perform(put("/v1/integration" + "/9").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + } - return connectionTestRQ; - } + @Test + @Disabled + void updateProjectBtsIntegration() throws Exception { - private PostTicketRQ getPostTicketRQ() { - PostTicketRQ postTicketRQ = new PostTicketRQ(); - postTicketRQ.setFields(getPostFormFields()); - postTicketRQ.setNumberOfLogs(10); - postTicketRQ.setIsIncludeScreenshots(false); - postTicketRQ.setIsIncludeComments(false); - postTicketRQ.setTestItemId(1L); + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.testConnection(any(Integration.class))).thenReturn(true); - return postTicketRQ; - } + IntegrationRQ request = getUpdateRQ(); - private List<PostFormField> getPostFormFields() { + mockMvc.perform( + put("/v1/integration/superadmin_personal/10").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + } - PostFormField field = new PostFormField("id", - "name", - "type", - true, - Lists.newArrayList("value"), - Lists.newArrayList(new AllowedValue("id", "name")) - ); + @Test + @Disabled + void checkConnection() throws Exception { - return Lists.newArrayList(field); - } + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.testConnection(any(Integration.class))).thenReturn(true); + + mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/integration/10/connection/test").with( + token(oAuthHelper.getSuperadminToken()))); + } + + @Test + void getSetOfIntegrationSystemFields() throws Exception { + + Map<String, List<String>> params = Maps.newHashMap(); + params.put("issueType", Lists.newArrayList("ISSUE01")); + + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.getTicketFields(any(String.class), any(Integration.class))).thenReturn( + Lists.newArrayList(new PostFormField())); + + mockMvc.perform(get("/v1/bts/superadmin_personal/10/fields-set").params( + CollectionUtils.toMultiValueMap(params)) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void getAllowableIssueTypes() throws Exception { + + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.getIssueTypes(any(Integration.class))).thenReturn( + Lists.newArrayList("type1", "type2")); + + mockMvc.perform(get("/v1/bts/superadmin_personal/10/issue_types").with( + token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void createIssue() throws Exception { + + PostTicketRQ request = getPostTicketRQ(); + + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.submitTicket(any(PostTicketRQ.class), any(Integration.class))).thenReturn( + new Ticket()); + + mockMvc.perform( + post("/v1/bts/superadmin_personal/10/ticket").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); + } + + @Test + void shouldNotCreateIssueWhenMoreThen300BackLinks() throws Exception { + + final PostTicketRQ request = new PostTicketRQ(); + final Map<Long, String> backLinks = LongStream.range(1, 302).boxed() + .collect(Collectors.toMap(it -> it, String::valueOf)); + request.setBackLinks(backLinks); + + final MvcResult mvcResult = mockMvc.perform( + post("/v1/bts/superadmin_personal/10/ticket").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isBadRequest()) + .andReturn(); + + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'backLinks' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + @Test + void getTicket() throws Exception { + + final String ticketId = "/ticket_id"; + + Map<String, List<String>> params = Maps.newHashMap(); + params.put("btsUrl", Lists.newArrayList("jira.com")); + params.put("btsProject", Lists.newArrayList("project")); + + when(pluginBox.getInstance("jira", BtsExtension.class)).thenReturn( + java.util.Optional.ofNullable(extension)); + when(extension.getTicket(any(String.class), any(Integration.class))).thenReturn( + java.util.Optional.of(new Ticket())); + + mockMvc.perform(get("/v1/bts/superadmin_personal/ticket" + ticketId).params( + CollectionUtils.toMultiValueMap(params)) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + private IntegrationRQ getUpdateRQ() { + + IntegrationRQ integrationRQ = new IntegrationRQ(); + integrationRQ.setEnabled(true); + integrationRQ.setName("jira1"); + Map<String, Object> integrationParams = new HashMap<>(); + integrationParams.put("defectFormFields", getPostFormFields()); + integrationRQ.setIntegrationParams(integrationParams); + return integrationRQ; + } + + private BtsConnectionTestRQ getConnectionRQ() { + BtsConnectionTestRQ connectionTestRQ = new BtsConnectionTestRQ(); + connectionTestRQ.setUrl("url"); + connectionTestRQ.setBtsProject("project"); + + return connectionTestRQ; + } + + private PostTicketRQ getPostTicketRQ() { + PostTicketRQ postTicketRQ = new PostTicketRQ(); + postTicketRQ.setFields(getPostFormFields()); + postTicketRQ.setNumberOfLogs(10); + postTicketRQ.setIsIncludeScreenshots(false); + postTicketRQ.setIsIncludeComments(false); + postTicketRQ.setTestItemId(1L); + + return postTicketRQ; + } + + private List<PostFormField> getPostFormFields() { + PostFormField field = PostFormField.builder().id("id").fieldName("name") + .fieldType("type").isRequired(true) + .value(List.of("value")).definedValues(List.of(new AllowedValue("id", "name"))).build(); + return Lists.newArrayList(field); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/DashboardControllerValidationTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/DashboardControllerValidationTest.java index 72f3dc129e..e156cc1915 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/DashboardControllerValidationTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/DashboardControllerValidationTest.java @@ -16,15 +16,14 @@ package com.epam.ta.reportportal.ws.controller; -import com.epam.ta.reportportal.ws.BaseMvcTest; -import com.epam.ta.reportportal.ws.model.ErrorRS; -import com.epam.ta.reportportal.ws.model.dashboard.CreateDashboardRQ; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.servlet.MvcResult; - -import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.*; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_BLANK_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_NULL_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.ID_PATH; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.LONG_NAME_VALUE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.SHORT_NAME_VALUE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.WHITESPACES_NAME_VALUE; import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,203 +32,232 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.epam.ta.reportportal.ws.BaseMvcTest; +import com.epam.ta.reportportal.ws.model.ErrorRS; +import com.epam.ta.reportportal.ws.model.dashboard.CreateDashboardRQ; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.web.servlet.MvcResult; + /** * @author <a href="mailto:tatyana_gladysheva@epam.com">Tatyana Gladysheva</a> */ class DashboardControllerValidationTest extends BaseMvcTest { - private static final String DASHBOARD_PATH = "/dashboard"; - - private static final String FIELD_NAME_SIZE_MESSAGE = String.format(FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 3, 128); - - @Autowired - private ObjectMapper objectMapper; - - @Test - public void createDashboardShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void createDashboardShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createDashboardShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createDashboardShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(SHORT_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createDashboardShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateDashboardShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void updateDashboardShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateDashboardShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateDashboardShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(SHORT_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateDashboardShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() throws Exception { - //GIVEN - CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); - createDashboardRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(createDashboardRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } + private static final String DASHBOARD_PATH = "/dashboard"; + + private static final String FIELD_NAME_SIZE_MESSAGE = String.format( + FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 3, 128); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void createDashboardShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void createDashboardShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createDashboardShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createDashboardShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(SHORT_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void createDashboardShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() + throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void updateDashboardShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void updateDashboardShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void updateDashboardShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void updateDashboardShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(SHORT_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void updateDashboardShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() + throws Exception { + //GIVEN + CreateDashboardRQ createDashboardRQ = new CreateDashboardRQ(); + createDashboardRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + DASHBOARD_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(createDashboardRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/IntegrationControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/IntegrationControllerTest.java index e8a180d97a..29d87b1166 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/IntegrationControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/IntegrationControllerTest.java @@ -16,239 +16,265 @@ package com.epam.ta.reportportal.ws.controller; +import static org.mockito.Mockito.doNothing; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.integration.IntegrationRQ; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.jdbc.Sql; -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.Mockito.doNothing; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Sql("/db/integration/integration-fill.sql") class IntegrationControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; - - @Test - void createGlobalIntegration() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - request.setName("email"); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - doNothing().when(emailService).testConnection(); - - mockMvc.perform(post("/v1/integration/email").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); - - mockMvc.perform(post("/v1/integration/email").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isConflict()); - } - - @Test - void createGlobalIntegrationNegative() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - request.setName("name"); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - mockMvc.perform(post("/v1/integration/unknown").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); - } - - @Test - void createProjectIntegration() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - request.setName("email"); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - doNothing().when(emailService).testConnection(); - - mockMvc.perform(post("/v1/integration/default_personal/email").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); - - mockMvc.perform(post("/v1/integration/default_personal/email").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isConflict()); - } - - @Test - void createProjectIntegrationNegative() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - mockMvc.perform(post("/v1/integration/default_personal/unknown").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); - } - - @Test - void updateGlobalIntegration() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - doNothing().when(emailService).testConnection(); - - mockMvc.perform(put("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - } - - @Test - void updateGlobalIntegrationNegative() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - mockMvc.perform(put("/v1/integration/77").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); - } - - @Test - void updateProjectIntegration() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - doNothing().when(emailService).testConnection(); - - mockMvc.perform(put("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - } - - @Test - void updateProjectIntegrationNegative() throws Exception { - IntegrationRQ request = new IntegrationRQ(); - Map<String, Object> params = new HashMap<>(); - params.put("param1", "value"); - params.put("param2", "lalala"); - request.setIntegrationParams(params); - request.setEnabled(true); - - mockMvc.perform(put("/v1/integration/default_personal/88").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); - } - - @Test - void getAllGlobal() throws Exception { - mockMvc.perform(get("/v1/integration/global/all").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void getAllGlobalByType() throws Exception { - mockMvc.perform(get("/v1/integration/global/all/jira").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void getAllProject() throws Exception { - mockMvc.perform(get("/v1/integration/project/superadmin_personal/all").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().isOk()); - } - - @Test - void getAllProjectByType() throws Exception { - mockMvc.perform(get("/v1/integration/project/superadmin_personal/all/jira").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().isOk()); - } - - @Test - void getGlobalIntegration() throws Exception { - mockMvc.perform(get("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - - @Test - void getGlobalIntegrationNegative() throws Exception { - mockMvc.perform(get("/v1/integration/100").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isNotFound()); - } - - @Test - void deleteGlobalIntegration() throws Exception { - mockMvc.perform(delete("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void deleteGlobalIntegrationNegative() throws Exception { - mockMvc.perform(delete("/v1/integration/100").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isNotFound()); - } - - @Test - void deleteAllIntegrations() throws Exception { - mockMvc.perform(delete("/v1/integration/all/email").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void getProjectIntegration() throws Exception { - mockMvc.perform(get("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void testProjectIntegrationConnection() throws Exception { - mockMvc.perform(get("/v1/integration/default_personal/8/connection/test").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getProjectIntegrationNegative() throws Exception { - mockMvc.perform(get("/v1/integration/default_personal/100").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isNotFound()); - } - - @Test - void deleteProjectIntegration() throws Exception { - mockMvc.perform(delete("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void deleteProjectIntegrationNegative() throws Exception { - mockMvc.perform(delete("/v1/integration/default_personal/100").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isNotFound()); - } - - @Test - void deleteAllProjectIntegrations() throws Exception { - mockMvc.perform(delete("/v1/integration/default_personal/all/email").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } + @Autowired + private ObjectMapper objectMapper; + + @Test + void createGlobalIntegration() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + request.setName("email"); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + doNothing().when(emailService).testConnection(); + + mockMvc.perform(post("/v1/integration/email").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); + + mockMvc.perform(post("/v1/integration/email").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isConflict()); + } + + @Test + void createGlobalIntegrationNegative() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + request.setName("name"); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + mockMvc.perform(post("/v1/integration/unknown").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); + } + + @Test + void createProjectIntegration() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + request.setName("email"); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + doNothing().when(emailService).testConnection(); + + mockMvc.perform( + post("/v1/integration/default_personal/email").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isCreated()); + + mockMvc.perform( + post("/v1/integration/default_personal/email").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isConflict()); + } + + @Test + void createProjectIntegrationNegative() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + mockMvc.perform( + post("/v1/integration/default_personal/unknown").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); + } + + @Test + void updateGlobalIntegration() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + doNothing().when(emailService).testConnection(); + + mockMvc.perform(put("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + } + + @Test + void updateGlobalIntegrationNegative() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + mockMvc.perform(put("/v1/integration/77").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); + } + + @Test + void updateProjectIntegration() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + doNothing().when(emailService).testConnection(); + + mockMvc.perform( + put("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + } + + @Test + void updateProjectIntegrationNegative() throws Exception { + IntegrationRQ request = new IntegrationRQ(); + Map<String, Object> params = new HashMap<>(); + params.put("param1", "value"); + params.put("param2", "lalala"); + request.setIntegrationParams(params); + request.setEnabled(true); + + mockMvc.perform( + put("/v1/integration/default_personal/88").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isNotFound()); + } + + @Test + void getAllGlobal() throws Exception { + mockMvc.perform(get("/v1/integration/global/all").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void getAllGlobalByType() throws Exception { + mockMvc.perform( + get("/v1/integration/global/all/jira").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void getAllProject() throws Exception { + mockMvc.perform(get("/v1/integration/project/superadmin_personal/all").with( + token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void getAllProjectByType() throws Exception { + mockMvc.perform(get("/v1/integration/project/superadmin_personal/all/jira").with( + token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void getGlobalIntegration() throws Exception { + mockMvc.perform(get("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + + @Test + void getGlobalIntegrationNegative() throws Exception { + mockMvc.perform(get("/v1/integration/100").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isNotFound()); + } + + @Test + void deleteGlobalIntegration() throws Exception { + mockMvc.perform(delete("/v1/integration/7").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void deleteGlobalIntegrationNegative() throws Exception { + mockMvc.perform(delete("/v1/integration/100").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isNotFound()); + } + + @Test + void deleteAllIntegrations() throws Exception { + mockMvc.perform( + delete("/v1/integration/all/email").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void getProjectIntegration() throws Exception { + mockMvc.perform( + get("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void testProjectIntegrationConnection() throws Exception { + mockMvc.perform(get("/v1/integration/default_personal/8/connection/test").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getProjectIntegrationNegative() throws Exception { + mockMvc.perform( + get("/v1/integration/default_personal/100").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isNotFound()); + } + + @Test + void deleteProjectIntegration() throws Exception { + mockMvc.perform( + delete("/v1/integration/default_personal/8").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void deleteProjectIntegrationNegative() throws Exception { + mockMvc.perform( + delete("/v1/integration/default_personal/100").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isNotFound()); + } + + @Test + void deleteAllProjectIntegrations() throws Exception { + mockMvc.perform(delete("/v1/integration/default_personal/all/email").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncControllerTest.java index 35092dfa1a..2ef618bcbd 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchAsyncControllerTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.launch.FinishLaunchHandler; import com.epam.ta.reportportal.core.launch.MergeLaunchHandler; @@ -27,6 +34,8 @@ import com.epam.ta.reportportal.ws.model.launch.MergeLaunchesRQ; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.collect.Lists; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -35,108 +44,119 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.web.savedrequest.Enumerator; -import javax.servlet.http.HttpServletRequest; -import java.util.UUID; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - /** * @author Konstantin Antipin */ @ExtendWith(MockitoExtension.class) class LaunchAsyncControllerTest { - @Mock - ProjectExtractor projectExtractor; - - @Mock - StartLaunchHandler startLaunchHandler; - - @Mock - FinishLaunchHandler finishLaunchHandler; - - @Mock - MergeLaunchHandler mergeLaunchHandler; - - @InjectMocks - LaunchAsyncController launchAsyncController; - - @Mock - HttpServletRequest httpServletRequest; - - @Test - void startLaunch() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<StartLaunchRQ> requestArgumentCaptor = ArgumentCaptor.forClass(StartLaunchRQ.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - launchAsyncController.startLaunch("test_project", startLaunchRQ, user); - verify(startLaunchHandler).startLaunch(userArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture(), requestArgumentCaptor.capture()); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(startLaunchRQ, requestArgumentCaptor.getValue()); - } - - @Test - void finishLaunch() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - - String launchId = UUID.randomUUID().toString(); - - ArgumentCaptor<String> launchIdArgumentCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<FinishExecutionRQ> requestArgumentCaptor = ArgumentCaptor.forClass(FinishExecutionRQ.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<String> urlArgumentCaptor = ArgumentCaptor.forClass(String.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - when(httpServletRequest.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080")); - when(httpServletRequest.getHeaderNames()).thenReturn(new Enumerator<>(Lists.newArrayList())); - launchAsyncController.finishLaunch("test_project", launchId, finishExecutionRQ, user, httpServletRequest); - verify(finishLaunchHandler).finishLaunch( - launchIdArgumentCaptor.capture(), - requestArgumentCaptor.capture(), - projectDetailsArgumentCaptor.capture(), - userArgumentCaptor.capture(), - urlArgumentCaptor.capture()); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(finishExecutionRQ, requestArgumentCaptor.getValue()); - } - - @Test - void mergeLaunch() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - MergeLaunchesRQ mergeLaunchesRQ = new MergeLaunchesRQ(); - - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<MergeLaunchesRQ> requestArgumentCaptor = ArgumentCaptor.forClass(MergeLaunchesRQ.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - launchAsyncController.mergeLaunches("test_project", mergeLaunchesRQ, user); - verify(mergeLaunchHandler).mergeLaunches(projectDetailsArgumentCaptor.capture(), userArgumentCaptor.capture(), requestArgumentCaptor.capture()); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(mergeLaunchesRQ, requestArgumentCaptor.getValue()); - } + @Mock + ProjectExtractor projectExtractor; + + @Mock + StartLaunchHandler startLaunchHandler; + + @Mock + FinishLaunchHandler finishLaunchHandler; + + @Mock + MergeLaunchHandler mergeLaunchHandler; + + @InjectMocks + LaunchAsyncController launchAsyncController; + + @Mock + HttpServletRequest httpServletRequest; + + @Test + void startLaunch() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<StartLaunchRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + StartLaunchRQ.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + launchAsyncController.startLaunch("test_project", startLaunchRQ, user); + verify(startLaunchHandler).startLaunch(userArgumentCaptor.capture(), + projectDetailsArgumentCaptor.capture(), requestArgumentCaptor.capture()); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(startLaunchRQ, requestArgumentCaptor.getValue()); + } + + @Test + void finishLaunch() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + + String launchId = UUID.randomUUID().toString(); + + ArgumentCaptor<String> launchIdArgumentCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<FinishExecutionRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + FinishExecutionRQ.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<String> urlArgumentCaptor = ArgumentCaptor.forClass(String.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + when(httpServletRequest.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080")); + when(httpServletRequest.getHeaderNames()).thenReturn(new Enumerator<>(Lists.newArrayList())); + launchAsyncController.finishLaunch("test_project", launchId, finishExecutionRQ, user, + httpServletRequest); + verify(finishLaunchHandler).finishLaunch( + launchIdArgumentCaptor.capture(), + requestArgumentCaptor.capture(), + projectDetailsArgumentCaptor.capture(), + userArgumentCaptor.capture(), + urlArgumentCaptor.capture()); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(finishExecutionRQ, requestArgumentCaptor.getValue()); + } + + @Test + void mergeLaunch() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + MergeLaunchesRQ mergeLaunchesRQ = new MergeLaunchesRQ(); + + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<MergeLaunchesRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + MergeLaunchesRQ.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + launchAsyncController.mergeLaunches("test_project", mergeLaunchesRQ, user); + verify(mergeLaunchHandler).mergeLaunches(projectDetailsArgumentCaptor.capture(), + userArgumentCaptor.capture(), requestArgumentCaptor.capture()); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(mergeLaunchesRQ, requestArgumentCaptor.getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerTest.java index 6b6e274e37..6b71d7fa7c 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerTest.java @@ -16,6 +16,22 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; +import static com.epam.ta.reportportal.ws.model.launch.Mode.DEBUG; +import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; +import static java.util.stream.Collectors.toMap; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.dao.LaunchRepository; @@ -38,26 +54,19 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.jdbc.Sql; - import java.time.LocalDateTime; import java.time.ZoneId; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_PROJECT_ID; -import static com.epam.ta.reportportal.ws.model.launch.Mode.DEBUG; -import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; -import static java.util.stream.Collectors.toMap; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.*; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.jdbc.Sql; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> @@ -65,329 +74,370 @@ @Sql("/db/launch/launch-fill.sql") class LaunchControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private LaunchRepository launchRepository; - - @Test - void happyCreateLaunch() throws Exception { - String name = "some launch name"; - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setDescription("some description"); - startLaunchRQ.setName(name); - startLaunchRQ.setStartTime(new Date()); - startLaunchRQ.setMode(DEFAULT); - startLaunchRQ.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); - - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/launch/").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startLaunchRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isCreated()); - } - - @Test - void getSuggestedItemsAnalyzerNotDeployed() throws Exception { - AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); - analyzeLaunchRQ.setLaunchId(1L); - analyzeLaunchRQ.setAnalyzeItemsModes(Collections.singletonList("TO_INVESTIGATE")); - analyzeLaunchRQ.setAnalyzerTypeName("autoAnalyzer"); - analyzeLaunchRQ.setAnalyzerHistoryMode("ALL"); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/launch/analyze").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(analyzeLaunchRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) - .andExpect(result -> assertEquals( - "Impossible interact with integration. There are no analyzer services are deployed.", - result.getResolvedException().getMessage() - )); - } - - @Test - void updateLaunchPositive() throws Exception { - UpdateLaunchRQ rq = new UpdateLaunchRQ(); - rq.setMode(DEFAULT); - rq.setDescription("description"); - rq.setAttributes(Sets.newHashSet(new ItemAttributeResource("test", "test"))); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/3/update").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON)).andExpect(status().is(200)); - } - - @Test - void getLaunchPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/2").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); - } - - @Test - void getLaunchStringPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/launch/4850a659-ac26-4a65-8ea4-a6756a57fb92").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void getLaunchUuidPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/launch/uuid/4850a659-ac26-4a65-8ea4-a6756a57fb92").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void getDebugLaunches() throws Exception { - mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/launch/mode").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().is(200)); - } - - @Test - void compareLaunches() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/compare?ids=1,2").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void mergeLaunchesPositive() throws Exception { - MergeLaunchesRQ rq = new MergeLaunchesRQ(); - HashSet<Long> set = new HashSet<>(); - set.add(1L); - set.add(2L); - rq.setLaunches(set); - rq.setName("Merged"); - rq.setMergeStrategyType("BASIC"); - rq.setStartTime(new Date()); - rq.setEndTime(new Date()); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/launch/merge").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().is(200)); - } - - @Test - void deleteLaunchPositive() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/launch/1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void deleteLaunchNegative() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/launch/3").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(406)); - } - - @Test - void getStatus() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/status?ids=1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void finishLaunch() throws Exception { - final FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/befef834-b2ef-4acf-aea3-b5a5b15fd93c/finish").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(finishExecutionRQ))).andExpect(status().is(200)); - } - - @Test - void forceFinishLaunch() throws Exception { - final FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/3/stop").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(finishExecutionRQ))).andExpect(status().is(200)); - } - - @Test - void bulkForceFinish() throws Exception { - final BulkRQ<Long, FinishExecutionRQ> bulkRQ = new BulkRQ<>(); - bulkRQ.setEntities(Stream.of(3L, 5L).collect(toMap(it -> it, it -> { - FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); - finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); - finishExecutionRQ.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - return finishExecutionRQ; - }))); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/stop").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(bulkRQ))).andExpect(status().isOk()); - } - - @Test - void getAllOwners() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/owners?filter.cnt.user=def").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); - } - - @Test - void getAllLaunchNames() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/names?filter.cnt.name=test").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); - } - - @Test - void bulkDeleteLaunches() throws Exception { - DeleteBulkRQ deleteBulkRQ = new DeleteBulkRQ(); - List<Long> ids = Lists.newArrayList(1L, 2L); - deleteBulkRQ.setIds(ids); - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/launch").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(deleteBulkRQ))).andExpect(status().is(200)); - List<Launch> launches = launchRepository.findAllById(ids); - assertTrue(launches.isEmpty()); - } - - @Test - void bulkMoveToDebug() throws Exception { - final List<Long> ids = launchRepository.findByFilter(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_PROJECT_ID, String.valueOf(2L)).build()) - .build()).stream().filter(it -> it.getMode() == LaunchModeEnum.DEFAULT).map(Launch::getId).collect(Collectors.toList()); - final Map<Long, UpdateLaunchRQ> entities = ids.stream().collect(toMap(it -> it, it -> { - final UpdateLaunchRQ updateLaunchRQ = new UpdateLaunchRQ(); - updateLaunchRQ.setMode(DEBUG); - return updateLaunchRQ; - })); - final BulkRQ<Long, UpdateLaunchRQ> bulkRQ = new BulkRQ<>(); - bulkRQ.setEntities(entities); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/update").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(bulkRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().is(200)); - launchRepository.findAllById(ids).forEach(it -> assertSame(it.getMode(), LaunchModeEnum.DEBUG)); - } - - @Test - void getLaunches() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/launch?page.page=1&page.size=50&page.sort=statistics$defects$product_bug$total,ASC").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); - } - - @Test - void getLatestLaunches() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/launch/latest?page.page=1&page.size=10&page.sort=name,ASC").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().is(200)); - } - - @Test - void getAttributeKeys() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/launch/attribute/keys?filter.cnt.attributeKey=browser").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getAttributeValues() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/launch/attribute/values?filter.eq.attributeKey=browser&filter.cnt.attributeValue=ch").with( - token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getProjectLaunches() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.content", hasSize(4))); - } - - @Test - void export() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/1/report").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void bulkUpdateItemAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.CREATE); - String comment = "created"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.UPDATE); - updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); - updateItemAttributeRQ.setTo(new ItemAttributeResource("updatedKey", "updatedValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<Launch> launches = launchRepository.findAllById(launchIds); - launches.forEach(it -> launchRepository.refresh(it)); - - launches.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") && !attr.isSystem())); - assertTrue(it.getAttributes() - .stream() - .anyMatch(attr -> "updatedKey".equals(attr.getKey()) && attr.getValue().equals("updatedValue") && !attr.isSystem())); - assertEquals(comment, it.getDescription()); - }); - } - - @Test - void bulkCreateAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.UPDATE); - String comment = "updated"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.CREATE); - updateItemAttributeRQ.setTo(new ItemAttributeResource("createdKey", "createdValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<Launch> launches = launchRepository.findAllById(launchIds); - launches.forEach(it -> launchRepository.refresh(it)); - - launches.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .anyMatch(attr -> "createdKey".equals(attr.getKey()) && attr.getValue().equals("createdValue") && !attr.isSystem())); - assertTrue(it.getDescription().length() > comment.length() && it.getDescription().contains(comment)); - }); - } - - @Test - void bulkDeleteAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.CREATE); - String comment = "created"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.DELETE); - updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<Launch> launches = launchRepository.findAllById(launchIds); - launches.forEach(it -> launchRepository.refresh(it)); - - launches.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") && !attr.isSystem())); - assertEquals(comment, it.getDescription()); - }); - } + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private LaunchRepository launchRepository; + + @Test + void happyCreateLaunch() throws Exception { + String name = "some launch name"; + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + startLaunchRQ.setDescription("some description"); + startLaunchRQ.setName(name); + startLaunchRQ.setStartTime(new Date()); + startLaunchRQ.setMode(DEFAULT); + startLaunchRQ.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); + + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/launch/").with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startLaunchRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isCreated()); + } + + @Test + void getSuggestedItemsAnalyzerNotDeployed() throws Exception { + AnalyzeLaunchRQ analyzeLaunchRQ = new AnalyzeLaunchRQ(); + analyzeLaunchRQ.setLaunchId(1L); + analyzeLaunchRQ.setAnalyzeItemsModes(Collections.singletonList("TO_INVESTIGATE")); + analyzeLaunchRQ.setAnalyzerTypeName("autoAnalyzer"); + analyzeLaunchRQ.setAnalyzerHistoryMode("ALL"); + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/launch/analyze").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(analyzeLaunchRQ)) + .contentType(APPLICATION_JSON)) + .andExpect( + result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) + .andExpect(result -> assertEquals( + "Impossible interact with integration. There are no analyzer services are deployed.", + result.getResolvedException().getMessage() + )); + } + + @Test + void updateLaunchPositive() throws Exception { + UpdateLaunchRQ rq = new UpdateLaunchRQ(); + rq.setMode(DEFAULT); + rq.setDescription("description"); + rq.setAttributes(Sets.newHashSet(new ItemAttributeResource("test", "test"))); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/3/update").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(rq)) + .contentType(APPLICATION_JSON)).andExpect(status().is(200)); + } + + @Test + void getLaunchPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/launch/2").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void getLaunchStringPositive() throws Exception { + mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + "/launch/4850a659-ac26-4a65-8ea4-a6756a57fb92").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void getLaunchUuidPositive() throws Exception { + mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + "/launch/uuid/4850a659-ac26-4a65-8ea4-a6756a57fb92").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void getDebugLaunches() throws Exception { + mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/launch/mode").with( + token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().is(200)); + } + + @Test + void compareLaunches() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/compare?ids=1,2").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void mergeLaunchesPositive() throws Exception { + MergeLaunchesRQ rq = new MergeLaunchesRQ(); + HashSet<Long> set = new HashSet<>(); + set.add(1L); + set.add(2L); + rq.setLaunches(set); + rq.setName("Merged"); + rq.setMergeStrategyType("BASIC"); + rq.setStartTime(new Date()); + rq.setEndTime(new Date()); + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/launch/merge").contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().is(200)); + } + + @Test + void deleteLaunchPositive() throws Exception { + mockMvc.perform( + delete(DEFAULT_PROJECT_BASE_URL + "/launch/1").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void deleteLaunchNegative() throws Exception { + mockMvc.perform( + delete(DEFAULT_PROJECT_BASE_URL + "/launch/3").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(406)); + } + + @Test + void getStatus() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/status?ids=1").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void finishLaunch() throws Exception { + final FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + + "/launch/befef834-b2ef-4acf-aea3-b5a5b15fd93c/finish").contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(finishExecutionRQ))).andExpect(status().is(200)); + } + + @Test + void forceFinishLaunch() throws Exception { + final FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/launch/3/stop").contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(finishExecutionRQ))).andExpect(status().is(200)); + } + + @Test + void bulkForceFinish() throws Exception { + final BulkRQ<Long, FinishExecutionRQ> bulkRQ = new BulkRQ<>(); + bulkRQ.setEntities(Stream.of(3L, 5L).collect(toMap(it -> it, it -> { + FinishExecutionRQ finishExecutionRQ = new FinishExecutionRQ(); + finishExecutionRQ.setStatus(StatusEnum.PASSED.name()); + finishExecutionRQ.setEndTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + return finishExecutionRQ; + }))); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/launch/stop").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(bulkRQ))).andExpect(status().isOk()); + } + + @Test + void getAllOwners() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/launch/owners?filter.cnt.user=def").contentType( + APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); + } + + @Test + void getAllLaunchNames() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/launch/names?filter.cnt.name=test").contentType( + APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); + } + + @Test + void bulkDeleteLaunches() throws Exception { + DeleteBulkRQ deleteBulkRQ = new DeleteBulkRQ(); + List<Long> ids = Lists.newArrayList(1L, 2L); + deleteBulkRQ.setIds(ids); + mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/launch").contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(deleteBulkRQ))).andExpect(status().is(200)); + List<Launch> launches = launchRepository.findAllById(ids); + assertTrue(launches.isEmpty()); + } + + @Test + void bulkMoveToDebug() throws Exception { + final List<Long> ids = launchRepository.findByFilter(Filter.builder() + .withTarget(Launch.class) + .withCondition( + FilterCondition.builder().eq(CRITERIA_PROJECT_ID, String.valueOf(2L)).build()) + .build()).stream().filter(it -> it.getMode() == LaunchModeEnum.DEFAULT).map(Launch::getId) + .collect(Collectors.toList()); + final Map<Long, UpdateLaunchRQ> entities = ids.stream().collect(toMap(it -> it, it -> { + final UpdateLaunchRQ updateLaunchRQ = new UpdateLaunchRQ(); + updateLaunchRQ.setMode(DEBUG); + return updateLaunchRQ; + })); + final BulkRQ<Long, UpdateLaunchRQ> bulkRQ = new BulkRQ<>(); + bulkRQ.setEntities(entities); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/launch/update").with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(bulkRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().is(200)); + launchRepository.findAllById(ids).forEach(it -> assertSame(it.getMode(), LaunchModeEnum.DEBUG)); + } + + @Test + void getLaunches() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/launch?page.page=1&page.size=50&page.sort=statistics$defects$product_bug$total,ASC").contentType( + APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().is(200)); + } + + @Test + void getLatestLaunches() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/launch/latest?page.page=1&page.size=10&page.sort=name,ASC").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().is(200)); + } + + @Test + void getAttributeKeys() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/launch/attribute/keys?filter.cnt.attributeKey=browser").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void getAttributeValues() throws Exception { + mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + + "/launch/attribute/values?filter.eq.attributeKey=browser&filter.cnt.attributeValue=ch").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getProjectLaunches() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/launch").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.content", hasSize(4))); + } + + @Test + void export() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/launch/1/report").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void bulkUpdateItemAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.CREATE); + String comment = "created"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.UPDATE); + updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); + updateItemAttributeRQ.setTo(new ItemAttributeResource("updatedKey", "updatedValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + List<Launch> launches = launchRepository.findAllById(launchIds); + launches.forEach(it -> launchRepository.refresh(it)); + + launches.forEach(it -> { + assertTrue(it.getAttributes() + .stream() + .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") + && !attr.isSystem())); + assertTrue(it.getAttributes() + .stream() + .anyMatch( + attr -> "updatedKey".equals(attr.getKey()) && attr.getValue().equals("updatedValue") + && !attr.isSystem())); + assertEquals(comment, it.getDescription()); + }); + } + + @Test + void bulkCreateAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.UPDATE); + String comment = "updated"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.CREATE); + updateItemAttributeRQ.setTo(new ItemAttributeResource("createdKey", "createdValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + List<Launch> launches = launchRepository.findAllById(launchIds); + launches.forEach(it -> launchRepository.refresh(it)); + + launches.forEach(it -> { + assertTrue(it.getAttributes() + .stream() + .anyMatch( + attr -> "createdKey".equals(attr.getKey()) && attr.getValue().equals("createdValue") + && !attr.isSystem())); + assertTrue( + it.getDescription().length() > comment.length() && it.getDescription().contains(comment)); + }); + } + + @Test + void bulkDeleteAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.CREATE); + String comment = "created"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.DELETE); + updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/launch/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + List<Launch> launches = launchRepository.findAllById(launchIds); + launches.forEach(it -> launchRepository.refresh(it)); + + launches.forEach(it -> { + assertTrue(it.getAttributes() + .stream() + .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") + && !attr.isSystem())); + assertEquals(comment, it.getDescription()); + }); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerValidationTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerValidationTest.java index b1e47da472..0b3070b83b 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerValidationTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/LaunchControllerValidationTest.java @@ -16,6 +16,19 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_BLANK_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_NULL_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.WHITESPACES_NAME_VALUE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; +import static org.apache.commons.lang3.StringUtils.EMPTY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.ErrorRS; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; @@ -23,210 +36,218 @@ import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; +import java.util.Date; +import java.util.HashSet; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.MvcResult; -import java.util.Date; -import java.util.HashSet; - -import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.*; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static com.epam.ta.reportportal.ws.model.launch.Mode.DEFAULT; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:tatyana_gladysheva@epam.com">Tatyana Gladysheva</a> */ public class LaunchControllerValidationTest extends BaseMvcTest { - private static final String LAUNCH_PATH = "/launch"; - private static final String MERGE_PATH = "/merge"; - - private static final String FIELD_NAME_SIZE_MESSAGE = String.format(FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 1, 256); - - private static final String LONG_NAME_VALUE = "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttt"; - - @Autowired - private ObjectMapper objectMapper; - - @Test - public void createLaunchShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - StartLaunchRQ startLaunchRQ = prepareLaunch(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startLaunchRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void createLaunchShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - StartLaunchRQ startLaunchRQ = prepareLaunch(); - startLaunchRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startLaunchRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createLaunchShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - StartLaunchRQ startLaunchRQ = prepareLaunch(); - startLaunchRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startLaunchRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createLaunchShouldReturnErrorWhenNameIsGreaterThanTwoHundredAndFiftySixCharacters() throws Exception { - //GIVEN - StartLaunchRQ startLaunchRQ = prepareLaunch(); - startLaunchRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startLaunchRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - private StartLaunchRQ prepareLaunch() { - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setDescription("some description"); - startLaunchRQ.setStartTime(new Date()); - startLaunchRQ.setMode(DEFAULT); - startLaunchRQ.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); - return startLaunchRQ; - } - - @Test - public void mergeLaunchShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void mergeLaunchShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); - mergeLaunchesRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void mergeLaunchShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); - mergeLaunchesRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void mergeLaunchShouldReturnErrorWhenNameIsGreaterThanTwoHundredAndFiftySixCharacters() throws Exception { - //GIVEN - MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); - mergeLaunchesRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - private MergeLaunchesRQ prepareLaunchesMerge() { - MergeLaunchesRQ mergeLaunchesRQ = new MergeLaunchesRQ(); - - HashSet<Long> set = new HashSet<>(); - set.add(1L); - set.add(2L); - - mergeLaunchesRQ.setLaunches(set); - mergeLaunchesRQ.setMergeStrategyType("BASIC"); - mergeLaunchesRQ.setStartTime(new Date()); - mergeLaunchesRQ.setEndTime(new Date()); - - return mergeLaunchesRQ; - } + private static final String LAUNCH_PATH = "/launch"; + private static final String MERGE_PATH = "/merge"; + + private static final String FIELD_NAME_SIZE_MESSAGE = String.format( + FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 1, 256); + + private static final String LONG_NAME_VALUE = + "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttt"; + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void createLaunchShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + StartLaunchRQ startLaunchRQ = prepareLaunch(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startLaunchRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void createLaunchShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + StartLaunchRQ startLaunchRQ = prepareLaunch(); + startLaunchRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startLaunchRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createLaunchShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + StartLaunchRQ startLaunchRQ = prepareLaunch(); + startLaunchRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startLaunchRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createLaunchShouldReturnErrorWhenNameIsGreaterThanTwoHundredAndFiftySixCharacters() + throws Exception { + //GIVEN + StartLaunchRQ startLaunchRQ = prepareLaunch(); + startLaunchRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startLaunchRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + private StartLaunchRQ prepareLaunch() { + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + startLaunchRQ.setDescription("some description"); + startLaunchRQ.setStartTime(new Date()); + startLaunchRQ.setMode(DEFAULT); + startLaunchRQ.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); + return startLaunchRQ; + } + + @Test + public void mergeLaunchShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void mergeLaunchShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); + mergeLaunchesRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void mergeLaunchShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); + mergeLaunchesRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void mergeLaunchShouldReturnErrorWhenNameIsGreaterThanTwoHundredAndFiftySixCharacters() + throws Exception { + //GIVEN + MergeLaunchesRQ mergeLaunchesRQ = prepareLaunchesMerge(); + mergeLaunchesRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + LAUNCH_PATH + MERGE_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(mergeLaunchesRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + private MergeLaunchesRQ prepareLaunchesMerge() { + MergeLaunchesRQ mergeLaunchesRQ = new MergeLaunchesRQ(); + + HashSet<Long> set = new HashSet<>(); + set.add(1L); + set.add(2L); + + mergeLaunchesRQ.setLaunches(set); + mergeLaunchesRQ.setMergeStrategyType("BASIC"); + mergeLaunchesRQ.setStartTime(new Date()); + mergeLaunchesRQ.setEndTime(new Date()); + + return mergeLaunchesRQ; + } } diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/LogAsyncControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/LogAsyncControllerTest.java index bec7d82a10..4edba9ed06 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/LogAsyncControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/LogAsyncControllerTest.java @@ -16,12 +16,22 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.log.CreateLogHandler; import com.epam.ta.reportportal.entity.project.ProjectRole; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Validator; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -30,106 +40,110 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Validator; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.internal.verification.VerificationModeFactory.times; - /** * @author Konstantin Antipin */ @ExtendWith(MockitoExtension.class) class LogAsyncControllerTest { - @Mock - ProjectExtractor projectExtractor; - - @Mock - CreateLogHandler createLogHandler; - - @Mock - Validator validator; - - @InjectMocks - LogAsyncController logAsyncController; - - @Mock - HttpServletRequest httpServletRequest; - - @Test - void createLog() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - SaveLogRQ saveLogRQ = new SaveLogRQ(); - - ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); - ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - logAsyncController.createLog("test_project", saveLogRQ, user); - verify(createLogHandler).createLog(requestArgumentCaptor.capture(), fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); - verify(validator).validate(requestArgumentCaptor.capture()); - - requestArgumentCaptor.getAllValues().forEach(rq -> assertEquals(saveLogRQ, rq)); - assertEquals(null, fileArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - } - - @Test - void createLogEntry() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - SaveLogRQ saveLogRQ = new SaveLogRQ(); - - ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); - ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - logAsyncController.createLogEntry("test_project", saveLogRQ, user); - verify(createLogHandler).createLog(requestArgumentCaptor.capture(), fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); - verify(validator).validate(requestArgumentCaptor.capture()); - - requestArgumentCaptor.getAllValues().forEach(rq -> assertEquals(saveLogRQ, rq)); - assertEquals(null, fileArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - } - - @Test - void createLogs() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - SaveLogRQ saveLogRQ = new SaveLogRQ(); - SaveLogRQ[] saveLogRQs = {saveLogRQ, saveLogRQ}; - - ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); - ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - logAsyncController.createLog("test_project", saveLogRQs, httpServletRequest, user); - verify(validator, times(4)).validate(requestArgumentCaptor.capture()); - verify(createLogHandler, times(2)).createLog(requestArgumentCaptor.capture(), fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); - - assertEquals(6,requestArgumentCaptor.getAllValues().size()); - assertEquals(2,fileArgumentCaptor.getAllValues().size()); - assertEquals(2, projectDetailsArgumentCaptor.getAllValues().size()); - - requestArgumentCaptor.getAllValues().forEach(arg -> assertEquals(saveLogRQ, arg)); - fileArgumentCaptor.getAllValues().forEach(arg -> assertEquals(null, arg)); - projectDetailsArgumentCaptor.getAllValues().forEach(arg -> assertEquals(user.getProjectDetails().get("test_project"), arg)); - } + @Mock + ProjectExtractor projectExtractor; + + @Mock + CreateLogHandler createLogHandler; + + @Mock + Validator validator; + + @InjectMocks + LogAsyncController logAsyncController; + + @Mock + HttpServletRequest httpServletRequest; + + @Test + void createLog() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + SaveLogRQ saveLogRQ = new SaveLogRQ(); + + ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); + ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + logAsyncController.createLog("test_project", saveLogRQ, user); + verify(createLogHandler).createLog(requestArgumentCaptor.capture(), + fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); + verify(validator).validate(requestArgumentCaptor.capture()); + + requestArgumentCaptor.getAllValues().forEach(rq -> assertEquals(saveLogRQ, rq)); + assertEquals(null, fileArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + } + + @Test + void createLogEntry() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + SaveLogRQ saveLogRQ = new SaveLogRQ(); + + ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); + ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + logAsyncController.createLogEntry("test_project", saveLogRQ, user); + verify(createLogHandler).createLog(requestArgumentCaptor.capture(), + fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); + verify(validator).validate(requestArgumentCaptor.capture()); + + requestArgumentCaptor.getAllValues().forEach(rq -> assertEquals(saveLogRQ, rq)); + assertEquals(null, fileArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + } + + @Test + void createLogs() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + SaveLogRQ saveLogRQ = new SaveLogRQ(); + SaveLogRQ[] saveLogRQs = {saveLogRQ, saveLogRQ}; + + ArgumentCaptor<SaveLogRQ> requestArgumentCaptor = ArgumentCaptor.forClass(SaveLogRQ.class); + ArgumentCaptor<MultipartFile> fileArgumentCaptor = ArgumentCaptor.forClass(MultipartFile.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + logAsyncController.createLog("test_project", saveLogRQs, httpServletRequest, user); + verify(validator, times(4)).validate(requestArgumentCaptor.capture()); + verify(createLogHandler, times(2)).createLog(requestArgumentCaptor.capture(), + fileArgumentCaptor.capture(), projectDetailsArgumentCaptor.capture()); + + assertEquals(6, requestArgumentCaptor.getAllValues().size()); + assertEquals(2, fileArgumentCaptor.getAllValues().size()); + assertEquals(2, projectDetailsArgumentCaptor.getAllValues().size()); + + requestArgumentCaptor.getAllValues().forEach(arg -> assertEquals(saveLogRQ, arg)); + fileArgumentCaptor.getAllValues().forEach(arg -> assertEquals(null, arg)); + projectDetailsArgumentCaptor.getAllValues() + .forEach(arg -> assertEquals(user.getProjectDetails().get("test_project"), arg)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/LogControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/LogControllerTest.java index d7f278b425..7076cf8f98 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/LogControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/LogControllerTest.java @@ -16,97 +16,109 @@ package com.epam.ta.reportportal.ws.controller; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import com.epam.ta.reportportal.ws.model.log.SearchLogRq; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.context.jdbc.Sql; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.context.jdbc.Sql; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ -@Sql({ "/db/test-item/test-item-fill.sql", "/db/log/log-fill.sql" }) +@Sql({"/db/test-item/test-item-fill.sql", "/db/log/log-fill.sql"}) class LogControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; + @Autowired + private ObjectMapper objectMapper; - @Test - void createLogPositive() throws Exception { - SaveLogRQ rq = new SaveLogRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setItemUuid("f3960757-1a06-405e-9eb7-607c34683154"); - rq.setLevel("ERROR"); - rq.setMessage("log message"); - rq.setLogTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/log").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isCreated()); - } + @Test + void createLogPositive() throws Exception { + SaveLogRQ rq = new SaveLogRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setItemUuid("f3960757-1a06-405e-9eb7-607c34683154"); + rq.setLevel("ERROR"); + rq.setMessage("log message"); + rq.setLogTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/log").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isCreated()); + } - @Test - void searchLogsNegative() throws Exception { - SearchLogRq rq = new SearchLogRq(); - rq.setSearchMode("currentLaunch"); - rq.setFilterId(1L); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/log/search/1").with(token(oAuthHelper.getDefaultToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) - .andExpect(result -> assertEquals( - "Unable to perform operation for non-finished test item.", - result.getResolvedException().getMessage() - )); - ; - } + @Test + void searchLogsNegative() throws Exception { + SearchLogRq rq = new SearchLogRq(); + rq.setSearchMode("currentLaunch"); + rq.setFilterId(1L); + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/log/search/1").with(token(oAuthHelper.getDefaultToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq))) + .andExpect( + result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) + .andExpect(result -> assertEquals( + "Unable to perform operation for non-finished test item.", + result.getResolvedException().getMessage() + )); + ; + } - @Test - void deleteLogPositive() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/log/1").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } + @Test + void deleteLogPositive() throws Exception { + mockMvc.perform( + delete(DEFAULT_PROJECT_BASE_URL + "/log/1").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } - @Test - void getLogsPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/log?filter.eq.item=2").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } + @Test + void getLogsPositive() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/log?filter.eq.item=2").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } - @Test - void getLogPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/log/2").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } + @Test + void getLogPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/log/2").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } - @Test - void getLogStringPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/log/9ba98f41-2cde-4510-8503-d8eda901cc71").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } + @Test + void getLogStringPositive() throws Exception { + mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + "/log/9ba98f41-2cde-4510-8503-d8eda901cc71").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } - @Test - void getLogUuidPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/log/uuid/9ba98f41-2cde-4510-8503-d8eda901cc71").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } + @Test + void getLogUuidPositive() throws Exception { + mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + "/log/uuid/9ba98f41-2cde-4510-8503-d8eda901cc71").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } - @Test - void getLogNegative() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/log/100").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isNotFound()); - } + @Test + void getLogNegative() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/log/100").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isNotFound()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/PluginControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/PluginControllerTest.java index 628e2a9cf3..1e365e529f 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/PluginControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/PluginControllerTest.java @@ -16,20 +16,27 @@ package com.epam.ta.reportportal.ws.controller; -import com.epam.ta.reportportal.ws.BaseMvcTest; -import org.junit.jupiter.api.Test; - import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.epam.ta.reportportal.ws.BaseMvcTest; +import org.junit.jupiter.api.Test; + /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PluginControllerTest extends BaseMvcTest { - @Test - void getLaunchPositive() throws Exception { - mockMvc.perform(get("/v1/plugin").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } + @Test + void getLaunchPositive() throws Exception { + mockMvc.perform(get("/v1/plugin").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void shouldNotGetFileWhenNotAuthenticated() throws Exception { + mockMvc.perform(get("/v1/plugin/pluginName/file/image.png")) + .andExpect(status().isUnauthorized()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/PluginPublicControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/PluginPublicControllerTest.java new file mode 100644 index 0000000000..b2e0c1a4a9 --- /dev/null +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/PluginPublicControllerTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2022 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.ws.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.epam.ta.reportportal.entity.attachment.BinaryData; +import com.epam.ta.reportportal.ws.BaseMvcTest; +import java.io.ByteArrayInputStream; +import java.util.Collections; +import java.util.Map; +import javax.activation.MimetypesFileTypeMap; +import javax.servlet.http.HttpServletResponse; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; + +/** + * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> + */ +class PluginPublicControllerTest extends BaseMvcTest { + + @Test + void shouldGetFileWhenAuthenticated() throws Exception { + + final ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[]{}); + final String contentType = MimetypesFileTypeMap.getDefaultFileTypeMap() + .getContentType("image.png"); + + final BinaryData binaryData = new BinaryData(contentType, (long) inputStream.available(), + inputStream); + when(pluginPublicFilesProvider.load("pluginName", "image.png")).thenReturn(binaryData); + + mockMvc.perform(get("/v1/plugin/public/pluginName/file/image.png").with( + token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + + verify(binaryDataResponseWriter, times(1)).write(eq(binaryData), + any(HttpServletResponse.class)); + } + + @Test + void shouldGetFileWhenNotAuthenticated() throws Exception { + final ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[]{}); + final String contentType = MimetypesFileTypeMap.getDefaultFileTypeMap() + .getContentType("image.png"); + + final BinaryData binaryData = new BinaryData(contentType, (long) inputStream.available(), + inputStream); + when(pluginPublicFilesProvider.load("pluginName", "image.png")).thenReturn(binaryData); + + mockMvc.perform(get("/v1/plugin/public/pluginName/file/image.png")).andExpect(status().isOk()); + + verify(binaryDataResponseWriter, times(1)).write(eq(binaryData), + any(HttpServletResponse.class)); + } + + @Test + void shouldExecutePublicCommandWhenAuthenticated() throws Exception { + final String plugin = "signup"; + final String command = "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + final String ok = "{'result': 'ok'}"; + when(executeIntegrationHandler.executePublicCommand(plugin, command, params)).thenReturn(ok); + + mockMvc.perform(put("/v1/plugin/public/{plugin}/{command}", plugin, command) + .with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isOk()) + .andExpect(content().string(Matchers.containsString(ok))); + + verify(executeIntegrationHandler).executePublicCommand(eq(plugin), eq(command), eq(params)); + } + + @Test + void shouldExecutePublicCommandWhenNotAuthenticated() throws Exception { + final String plugin = "signup"; + final String command = "testCommand"; + final Map<String, Object> params = Collections.emptyMap(); + final String ok = "{'result': 'ok'}"; + when(executeIntegrationHandler.executePublicCommand(plugin, command, params)).thenReturn(ok); + + mockMvc.perform(put("/v1/plugin/public/{plugin}/{command}", plugin, command) + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isOk()) + .andExpect(content().string(Matchers.containsString(ok))); + + verify(executeIntegrationHandler).executePublicCommand(eq(plugin), eq(command), eq(params)); + } + +} diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectControllerTest.java index 660c301c9c..7a08a2e65a 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectControllerTest.java @@ -510,6 +510,7 @@ void updateProjectNotificationConfig() throws Exception { senderCaseDTO.setRecipients(Collections.singletonList("default")); senderCaseDTO.setLaunchNames(Collections.singletonList("test launch")); senderCaseDTO.setEnabled(true); + senderCaseDTO.setRuleName("rule #1"); ItemAttributeResource launchAttribute = new ItemAttributeResource(); launchAttribute.setKey("key"); launchAttribute.setValue("val"); @@ -531,7 +532,7 @@ void indexProjectData() throws Exception { arguments.put("analyzer_index", true); arguments.put("analyzer", "test_analyzer"); exchangeInfo.setArguments(arguments); - when(rabbitClient.getExchanges(any())).thenReturn(Collections.singletonList(exchangeInfo)); + when(rabbitClient.getExchanges(any(String.class))).thenReturn(Collections.singletonList(exchangeInfo)); mockMvc.perform(put("/v1/project/default_personal/index").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); @@ -546,7 +547,7 @@ void deleteIndex() throws Exception { arguments.put("analyzer_index", true); arguments.put("analyzer", "test_analyzer"); exchangeInfo.setArguments(arguments); - when(rabbitClient.getExchanges(any())).thenReturn(Collections.singletonList(exchangeInfo)); + when(rabbitClient.getExchanges(any(String.class))).thenReturn(Collections.singletonList(exchangeInfo)); mockMvc.perform(delete("/v1/project/default_personal/index").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); @@ -565,4 +566,4 @@ private void verifyProjectIndexEvent() { assertEquals(2L, event.getUserId().longValue()); assertEquals("default", event.getUserLogin()); } -} \ No newline at end of file +} diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsControllerTest.java index 910685e81e..4ba4c88e86 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/ProjectSettingsControllerTest.java @@ -1,179 +1,292 @@ -/* - * Copyright 2019 EPAM Systems - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://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. - */ - -package com.epam.ta.reportportal.ws.controller; - -import com.epam.ta.reportportal.dao.IssueTypeRepository; -import com.epam.ta.reportportal.entity.item.issue.IssueType; -import com.epam.ta.reportportal.ws.BaseMvcTest; -import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; -import com.epam.ta.reportportal.ws.model.project.config.ProjectSettingsResource; -import com.epam.ta.reportportal.ws.model.project.config.UpdateIssueSubTypeRQ; -import com.epam.ta.reportportal.ws.model.project.config.UpdateOneIssueSubTypeRQ; -import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; -import com.epam.ta.reportportal.ws.model.project.config.pattern.UpdatePatternTemplateRQ; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.web.servlet.MvcResult; - -import java.util.Collection; -import java.util.Collections; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> - */ -@Sql("/db/project-settings/project-settings-fill.sql") -class ProjectSettingsControllerTest extends BaseMvcTest { - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private IssueTypeRepository issueTypeRepository; - - @Test - void createSubType() throws Exception { - CreateIssueSubTypeRQ rq = new CreateIssueSubTypeRQ(); - rq.setTypeRef("PRODUCT_BUG"); - rq.setColor("#eeeeee"); - rq.setLongName("LongName"); - rq.setShortName("name"); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type").contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isCreated()); - } - - @Test - void getProjectSettings() throws Exception { - final MvcResult mvcResult = mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/settings").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()) - .andReturn(); - final ProjectSettingsResource projectSettingsResource = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), - ProjectSettingsResource.class - ); - assertEquals(8, - projectSettingsResource.getSubTypes().values().stream().flatMap(Collection::stream).collect(Collectors.toList()).size() - ); - } - - @Test - void deleteSubType() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type/6").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - - Optional<IssueType> byId = issueTypeRepository.findById(6L); - assertFalse(byId.isPresent()); - - } - - @Test - void updateSubType() throws Exception { - UpdateIssueSubTypeRQ request = new UpdateIssueSubTypeRQ(); - final UpdateOneIssueSubTypeRQ updateOneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); - updateOneIssueSubTypeRQ.setColor("#000000"); - updateOneIssueSubTypeRQ.setLocator("custom_ti"); - updateOneIssueSubTypeRQ.setLongName("updated"); - updateOneIssueSubTypeRQ.setShortName("upd"); - updateOneIssueSubTypeRQ.setTypeRef("TO_INVESTIGATE"); - request.setIds(Collections.singletonList(updateOneIssueSubTypeRQ)); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - } - - @Test - void createPatternTemplate() throws Exception { - CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); - createPatternTemplateRQ.setEnabled(true); - createPatternTemplateRQ.setName("another_name"); - createPatternTemplateRQ.setType("string"); - createPatternTemplateRQ.setValue("qwe"); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))).andExpect(status().isCreated()); - } - - @Test - void createPatternTemplateWithWrongType() throws Exception { - CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); - createPatternTemplateRQ.setEnabled(true); - createPatternTemplateRQ.setName("name"); - createPatternTemplateRQ.setType("dd"); - createPatternTemplateRQ.setValue("qwe"); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))).andExpect(status().isBadRequest()); - } - - @Test - void createPatternTemplateWithDuplicateName() throws Exception { - CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); - createPatternTemplateRQ.setEnabled(true); - createPatternTemplateRQ.setName("some_name"); - createPatternTemplateRQ.setType("string"); - createPatternTemplateRQ.setValue("qwe"); - - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))).andExpect(status().isConflict()); - } - - @Test - void updatePatternTemplate() throws Exception { - - UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); - updatePatternTemplateRQ.setName("another_name"); - updatePatternTemplateRQ.setEnabled(true); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/1").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))).andExpect(status().isOk()); - } - - @Test - void updatePatternTemplateWithTheSameName() throws Exception { - - UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); - updatePatternTemplateRQ.setName("some_name"); - updatePatternTemplateRQ.setEnabled(true); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/1").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))).andExpect(status().isOk()); - } - - @Test - void updatePatternTemplateWithDuplicateName() throws Exception { - - UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); - updatePatternTemplateRQ.setName("some_name"); - updatePatternTemplateRQ.setEnabled(true); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/2").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))).andExpect(status().isConflict()); - } +/* + * Copyright 2019 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://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. + */ + +package com.epam.ta.reportportal.ws.controller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.epam.ta.reportportal.dao.IssueTypeRepository; +import com.epam.ta.reportportal.dao.SenderCaseRepository; +import com.epam.ta.reportportal.entity.enums.LogicalOperator; +import com.epam.ta.reportportal.entity.enums.SendCase; +import com.epam.ta.reportportal.entity.item.issue.IssueType; +import com.epam.ta.reportportal.entity.project.email.SenderCase; +import com.epam.ta.reportportal.ws.BaseMvcTest; +import com.epam.ta.reportportal.ws.model.project.config.CreateIssueSubTypeRQ; +import com.epam.ta.reportportal.ws.model.project.config.ProjectSettingsResource; +import com.epam.ta.reportportal.ws.model.project.config.UpdateIssueSubTypeRQ; +import com.epam.ta.reportportal.ws.model.project.config.UpdateOneIssueSubTypeRQ; +import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; +import com.epam.ta.reportportal.ws.model.project.config.pattern.UpdatePatternTemplateRQ; +import com.epam.ta.reportportal.ws.model.project.email.SenderCaseDTO; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MvcResult; + +/** + * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> + */ +@Sql("/db/project-settings/project-settings-fill.sql") +class ProjectSettingsControllerTest extends BaseMvcTest { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private IssueTypeRepository issueTypeRepository; + + @Autowired + private SenderCaseRepository senderCaseRepository; + + private static final String NOTIFICATION_URL = "/settings/notification/"; + + @Test + void createSubType() throws Exception { + CreateIssueSubTypeRQ rq = new CreateIssueSubTypeRQ(); + rq.setTypeRef("PRODUCT_BUG"); + rq.setColor("#eeeeee"); + rq.setLongName("LongName"); + rq.setShortName("name"); + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type").contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isCreated()); + } + + @Test + void getProjectSettings() throws Exception { + final MvcResult mvcResult = mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/settings").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()) + .andReturn(); + final ProjectSettingsResource projectSettingsResource = objectMapper.readValue( + mvcResult.getResponse().getContentAsString(), + ProjectSettingsResource.class + ); + assertEquals(8, + projectSettingsResource.getSubTypes().values().stream().flatMap(Collection::stream) + .collect(Collectors.toList()).size() + ); + } + + @Test + void deleteSubType() throws Exception { + mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type/6").with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + + Optional<IssueType> byId = issueTypeRepository.findById(6L); + assertFalse(byId.isPresent()); + + } + + @Test + void updateSubType() throws Exception { + UpdateIssueSubTypeRQ request = new UpdateIssueSubTypeRQ(); + final UpdateOneIssueSubTypeRQ updateOneIssueSubTypeRQ = new UpdateOneIssueSubTypeRQ(); + updateOneIssueSubTypeRQ.setColor("#000000"); + updateOneIssueSubTypeRQ.setLocator("custom_ti"); + updateOneIssueSubTypeRQ.setLongName("updated"); + updateOneIssueSubTypeRQ.setShortName("upd"); + updateOneIssueSubTypeRQ.setTypeRef("TO_INVESTIGATE"); + request.setIds(Collections.singletonList(updateOneIssueSubTypeRQ)); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/sub-type").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + } + + @Test + void createPatternTemplate() throws Exception { + CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); + createPatternTemplateRQ.setEnabled(true); + createPatternTemplateRQ.setName("another_name"); + createPatternTemplateRQ.setType("string"); + createPatternTemplateRQ.setValue("qwe"); + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))) + .andExpect(status().isCreated()); + } + + @Test + void createPatternTemplateWithWrongType() throws Exception { + CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); + createPatternTemplateRQ.setEnabled(true); + createPatternTemplateRQ.setName("name"); + createPatternTemplateRQ.setType("dd"); + createPatternTemplateRQ.setValue("qwe"); + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))) + .andExpect(status().isBadRequest()); + } + + @Test + void createPatternTemplateWithDuplicateName() throws Exception { + CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); + createPatternTemplateRQ.setEnabled(true); + createPatternTemplateRQ.setName("some_name"); + createPatternTemplateRQ.setType("string"); + createPatternTemplateRQ.setValue("qwe"); + + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/settings/pattern").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(createPatternTemplateRQ))) + .andExpect(status().isConflict()); + } + + @Test + void updatePatternTemplate() throws Exception { + + UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); + updatePatternTemplateRQ.setName("another_name"); + updatePatternTemplateRQ.setEnabled(true); + + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/1").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))) + .andExpect(status().isOk()); + } + + @Test + void updatePatternTemplateWithTheSameName() throws Exception { + + UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); + updatePatternTemplateRQ.setName("some_name"); + updatePatternTemplateRQ.setEnabled(true); + + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/1").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))) + .andExpect(status().isOk()); + } + + @Test + void updatePatternTemplateWithDuplicateName() throws Exception { + + UpdatePatternTemplateRQ updatePatternTemplateRQ = new UpdatePatternTemplateRQ(); + updatePatternTemplateRQ.setName("some_name"); + updatePatternTemplateRQ.setEnabled(true); + + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/settings/pattern/2").with( + token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(updatePatternTemplateRQ))) + .andExpect(status().isConflict()); + } + + @Test + void getNotifications() throws Exception { + final MvcResult mvcResult = mockMvc.perform(get( + DEFAULT_PROJECT_BASE_URL + NOTIFICATION_URL).with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()) + .andReturn(); + final List<SenderCaseDTO> senderCaseDTOS = objectMapper.readValue( + mvcResult.getResponse().getContentAsString(), + new TypeReference<>() { + } + ); + assertEquals(4, senderCaseDTOS.size()); + } + + @Test + void createNotification() throws Exception { + + SenderCaseDTO senderCaseDTO = new SenderCaseDTO(); + senderCaseDTO.setId(5L); + senderCaseDTO.setSendCase(SendCase.MORE_20.getCaseString()); + senderCaseDTO.setEnabled(true); + senderCaseDTO.setRuleName("rule #5"); + senderCaseDTO.setRecipients(List.of("test1@email.com", "test2@email.com")); + senderCaseDTO.setAttributesOperator(LogicalOperator.AND.getOperator()); + + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + NOTIFICATION_URL).with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(senderCaseDTO))) + .andExpect(status().isCreated()); + } + + @Test + void createNotificationWithDuplicateRuleName() throws Exception { + + SenderCaseDTO senderCaseDTO = new SenderCaseDTO(); + senderCaseDTO.setId(5L); + senderCaseDTO.setSendCase(SendCase.MORE_20.getCaseString()); + senderCaseDTO.setEnabled(true); + senderCaseDTO.setRuleName("rule #2"); + senderCaseDTO.setRecipients(List.of("test1@email.com", "test2@email.com")); + senderCaseDTO.setAttributesOperator(LogicalOperator.AND.getOperator()); + + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + NOTIFICATION_URL).with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(senderCaseDTO))) + .andExpect(status().isConflict()); + } + + @Test + void updateNotification() throws Exception { + + SenderCaseDTO updateRq = new SenderCaseDTO(); + updateRq.setId(1L); + updateRq.setRuleName("rule #5"); + updateRq.setSendCase(SendCase.ALWAYS.getCaseString()); + updateRq.setRecipients(List.of("test1@email.com", "test2@email.com")); + updateRq.setLaunchNames(List.of("launch")); + updateRq.setAttributesOperator(LogicalOperator.AND.getOperator()); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + NOTIFICATION_URL).with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(updateRq))).andExpect(status().isCreated()); + } + + @Test + void deleteNotification() throws Exception { + Long id = 1L; + + mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + NOTIFICATION_URL + id).with( + token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + + List<SenderCase> senderCases = senderCaseRepository.findAll(); + + assertFalse(senderCases.stream().anyMatch(s -> s.getId().equals(id))); + } + } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/SettingsControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/SettingsControllerTest.java index c6a8cc09c9..f674aa8b31 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/SettingsControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/SettingsControllerTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.ws.controller; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.settings.AnalyticsResource; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,41 +28,37 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class SettingsControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; - - @Test - void getServerSettings() throws Exception { - mockMvc.perform(get("/v1/settings").with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void updateAnalyticsSettings() throws Exception { - AnalyticsResource resource = new AnalyticsResource(); - resource.setType("server.analytics.all"); - resource.setEnabled(true); - mockMvc.perform(put("/v1/settings/analytics").with(token(oAuthHelper.getSuperadminToken())) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(resource))).andExpect(status().isOk()); - } - - @Test - void saveAnalyticsSettingsNegative() throws Exception { - AnalyticsResource resource = new AnalyticsResource(); - resource.setEnabled(true); - resource.setType(""); - mockMvc.perform(put("/v1/settings/analytics").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(resource))).andExpect(status().isBadRequest()); - } + @Autowired + private ObjectMapper objectMapper; + + @Test + void getServerSettings() throws Exception { + mockMvc.perform(get("/v1/settings").with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isOk()); + } + + @Test + void updateAnalyticsSettings() throws Exception { + AnalyticsResource resource = new AnalyticsResource(); + resource.setType("server.analytics.all"); + resource.setEnabled(true); + mockMvc.perform(put("/v1/settings/analytics").with(token(oAuthHelper.getSuperadminToken())) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(resource))).andExpect(status().isOk()); + } + + @Test + void saveAnalyticsSettingsNegative() throws Exception { + AnalyticsResource resource = new AnalyticsResource(); + resource.setEnabled(true); + resource.setType(""); + mockMvc.perform(put("/v1/settings/analytics").with(token(oAuthHelper.getSuperadminToken())) + .contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(resource))).andExpect(status().isBadRequest()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncControllerTest.java index e9d9d7e990..d0618eabc4 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemAsyncControllerTest.java @@ -16,6 +16,13 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.ReportPortalUser; import com.epam.ta.reportportal.core.item.FinishTestItemHandler; import com.epam.ta.reportportal.core.item.StartTestItemHandler; @@ -24,6 +31,7 @@ import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -31,106 +39,115 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.UUID; - -import static com.epam.ta.reportportal.ReportPortalUserUtil.getRpUser; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - /** * @author Konstantin Antipin */ @ExtendWith(MockitoExtension.class) class TestItemAsyncControllerTest { - @Mock - ProjectExtractor projectExtractor; - - @Mock - StartTestItemHandler startTestItemHandler; - - @Mock - FinishTestItemHandler finishTestItemHandler; - - @InjectMocks - TestItemAsyncController testItemAsyncController; - - @Test - void startRootItem() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<StartTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - testItemAsyncController.startRootItem("test_project", user, startTestItemRQ); - verify(startTestItemHandler).startRootItem(userArgumentCaptor.capture(), - projectDetailsArgumentCaptor.capture(), - requestArgumentCaptor.capture() - ); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(startTestItemRQ, requestArgumentCaptor.getValue()); - } - - @Test - void startChildItem() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - String parentItem = "parent"; - - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<StartTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass(StartTestItemRQ.class); - ArgumentCaptor<String> parentArgumentCaptor = ArgumentCaptor.forClass(String.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - testItemAsyncController.startChildItem("test_project", user, parentItem, startTestItemRQ); - verify(startTestItemHandler).startChildItem(userArgumentCaptor.capture(), - projectDetailsArgumentCaptor.capture(), - requestArgumentCaptor.capture(), - parentArgumentCaptor.capture() - ); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(startTestItemRQ, requestArgumentCaptor.getValue()); - } - - @Test - void finishTestItem() { - ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, 1L); - - FinishTestItemRQ finishTestItemRQ = new FinishTestItemRQ(); - String testItemId = UUID.randomUUID().toString(); - finishTestItemRQ.setLaunchUuid(UUID.randomUUID().toString()); - - ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.class); - ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass(ReportPortalUser.ProjectDetails.class); - ArgumentCaptor<String> testItemCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor<FinishTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); - - when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), anyString())).thenReturn(user.getProjectDetails() - .get("test_project")); - - testItemAsyncController.finishTestItem("test_project", user, testItemId, finishTestItemRQ); - verify(finishTestItemHandler).finishTestItem(userArgumentCaptor.capture(), - projectDetailsArgumentCaptor.capture(), - testItemCaptor.capture(), - requestArgumentCaptor.capture() - ); - assertEquals(user, userArgumentCaptor.getValue()); - assertEquals(user.getProjectDetails().get("test_project"), projectDetailsArgumentCaptor.getValue()); - assertEquals(finishTestItemRQ, requestArgumentCaptor.getValue()); - } + @Mock + ProjectExtractor projectExtractor; + + @Mock + StartTestItemHandler startTestItemHandler; + + @Mock + FinishTestItemHandler finishTestItemHandler; + + @InjectMocks + TestItemAsyncController testItemAsyncController; + + @Test + void startRootItem() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<StartTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + StartTestItemRQ.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + testItemAsyncController.startRootItem("test_project", user, startTestItemRQ); + verify(startTestItemHandler).startRootItem(userArgumentCaptor.capture(), + projectDetailsArgumentCaptor.capture(), + requestArgumentCaptor.capture() + ); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(startTestItemRQ, requestArgumentCaptor.getValue()); + } + + @Test + void startChildItem() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + String parentItem = "parent"; + + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<StartTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + StartTestItemRQ.class); + ArgumentCaptor<String> parentArgumentCaptor = ArgumentCaptor.forClass(String.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + testItemAsyncController.startChildItem("test_project", user, parentItem, startTestItemRQ); + verify(startTestItemHandler).startChildItem(userArgumentCaptor.capture(), + projectDetailsArgumentCaptor.capture(), + requestArgumentCaptor.capture(), + parentArgumentCaptor.capture() + ); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(startTestItemRQ, requestArgumentCaptor.getValue()); + } + + @Test + void finishTestItem() { + ReportPortalUser user = getRpUser("test", UserRole.ADMINISTRATOR, ProjectRole.PROJECT_MANAGER, + 1L); + + FinishTestItemRQ finishTestItemRQ = new FinishTestItemRQ(); + String testItemId = UUID.randomUUID().toString(); + finishTestItemRQ.setLaunchUuid(UUID.randomUUID().toString()); + + ArgumentCaptor<ReportPortalUser> userArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.class); + ArgumentCaptor<ReportPortalUser.ProjectDetails> projectDetailsArgumentCaptor = ArgumentCaptor.forClass( + ReportPortalUser.ProjectDetails.class); + ArgumentCaptor<String> testItemCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<FinishTestItemRQ> requestArgumentCaptor = ArgumentCaptor.forClass( + FinishTestItemRQ.class); + + when(projectExtractor.extractProjectDetails(any(ReportPortalUser.class), + anyString())).thenReturn(user.getProjectDetails() + .get("test_project")); + + testItemAsyncController.finishTestItem("test_project", user, testItemId, finishTestItemRQ); + verify(finishTestItemHandler).finishTestItem(userArgumentCaptor.capture(), + projectDetailsArgumentCaptor.capture(), + testItemCaptor.capture(), + requestArgumentCaptor.capture() + ); + assertEquals(user, userArgumentCaptor.getValue()); + assertEquals(user.getProjectDetails().get("test_project"), + projectDetailsArgumentCaptor.getValue()); + assertEquals(finishTestItemRQ, requestArgumentCaptor.getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerTest.java index 56d96cb788..98a4098ce4 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerTest.java @@ -16,6 +16,20 @@ package com.epam.ta.reportportal.ws.controller; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.core.analyzer.auto.client.model.SuggestInfo; import com.epam.ta.reportportal.dao.LaunchRepository; import com.epam.ta.reportportal.dao.TestItemRepository; @@ -41,939 +55,1008 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.jdbc.Sql; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.*; - -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @Sql("/db/test-item/test-item-fill.sql") class TestItemControllerTest extends BaseMvcTest { - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private TestItemRepository testItemRepository; - - @Autowired - private LaunchRepository launchRepository; - - @Test - void startRootItemPositive() throws Exception { - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); - rq.setName("RootItem"); - rq.setType("SUITE"); - rq.setParameters(getParameters()); - rq.setUniqueId(UUID.randomUUID().toString()); - rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/item").contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq)) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isCreated()); - } - - @Test - void startRootItemWithoutUuid() throws Exception { - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); - rq.setName("RootItem"); - rq.setType("SUITE"); - rq.setParameters(getParameters()); - rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(post(SUPERADMIN_PROJECT_BASE_URL + "/item").contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq)) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isCreated()); - } - - @Test - void startChildItemPositive() throws Exception { - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); - rq.setName("ChildItem"); - rq.setType("TEST"); - rq.setUniqueId(UUID.randomUUID().toString()); - rq.setParameters(getParameters()); - rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(post( - DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isCreated()); - } - - @Test - void startChildItemWithoutUuid() throws Exception { - StartTestItemRQ rq = new StartTestItemRQ(); - rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); - rq.setName("ChildItem"); - rq.setType("TEST"); - rq.setParameters(getParameters()); - rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(post( - DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isCreated()); - } - - @Test - void finishTestItemPositive() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("PASSED"); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content(objectMapper.writeValueAsBytes( - rq)).contentType(APPLICATION_JSON).with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void finishRootTestItemWithoutStatus() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content(objectMapper.writeValueAsBytes( - rq)).contentType(APPLICATION_JSON).with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void finishTestItemWithFailedStatus() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - Issue issue = new Issue(); - issue.setIssueType("pb001"); - rq.setIssue(issue); - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void finishTestItemWithoutIssueType() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void getSuggestedItemsAnalyzerNotDeployed() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/suggest/1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) - .andExpect(result -> assertEquals( - "Impossible interact with integration. There are no analyzer services with suggest items support deployed.", - result.getResolvedException().getMessage() - )); - } - - @Test - void getTestItemPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/1").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getTestItemStringPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemRetryPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/7").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getTestItemRetryStringPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-retry").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemUuidPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/uuid/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemsPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item?filter.eq.launchId=1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemsBadProvider() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=bad").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isBadRequest()); - } - - @Test - void getTestItemsLaunchProvider() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=launch&launchId=1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemsLaunchProviderMissedParam() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=launch").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isBadRequest()); - } - - @Test - void getTestItemsFilterProvider() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=filter&filterId=1&launchesLimit=10").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getTestItemsFilterProviderMissedParam() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=filter").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isBadRequest()); - } - - @Test - void getTestItemsWidgetProvider() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=widget").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isBadRequest()); - } - - @Test - void getTestItemBySpecifiedIds() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/items?ids=1,2,3").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void deleteTestItemPositive() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/item/2").with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void deleteTestItemBySpecifiedIds() throws Exception { - mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/item?ids=2,3").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getAccumulatedStatisticsByFilter() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/statistics?providerType=launch&launchId=1").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getItemHistoryByParentIdPositive() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/history?filter.eq.parentId=1&historyDepth=3").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getItemHistoryByLaunchIdPositive() throws Exception { - mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL - + "/item/history?filter.eq.launchId=1&historyDepth=3").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().isOk()); - } - - @Test - void getItemHistoryByFilterIdPositive() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/item/history?filterId=1&launchesLimit=10&historyDepth=3").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void updateTestItemPositive() throws Exception { - UpdateTestItemRQ rq = new UpdateTestItemRQ(); - rq.setDescription("updated"); - rq.setAttributes(Sets.newHashSet(new ItemAttributeResource("test", "test"))); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/1/update").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isOk()); - } - - @Test - void handleSuggestChooseAnalyzerNotDeployed() throws Exception { - SuggestInfo suggestInfo = new SuggestInfo(); - suggestInfo.setTestItem(1L); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/suggest/choice").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(Lists.newArrayList(suggestInfo)))) - .andExpect(result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) - .andExpect(result -> assertEquals( - "Impossible interact with integration. There are no analyzer services with suggest items support deployed.", - result.getResolvedException().getMessage() - )); - } - - @Test - void getTickets() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/ticket/ids?launch=1&term=ticket").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getAttributeKeys() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/item/attribute/keys?launch=1&filter.cnt.attributeKey=bro").with(token(oAuthHelper.getDefaultToken()))) - .andExpect(status().isOk()); - } - - @Test - void getAttributeKeysForProject() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL - + "/item/attribute/keys/all?filterId=1&launchesLimit=600&isLatest=false&filter.cnt.attributeKey=bro").with(token(oAuthHelper - .getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getAttributeValues() throws Exception { - mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/attribute/values?launch=1&filter.cnt.attributeValue=lin").with(token( - oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getAttributeKeysByProjectId() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/step/attribute/keys?filter.eq.name=test launch&filter.cnt.attributeKey=bro").with(token( - oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void getAttributeValuesByKeyAndProjectId() throws Exception { - mockMvc.perform(get( - DEFAULT_PROJECT_BASE_URL + "/item/step/attribute/values?filter.eq.name=test launch&filter.cnt.attributeValue=lin").with( - token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); - } - - @Test - void defineTestItemIssue() throws Exception { - DefineIssueRQ rq = new DefineIssueRQ(); - IssueDefinition issueDefinition = new IssueDefinition(); - issueDefinition.setId(3L); - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issueDefinition.setIssue(issue); - rq.setIssues(Collections.singletonList(issueDefinition)); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isOk()); - } - - @Test - void defineTestItemIssueNegative() throws Exception { - DefineIssueRQ rq = new DefineIssueRQ(); - IssueDefinition issueDefinition = new IssueDefinition(); - issueDefinition.setId(100L); - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issueDefinition.setIssue(issue); - rq.setIssues(Collections.singletonList(issueDefinition)); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isBadRequest()); - } - - @Test - void finishTestItemWithLinkedTicketsBadTicketId() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setBtsUrl("jira.com"); - ticket.setBtsProject("project"); - ticket.setUrl("https://example.com/NEWTICKET1"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet(ticket)); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); - } - - @Test - void finishTestItemWithLinkedTicketsBadBtsUrl() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setBtsProject("project"); - ticket.setTicketId("ticket1"); - ticket.setUrl("https://example.com/NEWTICKET1"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet(ticket)); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); - } - - @Test - void finishTestItemWithLinkedTicketsBadBtsProject() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setBtsUrl("jira.com"); - ticket.setTicketId("ticket1"); - ticket.setUrl("https://example.com/NEWTICKET1"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet(ticket)); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); - } - - @Test - void finishTestItemWithLinkedTicketsBadUrl() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setBtsUrl("jira.com"); - ticket.setBtsProject("project"); - ticket.setTicketId("ticket1"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet(ticket)); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); - } - - @Test - void finishTestItemWithEmptyLinkedTickets() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet()); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void finishTestItemWithLinkedTickets() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - - Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); - ticket.setBtsUrl("jira.com"); - ticket.setBtsProject("project"); - ticket.setTicketId("ticket1"); - ticket.setUrl("https://example.com/NEWTICKET1"); - - Issue issue = new Issue(); - issue.setIssueType("pb001"); - issue.setIgnoreAnalyzer(false); - issue.setExternalSystemIssues(Sets.newHashSet(ticket)); - - rq.setIssue(issue); - - mockMvc.perform(put( - SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - } - - @Test - void linkExternalIssues() throws Exception { - LinkExternalIssueRQ rq = new LinkExternalIssueRQ(); - rq.setTestItemIds(Collections.singletonList(3L)); - Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); - issue.setBtsUrl("jira.com"); - issue.setBtsProject("project"); - issue.setTicketId("ticket1"); - issue.setUrl("https://example.com/NEWTICKET1"); - rq.setIssues(Collections.singletonList(issue)); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/link").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON)).andExpect(status().isOk()); - } - - @Test - void linkExternalIssueNegative() throws Exception { - LinkExternalIssueRQ rq = new LinkExternalIssueRQ(); - rq.setTestItemIds(Collections.singletonList(2L)); - Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); - issue.setBtsUrl("jira.com"); - issue.setBtsProject("project"); - issue.setTicketId("ticket1"); - issue.setUrl("https://example.com/NEWTICKET1"); - rq.setIssues(Collections.singletonList(issue)); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/link").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()); - } - - @Test - void unlinkExternalIssues() throws Exception { - UnlinkExternalIssueRQ rq = new UnlinkExternalIssueRQ(); - rq.setTestItemIds(Collections.singletonList(3L)); - rq.setTicketIds(Collections.singletonList("ticket")); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/unlink").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isOk()); - } - - @Test - void unlinkExternalIssuesNegative() throws Exception { - UnlinkExternalIssueRQ rq = new UnlinkExternalIssueRQ(); - rq.setTestItemIds(Collections.singletonList(2L)); - rq.setTicketIds(Collections.singletonList("ticket")); - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/unlink").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isBadRequest()); - } - - private List<ParameterResource> getParameters() { - ParameterResource parameters = new ParameterResource(); - parameters.setKey("CardNumber"); - parameters.setValue("4444333322221111"); - ParameterResource parameters1 = new ParameterResource(); - parameters1.setKey("Stars"); - parameters1.setValue("2 stars"); - return ImmutableList.<ParameterResource>builder().add(parameters).add(parameters1).build(); - } - - @Test - void getItemsByAdmin() throws Exception { - mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/item/items?ids=1,2,4").with(token(oAuthHelper.getSuperadminToken()))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$", hasSize(3))); - } - - @Sql("/db/test-item/item-change-status-from-passed.sql") - @Test - void changeStatusFromPassedToFailed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("failed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-passed.sql") - @Test - void changeStatusFromPassedToSkipped() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("skipped"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.TO_INVESTIGATE, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-passed.sql") - @Test - void changeStatusFromPassedToSkippedWithoutIssue() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("skipped"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/9/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(9L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); - assertNull(updatedItem.get().getItemResults().getIssue()); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-passed.sql") - @Test - void finishTestItemWithFinishedParent() throws Exception { - FinishTestItemRQ rq = new FinishTestItemRQ(); - rq.setLaunchUuid(UUID.randomUUID().toString()); - rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - rq.setStatus("FAILED"); - Issue issue = new Issue(); - issue.setIssueType("pb001"); - rq.setIssue(issue); - - Optional<TestItem> updatedItem = testItemRepository.findById(11L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.IN_PROGRESS, updatedItem.get().getItemResults().getStatus()); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/uuid_s_2_9").content(objectMapper.writeValueAsBytes(rq)) - .contentType(APPLICATION_JSON) - .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); - - updatedItem = testItemRepository.findById(11L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.PRODUCT_BUG, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - } - - @Sql("/db/test-item/item-change-status-from-failed.sql") - @Test - void changeStatusFromFailedToPassed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("passed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); - assertNull(updatedItem.get().getItemResults().getIssue()); - assertEquals(StatusEnum.PASSED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.PASSED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-failed.sql") - @Test - void changeStatusFromFailedToSkipped() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("skipped"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.AUTOMATION_BUG, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-skipped.sql") - @Test - void changeStatusFromSkippedToFailed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("failed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.TO_INVESTIGATE, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-skipped.sql") - @Test - void changeStatusFromSkippedToPassed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("passed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); - assertNull(updatedItem.get().getItemResults().getIssue()); - assertEquals(StatusEnum.PASSED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.PASSED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-interrupted.sql") - @Test - void changeStatusFromInterruptedToPassed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("passed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); - assertNull(updatedItem.get().getItemResults().getIssue()); - assertEquals(StatusEnum.PASSED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.PASSED, launch.getStatus()); - - verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-interrupted.sql") - @Test - void changeStatusFromInterruptedToSkipped() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("skipped"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.TO_INVESTIGATE, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); - } - - @Sql("/db/test-item/item-change-status-from-interrupted.sql") - @Test - void changeStatusFromInterruptedToFailed() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("failed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - Optional<TestItem> updatedItem = testItemRepository.findById(6L); - assertTrue(updatedItem.isPresent()); - assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); - assertEquals(TestItemIssueGroup.TO_INVESTIGATE, - updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup().getTestItemIssueGroup() - ); - assertEquals(StatusEnum.FAILED, testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults().getStatus()); - - Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); - assertEquals(StatusEnum.FAILED, launch.getStatus()); - - verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); - } - - @Test - void changeStatusNegative() throws Exception { - UpdateTestItemRQ request = new UpdateTestItemRQ(); - request.setStatus("failed"); - - mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/5/update").with(token(oAuthHelper.getSuperadminToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().is(400)); - } - - @Test - void bulkUpdateItemAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.CREATE); - String comment = "created"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.UPDATE); - updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); - updateItemAttributeRQ.setTo(new ItemAttributeResource("updatedKey", "updatedValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<TestItem> items = testItemRepository.findAllById(launchIds); - items.forEach(it -> testItemRepository.refresh(it)); - - items.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") && !attr.isSystem())); - assertTrue(it.getAttributes() - .stream() - .anyMatch(attr -> "updatedKey".equals(attr.getKey()) && attr.getValue().equals("updatedValue") && !attr.isSystem())); - assertEquals(comment, it.getDescription()); - }); - } - - @Test - void bulkCreateAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.UPDATE); - String comment = "updated"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.CREATE); - updateItemAttributeRQ.setTo(new ItemAttributeResource("createdKey", "createdValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<TestItem> items = testItemRepository.findAllById(launchIds); - items.forEach(it -> testItemRepository.refresh(it)); - - items.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .anyMatch(attr -> "createdKey".equals(attr.getKey()) && attr.getValue().equals("createdValue") && !attr.isSystem())); - assertTrue(it.getDescription().length() > comment.length() && it.getDescription().contains(comment)); - }); - } - - @Test - void bulkDeleteAttributes() throws Exception { - BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); - List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); - request.setIds(launchIds); - BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); - description.setAction(BulkInfoUpdateRQ.Action.CREATE); - String comment = "created"; - description.setComment(comment); - request.setDescription(description); - UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); - updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.DELETE); - updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); - request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); - - mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) - .contentType(APPLICATION_JSON) - .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); - - List<TestItem> items = testItemRepository.findAllById(launchIds); - items.forEach(it -> testItemRepository.refresh(it)); - - items.forEach(it -> { - assertTrue(it.getAttributes() - .stream() - .noneMatch(attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") && !attr.isSystem())); - assertEquals(comment, it.getDescription()); - }); - } + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private TestItemRepository testItemRepository; + + @Autowired + private LaunchRepository launchRepository; + + @Test + void startRootItemPositive() throws Exception { + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); + rq.setName("RootItem"); + rq.setType("SUITE"); + rq.setParameters(getParameters()); + rq.setUniqueId(UUID.randomUUID().toString()); + rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + "/item").contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq)).with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isCreated()); + } + + @Test + void startRootItemWithoutUuid() throws Exception { + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); + rq.setName("RootItem"); + rq.setType("SUITE"); + rq.setParameters(getParameters()); + rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform(post(SUPERADMIN_PROJECT_BASE_URL + "/item").contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq)).with(token(oAuthHelper.getSuperadminToken()))) + .andExpect(status().isCreated()); + } + + @Test + void startChildItemPositive() throws Exception { + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); + rq.setName("ChildItem"); + rq.setType("TEST"); + rq.setUniqueId(UUID.randomUUID().toString()); + rq.setParameters(getParameters()); + rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isCreated()); + } + + @Test + void startChildItemWithoutUuid() throws Exception { + StartTestItemRQ rq = new StartTestItemRQ(); + rq.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); + rq.setName("ChildItem"); + rq.setType("TEST"); + rq.setParameters(getParameters()); + rq.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isCreated()); + } + + @Test + void finishTestItemPositive() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("PASSED"); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void finishRootTestItemWithoutStatus() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void finishTestItemWithFailedStatus() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + rq.setIssue(issue); + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void finishTestItemWithoutIssueType() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void getSuggestedItemsAnalyzerNotDeployed() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/suggest/1").with( + token(oAuthHelper.getDefaultToken()))).andExpect( + result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) + .andExpect(result -> assertEquals( + "Impossible interact with integration. There are no analyzer services with suggest items support deployed.", + result.getResolvedException().getMessage() + )); + } + + @Test + void getTestItemPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/1").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void getTestItemStringPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemRetryPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/7").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void getTestItemRetryStringPositive() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-retry").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemUuidPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/uuid/0f7ca5bc-cfae-4cc1-9682-e59c2860131e").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemsPositive() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item?filter.eq.launchId=1").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemsBadProvider() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=bad").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isBadRequest()); + } + + @Test + void getTestItemsLaunchProvider() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=launch&launchId=1").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemsLaunchProviderMissedParam() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=launch").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isBadRequest()); + } + + @Test + void getTestItemsFilterProvider() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/v2?providerType=filter&filterId=1&launchesLimit=10").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getTestItemsFilterProviderMissedParam() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=filter").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isBadRequest()); + } + + @Test + void getTestItemsWidgetProvider() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/v2?providerType=widget").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isBadRequest()); + } + + @Test + void getTestItemBySpecifiedIds() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/items?ids=1,2,3").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void deleteTestItemPositive() throws Exception { + mockMvc.perform( + delete(DEFAULT_PROJECT_BASE_URL + "/item/2").with(token(oAuthHelper.getDefaultToken()))) + .andExpect(status().isOk()); + } + + @Test + void deleteTestItemBySpecifiedIds() throws Exception { + mockMvc.perform(delete(DEFAULT_PROJECT_BASE_URL + "/item?ids=2,3").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAccumulatedStatisticsByFilter() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/statistics?providerType=launch&launchId=1").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getItemHistoryByParentIdPositive() throws Exception { + mockMvc.perform( + get(DEFAULT_PROJECT_BASE_URL + "/item/history?filter.eq.parentId=1&historyDepth=3").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getItemHistoryByLaunchIdPositive() throws Exception { + mockMvc.perform( + get(SUPERADMIN_PROJECT_BASE_URL + "/item/history?filter.eq.launchId=1&historyDepth=3").with( + token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void getItemHistoryByFilterIdPositive() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/history?filterId=1&launchesLimit=10&historyDepth=3").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void updateTestItemPositive() throws Exception { + UpdateTestItemRQ rq = new UpdateTestItemRQ(); + rq.setDescription("updated"); + rq.setAttributes(Sets.newHashSet(new ItemAttributeResource("test", "test"))); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/1/update").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(rq))) + .andExpect(status().isOk()); + } + + @Test + void handleSuggestChooseAnalyzerNotDeployed() throws Exception { + SuggestInfo suggestInfo = new SuggestInfo(); + suggestInfo.setTestItem(1L); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/suggest/choice").with( + token(oAuthHelper.getDefaultToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(Lists.newArrayList(suggestInfo)))).andExpect( + result -> assertTrue(result.getResolvedException() instanceof ReportPortalException)) + .andExpect(result -> assertEquals( + "Impossible interact with integration. There are no analyzer services with suggest items support deployed.", + result.getResolvedException().getMessage() + )); + } + + @Test + void getTickets() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + "/item/ticket/ids?launch=1&term=ticket").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAttributeKeys() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/attribute/keys?launch=1&filter.cnt.attributeKey=bro").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAttributeKeysForProject() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/attribute/keys/all?filterId=1&launchesLimit=600&isLatest=false&filter.cnt.attributeKey=bro").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAttributeValues() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/attribute/values?launch=1&filter.cnt.attributeValue=lin").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAttributeKeysByProjectId() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/step/attribute/keys?filter.eq.name=test launch&filter.cnt.attributeKey=bro").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void getAttributeValuesByKeyAndProjectId() throws Exception { + mockMvc.perform(get(DEFAULT_PROJECT_BASE_URL + + "/item/step/attribute/values?filter.eq.name=test launch&filter.cnt.attributeValue=lin").with( + token(oAuthHelper.getDefaultToken()))).andExpect(status().isOk()); + } + + @Test + void defineTestItemIssue() throws Exception { + DefineIssueRQ rq = new DefineIssueRQ(); + IssueDefinition issueDefinition = new IssueDefinition(); + issueDefinition.setId(3L); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issueDefinition.setIssue(issue); + rq.setIssues(Collections.singletonList(issueDefinition)); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(rq))) + .andExpect(status().isOk()); + } + + @Test + void defineTestItemIssueNegative() throws Exception { + DefineIssueRQ rq = new DefineIssueRQ(); + IssueDefinition issueDefinition = new IssueDefinition(); + issueDefinition.setId(100L); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issueDefinition.setIssue(issue); + rq.setIssues(Collections.singletonList(issueDefinition)); + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(rq))) + .andExpect(status().isBadRequest()); + } + + @Test + void finishTestItemWithLinkedTicketsBadTicketId() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setBtsUrl("jira.com"); + ticket.setBtsProject("project"); + ticket.setUrl("https://example.com/NEWTICKET1"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet(ticket)); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); + } + + @Test + void finishTestItemWithLinkedTicketsBadBtsUrl() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setBtsProject("project"); + ticket.setTicketId("ticket1"); + ticket.setUrl("https://example.com/NEWTICKET1"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet(ticket)); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); + } + + @Test + void finishTestItemWithLinkedTicketsBadBtsProject() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setBtsUrl("jira.com"); + ticket.setTicketId("ticket1"); + ticket.setUrl("https://example.com/NEWTICKET1"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet(ticket)); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); + } + + @Test + void finishTestItemWithLinkedTicketsBadUrl() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setBtsUrl("jira.com"); + ticket.setBtsProject("project"); + ticket.setTicketId("ticket1"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet(ticket)); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isBadRequest()); + } + + @Test + void finishTestItemWithEmptyLinkedTickets() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet()); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void finishTestItemWithLinkedTickets() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid("334d153c-8f9c-4dff-8627-47dd003bee0f"); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + + Issue.ExternalSystemIssue ticket = new Issue.ExternalSystemIssue(); + ticket.setBtsUrl("jira.com"); + ticket.setBtsProject("project"); + ticket.setTicketId("ticket1"); + ticket.setUrl("https://example.com/NEWTICKET1"); + + Issue issue = new Issue(); + issue.setIssueType("pb001"); + issue.setIgnoreAnalyzer(false); + issue.setExternalSystemIssues(Sets.newHashSet(ticket)); + + rq.setIssue(issue); + + mockMvc.perform( + put(SUPERADMIN_PROJECT_BASE_URL + "/item/3ab067e5-537b-45ff-9605-843ab695c96a").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + } + + @Test + void linkExternalIssues() throws Exception { + LinkExternalIssueRQ rq = new LinkExternalIssueRQ(); + rq.setTestItemIds(Collections.singletonList(3L)); + Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); + issue.setBtsUrl("jira.com"); + issue.setBtsProject("project"); + issue.setTicketId("ticket1"); + issue.setUrl("https://example.com/NEWTICKET1"); + rq.setIssues(Collections.singletonList(issue)); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/link").with( + token(oAuthHelper.getDefaultToken())).content(objectMapper.writeValueAsBytes(rq)) + .contentType(APPLICATION_JSON)).andExpect(status().isOk()); + } + + @Test + void linkExternalIssueNegative() throws Exception { + LinkExternalIssueRQ rq = new LinkExternalIssueRQ(); + rq.setTestItemIds(Collections.singletonList(2L)); + Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); + issue.setBtsUrl("jira.com"); + issue.setBtsProject("project"); + issue.setTicketId("ticket1"); + issue.setUrl("https://example.com/NEWTICKET1"); + rq.setIssues(Collections.singletonList(issue)); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/link").with( + token(oAuthHelper.getDefaultToken())).content(objectMapper.writeValueAsBytes(rq)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()); + } + + @Test + void unlinkExternalIssues() throws Exception { + UnlinkExternalIssueRQ rq = new UnlinkExternalIssueRQ(); + rq.setTestItemIds(Collections.singletonList(3L)); + rq.setTicketIds(Collections.singletonList("ticket")); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/unlink").with( + token(oAuthHelper.getDefaultToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isOk()); + } + + @Test + void unlinkExternalIssuesNegative() throws Exception { + UnlinkExternalIssueRQ rq = new UnlinkExternalIssueRQ(); + rq.setTestItemIds(Collections.singletonList(2L)); + rq.setTicketIds(Collections.singletonList("ticket")); + mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + "/item/issue/unlink").with( + token(oAuthHelper.getDefaultToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(rq))).andExpect(status().isBadRequest()); + } + + private List<ParameterResource> getParameters() { + ParameterResource parameters = new ParameterResource(); + parameters.setKey("CardNumber"); + parameters.setValue("4444333322221111"); + ParameterResource parameters1 = new ParameterResource(); + parameters1.setKey("Stars"); + parameters1.setValue("2 stars"); + return ImmutableList.<ParameterResource>builder().add(parameters).add(parameters1).build(); + } + + @Test + void getItemsByAdmin() throws Exception { + mockMvc.perform(get(SUPERADMIN_PROJECT_BASE_URL + "/item/items?ids=1,2,4").with( + token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(3))); + } + + @Sql("/db/test-item/item-change-status-from-passed.sql") + @Test + void changeStatusFromPassedToFailed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("failed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-passed.sql") + @Test + void changeStatusFromPassedToSkipped() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("skipped"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.TO_INVESTIGATE, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-passed.sql") + @Test + void changeStatusFromPassedToSkippedWithoutIssue() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("skipped"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/9/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(9L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); + assertNull(updatedItem.get().getItemResults().getIssue()); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-passed.sql") + @Test + void finishChildTestItemWithFailedStatusWithFinishedParentWithPassedStatus() throws Exception { + FinishTestItemRQ rq = new FinishTestItemRQ(); + rq.setLaunchUuid(UUID.randomUUID().toString()); + rq.setEndTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + rq.setStatus("FAILED"); + Issue issue = new Issue(); + issue.setIssueType("pb001"); + rq.setIssue(issue); + + Optional<TestItem> updatedItem = testItemRepository.findById(11L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.IN_PROGRESS, updatedItem.get().getItemResults().getStatus()); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/uuid_s_2_9").content( + objectMapper.writeValueAsBytes(rq)).contentType(APPLICATION_JSON) + .with(token(oAuthHelper.getSuperadminToken()))).andExpect(status().isOk()); + + updatedItem = testItemRepository.findById(11L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.PRODUCT_BUG, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.PASSED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.PASSED, launch.getStatus()); + } + + @Sql("/db/test-item/item-change-status-from-failed.sql") + @Test + void changeStatusFromFailedToPassed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("passed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); + assertNull(updatedItem.get().getItemResults().getIssue()); + assertEquals( + StatusEnum.PASSED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.PASSED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-failed.sql") + @Test + void changeStatusFromFailedToSkipped() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("skipped"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.AUTOMATION_BUG, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-skipped.sql") + @Test + void changeStatusFromSkippedToFailed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("failed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.TO_INVESTIGATE, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-skipped.sql") + @Test + void changeStatusFromSkippedToPassed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("passed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); + assertNull(updatedItem.get().getItemResults().getIssue()); + assertEquals( + StatusEnum.PASSED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.PASSED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-interrupted.sql") + @Test + void changeStatusFromInterruptedToPassed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("passed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.PASSED, updatedItem.get().getItemResults().getStatus()); + assertNull(updatedItem.get().getItemResults().getIssue()); + assertEquals( + StatusEnum.PASSED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.PASSED, launch.getStatus()); + + verify(messageBus, times(2)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-interrupted.sql") + @Test + void changeStatusFromInterruptedToSkipped() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("skipped"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.SKIPPED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.TO_INVESTIGATE, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); + } + + @Sql("/db/test-item/item-change-status-from-interrupted.sql") + @Test + void changeStatusFromInterruptedToFailed() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("failed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/6/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().isOk()); + + Optional<TestItem> updatedItem = testItemRepository.findById(6L); + assertTrue(updatedItem.isPresent()); + assertEquals(StatusEnum.FAILED, updatedItem.get().getItemResults().getStatus()); + assertEquals( + TestItemIssueGroup.TO_INVESTIGATE, + updatedItem.get().getItemResults().getIssue().getIssueType().getIssueGroup() + .getTestItemIssueGroup() + ); + assertEquals( + StatusEnum.FAILED, + testItemRepository.findById(updatedItem.get().getParentId()).get().getItemResults() + .getStatus() + ); + + Launch launch = launchRepository.findById(updatedItem.get().getLaunchId()).get(); + assertEquals(StatusEnum.FAILED, launch.getStatus()); + + verify(messageBus, times(1)).publishActivity(ArgumentMatchers.any()); + } + + @Test + void changeStatusNegative() throws Exception { + UpdateTestItemRQ request = new UpdateTestItemRQ(); + request.setStatus("failed"); + + mockMvc.perform(put(SUPERADMIN_PROJECT_BASE_URL + "/item/5/update").with( + token(oAuthHelper.getSuperadminToken())).contentType(APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(request))).andExpect(status().is(400)); + } + + @Test + void bulkUpdateItemAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.CREATE); + String comment = "created"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.UPDATE); + updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); + updateItemAttributeRQ.setTo(new ItemAttributeResource("updatedKey", "updatedValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(request))) + .andExpect(status().isOk()); + + List<TestItem> items = testItemRepository.findAllById(launchIds); + items.forEach(it -> testItemRepository.refresh(it)); + + items.forEach(it -> { + assertTrue(it.getAttributes().stream().noneMatch( + attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") + && !attr.isSystem())); + assertTrue(it.getAttributes().stream().anyMatch( + attr -> "updatedKey".equals(attr.getKey()) && attr.getValue().equals("updatedValue") + && !attr.isSystem())); + assertEquals(comment, it.getDescription()); + }); + } + + @Test + void bulkCreateAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.UPDATE); + String comment = "updated"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.CREATE); + updateItemAttributeRQ.setTo(new ItemAttributeResource("createdKey", "createdValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(request))) + .andExpect(status().isOk()); + + List<TestItem> items = testItemRepository.findAllById(launchIds); + items.forEach(it -> testItemRepository.refresh(it)); + + items.forEach(it -> { + assertTrue(it.getAttributes().stream().anyMatch( + attr -> "createdKey".equals(attr.getKey()) && attr.getValue().equals("createdValue") + && !attr.isSystem())); + assertTrue( + it.getDescription().length() > comment.length() && it.getDescription().contains(comment)); + }); + } + + @Test + void bulkDeleteAttributes() throws Exception { + BulkInfoUpdateRQ request = new BulkInfoUpdateRQ(); + List<Long> launchIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L); + request.setIds(launchIds); + BulkInfoUpdateRQ.Description description = new BulkInfoUpdateRQ.Description(); + description.setAction(BulkInfoUpdateRQ.Action.CREATE); + String comment = "created"; + description.setComment(comment); + request.setDescription(description); + UpdateItemAttributeRQ updateItemAttributeRQ = new UpdateItemAttributeRQ(); + updateItemAttributeRQ.setAction(BulkInfoUpdateRQ.Action.DELETE); + updateItemAttributeRQ.setFrom(new ItemAttributeResource("testKey", "testValue")); + request.setAttributes(Lists.newArrayList(updateItemAttributeRQ)); + + mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + "/item/info").with(token(oAuthHelper.getDefaultToken())) + .contentType(APPLICATION_JSON).content(objectMapper.writeValueAsBytes(request))) + .andExpect(status().isOk()); + + List<TestItem> items = testItemRepository.findAllById(launchIds); + items.forEach(it -> testItemRepository.refresh(it)); + + items.forEach(it -> { + assertTrue(it.getAttributes().stream().noneMatch( + attr -> "testKey".equals(attr.getKey()) && attr.getValue().equals("testValue") + && !attr.isSystem())); + assertEquals(comment, it.getDescription()); + }); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerValidationTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerValidationTest.java index 30c3dd001c..ac34e211de 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerValidationTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/TestItemControllerValidationTest.java @@ -16,6 +16,18 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_BLANK_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_NULL_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.WHITESPACES_NAME_VALUE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static org.apache.commons.lang3.StringUtils.EMPTY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.ErrorRS; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; @@ -25,10 +37,6 @@ import com.epam.ta.reportportal.ws.model.item.LinkExternalIssueRQ; import com.epam.ta.reportportal.ws.model.item.UnlinkExternalIssueRQ; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.servlet.MvcResult; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; @@ -36,319 +44,353 @@ import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.*; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.web.servlet.MvcResult; /** * @author <a href="mailto:tatyana_gladysheva@epam.com">Tatyana Gladysheva</a> */ public class TestItemControllerValidationTest extends BaseMvcTest { - private static final String ITEM_PATH = "/item"; - private static final String PARENT_ID_PATH = "/555"; - - private static final String FIELD_NAME_SIZE_MESSAGE = "Field 'name' should have size from '1' to '1,024'."; - - private static final String LONG_NAME_VALUE = "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" - + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"; - - @Autowired - private ObjectMapper objectMapper; - - @Test - public void startRootTestItemShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void startRootTestItemShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void startRootTestItemShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void startRootTestItemShouldReturnErrorWhenNameIsGreaterThanOneThousandTwentyFourCharacters() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void startChildTestItemShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void startChildTestItemShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void startChildTestItemShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void startChildTestItemShouldReturnErrorWhenNameIsGreaterThanOneThousandTwentyFourCharacters() throws Exception { - //GIVEN - StartTestItemRQ startTestItemRQ = prepareTestItem(); - startTestItemRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(startTestItemRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void shouldReturnBadRequestWhenMoreThan300Issues() throws Exception { - //GIVEN - final DefineIssueRQ defineIssueRQ = new DefineIssueRQ(); - defineIssueRQ.setIssues(Stream.generate(() -> { - final IssueDefinition issueDefinition = new IssueDefinition(); - issueDefinition.setId(1L); - final Issue issue = new Issue(); - issue.setComment("comment"); - issue.setIssueType("ab001"); - issueDefinition.setIssue(issue); - return issueDefinition; - }).limit(301).collect(Collectors.toList())); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + ITEM_PATH).with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(defineIssueRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'issues' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - @Test - public void shouldReturnBadRequestWhenMoreThan300IssuesToLink() throws Exception { - //GIVEN - final LinkExternalIssueRQ linkExternalIssueRQ = new LinkExternalIssueRQ(); - final Issue.ExternalSystemIssue externalSystemIssue = getExternalSystemIssue(); - linkExternalIssueRQ.setIssues(Stream.generate(() -> externalSystemIssue).limit(301).collect(Collectors.toList())); - linkExternalIssueRQ.setTestItemIds(List.of(1L)); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put( - DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/link").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(linkExternalIssueRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'issues' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - private Issue.ExternalSystemIssue getExternalSystemIssue() { - final Issue.ExternalSystemIssue externalSystemIssue = new Issue.ExternalSystemIssue(); - externalSystemIssue.setBtsProject("prj"); - externalSystemIssue.setUrl("url"); - externalSystemIssue.setBtsUrl("btsUrl"); - externalSystemIssue.setSubmitDate(123L); - externalSystemIssue.setTicketId("id"); - return externalSystemIssue; - } - - @Test - public void shouldReturnBadRequestWhenMoreThan300ItemIdsToLink() throws Exception { - //GIVEN - final LinkExternalIssueRQ linkExternalIssueRQ = new LinkExternalIssueRQ(); - final Issue.ExternalSystemIssue externalSystemIssue = getExternalSystemIssue(); - linkExternalIssueRQ.setIssues(List.of(externalSystemIssue)); - final List<Long> itemIds = Stream.generate(() -> 1L).limit(301).collect(Collectors.toList()); - linkExternalIssueRQ.setTestItemIds(itemIds); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put( - DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/link").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(linkExternalIssueRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'testItemIds' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - @Test - public void shouldReturnBadRequestWhenMoreThan300TicketsToUnlink() throws Exception { - //GIVEN - final UnlinkExternalIssueRQ unlinkExternalIssueRQ = new UnlinkExternalIssueRQ(); - unlinkExternalIssueRQ.setTicketIds(Stream.generate(() -> "id").limit(301).collect(Collectors.toList())); - unlinkExternalIssueRQ.setTestItemIds(List.of(1L)); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put( - DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/unlink").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(unlinkExternalIssueRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'ticketIds' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - @Test - public void shouldReturnBadRequestWhenMoreThan300ItemIdsToUnlink() throws Exception { - //GIVEN - final UnlinkExternalIssueRQ unlinkExternalIssueRQ = new UnlinkExternalIssueRQ(); - unlinkExternalIssueRQ.setTicketIds(List.of("id")); - unlinkExternalIssueRQ.setTestItemIds(Stream.generate(() -> 1L).limit(301).collect(Collectors.toList())); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put( - DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/unlink").with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(unlinkExternalIssueRQ)) - .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[Field 'testItemIds' should have size from '0' to '300'.] ", - error.getMessage() - ); - } - - private StartTestItemRQ prepareTestItem() { - StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); - startTestItemRQ.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); - startTestItemRQ.setType("SUITE"); - startTestItemRQ.setUniqueId(UUID.randomUUID().toString()); - startTestItemRQ.setStartTime(Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); - return startTestItemRQ; - } + private static final String ITEM_PATH = "/item"; + private static final String PARENT_ID_PATH = "/555"; + + private static final String FIELD_NAME_SIZE_MESSAGE = "Field 'name' should have size from '1' to '1,024'."; + + private static final String LONG_NAME_VALUE = + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt" + + "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"; + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void startRootTestItemShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void startRootTestItemShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void startRootTestItemShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void startRootTestItemShouldReturnErrorWhenNameIsGreaterThanOneThousandTwentyFourCharacters() + throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void startChildTestItemShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + + //WHEN + MvcResult mvcResult = mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void startChildTestItemShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void startChildTestItemShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void startChildTestItemShouldReturnErrorWhenNameIsGreaterThanOneThousandTwentyFourCharacters() + throws Exception { + //GIVEN + StartTestItemRQ startTestItemRQ = prepareTestItem(); + startTestItemRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform( + post(DEFAULT_PROJECT_BASE_URL + ITEM_PATH + PARENT_ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(startTestItemRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void shouldReturnBadRequestWhenMoreThan300Issues() throws Exception { + //GIVEN + final DefineIssueRQ defineIssueRQ = new DefineIssueRQ(); + defineIssueRQ.setIssues(Stream.generate(() -> { + final IssueDefinition issueDefinition = new IssueDefinition(); + issueDefinition.setId(1L); + final Issue issue = new Issue(); + issue.setComment("comment"); + issue.setIssueType("ab001"); + issueDefinition.setIssue(issue); + return issueDefinition; + }).limit(301).collect(Collectors.toList())); + + //WHEN + MvcResult mvcResult = mockMvc.perform( + put(DEFAULT_PROJECT_BASE_URL + ITEM_PATH).with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(defineIssueRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'issues' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + @Test + public void shouldReturnBadRequestWhenMoreThan300IssuesToLink() throws Exception { + //GIVEN + final LinkExternalIssueRQ linkExternalIssueRQ = new LinkExternalIssueRQ(); + final Issue.ExternalSystemIssue externalSystemIssue = getExternalSystemIssue(); + linkExternalIssueRQ.setIssues( + Stream.generate(() -> externalSystemIssue).limit(301).collect(Collectors.toList())); + linkExternalIssueRQ.setTestItemIds(List.of(1L)); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put( + DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/link").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(linkExternalIssueRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'issues' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + private Issue.ExternalSystemIssue getExternalSystemIssue() { + final Issue.ExternalSystemIssue externalSystemIssue = new Issue.ExternalSystemIssue(); + externalSystemIssue.setBtsProject("prj"); + externalSystemIssue.setUrl("url"); + externalSystemIssue.setBtsUrl("btsUrl"); + externalSystemIssue.setSubmitDate(123L); + externalSystemIssue.setTicketId("id"); + return externalSystemIssue; + } + + @Test + public void shouldReturnBadRequestWhenMoreThan300ItemIdsToLink() throws Exception { + //GIVEN + final LinkExternalIssueRQ linkExternalIssueRQ = new LinkExternalIssueRQ(); + final Issue.ExternalSystemIssue externalSystemIssue = getExternalSystemIssue(); + linkExternalIssueRQ.setIssues(List.of(externalSystemIssue)); + final List<Long> itemIds = Stream.generate(() -> 1L).limit(301).collect(Collectors.toList()); + linkExternalIssueRQ.setTestItemIds(itemIds); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put( + DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/link").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(linkExternalIssueRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'testItemIds' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + @Test + public void shouldReturnBadRequestWhenMoreThan300TicketsToUnlink() throws Exception { + //GIVEN + final UnlinkExternalIssueRQ unlinkExternalIssueRQ = new UnlinkExternalIssueRQ(); + unlinkExternalIssueRQ.setTicketIds( + Stream.generate(() -> "id").limit(301).collect(Collectors.toList())); + unlinkExternalIssueRQ.setTestItemIds(List.of(1L)); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put( + DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/unlink").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(unlinkExternalIssueRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'ticketIds' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + @Test + public void shouldReturnBadRequestWhenMoreThan300ItemIdsToUnlink() throws Exception { + //GIVEN + final UnlinkExternalIssueRQ unlinkExternalIssueRQ = new UnlinkExternalIssueRQ(); + unlinkExternalIssueRQ.setTicketIds(List.of("id")); + unlinkExternalIssueRQ.setTestItemIds( + Stream.generate(() -> 1L).limit(301).collect(Collectors.toList())); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put( + DEFAULT_PROJECT_BASE_URL + ITEM_PATH + "/issue/unlink").with( + token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(unlinkExternalIssueRQ)) + .contentType(APPLICATION_JSON)).andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals( + INCORRECT_REQUEST_MESSAGE + "[Field 'testItemIds' should have size from '0' to '300'.] ", + error.getMessage() + ); + } + + private StartTestItemRQ prepareTestItem() { + StartTestItemRQ startTestItemRQ = new StartTestItemRQ(); + startTestItemRQ.setLaunchUuid("a7b66ef2-db30-4db7-94df-f5f7786b398a"); + startTestItemRQ.setType("SUITE"); + startTestItemRQ.setUniqueId(UUID.randomUUID().toString()); + startTestItemRQ.setStartTime( + Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant())); + return startTestItemRQ; + } } diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/UserFilterControllerValidationTest.java b/src/test/java/com/epam/ta/reportportal/ws/controller/UserFilterControllerValidationTest.java index 209cdf62d4..def3e3e20b 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/UserFilterControllerValidationTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/UserFilterControllerValidationTest.java @@ -16,6 +16,22 @@ package com.epam.ta.reportportal.ws.controller; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_BLANK_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_IS_NULL_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.ID_PATH; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.INCORRECT_REQUEST_MESSAGE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.LONG_NAME_VALUE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.SHORT_NAME_VALUE; +import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.WHITESPACES_NAME_VALUE; +import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; +import static org.apache.commons.lang3.StringUtils.EMPTY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.epam.ta.reportportal.ws.BaseMvcTest; import com.epam.ta.reportportal.ws.model.ErrorRS; import com.epam.ta.reportportal.ws.model.filter.Order; @@ -28,228 +44,240 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.MvcResult; -import static com.epam.ta.reportportal.ws.controller.constants.ValidationTestsConstants.*; -import static com.epam.ta.reportportal.ws.model.ErrorType.INCORRECT_REQUEST; -import static org.apache.commons.lang3.StringUtils.EMPTY; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author <a href="mailto:tatyana_gladysheva@epam.com">Tatyana Gladysheva</a> */ public class UserFilterControllerValidationTest extends BaseMvcTest { - private static final String FILTER_PATH = "/filter"; - - private static final String FIELD_NAME_SIZE_MESSAGE = String.format(FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 3, 128); - - @Autowired - private ObjectMapper objectMapper; - - @Test - public void createFilterShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void createFilterShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createFilterShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createFilterShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(SHORT_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void createFilterShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateFilterShouldReturnErrorWhenNameIsNull() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); - } - - @Test - public void updateFilterShouldReturnErrorWhenNameIsEmpty() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(EMPTY); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateFilterShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(WHITESPACES_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateFilterShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(SHORT_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - @Test - public void updateFilterShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() throws Exception { - //GIVEN - UpdateUserFilterRQ userFilterRQ = prepareFilter(); - userFilterRQ.setName(LONG_NAME_VALUE); - - //WHEN - MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) - .with(token(oAuthHelper.getDefaultToken())) - .content(objectMapper.writeValueAsBytes(userFilterRQ)) - .contentType(APPLICATION_JSON)) - .andExpect(status().isBadRequest()).andReturn(); - - //THEN - ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorRS.class); - assertEquals(INCORRECT_REQUEST, error.getErrorType()); - assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); - } - - private UpdateUserFilterRQ prepareFilter() { - UpdateUserFilterRQ userFilterRQ = new UpdateUserFilterRQ(); - userFilterRQ.setObjectType("Launch"); - - Order order = new Order(); - order.setIsAsc(false); - order.setSortingColumnName("startTime"); - - userFilterRQ.setOrders(Lists.newArrayList(order)); - - userFilterRQ.setDescription("description"); - userFilterRQ.setConditions(Sets.newHashSet(new UserFilterCondition("name", "cnt", "test"))); - - return userFilterRQ; - } + private static final String FILTER_PATH = "/filter"; + + private static final String FIELD_NAME_SIZE_MESSAGE = String.format( + FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT, 3, 128); + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void createFilterShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void createFilterShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createFilterShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void createFilterShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(SHORT_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void createFilterShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() + throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(post(DEFAULT_PROJECT_BASE_URL + FILTER_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void updateFilterShouldReturnErrorWhenNameIsNull() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + FIELD_NAME_IS_NULL_MESSAGE, error.getMessage()); + } + + @Test + public void updateFilterShouldReturnErrorWhenNameIsEmpty() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(EMPTY); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void updateFilterShouldReturnErrorWhenNameConsistsOfWhitespaces() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(WHITESPACES_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_IS_BLANK_MESSAGE + " " + + FIELD_NAME_SIZE_MESSAGE + "] ", error.getMessage()); + } + + @Test + public void updateFilterShouldReturnErrorWhenNameIsLessThanThreeCharacters() throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(SHORT_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + @Test + public void updateFilterShouldReturnErrorWhenNameIsGreaterThanOneHundredAndTwentyEightCharacters() + throws Exception { + //GIVEN + UpdateUserFilterRQ userFilterRQ = prepareFilter(); + userFilterRQ.setName(LONG_NAME_VALUE); + + //WHEN + MvcResult mvcResult = mockMvc.perform(put(DEFAULT_PROJECT_BASE_URL + FILTER_PATH + ID_PATH) + .with(token(oAuthHelper.getDefaultToken())) + .content(objectMapper.writeValueAsBytes(userFilterRQ)) + .contentType(APPLICATION_JSON)) + .andExpect(status().isBadRequest()).andReturn(); + + //THEN + ErrorRS error = objectMapper.readValue(mvcResult.getResponse().getContentAsString(), + ErrorRS.class); + assertEquals(INCORRECT_REQUEST, error.getErrorType()); + assertEquals(INCORRECT_REQUEST_MESSAGE + "[" + FIELD_NAME_SIZE_MESSAGE + "] ", + error.getMessage()); + } + + private UpdateUserFilterRQ prepareFilter() { + UpdateUserFilterRQ userFilterRQ = new UpdateUserFilterRQ(); + userFilterRQ.setObjectType("Launch"); + + Order order = new Order(); + order.setIsAsc(false); + order.setSortingColumnName("startTime"); + + userFilterRQ.setOrders(Lists.newArrayList(order)); + + userFilterRQ.setDescription("description"); + userFilterRQ.setConditions(Sets.newHashSet(new UserFilterCondition("name", "cnt", "test"))); + + return userFilterRQ; + } } diff --git a/src/test/java/com/epam/ta/reportportal/ws/controller/constants/ValidationTestsConstants.java b/src/test/java/com/epam/ta/reportportal/ws/controller/constants/ValidationTestsConstants.java index b168ffab57..2bc23bda71 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/controller/constants/ValidationTestsConstants.java +++ b/src/test/java/com/epam/ta/reportportal/ws/controller/constants/ValidationTestsConstants.java @@ -21,16 +21,17 @@ */ public final class ValidationTestsConstants { - public static final String ID_PATH = "/555"; + public static final String ID_PATH = "/555"; - public static final String WHITESPACES_NAME_VALUE = " "; - public static final String SHORT_NAME_VALUE = "cc"; - public static final String LONG_NAME_VALUE = "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"; + public static final String WHITESPACES_NAME_VALUE = " "; + public static final String SHORT_NAME_VALUE = "cc"; + public static final String LONG_NAME_VALUE = "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt"; - public static final String INCORRECT_REQUEST_MESSAGE = "Incorrect Request. "; - public static final String FIELD_NAME_IS_NULL_MESSAGE = "[Field 'name' should not be null.] "; - public static final String FIELD_NAME_IS_BLANK_MESSAGE = "Field 'name' should not contain only white spaces and shouldn't be empty."; - public static final String FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT = "Field 'name' should have size from '%d' to '%d'."; + public static final String INCORRECT_REQUEST_MESSAGE = "Incorrect Request. "; + public static final String FIELD_NAME_IS_NULL_MESSAGE = "[Field 'name' should not be null.] "; + public static final String FIELD_NAME_IS_BLANK_MESSAGE = "Field 'name' should not contain only white spaces and shouldn't be empty."; + public static final String FIELD_NAME_SIZE_MESSAGE_WITH_FORMAT = "Field 'name' should have size from '%d' to '%d'."; - private ValidationTestsConstants() {} + private ValidationTestsConstants() { + } } diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/LogResourceAssemblerTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/LogResourceAssemblerTest.java index f376803ebe..8c7b6c7598 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/LogResourceAssemblerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/LogResourceAssemblerTest.java @@ -16,66 +16,66 @@ package com.epam.ta.reportportal.ws.converter; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.model.log.LogResource; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.util.Collections; import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class LogResourceAssemblerTest { - @Test - void toResource() { - LogResourceAssembler resourceAssembler = new LogResourceAssembler(); - Log log = getLog(); - LogResource logResource = resourceAssembler.toResource(log); + @Test + void toResource() { + LogResourceAssembler resourceAssembler = new LogResourceAssembler(); + LogFull logFull = getFullLog(); + LogResource logResource = resourceAssembler.toResource(logFull); - assertEquals(logResource.getId(), log.getId()); - assertEquals(logResource.getLevel(), LogLevel.toLevel(log.getLogLevel()).name()); - assertEquals(logResource.getMessage(), log.getLogMessage()); - assertEquals(logResource.getItemId(), log.getTestItem().getItemId()); - } + assertEquals(logResource.getId(), logFull.getId()); + assertEquals(logResource.getLevel(), LogLevel.toLevel(logFull.getLogLevel()).name()); + assertEquals(logResource.getMessage(), logFull.getLogMessage()); + assertEquals(logResource.getItemId(), logFull.getTestItem().getItemId()); + } - @Test - void toResources() { - LogResourceAssembler resourceAssembler = new LogResourceAssembler(); - List<LogResource> logResources = resourceAssembler.toResources(Collections.singleton(getLog())); + @Test + void toResources() { + LogResourceAssembler resourceAssembler = new LogResourceAssembler(); + List<LogResource> logResources = resourceAssembler.toResources( + Collections.singleton(getFullLog())); - assertEquals(1, logResources.size()); - } + assertEquals(1, logResources.size()); + } - @Test - void apply() { - LogResourceAssembler resourceAssembler = new LogResourceAssembler(); - Log log = getLog(); - LogResource logResource = resourceAssembler.apply(log); + @Test + void apply() { + LogResourceAssembler resourceAssembler = new LogResourceAssembler(); + LogFull logFull = getFullLog(); + LogResource logResource = resourceAssembler.apply(logFull); - assertEquals(logResource.getId(), log.getId()); - assertEquals(logResource.getLevel(), LogLevel.toLevel(log.getLogLevel()).name()); - assertEquals(logResource.getMessage(), log.getLogMessage()); - assertEquals(logResource.getItemId(), log.getTestItem().getItemId()); - } + assertEquals(logResource.getId(), logFull.getId()); + assertEquals(logResource.getLevel(), LogLevel.toLevel(logFull.getLogLevel()).name()); + assertEquals(logResource.getMessage(), logFull.getLogMessage()); + assertEquals(logResource.getItemId(), logFull.getTestItem().getItemId()); + } - private Log getLog() { - Log log = new Log(); - log.setId(1L); - log.setLogTime(LocalDateTime.now()); - log.setLastModified(LocalDateTime.now()); - log.setLogMessage("message"); - log.setLogLevel(40000); - TestItem testItem = new TestItem(); - testItem.setItemId(2L); - log.setTestItem(testItem); + private LogFull getFullLog() { + LogFull logFull = new LogFull(); + logFull.setId(1L); + logFull.setLogTime(LocalDateTime.now()); + logFull.setLastModified(LocalDateTime.now()); + logFull.setLogMessage("message"); + logFull.setLogLevel(40000); + TestItem testItem = new TestItem(); + testItem.setItemId(2L); + logFull.setTestItem(testItem); - return log; - } + return logFull; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilderTest.java index 37c1b359ea..28743fad3b 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IntegrationBuilderTest.java @@ -16,100 +16,99 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.epam.ta.reportportal.entity.integration.Integration; import com.epam.ta.reportportal.entity.integration.IntegrationParams; import com.epam.ta.reportportal.entity.integration.IntegrationType; import com.epam.ta.reportportal.entity.project.Project; import com.google.common.collect.Maps; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.util.HashMap; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IntegrationBuilderTest { - @Test - void integrationBuilderTest() { - final Project project = new Project(); - project.setId(1L); - project.setName("project"); - final IntegrationParams params = new IntegrationParams(); - final HashMap<String, Object> parameters = Maps.newHashMap(); - parameters.put("param1", "val1"); - parameters.put("param2", "val2"); - params.setParams(parameters); - final IntegrationType type = new IntegrationType(); - type.setName("type"); + @Test + void integrationBuilderTest() { + final Project project = new Project(); + project.setId(1L); + project.setName("project"); + final IntegrationParams params = new IntegrationParams(); + final HashMap<String, Object> parameters = Maps.newHashMap(); + parameters.put("param1", "val1"); + parameters.put("param2", "val2"); + params.setParams(parameters); + final IntegrationType type = new IntegrationType(); + type.setName("type"); - final String name = "name"; - final boolean enabled = true; - final LocalDateTime creationDate = LocalDateTime.now(); - final String creator = "creator"; + final String name = "name"; + final boolean enabled = true; + final LocalDateTime creationDate = LocalDateTime.now(); + final String creator = "creator"; - final Integration integration = new IntegrationBuilder().withName(name) - .withEnabled(enabled) - .withCreationDate(creationDate) - .withProject(project) - .withCreator(creator) - .withParams(params) - .withType(type) - .get(); + final Integration integration = new IntegrationBuilder().withName(name) + .withEnabled(enabled) + .withCreationDate(creationDate) + .withProject(project) + .withCreator(creator) + .withParams(params) + .withType(type) + .get(); - assertNotNull(integration); - assertEquals(name, integration.getName()); - assertEquals(enabled, integration.isEnabled()); - assertEquals(creationDate, integration.getCreationDate()); - assertEquals(creator, integration.getCreator()); - assertEquals(project, integration.getProject()); - assertThat(integration.getType()).isEqualToComparingFieldByField(type); - assertEquals(params.getParams(), integration.getParams().getParams()); - } + assertNotNull(integration); + assertEquals(name, integration.getName()); + assertEquals(enabled, integration.isEnabled()); + assertEquals(creationDate, integration.getCreationDate()); + assertEquals(creator, integration.getCreator()); + assertEquals(project, integration.getProject()); + assertThat(integration.getType()).isEqualToComparingFieldByField(type); + assertEquals(params.getParams(), integration.getParams().getParams()); + } - @Test - void updateExistIntegrationTest() { - final Integration integration = new Integration(); - integration.setName("name"); - integration.setEnabled(false); + @Test + void updateExistIntegrationTest() { + final Integration integration = new Integration(); + integration.setName("name"); + integration.setEnabled(false); - final Project project = new Project(); - project.setId(1L); - project.setName("project"); - final IntegrationParams params = new IntegrationParams(); - final HashMap<String, Object> parameters = Maps.newHashMap(); - parameters.put("param1", "val1"); - parameters.put("param2", "val2"); - params.setParams(parameters); - final IntegrationType type = new IntegrationType(); - type.setName("type"); + final Project project = new Project(); + project.setId(1L); + project.setName("project"); + final IntegrationParams params = new IntegrationParams(); + final HashMap<String, Object> parameters = Maps.newHashMap(); + parameters.put("param1", "val1"); + parameters.put("param2", "val2"); + params.setParams(parameters); + final IntegrationType type = new IntegrationType(); + type.setName("type"); - final String name = "name"; - final boolean enabled = true; - final LocalDateTime creationDate = LocalDateTime.now(); - final String creator = "creator"; + final String name = "name"; + final boolean enabled = true; + final LocalDateTime creationDate = LocalDateTime.now(); + final String creator = "creator"; - final Integration updatedIntegration = new IntegrationBuilder(integration).withName(name) - .withEnabled(enabled) - .withCreationDate(creationDate) - .withProject(project) - .withCreator(creator) - .withParams(params) - .withType(type) - .get(); + final Integration updatedIntegration = new IntegrationBuilder(integration).withName(name) + .withEnabled(enabled) + .withCreationDate(creationDate) + .withProject(project) + .withCreator(creator) + .withParams(params) + .withType(type) + .get(); - assertNotNull(updatedIntegration); - assertEquals(name, updatedIntegration.getName()); - assertEquals(enabled, updatedIntegration.isEnabled()); - assertEquals(creationDate, updatedIntegration.getCreationDate()); - assertEquals(creator, updatedIntegration.getCreator()); - assertEquals(project, updatedIntegration.getProject()); - assertThat(integration.getType()).isEqualToComparingFieldByField(type); - assertEquals(params.getParams(), updatedIntegration.getParams().getParams()); - } + assertNotNull(updatedIntegration); + assertEquals(name, updatedIntegration.getName()); + assertEquals(enabled, updatedIntegration.isEnabled()); + assertEquals(creationDate, updatedIntegration.getCreationDate()); + assertEquals(creator, updatedIntegration.getCreator()); + assertEquals(project, updatedIntegration.getProject()); + assertThat(integration.getType()).isEqualToComparingFieldByField(type); + assertEquals(params.getParams(), updatedIntegration.getParams().getParams()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilderTest.java index 572f60d2c4..a255c06c8a 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueEntityBuilderTest.java @@ -16,41 +16,41 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueType; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IssueEntityBuilderTest { - @Test - void issueEntityBuilder() { - final boolean autoAnalyzed = false; - final boolean ignoreAnalyzer = true; - final IssueType issueType = new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), - "locator", - "longName", - "shortName", - "color" - ); - final String description = "description"; + @Test + void issueEntityBuilder() { + final boolean autoAnalyzed = false; + final boolean ignoreAnalyzer = true; + final IssueType issueType = new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), + "locator", + "longName", + "shortName", + "color" + ); + final String description = "description"; - final IssueEntity issueEntity = new IssueEntityBuilder().addAutoAnalyzedFlag(autoAnalyzed) - .addIgnoreFlag(ignoreAnalyzer) - .addIssueType(issueType) - .addDescription(description) - .get(); + final IssueEntity issueEntity = new IssueEntityBuilder().addAutoAnalyzedFlag(autoAnalyzed) + .addIgnoreFlag(ignoreAnalyzer) + .addIssueType(issueType) + .addDescription(description) + .get(); - assertEquals(autoAnalyzed, issueEntity.getAutoAnalyzed()); - assertEquals(ignoreAnalyzer, issueEntity.getIgnoreAnalyzer()); - assertThat(issueEntity.getIssueType()).isEqualToComparingFieldByField(issueType); - assertEquals(description, issueEntity.getIssueDescription()); - } + assertEquals(autoAnalyzed, issueEntity.getAutoAnalyzed()); + assertEquals(ignoreAnalyzer, issueEntity.getIgnoreAnalyzer()); + assertThat(issueEntity.getIssueType()).isEqualToComparingFieldByField(issueType); + assertEquals(description, issueEntity.getIssueDescription()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilderTest.java index 92723090a7..a565362707 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/IssueTypeBuilderTest.java @@ -16,38 +16,38 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueType; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IssueTypeBuilderTest { - @Test - void issueTypeBuilderTest() { - final String color = "color"; - final IssueGroup issueGroup = new IssueGroup(TestItemIssueGroup.PRODUCT_BUG); - final String locator = "locator"; - final String longName = "longName"; - final String shortName = "shortName"; + @Test + void issueTypeBuilderTest() { + final String color = "color"; + final IssueGroup issueGroup = new IssueGroup(TestItemIssueGroup.PRODUCT_BUG); + final String locator = "locator"; + final String longName = "longName"; + final String shortName = "shortName"; - final IssueType issueType = new IssueTypeBuilder().addHexColor(color) - .addIssueGroup(issueGroup) - .addLocator(locator) - .addLongName(longName) - .addShortName(shortName) - .get(); + final IssueType issueType = new IssueTypeBuilder().addHexColor(color) + .addIssueGroup(issueGroup) + .addLocator(locator) + .addLongName(longName) + .addShortName(shortName) + .get(); - assertEquals(color, issueType.getHexColor()); - assertThat(issueType.getIssueGroup()).isEqualToComparingFieldByField(issueGroup); - assertEquals(locator, issueType.getLocator()); - assertEquals(longName, issueType.getLongName()); - assertEquals(shortName.toUpperCase(), issueType.getShortName()); - } + assertEquals(color, issueType.getHexColor()); + assertThat(issueType.getIssueGroup()).isEqualToComparingFieldByField(issueGroup); + assertEquals(locator, issueType.getLocator()); + assertEquals(longName, issueType.getLongName()); + assertEquals(shortName.toUpperCase(), issueType.getShortName()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilderTest.java index 95a7f1eca7..2c2374bab9 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LaunchBuilderTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.LaunchModeEnum; import com.epam.ta.reportportal.entity.launch.Launch; @@ -24,86 +29,83 @@ import com.epam.ta.reportportal.ws.model.launch.Mode; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.Date; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class LaunchBuilderTest { - @Test - void launchBuilder() { - final String description = "description"; - final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); - final Date date = TO_DATE.apply(now); - final Long projectId = 1L; - final ItemAttributeResource attributeResource = new ItemAttributeResource("key", "value"); - final Long userId = 2L; - final String passed = "PASSED"; - final Mode mode = Mode.DEFAULT; + @Test + void launchBuilder() { + final String description = "description"; + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + final Date date = TO_DATE.apply(now); + final Long projectId = 1L; + final ItemAttributeResource attributeResource = new ItemAttributeResource("key", "value"); + final Long userId = 2L; + final String passed = "PASSED"; + final Mode mode = Mode.DEFAULT; - final Launch launch = new LaunchBuilder().addDescription(description) - .addEndTime(date) - .addProject(projectId) - .addAttribute(attributeResource) - .addUserId(userId) - .addStatus(passed) - .addMode(mode) - .get(); + final Launch launch = new LaunchBuilder().addDescription(description) + .addEndTime(date) + .addProject(projectId) + .addAttribute(attributeResource) + .addUserId(userId) + .addStatus(passed) + .addMode(mode) + .get(); - assertEquals(description, launch.getDescription()); - assertEquals(now, launch.getEndTime()); - assertEquals(projectId, launch.getProjectId()); - assertTrue(launch.getAttributes().contains(new ItemAttribute("key", "value", false))); - assertEquals(userId, launch.getUserId()); - assertEquals(passed, launch.getStatus().name()); - assertEquals(LaunchModeEnum.DEFAULT, launch.getMode()); - } + assertEquals(description, launch.getDescription()); + assertEquals(now, launch.getEndTime()); + assertEquals(projectId, launch.getProjectId()); + assertTrue(launch.getAttributes().contains(new ItemAttribute("key", "value", false))); + assertEquals(userId, launch.getUserId()); + assertEquals(passed, launch.getStatus().name()); + assertEquals(LaunchModeEnum.DEFAULT, launch.getMode()); + } - @Test - void addStartRqTest() { - final StartLaunchRQ request = new StartLaunchRQ(); - final String uuid = "uuid"; - request.setUuid(uuid); - request.setMode(Mode.DEFAULT); - final String description = "description"; - request.setDescription(description); - final String name = "name"; - request.setName(name); - final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); - request.setStartTime(TO_DATE.apply(now)); - request.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); + @Test + void addStartRqTest() { + final StartLaunchRQ request = new StartLaunchRQ(); + final String uuid = "uuid"; + request.setUuid(uuid); + request.setMode(Mode.DEFAULT); + final String description = "description"; + request.setDescription(description); + final String name = "name"; + request.setName(name); + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + request.setStartTime(TO_DATE.apply(now)); + request.setAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))); - final Launch launch = new LaunchBuilder().addStartRQ(request).addAttributes(request.getAttributes()).get(); + final Launch launch = new LaunchBuilder().addStartRQ(request) + .addAttributes(request.getAttributes()).get(); - assertEquals(name, launch.getName()); - assertEquals(uuid, launch.getUuid()); - assertEquals(description, launch.getDescription()); - assertEquals(now, launch.getStartTime()); - assertTrue(launch.getAttributes().contains(new ItemAttribute("key", "value", false))); - assertEquals(LaunchModeEnum.DEFAULT, launch.getMode()); - } + assertEquals(name, launch.getName()); + assertEquals(uuid, launch.getUuid()); + assertEquals(description, launch.getDescription()); + assertEquals(now, launch.getStartTime()); + assertTrue(launch.getAttributes().contains(new ItemAttribute("key", "value", false))); + assertEquals(LaunchModeEnum.DEFAULT, launch.getMode()); + } - @Test - void overwriteAttributes() { - Launch launch = new Launch(); - final ItemAttribute systemAttribute = new ItemAttribute("key", "value", true); - launch.setAttributes(Sets.newHashSet(new ItemAttribute("key", "value", false), systemAttribute)); + @Test + void overwriteAttributes() { + Launch launch = new Launch(); + final ItemAttribute systemAttribute = new ItemAttribute("key", "value", true); + launch.setAttributes( + Sets.newHashSet(new ItemAttribute("key", "value", false), systemAttribute)); - final Launch buildLaunch = new LaunchBuilder(launch).overwriteAttributes(Sets.newHashSet(new ItemAttributeResource("newKey", - "newVal" + final Launch buildLaunch = new LaunchBuilder(launch).overwriteAttributes( + Sets.newHashSet(new ItemAttributeResource("newKey", + "newVal" ))).get(); - assertThat(buildLaunch.getAttributes()).containsExactlyInAnyOrder(new ItemAttribute("newKey", "newVal", false), systemAttribute); - } + assertThat(buildLaunch.getAttributes()).containsExactlyInAnyOrder( + new ItemAttribute("newKey", "newVal", false), systemAttribute); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilderTest.java similarity index 55% rename from src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilderTest.java rename to src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilderTest.java index f384806541..1451a9bd37 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/LogFullBuilderTest.java @@ -16,44 +16,40 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalUnit; -import java.util.Date; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ -class LogBuilderTest { - - @Test - void logBuilder() { - final SaveLogRQ createLogRQ = new SaveLogRQ(); - final String message = "message"; - createLogRQ.setMessage(message); - createLogRQ.setLevel("ERROR"); - final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); - - createLogRQ.setLogTime(TO_DATE.apply(now)); - TestItem item = new TestItem(); - item.setItemId(1L); - item.setUniqueId("uuid"); - - final Log log = new LogBuilder().addSaveLogRq(createLogRQ).addTestItem(item).get(); - - assertEquals(message, log.getLogMessage()); - assertEquals(40000, (int) log.getLogLevel()); - assertEquals(now, log.getLogTime()); - assertThat(log.getTestItem()).isEqualToComparingFieldByField(item); - } +class LogFullBuilderTest { + + @Test + void logBuilder() { + final SaveLogRQ createLogRQ = new SaveLogRQ(); + final String message = "message"; + createLogRQ.setMessage(message); + createLogRQ.setLevel("ERROR"); + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + + createLogRQ.setLogTime(TO_DATE.apply(now)); + TestItem item = new TestItem(); + item.setItemId(1L); + item.setUniqueId("uuid"); + + final LogFull logFull = new LogFullBuilder().addSaveLogRq(createLogRQ).addTestItem(item).get(); + + assertEquals(message, logFull.getLogMessage()); + assertEquals(40000, (int) logFull.getLogLevel()); + assertEquals(now, logFull.getLogTime()); + assertThat(logFull.getTestItem()).isEqualToComparingFieldByField(item); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilderTest.java index 5d1b81b721..bfb72f7c32 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/PatternTemplateBuilderTest.java @@ -16,34 +16,35 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.pattern.PatternTemplate; import com.epam.ta.reportportal.ws.model.project.config.pattern.CreatePatternTemplateRQ; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PatternTemplateBuilderTest { - @Test - void patternTemplateBuilder() { - CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); - String name = "name"; - String type = "STRING"; - boolean enabled = true; - String value = "qwe"; - createPatternTemplateRQ.setName(name); - createPatternTemplateRQ.setType(type); - createPatternTemplateRQ.setEnabled(enabled); - createPatternTemplateRQ.setValue(value); + @Test + void patternTemplateBuilder() { + CreatePatternTemplateRQ createPatternTemplateRQ = new CreatePatternTemplateRQ(); + String name = "name"; + String type = "STRING"; + boolean enabled = true; + String value = "qwe"; + createPatternTemplateRQ.setName(name); + createPatternTemplateRQ.setType(type); + createPatternTemplateRQ.setEnabled(enabled); + createPatternTemplateRQ.setValue(value); - PatternTemplate patternTemplate = new PatternTemplateBuilder().withCreateRequest(createPatternTemplateRQ).get(); + PatternTemplate patternTemplate = new PatternTemplateBuilder().withCreateRequest( + createPatternTemplateRQ).get(); - assertEquals(name, patternTemplate.getName()); - assertEquals(type, patternTemplate.getTemplateType().name()); - assertEquals(enabled, patternTemplate.isEnabled()); - assertEquals(value, patternTemplate.getValue()); - } + assertEquals(name, patternTemplate.getName()); + assertEquals(type, patternTemplate.getTemplateType().name()); + assertEquals(enabled, patternTemplate.isEnabled()); + assertEquals(value, patternTemplate.getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilderTest.java index aa47a7e27a..bcd8e4de3c 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/TestItemBuilderTest.java @@ -16,6 +16,12 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.enums.StatusEnum; import com.epam.ta.reportportal.entity.enums.TestItemTypeEnum; @@ -29,170 +35,189 @@ import com.epam.ta.reportportal.ws.model.attribute.ItemAttributesRQ; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import org.apache.commons.lang3.RandomStringUtils; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.Collections; - -import static com.epam.ta.reportportal.commons.EntityUtils.TO_DATE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class TestItemBuilderTest { - @Test - void testItemBuilder() { - final Launch launch = new Launch(); - launch.setId(1L); - launch.setName("name"); - final ParameterResource parameterResource = new ParameterResource(); - parameterResource.setKey("key"); - parameterResource.setValue("value"); - final String description = "description"; - final String typeValue = "step"; - - final TestItem testItem = new TestItemBuilder().addDescription(description) - .addType(typeValue) - .addLaunchId(launch.getId()) - .addParameters(Collections.singletonList(parameterResource)) - .addAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))) - .addParentId(1L) - .get(); - - assertThat(testItem.getLaunchId()).isEqualToComparingFieldByField(launch.getId()); - assertEquals(description, testItem.getDescription()); - assertEquals(TestItemTypeEnum.STEP, testItem.getType()); - final Parameter param = new Parameter(); - param.setKey("key"); - param.setValue("value"); - assertTrue(testItem.getParameters().contains(param)); - assertThat(testItem.getAttributes()).containsExactly(new ItemAttribute("key", "value", false)); - assertNotNull(testItem.getParentId()); - } - - @Test - void addStartRqTest() { - final StartTestItemRQ rq = new StartTestItemRQ(); - rq.setType("step"); - final ParameterResource parameterResource = new ParameterResource(); - parameterResource.setKey("key"); - parameterResource.setValue("value"); - rq.setParameters(Collections.singletonList(parameterResource)); - final String uuid = "uuid"; - rq.setUniqueId(uuid); - final String description = "description"; - rq.setDescription(description); - final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); - rq.setStartTime(TO_DATE.apply(now)); - final String name = "name"; - rq.setName(name); - - final TestItem testItem = new TestItemBuilder().addStartItemRequest(rq).get(); - - assertEquals(TestItemTypeEnum.STEP, testItem.getType()); - final Parameter param = new Parameter(); - param.setKey("key"); - param.setValue("value"); - assertTrue(testItem.getParameters().contains(param)); - assertEquals(uuid, testItem.getUniqueId()); - assertEquals(description, testItem.getDescription()); - assertEquals(now, testItem.getStartTime()); - assertEquals(name, testItem.getName()); - } - - @Test - void addResultsTest() { - TestItem item = new TestItem(); - final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); - item.setStartTime(now); - final TestItemResults itemResults = new TestItemResults(); - itemResults.setEndTime(now.plusSeconds(120)); - item.setItemResults(itemResults); - final ItemAttribute systemAttribute = new ItemAttribute("key", "val", true); - item.setAttributes(Sets.newHashSet(new ItemAttribute("key", "val", false), systemAttribute)); - - final TestItem resultItem = new TestItemBuilder(item).addTestItemResults(itemResults) - .addStatus(StatusEnum.PASSED) - .overwriteAttributes(Sets.newHashSet(new ItemAttributeResource("k", "v"))) - .get(); - - assertEquals(120, resultItem.getItemResults().getDuration(), 0.1); - assertEquals(StatusEnum.PASSED, resultItem.getItemResults().getStatus()); - assertThat(resultItem.getAttributes()).containsExactlyInAnyOrder(systemAttribute, new ItemAttribute("k", "v", false)); - } - - @Test - void providedTestCaseIdTest() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setName("item"); - request.setType("step"); - String testCaseId = "my-test-case-id"; - request.setTestCaseId(testCaseId); - - TestItem testItem = new TestItemBuilder().addStartItemRequest(request).get(); - - assertEquals(testCaseId, testItem.getTestCaseId()); - assertEquals(testCaseId.hashCode(), testItem.getTestCaseHash().intValue()); - } - - @Test - void providedTestCaseIdWith1025SymbolsTest() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setName("item"); - request.setType("step"); - String testCaseId = RandomStringUtils.random(1025, true, true); - request.setTestCaseId(testCaseId); - - TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); - - assertTrue(item.getTestCaseId().length() <= 1024); - assertEquals(testCaseId.substring(0, 1010), item.getTestCaseId().substring(0, 1010)); - assertEquals("[" + testCaseId.substring(1011).hashCode() + "]", item.getTestCaseId().substring(1011)); - assertEquals(testCaseId.hashCode(), item.getTestCaseHash().intValue()); - } - - @Test - void testCaseIdGeneratedFromCodeRefTest() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setName("item"); - request.setType("step"); - String codeRef = "com.epam.ta.reportportal.core.item.identity.TestCaseIdHandlerImplTest"; - request.setCodeRef(codeRef); - - TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); - - assertEquals(codeRef, item.getTestCaseId()); - assertEquals(codeRef.hashCode(), item.getTestCaseHash().intValue()); - } - - @Test - void testCaseIdGeneratedFromCodeRefAndParamsTest() { - StartTestItemRQ request = new StartTestItemRQ(); - request.setName("item"); - request.setType("step"); - String codeRef = "com.epam.ta.reportportal.core.item.identity.TestCaseIdHandlerImplTest"; - request.setCodeRef(codeRef); - ParameterResource param1 = new ParameterResource(); - param1.setKey("key1"); - String value1 = "value1"; - param1.setValue(value1); - ParameterResource param2 = new ParameterResource(); - param2.setKey("key2"); - String value2 = "value2"; - param2.setValue(value2); - ParameterResource param3 = new ParameterResource(); - param1.setKey("key3"); - request.setParameters(Lists.newArrayList(param1, param2, param3)); - - TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); - - String expected = codeRef + "[" + value1 + "," + value2 + ",null]"; - assertEquals(expected, item.getTestCaseId()); - assertEquals(expected.hashCode(), item.getTestCaseHash().intValue()); - } + @Test + void testItemBuilder() { + final Launch launch = new Launch(); + launch.setId(1L); + launch.setName("name"); + final ParameterResource parameterResource = new ParameterResource(); + parameterResource.setKey("key"); + parameterResource.setValue("value"); + final String description = "description"; + final String typeValue = "step"; + + final TestItem testItem = new TestItemBuilder().addDescription(description) + .addType(typeValue) + .addLaunchId(launch.getId()) + .addParameters(Collections.singletonList(parameterResource)) + .addAttributes(Sets.newHashSet(new ItemAttributesRQ("key", "value"))) + .addParentId(1L) + .get(); + + assertEquals(testItem.getLaunchId(), launch.getId()); + assertEquals(description, testItem.getDescription()); + assertEquals(TestItemTypeEnum.STEP, testItem.getType()); + final Parameter param = new Parameter(); + param.setKey("key"); + param.setValue("value"); + assertTrue(testItem.getParameters().contains(param)); + assertThat(testItem.getAttributes()).containsExactly(new ItemAttribute("key", "value", false)); + assertNotNull(testItem.getParentId()); + } + + @Test + void addStartRqTest() { + final StartTestItemRQ rq = new StartTestItemRQ(); + rq.setType("step"); + final ParameterResource parameterResource = new ParameterResource(); + parameterResource.setKey("key"); + parameterResource.setValue("value"); + rq.setParameters(Collections.singletonList(parameterResource)); + final String uuid = "uuid"; + rq.setUniqueId(uuid); + final String description = "description"; + rq.setDescription(description); + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + rq.setStartTime(TO_DATE.apply(now)); + final String name = "name"; + rq.setName(name); + + final TestItem testItem = new TestItemBuilder().addStartItemRequest(rq).get(); + + assertEquals(TestItemTypeEnum.STEP, testItem.getType()); + final Parameter param = new Parameter(); + param.setKey("key"); + param.setValue("value"); + assertTrue(testItem.getParameters().contains(param)); + assertEquals(uuid, testItem.getUniqueId()); + assertEquals(description, testItem.getDescription()); + assertEquals(now, testItem.getStartTime()); + assertEquals(name, testItem.getName()); + } + + @Test + void addResultsTest() { + TestItem item = new TestItem(); + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + item.setStartTime(now); + final TestItemResults itemResults = new TestItemResults(); + itemResults.setEndTime(now.plusSeconds(120)); + item.setItemResults(itemResults); + final ItemAttribute systemAttribute = new ItemAttribute("key", "val", true); + item.setAttributes(Sets.newHashSet(new ItemAttribute("key", "val", false), systemAttribute)); + + final TestItem resultItem = new TestItemBuilder(item).addTestItemResults(itemResults) + .addStatus(StatusEnum.PASSED) + .overwriteAttributes(Sets.newHashSet(new ItemAttributeResource("k", "v"))) + .get(); + + assertEquals(120, resultItem.getItemResults().getDuration(), 0.1); + assertEquals(StatusEnum.PASSED, resultItem.getItemResults().getStatus()); + assertThat(resultItem.getAttributes()).containsExactlyInAnyOrder(systemAttribute, + new ItemAttribute("k", "v", false)); + } + + @Test + void overwriteAttributesValuesTest() { + TestItem item = new TestItem(); + final LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + item.setStartTime(now); + final TestItemResults itemResults = new TestItemResults(); + itemResults.setEndTime(now.plusSeconds(120)); + item.setItemResults(itemResults); + final ItemAttribute systemAttribute = new ItemAttribute("key", "val", true); + item.setAttributes(Sets.newHashSet(new ItemAttribute("someKey", "val", false), systemAttribute)); + + final TestItem resultItem = new TestItemBuilder(item).addTestItemResults(itemResults) + .addStatus(StatusEnum.PASSED) + .overwriteAttributesValues(Sets.newHashSet(new ItemAttributeResource("someKey", "newVal"))) + .get(); + + assertEquals(120, resultItem.getItemResults().getDuration(), 0.1); + assertEquals(StatusEnum.PASSED, resultItem.getItemResults().getStatus()); + assertThat(resultItem.getAttributes()).containsExactlyInAnyOrder(systemAttribute, + new ItemAttribute("someKey", "newVal", false)); + } + + @Test + void providedTestCaseIdTest() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setName("item"); + request.setType("step"); + String testCaseId = "my-test-case-id"; + request.setTestCaseId(testCaseId); + + TestItem testItem = new TestItemBuilder().addStartItemRequest(request).get(); + + assertEquals(testCaseId, testItem.getTestCaseId()); + assertEquals(testCaseId.hashCode(), testItem.getTestCaseHash().intValue()); + } + + @Test + void providedTestCaseIdWith1025SymbolsTest() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setName("item"); + request.setType("step"); + String testCaseId = RandomStringUtils.random(1025, true, true); + request.setTestCaseId(testCaseId); + + TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); + + assertTrue(item.getTestCaseId().length() <= 1024); + assertEquals(testCaseId.substring(0, 1010), item.getTestCaseId().substring(0, 1010)); + assertEquals("[" + testCaseId.substring(1011).hashCode() + "]", + item.getTestCaseId().substring(1011)); + assertEquals(testCaseId.hashCode(), item.getTestCaseHash().intValue()); + } + + @Test + void testCaseIdGeneratedFromCodeRefTest() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setName("item"); + request.setType("step"); + String codeRef = "com.epam.ta.reportportal.core.item.identity.TestCaseIdHandlerImplTest"; + request.setCodeRef(codeRef); + + TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); + + assertEquals(codeRef, item.getTestCaseId()); + assertEquals(codeRef.hashCode(), item.getTestCaseHash().intValue()); + } + + @Test + void testCaseIdGeneratedFromCodeRefAndParamsTest() { + StartTestItemRQ request = new StartTestItemRQ(); + request.setName("item"); + request.setType("step"); + String codeRef = "com.epam.ta.reportportal.core.item.identity.TestCaseIdHandlerImplTest"; + request.setCodeRef(codeRef); + ParameterResource param1 = new ParameterResource(); + param1.setKey("key1"); + String value1 = "value1"; + param1.setValue(value1); + ParameterResource param2 = new ParameterResource(); + param2.setKey("key2"); + String value2 = "value2"; + param2.setValue(value2); + ParameterResource param3 = new ParameterResource(); + param1.setKey("key3"); + request.setParameters(Lists.newArrayList(param1, param2, param3)); + + TestItem item = new TestItemBuilder().addStartItemRequest(request).get(); + + String expected = codeRef + "[" + value1 + "," + value2 + ",null]"; + assertEquals(expected, item.getTestCaseId()); + assertEquals(expected.hashCode(), item.getTestCaseHash().intValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilderTest.java index eaa5a29910..7cfb8a0fd3 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserBuilderTest.java @@ -16,40 +16,43 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.epam.ta.reportportal.entity.user.User; import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.entity.user.UserType; import com.epam.ta.reportportal.ws.model.user.CreateUserRQConfirm; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class UserBuilderTest { - @Test - void userBuilder() { - final CreateUserRQConfirm request = new CreateUserRQConfirm(); - final String login = "login"; - request.setLogin(login); - final String email = "email@domain.com"; - request.setEmail(email); - final String fullName = "full name"; - request.setFullName(fullName); - request.setPassword("password"); - final UserRole role = UserRole.USER; + @Test + void userBuilder() { + final CreateUserRQConfirm request = new CreateUserRQConfirm(); + final String login = "login"; + request.setLogin(login); + final String email = "email@domain.com"; + request.setEmail(email); + final String fullName = "full name"; + request.setFullName(fullName); + request.setPassword("password"); + final UserRole role = UserRole.USER; - final User user = new UserBuilder().addCreateUserRQ(request).addUserRole(role).addPassword(request.getPassword()).get(); + final User user = new UserBuilder().addCreateUserRQ(request).addUserRole(role) + .addPassword(request.getPassword()).get(); - assertEquals(login, user.getLogin()); - assertEquals(email, user.getEmail()); - assertEquals(fullName, user.getFullName()); - assertNotNull(user.getPassword()); - assertEquals(role, user.getRole()); - assertEquals(UserType.INTERNAL, user.getUserType()); - assertNotNull(user.getMetadata()); - assertFalse(user.isExpired()); - } + assertEquals(login, user.getLogin()); + assertEquals(email, user.getEmail()); + assertEquals(fullName, user.getFullName()); + assertNotNull(user.getPassword()); + assertEquals(role, user.getRole()); + assertEquals(UserType.INTERNAL, user.getUserType()); + assertNotNull(user.getMetadata()); + assertFalse(user.isExpired()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilderTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilderTest.java index b38baaf1ec..d5827b169f 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilderTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/builders/UserPreferenceBuilderTest.java @@ -16,30 +16,31 @@ package com.epam.ta.reportportal.ws.converter.builders; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.filter.UserFilter; import com.epam.ta.reportportal.entity.preference.UserPreference; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class UserPreferenceBuilderTest { - @Test - void userPreferenceBuilder() { - final UserFilter filter = new UserFilter(); - filter.setName("name"); - filter.setOwner("owner"); - final Long projectId = 1L; - final Long userId = 2L; + @Test + void userPreferenceBuilder() { + final UserFilter filter = new UserFilter(); + filter.setName("name"); + filter.setOwner("owner"); + final Long projectId = 1L; + final Long userId = 2L; - final UserPreference userPreference = new UserPreferenceBuilder().withFilter(filter).withProject(projectId).withUser(userId).get(); + final UserPreference userPreference = new UserPreferenceBuilder().withFilter(filter) + .withProject(projectId).withUser(userId).get(); - assertThat(userPreference.getFilter()).isEqualToComparingFieldByField(filter); - assertEquals(projectId, userPreference.getProject().getId()); - assertEquals(userId, userPreference.getUser().getId()); - } + assertThat(userPreference.getFilter()).isEqualToComparingFieldByField(filter); + assertEquals(projectId, userPreference.getProject().getId()); + assertEquals(userId, userPreference.getUser().getId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverterTest.java index b2739cde92..114abaebb4 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationConverterTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.IntegrationAuthFlowEnum; import com.epam.ta.reportportal.entity.enums.IntegrationGroupEnum; import com.epam.ta.reportportal.entity.integration.Integration; @@ -26,81 +29,83 @@ import com.epam.ta.reportportal.ws.model.integration.IntegrationResource; import com.epam.ta.reportportal.ws.model.integration.IntegrationTypeResource; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.sql.Date; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.HashMap; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IntegrationConverterTest { - @Test - void toResource() { - final Integration integration = getIntegration(); - final IntegrationResource resource = IntegrationConverter.TO_INTEGRATION_RESOURCE.apply(integration); + @Test + void toResource() { + final Integration integration = getIntegration(); + final IntegrationResource resource = IntegrationConverter.TO_INTEGRATION_RESOURCE.apply( + integration); - assertEquals(resource.getCreationDate(), Date.from(integration.getCreationDate().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getEnabled(), integration.isEnabled()); - assertEquals(resource.getId(), integration.getId()); - assertEquals(resource.getProjectId(), integration.getProject().getId()); + assertEquals(resource.getCreationDate(), + Date.from(integration.getCreationDate().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getEnabled(), integration.isEnabled()); + assertEquals(resource.getId(), integration.getId()); + assertEquals(resource.getProjectId(), integration.getProject().getId()); - assertThat(resource.getIntegrationParams()).containsOnlyKeys("param1", "param2", "nullParam", null); - assertThat(resource.getIntegrationParams()).doesNotContainKey("accessToken"); - assertThat(resource.getIntegrationParams()).containsValues("qwerty", "asdfgh", "value", null); + assertThat(resource.getIntegrationParams()).containsOnlyKeys("param1", "param2", "nullParam", + null); + assertThat(resource.getIntegrationParams()).doesNotContainKey("accessToken"); + assertThat(resource.getIntegrationParams()).containsValues("qwerty", "asdfgh", "value", null); - final IntegrationTypeResource integrationTypeResource = resource.getIntegrationType(); + final IntegrationTypeResource integrationTypeResource = resource.getIntegrationType(); - assertEquals(integrationTypeResource.getAuthFlow().name(), integration.getType().getAuthFlow().name()); - assertEquals(integrationTypeResource.getId(), integration.getType().getId()); - assertEquals(integrationTypeResource.getName(), integration.getType().getName()); - assertEquals(integrationTypeResource.getGroupType(), integration.getType().getIntegrationGroup().name()); - } + assertEquals(integrationTypeResource.getAuthFlow().name(), + integration.getType().getAuthFlow().name()); + assertEquals(integrationTypeResource.getId(), integration.getType().getId()); + assertEquals(integrationTypeResource.getName(), integration.getType().getName()); + assertEquals(integrationTypeResource.getGroupType(), + integration.getType().getIntegrationGroup().name()); + } - @Test - void toActivityResource() { - final Integration integration = getIntegration(); - final IntegrationActivityResource resource = IntegrationConverter.TO_ACTIVITY_RESOURCE.apply(integration); + @Test + void toActivityResource() { + final Integration integration = getIntegration(); + final IntegrationActivityResource resource = IntegrationConverter.TO_ACTIVITY_RESOURCE.apply( + integration); - assertEquals(resource.getId(), integration.getId()); - assertEquals(resource.getProjectId(), integration.getProject().getId()); - assertEquals(resource.getProjectName(), integration.getProject().getName()); - assertEquals(resource.getTypeName(), integration.getType().getName()); - } + assertEquals(resource.getId(), integration.getId()); + assertEquals(resource.getProjectId(), integration.getProject().getId()); + assertEquals(resource.getProjectName(), integration.getProject().getName()); + assertEquals(resource.getTypeName(), integration.getType().getName()); + } - private static Integration getIntegration() { - Integration integration = new Integration(); - final IntegrationType type = new IntegrationType(); - type.setCreationDate(LocalDateTime.now()); - type.setIntegrationGroup(IntegrationGroupEnum.NOTIFICATION); - type.setName("typeName"); - type.setAuthFlow(IntegrationAuthFlowEnum.BASIC); - type.setEnabled(true); - type.setId(1L); - type.setIntegrations(Sets.newHashSet(integration)); - integration.setType(type); - final IntegrationParams params = new IntegrationParams(); - final HashMap<String, Object> paramMap = new HashMap<>(); - paramMap.put("param1", "qwerty"); - paramMap.put("param2", "asdfgh"); - paramMap.put("nullParam", null); - paramMap.put(null, "value"); - paramMap.put("accessToken", "asdfgh"); - params.setParams(paramMap); - integration.setParams(params); - integration.setEnabled(true); - final Project project = new Project(); - project.setId(2L); - project.setName("projectName"); - integration.setProject(project); - integration.setId(3L); - integration.setCreationDate(LocalDateTime.now()); - return integration; - } + private static Integration getIntegration() { + Integration integration = new Integration(); + final IntegrationType type = new IntegrationType(); + type.setCreationDate(LocalDateTime.now()); + type.setIntegrationGroup(IntegrationGroupEnum.NOTIFICATION); + type.setName("typeName"); + type.setAuthFlow(IntegrationAuthFlowEnum.BASIC); + type.setEnabled(true); + type.setId(1L); + type.setIntegrations(Sets.newHashSet(integration)); + integration.setType(type); + final IntegrationParams params = new IntegrationParams(); + final HashMap<String, Object> paramMap = new HashMap<>(); + paramMap.put("param1", "qwerty"); + paramMap.put("param2", "asdfgh"); + paramMap.put("nullParam", null); + paramMap.put(null, "value"); + paramMap.put("accessToken", "asdfgh"); + params.setParams(paramMap); + integration.setParams(params); + integration.setEnabled(true); + final Project project = new Project(); + project.setId(2L); + project.setName("projectName"); + integration.setProject(project); + integration.setId(3L); + integration.setCreationDate(LocalDateTime.now()); + return integration; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverterTest.java index de380e7965..e572322fa8 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IntegrationFieldsConverterTest.java @@ -16,70 +16,72 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.bts.DefectFieldAllowedValue; import com.epam.ta.reportportal.entity.bts.DefectFormField; import com.epam.ta.reportportal.ws.model.externalsystem.AllowedValue; import com.epam.ta.reportportal.ws.model.externalsystem.PostFormField; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.util.Collections; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IntegrationFieldsConverterTest { - @Test - void fieldToDb() { - final PostFormField field = getField(); - final DefectFormField defectFormField = IntegrationFieldsConverter.FIELD_TO_DB.apply(field); + @Test + void fieldToDb() { + final PostFormField field = getField(); + final DefectFormField defectFormField = IntegrationFieldsConverter.FIELD_TO_DB.apply(field); - assertEquals(defectFormField.getFieldId(), field.getId()); - assertEquals(defectFormField.getType(), field.getFieldType()); - assertEquals(defectFormField.isRequired(), field.getIsRequired()); - assertThat(defectFormField.getValues()).containsExactlyElementsOf(field.getValue()); - assertThat(defectFormField.getDefectFieldAllowedValues()).hasSameSizeAs(field.getDefinedValues()); - } + assertEquals(defectFormField.getFieldId(), field.getId()); + assertEquals(defectFormField.getType(), field.getFieldType()); + assertEquals(defectFormField.isRequired(), field.getIsRequired()); + assertThat(defectFormField.getValues()).containsExactlyElementsOf(field.getValue()); + assertThat(defectFormField.getDefectFieldAllowedValues()).hasSameSizeAs( + field.getDefinedValues()); + } - @Test - void fieldToModel() { - final DefectFormField defectFormField = getDefectFormField(); - final PostFormField postFormField = IntegrationFieldsConverter.FIELD_TO_MODEL.apply(defectFormField); + @Test + void fieldToModel() { + final DefectFormField defectFormField = getDefectFormField(); + final PostFormField postFormField = IntegrationFieldsConverter.FIELD_TO_MODEL.apply( + defectFormField); - assertEquals(postFormField.getFieldType(), defectFormField.getType()); - assertEquals(postFormField.getIsRequired(), defectFormField.isRequired()); - assertThat(postFormField.getValue()).containsExactlyInAnyOrder("value1", "value2"); - assertThat(postFormField.getDefinedValues()).hasSameSizeAs(defectFormField.getDefectFieldAllowedValues()); - } + assertEquals(postFormField.getFieldType(), defectFormField.getType()); + assertEquals(postFormField.getIsRequired(), defectFormField.isRequired()); + assertThat(postFormField.getValue()).containsExactlyInAnyOrder("value1", "value2"); + assertThat(postFormField.getDefinedValues()).hasSameSizeAs( + defectFormField.getDefectFieldAllowedValues()); + } - private static PostFormField getField() { - final PostFormField postFormField = new PostFormField(); - postFormField.setFieldType("type"); - postFormField.setId("id"); - postFormField.setIsRequired(true); - postFormField.setFieldName("name"); - final AllowedValue allowedValue = new AllowedValue(); - allowedValue.setValueId("valueId"); - allowedValue.setValueName("valueName"); - postFormField.setDefinedValues(Collections.singletonList(allowedValue)); - postFormField.setValue(Collections.singletonList("value")); - return postFormField; - } + private static PostFormField getField() { + final PostFormField postFormField = new PostFormField(); + postFormField.setFieldType("type"); + postFormField.setId("id"); + postFormField.setIsRequired(true); + postFormField.setFieldName("name"); + final AllowedValue allowedValue = new AllowedValue(); + allowedValue.setValueId("valueId"); + allowedValue.setValueName("valueName"); + postFormField.setDefinedValues(Collections.singletonList(allowedValue)); + postFormField.setValue(Collections.singletonList("value")); + return postFormField; + } - private static DefectFormField getDefectFormField() { - final DefectFormField defectFormField = new DefectFormField(); - defectFormField.setFieldId("fieldId"); - defectFormField.setRequired(true); - defectFormField.setType("type"); - defectFormField.setValues(Sets.newHashSet("value1", "value2")); - final DefectFieldAllowedValue defectFieldAllowedValue = new DefectFieldAllowedValue(); - defectFieldAllowedValue.setValueId("id"); - defectFieldAllowedValue.setValueName("name"); - defectFormField.setDefectFieldAllowedValues(Sets.newHashSet(defectFieldAllowedValue)); - return defectFormField; - } + private static DefectFormField getDefectFormField() { + final DefectFormField defectFormField = new DefectFormField(); + defectFormField.setFieldId("fieldId"); + defectFormField.setRequired(true); + defectFormField.setType("type"); + defectFormField.setValues(Sets.newHashSet("value1", "value2")); + final DefectFieldAllowedValue defectFieldAllowedValue = new DefectFieldAllowedValue(); + defectFieldAllowedValue.setValueId("id"); + defectFieldAllowedValue.setValueName("name"); + defectFormField.setDefectFieldAllowedValues(Sets.newHashSet(defectFieldAllowedValue)); + return defectFormField; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverterTest.java index c459775b51..eb5e34dab8 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/IssueConverterTest.java @@ -16,6 +16,8 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.enums.TestItemIssueGroup; import com.epam.ta.reportportal.entity.item.issue.IssueEntity; import com.epam.ta.reportportal.entity.item.issue.IssueGroup; @@ -23,48 +25,48 @@ import com.epam.ta.reportportal.ws.model.issue.Issue; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class IssueConverterTest { - @Test - void toModel() { - final IssueEntity issueEntity = getIssueEntity(); - final Issue resource = IssueConverter.TO_MODEL.apply(issueEntity); + @Test + void toModel() { + final IssueEntity issueEntity = getIssueEntity(); + final Issue resource = IssueConverter.TO_MODEL.apply(issueEntity); - assertEquals(resource.getAutoAnalyzed(), issueEntity.getAutoAnalyzed()); - assertEquals(resource.getComment(), issueEntity.getIssueDescription()); - assertEquals(resource.getIgnoreAnalyzer(), issueEntity.getIgnoreAnalyzer()); - assertEquals(resource.getIssueType(), issueEntity.getIssueType().getLocator()); - } + assertEquals(resource.getAutoAnalyzed(), issueEntity.getAutoAnalyzed()); + assertEquals(resource.getComment(), issueEntity.getIssueDescription()); + assertEquals(resource.getIgnoreAnalyzer(), issueEntity.getIgnoreAnalyzer()); + assertEquals(resource.getIssueType(), issueEntity.getIssueType().getLocator()); + } - @Test - void toResource() { - final Issue issue = getIssue(); - final IssueEntity issueEntity = IssueConverter.TO_ISSUE.apply(issue); + @Test + void toResource() { + final Issue issue = getIssue(); + final IssueEntity issueEntity = IssueConverter.TO_ISSUE.apply(issue); - assertEquals(issueEntity.getIgnoreAnalyzer(), issue.getIgnoreAnalyzer()); - assertEquals(issueEntity.getAutoAnalyzed(), issue.getAutoAnalyzed()); - assertEquals(issue.getComment(), issue.getComment()); - } + assertEquals(issueEntity.getIgnoreAnalyzer(), issue.getIgnoreAnalyzer()); + assertEquals(issueEntity.getAutoAnalyzed(), issue.getAutoAnalyzed()); + assertEquals(issue.getComment(), issue.getComment()); + } - private static IssueEntity getIssueEntity() { - final IssueEntity issue = new IssueEntity(); - issue.setIssueType(new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), "locator", "long name", "SNA", "color")); - issue.setIgnoreAnalyzer(false); - issue.setAutoAnalyzed(false); - issue.setIssueDescription("issue description"); - return issue; - } + private static IssueEntity getIssueEntity() { + final IssueEntity issue = new IssueEntity(); + issue.setIssueType( + new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), "locator", "long name", "SNA", + "color")); + issue.setIgnoreAnalyzer(false); + issue.setAutoAnalyzed(false); + issue.setIssueDescription("issue description"); + return issue; + } - private static Issue getIssue() { - Issue issue = new Issue(); - issue.setComment("comment"); - issue.setIgnoreAnalyzer(false); - issue.setAutoAnalyzed(false); - return issue; - } + private static Issue getIssue() { + Issue issue = new Issue(); + issue.setComment("comment"); + issue.setIgnoreAnalyzer(false); + issue.setAutoAnalyzed(false); + return issue; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ItemAttributeConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ItemAttributeConverterTest.java index 2042e33277..acf039c71f 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ItemAttributeConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ItemAttributeConverterTest.java @@ -16,24 +16,24 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class ItemAttributeConverterTest { - @Test - void fromResource() { - ItemAttributeResource resource = new ItemAttributeResource("key", "val"); - final ItemAttribute itemAttribute = ItemAttributeConverter.FROM_RESOURCE.apply(resource); + @Test + void fromResource() { + ItemAttributeResource resource = new ItemAttributeResource("key", "val"); + final ItemAttribute itemAttribute = ItemAttributeConverter.FROM_RESOURCE.apply(resource); - assertEquals(itemAttribute.getKey(), resource.getKey()); - assertEquals(itemAttribute.getValue(), resource.getValue()); - assertEquals(itemAttribute.isSystem(), false); - } + assertEquals(itemAttribute.getKey(), resource.getKey()); + assertEquals(itemAttribute.getValue(), resource.getValue()); + assertEquals(itemAttribute.isSystem(), false); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/LogConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/LogConverterTest.java index 5264651a8e..33d700039e 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/LogConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/LogConverterTest.java @@ -16,60 +16,60 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.attachment.Attachment; import com.epam.ta.reportportal.entity.enums.LogLevel; import com.epam.ta.reportportal.entity.item.TestItem; -import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.ws.model.log.LogResource; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; - -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class LogConverterTest { - private static Log getLog() { - Log log = new Log(); - log.setLogLevel(50000); - log.setLogMessage("message"); - final TestItem testItem = new TestItem(); - testItem.setItemId(1L); - log.setTestItem(testItem); - Attachment attachment = new Attachment(); - attachment.setId(1L); - attachment.setFileId("attachId"); - attachment.setContentType("contentType"); - attachment.setThumbnailId("thumbnailId"); - log.setAttachment(attachment); - log.setLogTime(LocalDateTime.now()); - log.setId(2L); - log.setUuid("uuid"); - log.setLastModified(LocalDateTime.now()); - return log; - } + private static LogFull getLogFull() { + LogFull logFull = new LogFull(); + logFull.setLogLevel(50000); + logFull.setLogMessage("message"); + final TestItem testItem = new TestItem(); + testItem.setItemId(1L); + logFull.setTestItem(testItem); + Attachment attachment = new Attachment(); + attachment.setId(1L); + attachment.setFileId("attachId"); + attachment.setContentType("contentType"); + attachment.setThumbnailId("thumbnailId"); + logFull.setAttachment(attachment); + logFull.setLogTime(LocalDateTime.now()); + logFull.setId(2L); + logFull.setUuid("uuid"); + logFull.setLastModified(LocalDateTime.now()); + return logFull; + } - @Test - void toResource() { - final Log log = getLog(); - final LogResource resource = LogConverter.TO_RESOURCE.apply(log); + @Test + void toResource() { + final LogFull logFull = getLogFull(); + final LogResource resource = LogConverter.TO_RESOURCE.apply(logFull); - assertEquals(resource.getId(), log.getId()); - assertEquals(resource.getUuid(), log.getUuid()); - assertEquals(resource.getMessage(), log.getLogMessage()); - assertEquals(resource.getLevel(), LogLevel.toLevel(log.getLogLevel()).toString()); - assertEquals(resource.getLogTime(), Date.from(log.getLogTime().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getItemId(), log.getTestItem().getItemId()); + assertEquals(resource.getId(), logFull.getId()); + assertEquals(resource.getUuid(), logFull.getUuid()); + assertEquals(resource.getMessage(), logFull.getLogMessage()); + assertEquals(resource.getLevel(), LogLevel.toLevel(logFull.getLogLevel()).toString()); + assertEquals(resource.getLogTime(), + Date.from(logFull.getLogTime().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getItemId(), logFull.getTestItem().getItemId()); - final LogResource.BinaryContent binaryContent = resource.getBinaryContent(); + final LogResource.BinaryContent binaryContent = resource.getBinaryContent(); - assertEquals(binaryContent.getContentType(), log.getAttachment().getContentType()); - assertEquals(binaryContent.getBinaryDataId(), String.valueOf(log.getAttachment().getId())); - assertEquals(binaryContent.getThumbnailId(), log.getAttachment().getThumbnailId()); - } + assertEquals(binaryContent.getContentType(), logFull.getAttachment().getContentType()); + assertEquals(binaryContent.getBinaryDataId(), String.valueOf(logFull.getAttachment().getId())); + assertEquals(binaryContent.getThumbnailId(), logFull.getAttachment().getThumbnailId()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverterTest.java index 2085389af5..a71e99c26a 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ParametersConverterTest.java @@ -16,46 +16,46 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.item.Parameter; import com.epam.ta.reportportal.ws.model.ParameterResource; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class ParametersConverterTest { - @Test - void toResource() { - final Parameter parameter = getParameter(); - final ParameterResource resource = ParametersConverter.TO_RESOURCE.apply(parameter); - - assertEquals(resource.getKey(), parameter.getKey()); - assertEquals(resource.getValue(), parameter.getValue()); - } - - @Test - void toModel() { - final ParameterResource resource = getResource(); - final Parameter parameter = ParametersConverter.TO_MODEL.apply(resource); - - assertEquals(parameter.getKey(), resource.getKey()); - assertEquals(parameter.getValue(), resource.getValue()); - } - - private static Parameter getParameter() { - Parameter parameter = new Parameter(); - parameter.setKey("key"); - parameter.setValue("value"); - return parameter; - } - - private static ParameterResource getResource() { - ParameterResource resource = new ParameterResource(); - resource.setKey("key"); - resource.setValue("value"); - return resource; - } + @Test + void toResource() { + final Parameter parameter = getParameter(); + final ParameterResource resource = ParametersConverter.TO_RESOURCE.apply(parameter); + + assertEquals(resource.getKey(), parameter.getKey()); + assertEquals(resource.getValue(), parameter.getValue()); + } + + @Test + void toModel() { + final ParameterResource resource = getResource(); + final Parameter parameter = ParametersConverter.TO_MODEL.apply(resource); + + assertEquals(parameter.getKey(), resource.getKey()); + assertEquals(parameter.getValue(), resource.getValue()); + } + + private static Parameter getParameter() { + Parameter parameter = new Parameter(); + parameter.setKey("key"); + parameter.setValue("value"); + return parameter; + } + + private static ParameterResource getResource() { + ParameterResource resource = new ParameterResource(); + resource.setKey("key"); + resource.setValue("value"); + return resource; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverterTest.java index d329c12fc2..f97b2dbb7e 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/PatternTemplateConverterTest.java @@ -16,54 +16,55 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.pattern.PatternTemplate; import com.epam.ta.reportportal.entity.pattern.PatternTemplateType; import com.epam.ta.reportportal.ws.model.activity.PatternTemplateActivityResource; import com.epam.ta.reportportal.ws.model.project.config.pattern.PatternTemplateResource; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PatternTemplateConverterTest { - @Test - public void toResourceTest() { + @Test + public void toResourceTest() { - PatternTemplate patternTemplate = get(); + PatternTemplate patternTemplate = get(); - PatternTemplateResource resource = PatternTemplateConverter.TO_RESOURCE.apply(patternTemplate); + PatternTemplateResource resource = PatternTemplateConverter.TO_RESOURCE.apply(patternTemplate); - assertEquals(patternTemplate.getId(), resource.getId()); - assertEquals(patternTemplate.getTemplateType().name(), resource.getType()); - assertEquals(patternTemplate.getName(), resource.getName()); - assertEquals(patternTemplate.getValue(), resource.getValue()); - assertEquals(patternTemplate.isEnabled(), resource.getEnabled()); - } + assertEquals(patternTemplate.getId(), resource.getId()); + assertEquals(patternTemplate.getTemplateType().name(), resource.getType()); + assertEquals(patternTemplate.getName(), resource.getName()); + assertEquals(patternTemplate.getValue(), resource.getValue()); + assertEquals(patternTemplate.isEnabled(), resource.getEnabled()); + } - @Test - public void toActivityResourceTest() { + @Test + public void toActivityResourceTest() { - PatternTemplate patternTemplate = get(); + PatternTemplate patternTemplate = get(); - PatternTemplateActivityResource resource = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply(patternTemplate); + PatternTemplateActivityResource resource = PatternTemplateConverter.TO_ACTIVITY_RESOURCE.apply( + patternTemplate); - assertEquals(patternTemplate.getId(), resource.getId()); - assertEquals(patternTemplate.getProjectId(), resource.getProjectId()); - assertEquals(patternTemplate.getName(), resource.getName()); - } + assertEquals(patternTemplate.getId(), resource.getId()); + assertEquals(patternTemplate.getProjectId(), resource.getProjectId()); + assertEquals(patternTemplate.getName(), resource.getName()); + } - private PatternTemplate get() { - PatternTemplate patternTemplate = new PatternTemplate(); - patternTemplate.setId(1L); - patternTemplate.setProjectId(1L); - patternTemplate.setTemplateType(PatternTemplateType.STRING); - patternTemplate.setEnabled(true); - patternTemplate.setValue("qwe"); - patternTemplate.setName("name"); - return patternTemplate; - } + private PatternTemplate get() { + PatternTemplate patternTemplate = new PatternTemplate(); + patternTemplate.setId(1L); + patternTemplate.setProjectId(1L); + patternTemplate.setTemplateType(PatternTemplateType.STRING); + patternTemplate.setEnabled(true); + patternTemplate.setValue("qwe"); + patternTemplate.setName("name"); + return patternTemplate; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverterTest.java index abbfc0ecd3..05a4dfb394 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/ProjectActivityConverterTest.java @@ -16,6 +16,9 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.attribute.Attribute; import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectAttribute; @@ -23,35 +26,34 @@ import com.google.common.collect.Sets; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Java6Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class ProjectActivityConverterTest { - @Test - void toActivityResource() { - final Project project = getProject(); - final ProjectAttributesActivityResource resource = ProjectActivityConverter.TO_ACTIVITY_RESOURCE.apply(project); - - assertEquals(resource.getProjectId(), project.getId()); - assertEquals(resource.getProjectName(), project.getName()); - assertThat(resource.getConfig()).containsOnlyKeys("attr.lol"); - assertThat(resource.getConfig()).containsValue("value"); - - } - - private static Project getProject() { - Project project = new Project(); - project.setId(1L); - project.setName("name"); - final Attribute attribute = new Attribute(); - attribute.setId(2L); - attribute.setName("attr.lol"); - final ProjectAttribute projectAttribute = new ProjectAttribute().withProject(project).withValue("value").withAttribute(attribute); - project.setProjectAttributes(Sets.newHashSet(projectAttribute)); - return project; - } + @Test + void toActivityResource() { + final Project project = getProject(); + final ProjectAttributesActivityResource resource = ProjectActivityConverter.TO_ACTIVITY_RESOURCE.apply( + project); + + assertEquals(resource.getProjectId(), project.getId()); + assertEquals(resource.getProjectName(), project.getName()); + assertThat(resource.getConfig()).containsOnlyKeys("attr.lol"); + assertThat(resource.getConfig()).containsValue("value"); + + } + + private static Project getProject() { + Project project = new Project(); + project.setId(1L); + project.setName("name"); + final Attribute attribute = new Attribute(); + attribute.setId(2L); + attribute.setName("attr.lol"); + final ProjectAttribute projectAttribute = new ProjectAttribute().withProject(project) + .withValue("value").withAttribute(attribute); + project.setProjectAttributes(Sets.newHashSet(projectAttribute)); + return project; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverterTest.java index 94f82f3f14..6d4bdd0f36 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/RestorePasswordBidConverterTest.java @@ -16,26 +16,26 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.epam.ta.reportportal.entity.user.RestorePasswordBid; import com.epam.ta.reportportal.ws.model.user.RestorePasswordRQ; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class RestorePasswordBidConverterTest { - @Test - void toBid() { - final RestorePasswordRQ request = new RestorePasswordRQ(); - request.setEmail("email@example.com"); + @Test + void toBid() { + final RestorePasswordRQ request = new RestorePasswordRQ(); + request.setEmail("email@example.com"); - final RestorePasswordBid bid = RestorePasswordBidConverter.TO_BID.apply(request); + final RestorePasswordBid bid = RestorePasswordBidConverter.TO_BID.apply(request); - assertEquals(bid.getEmail(), request.getEmail()); - assertNotNull(bid.getUuid()); - } + assertEquals(bid.getEmail(), request.getEmail()); + assertNotNull(bid.getUuid()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverterTest.java index 73b4e49f93..3d1a8139c6 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TestItemConverterTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.entity.bts.Ticket; import com.epam.ta.reportportal.entity.enums.StatusEnum; @@ -33,163 +38,179 @@ import com.epam.ta.reportportal.ws.model.TestItemResource; import com.epam.ta.reportportal.ws.model.activity.TestItemActivityResource; import com.google.common.collect.Sets; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class TestItemConverterTest { - @Test - void toActivityResourceNullTest() { - assertThrows(NullPointerException.class, () -> TestItemConverter.TO_ACTIVITY_RESOURCE.apply(null, null)); - } + @Test + void toActivityResourceNullTest() { + assertThrows(NullPointerException.class, + () -> TestItemConverter.TO_ACTIVITY_RESOURCE.apply(null, null)); + } - @Test - void toResourceNullTest() { - assertThrows(NullPointerException.class, () -> TestItemConverter.TO_RESOURCE.apply(null)); - } + @Test + void toResourceNullTest() { + assertThrows(NullPointerException.class, () -> TestItemConverter.TO_RESOURCE.apply(null)); + } - @Test - void toActivityResource() { - final TestItem item = getItem(true); - final TestItemActivityResource activityResource = TestItemConverter.TO_ACTIVITY_RESOURCE.apply(item, 4L); + @Test + void toActivityResource() { + final TestItem item = getItem(true); + final TestItemActivityResource activityResource = TestItemConverter.TO_ACTIVITY_RESOURCE.apply( + item, 4L); - assertEquals(activityResource.getId(), item.getItemId()); - assertEquals(activityResource.getName(), item.getName()); - assertEquals((long) activityResource.getProjectId(), 4L); - assertEquals(activityResource.getIssueDescription(), item.getItemResults().getIssue().getIssueDescription()); - assertEquals(activityResource.getIssueTypeLongName(), item.getItemResults().getIssue().getIssueType().getLongName()); - assertEquals(activityResource.getStatus(), item.getItemResults().getStatus().name()); - assertEquals( - activityResource.getTickets(), - item.getItemResults() - .getIssue() - .getTickets() - .stream() - .map(it -> it.getTicketId().concat(":").concat(it.getUrl())) - .collect(Collectors.joining(", ")) - ); - assertEquals(activityResource.isIgnoreAnalyzer(), item.getItemResults().getIssue().getIgnoreAnalyzer()); - assertEquals(activityResource.isAutoAnalyzed(), item.getItemResults().getIssue().getAutoAnalyzed()); - } + assertEquals(activityResource.getId(), item.getItemId()); + assertEquals(activityResource.getName(), item.getName()); + assertEquals((long) activityResource.getProjectId(), 4L); + assertEquals(activityResource.getIssueDescription(), + item.getItemResults().getIssue().getIssueDescription()); + assertEquals(activityResource.getIssueTypeLongName(), + item.getItemResults().getIssue().getIssueType().getLongName()); + assertEquals(activityResource.getStatus(), item.getItemResults().getStatus().name()); + assertEquals( + activityResource.getTickets(), + item.getItemResults() + .getIssue() + .getTickets() + .stream() + .map(it -> it.getTicketId().concat(":").concat(it.getUrl())) + .collect(Collectors.joining(", ")) + ); + assertEquals(activityResource.isIgnoreAnalyzer(), + item.getItemResults().getIssue().getIgnoreAnalyzer()); + assertEquals(activityResource.isAutoAnalyzed(), + item.getItemResults().getIssue().getAutoAnalyzed()); + } - @Test - void toResource() { - final TestItem item = getItem(true); - final TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(item); + @Test + void toResource() { + final TestItem item = getItem(true); + final TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(item); - assertEquals(resource.getName(), item.getName()); - assertEquals(resource.getDescription(), item.getDescription()); - assertEquals(resource.getLaunchId(), item.getLaunchId()); - assertEquals(resource.getUuid(), item.getUuid()); - assertEquals(resource.getItemId(), item.getItemId()); - assertEquals(resource.getParent(), item.getParentId()); - assertEquals(resource.getPath(), item.getPath()); - assertEquals(resource.getStatus(), item.getItemResults().getStatus().name()); - assertEquals(resource.getType(), item.getType().name()); - assertEquals(resource.getStartTime(), Date.from(item.getStartTime().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getEndTime(), Date.from(item.getItemResults().getEndTime().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getUniqueId(), item.getUniqueId()); - assertThat(resource.getAttributes() - .stream() - .map(ItemAttributeConverter.FROM_RESOURCE) - .collect(Collectors.toSet())).containsExactlyElementsOf(item.getAttributes()); - assertThat(resource.getParameters() - .stream() - .map(ParametersConverter.TO_MODEL) - .collect(Collectors.toSet())).containsExactlyElementsOf(item.getParameters()); - assertThat(resource.getStatisticsResource()).isEqualToComparingFieldByField(StatisticsConverter.TO_RESOURCE.apply(item.getItemResults() - .getStatistics())); - assertEquals(resource.getIssue().getComment(), item.getItemResults().getIssue().getIssueDescription()); - assertEquals(resource.getIssue().getAutoAnalyzed(), item.getItemResults().getIssue().getAutoAnalyzed()); - assertEquals(resource.getIssue().getIssueType(), item.getItemResults().getIssue().getIssueType().getLocator()); - assertEquals(resource.getIssue().getIgnoreAnalyzer(), item.getItemResults().getIssue().getIgnoreAnalyzer()); - } + assertEquals(resource.getName(), item.getName()); + assertEquals(resource.getDescription(), item.getDescription()); + assertEquals(resource.getLaunchId(), item.getLaunchId()); + assertEquals(resource.getUuid(), item.getUuid()); + assertEquals(resource.getItemId(), item.getItemId()); + assertEquals(resource.getParent(), item.getParentId()); + assertEquals(resource.getPath(), item.getPath()); + assertEquals(resource.getStatus(), item.getItemResults().getStatus().name()); + assertEquals(resource.getType(), item.getType().name()); + assertEquals(resource.getStartTime(), + Date.from(item.getStartTime().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getEndTime(), + Date.from(item.getItemResults().getEndTime().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getUniqueId(), item.getUniqueId()); + assertThat(resource.getAttributes() + .stream() + .map(ItemAttributeConverter.FROM_RESOURCE) + .collect(Collectors.toSet())).containsExactlyElementsOf(item.getAttributes()); + assertThat(resource.getParameters() + .stream() + .map(ParametersConverter.TO_MODEL) + .collect(Collectors.toSet())).containsExactlyElementsOf(item.getParameters()); + assertThat(resource.getStatisticsResource()).isEqualToComparingFieldByField( + StatisticsConverter.TO_RESOURCE.apply(item.getItemResults() + .getStatistics())); + assertEquals(resource.getIssue().getComment(), + item.getItemResults().getIssue().getIssueDescription()); + assertEquals(resource.getIssue().getAutoAnalyzed(), + item.getItemResults().getIssue().getAutoAnalyzed()); + assertEquals(resource.getIssue().getIssueType(), + item.getItemResults().getIssue().getIssueType().getLocator()); + assertEquals(resource.getIssue().getIgnoreAnalyzer(), + item.getItemResults().getIssue().getIgnoreAnalyzer()); + } - @Test - void toResourceWithoutIssue() { - final TestItem item = getItem(false); - final TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(item); + @Test + void toResourceWithoutIssue() { + final TestItem item = getItem(false); + final TestItemResource resource = TestItemConverter.TO_RESOURCE.apply(item); - assertEquals(resource.getName(), item.getName()); - assertEquals(resource.getDescription(), item.getDescription()); - assertEquals(resource.getLaunchId(), item.getLaunchId()); - assertEquals(resource.getUuid(), item.getUuid()); - assertEquals(resource.getItemId(), item.getItemId()); - assertEquals(resource.getParent(), item.getParentId()); - assertEquals(resource.getPath(), item.getPath()); - assertEquals(resource.getStatus(), item.getItemResults().getStatus().name()); - assertEquals(resource.getType(), item.getType().name()); - assertEquals(resource.getStartTime(), Date.from(item.getStartTime().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getEndTime(), Date.from(item.getItemResults().getEndTime().atZone(ZoneId.of("UTC")).toInstant())); - assertEquals(resource.getUniqueId(), item.getUniqueId()); - assertThat(resource.getAttributes() - .stream() - .map(ItemAttributeConverter.FROM_RESOURCE) - .collect(Collectors.toSet())).containsExactlyElementsOf(item.getAttributes()); - assertThat(resource.getParameters() - .stream() - .map(ParametersConverter.TO_MODEL) - .collect(Collectors.toSet())).containsExactlyElementsOf(item.getParameters()); - assertThat(resource.getStatisticsResource()).isEqualToComparingFieldByField(StatisticsConverter.TO_RESOURCE.apply(item.getItemResults() - .getStatistics())); - assertNull(resource.getIssue()); - } + assertEquals(resource.getName(), item.getName()); + assertEquals(resource.getDescription(), item.getDescription()); + assertEquals(resource.getLaunchId(), item.getLaunchId()); + assertEquals(resource.getUuid(), item.getUuid()); + assertEquals(resource.getItemId(), item.getItemId()); + assertEquals(resource.getParent(), item.getParentId()); + assertEquals(resource.getPath(), item.getPath()); + assertEquals(resource.getStatus(), item.getItemResults().getStatus().name()); + assertEquals(resource.getType(), item.getType().name()); + assertEquals(resource.getStartTime(), + Date.from(item.getStartTime().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getEndTime(), + Date.from(item.getItemResults().getEndTime().atZone(ZoneId.of("UTC")).toInstant())); + assertEquals(resource.getUniqueId(), item.getUniqueId()); + assertThat(resource.getAttributes() + .stream() + .map(ItemAttributeConverter.FROM_RESOURCE) + .collect(Collectors.toSet())).containsExactlyElementsOf(item.getAttributes()); + assertThat(resource.getParameters() + .stream() + .map(ParametersConverter.TO_MODEL) + .collect(Collectors.toSet())).containsExactlyElementsOf(item.getParameters()); + assertThat(resource.getStatisticsResource()).isEqualToComparingFieldByField( + StatisticsConverter.TO_RESOURCE.apply(item.getItemResults() + .getStatistics())); + assertNull(resource.getIssue()); + } - private TestItem getItem(boolean hasIssue) { - TestItem item = new TestItem(); - item.setName("name"); - item.setDescription("description"); - item.setStartTime(LocalDateTime.now()); - item.setUniqueId("uniqueId"); - item.setUuid("uuid"); - item.setItemId(1L); - item.setType(TestItemTypeEnum.STEP); - item.setPath("1.2.3"); - final Parameter parameter = new Parameter(); - parameter.setKey("key"); - parameter.setValue("value"); - item.setParameters(Sets.newHashSet(parameter)); - item.setAttributes(Sets.newHashSet(new ItemAttribute("key1", "value1", false), new ItemAttribute("key2", "value2", false))); - final Launch launch = new Launch(); - launch.setProjectId(4L); - launch.setId(2L); - item.setLaunchId(launch.getId()); - item.setHasChildren(false); - final TestItem parent = new TestItem(); - parent.setItemId(3L); - item.setParentId(parent.getItemId()); - final TestItemResults itemResults = new TestItemResults(); - itemResults.setStatus(StatusEnum.FAILED); - itemResults.setEndTime(LocalDateTime.now()); - if (hasIssue) { - final IssueEntity issue = new IssueEntity(); - issue.setIssueId(3L); - issue.setIssueType(new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), "locator", "long name", "SNA", "color")); - issue.setIgnoreAnalyzer(false); - issue.setAutoAnalyzed(false); - issue.setIssueDescription("issue description"); - final Ticket ticket = new Ticket(); - ticket.setTicketId("ticketId1"); - ticket.setUrl("http:/example.com/ticketId1"); - final Ticket ticket1 = new Ticket(); - ticket1.setTicketId("ticketId2"); - ticket1.setUrl("http:/example.com/ticketId2"); - issue.setTickets(Sets.newHashSet(ticket, ticket1)); - itemResults.setIssue(issue); - } - itemResults.setStatistics(Sets.newHashSet(new Statistics(new StatisticsField("statistics$defects$automation_bug$total"), 1, 2L))); - item.setItemResults(itemResults); - return item; - } + private TestItem getItem(boolean hasIssue) { + TestItem item = new TestItem(); + item.setName("name"); + item.setDescription("description"); + item.setStartTime(LocalDateTime.now()); + item.setUniqueId("uniqueId"); + item.setUuid("uuid"); + item.setItemId(1L); + item.setType(TestItemTypeEnum.STEP); + item.setPath("1.2.3"); + final Parameter parameter = new Parameter(); + parameter.setKey("key"); + parameter.setValue("value"); + item.setParameters(Sets.newHashSet(parameter)); + item.setAttributes(Sets.newHashSet(new ItemAttribute("key1", "value1", false), + new ItemAttribute("key2", "value2", false))); + final Launch launch = new Launch(); + launch.setProjectId(4L); + launch.setId(2L); + item.setLaunchId(launch.getId()); + item.setHasChildren(false); + final TestItem parent = new TestItem(); + parent.setItemId(3L); + item.setParentId(parent.getItemId()); + final TestItemResults itemResults = new TestItemResults(); + itemResults.setStatus(StatusEnum.FAILED); + itemResults.setEndTime(LocalDateTime.now()); + if (hasIssue) { + final IssueEntity issue = new IssueEntity(); + issue.setIssueId(3L); + issue.setIssueType( + new IssueType(new IssueGroup(TestItemIssueGroup.PRODUCT_BUG), "locator", "long name", + "SNA", "color")); + issue.setIgnoreAnalyzer(false); + issue.setAutoAnalyzed(false); + issue.setIssueDescription("issue description"); + final Ticket ticket = new Ticket(); + ticket.setTicketId("ticketId1"); + ticket.setUrl("http:/example.com/ticketId1"); + final Ticket ticket1 = new Ticket(); + ticket1.setTicketId("ticketId2"); + ticket1.setUrl("http:/example.com/ticketId2"); + issue.setTickets(Sets.newHashSet(ticket, ticket1)); + itemResults.setIssue(issue); + } + itemResults.setStatistics(Sets.newHashSet( + new Statistics(new StatisticsField("statistics$defects$automation_bug$total"), 1, 2L))); + item.setItemResults(itemResults); + return item; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverterTest.java index ce89064856..c286ef43e2 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/TicketConverterTest.java @@ -16,34 +16,34 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.bts.Ticket; import com.epam.ta.reportportal.ws.model.issue.Issue; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class TicketConverterTest { - @Test - void toTicket() { - final Issue.ExternalSystemIssue issue = getIssue(); - final Ticket resource = TicketConverter.TO_TICKET.apply(issue); + @Test + void toTicket() { + final Issue.ExternalSystemIssue issue = getIssue(); + final Ticket resource = TicketConverter.TO_TICKET.apply(issue); - assertEquals(resource.getTicketId(), issue.getTicketId()); - assertEquals(resource.getUrl(), issue.getUrl()); - assertEquals(resource.getBtsUrl(), issue.getBtsUrl()); - assertEquals(resource.getBtsProject(), issue.getBtsProject()); - } + assertEquals(resource.getTicketId(), issue.getTicketId()); + assertEquals(resource.getUrl(), issue.getUrl()); + assertEquals(resource.getBtsUrl(), issue.getBtsUrl()); + assertEquals(resource.getBtsProject(), issue.getBtsProject()); + } - private static Issue.ExternalSystemIssue getIssue() { - Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); - issue.setBtsUrl("jira.com"); - issue.setBtsUrl("project"); - issue.setTicketId("ticketId"); - issue.setUrl("https:/example.com/ticketId"); - return issue; - } + private static Issue.ExternalSystemIssue getIssue() { + Issue.ExternalSystemIssue issue = new Issue.ExternalSystemIssue(); + issue.setBtsUrl("jira.com"); + issue.setBtsUrl("project"); + issue.setTicketId("ticketId"); + issue.setUrl("https:/example.com/ticketId"); + return issue; + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverterTest.java index ef5c66853b..b1b0935fdc 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/converters/UserCreationBidConverterTest.java @@ -16,40 +16,39 @@ package com.epam.ta.reportportal.ws.converter.converters; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.user.UserCreationBid; import com.epam.ta.reportportal.ws.model.user.CreateUserRQ; -import org.junit.jupiter.api.Test; - import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ class UserCreationBidConverterTest { - @Test - void toUser() { - CreateUserRQ request = new CreateUserRQ(); - final String email = "email@example.com"; - request.setEmail(email); - final String role = "role"; - request.setRole(role); - final Project project = new Project(); - project.setName("projectName"); - final Date creationDate = Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant()); - project.setCreationDate(creationDate); - - final UserCreationBid bid = UserCreationBidConverter.TO_USER.apply(request, project); - - assertNotNull(bid.getUuid()); - assertEquals(bid.getEmail(), email); - assertEquals(bid.getRole(), role); - assertEquals(bid.getDefaultProject(), project); - } + @Test + void toUser() { + CreateUserRQ request = new CreateUserRQ(); + final String email = "email@example.com"; + request.setEmail(email); + final String role = "role"; + request.setRole(role); + final Project project = new Project(); + project.setName("projectName"); + final Date creationDate = Date.from(LocalDateTime.now().atZone(ZoneId.of("UTC")).toInstant()); + project.setCreationDate(creationDate); + + final UserCreationBid bid = UserCreationBidConverter.TO_USER.apply(request, project); + + assertNotNull(bid.getUuid()); + assertEquals(bid.getEmail(), email); + assertEquals(bid.getRole(), role); + assertEquals(bid.getProjectName(), project.getName()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdaterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdaterTest.java index 8d18fc62ed..f58d7b5c7a 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdaterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceAttributeUpdaterTest.java @@ -16,51 +16,51 @@ package com.epam.ta.reportportal.ws.converter.resource.handler.attribute.launch; +import static java.util.stream.Collectors.groupingBy; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.model.attribute.ItemAttributeResource; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; import java.util.Set; - -import static java.util.stream.Collectors.groupingBy; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchResourceAttributeUpdaterTest { - private final LaunchResourceAttributeUpdater launchResourceAttributeUpdater = new LaunchResourceAttributeUpdater(); + private final LaunchResourceAttributeUpdater launchResourceAttributeUpdater = new LaunchResourceAttributeUpdater(); - @Test - void shouldUpdate() { - final LaunchResource launchResource = new LaunchResource(); - final List<ItemAttribute> attributes = List.of(new ItemAttribute("k1", "v1", false), new ItemAttribute("k2", "v2", false)); - launchResourceAttributeUpdater.handle(launchResource, attributes); + @Test + void shouldUpdate() { + final LaunchResource launchResource = new LaunchResource(); + final List<ItemAttribute> attributes = List.of(new ItemAttribute("k1", "v1", false), + new ItemAttribute("k2", "v2", false)); + launchResourceAttributeUpdater.handle(launchResource, attributes); - final Set<ItemAttributeResource> resourceAttributes = launchResource.getAttributes(); - Assertions.assertEquals(2, resourceAttributes.size()); + final Set<ItemAttributeResource> resourceAttributes = launchResource.getAttributes(); + Assertions.assertEquals(2, resourceAttributes.size()); - final Map<String, List<ItemAttributeResource>> mapping = resourceAttributes.stream() - .collect(groupingBy(ItemAttributeResource::getKey)); + final Map<String, List<ItemAttributeResource>> mapping = resourceAttributes.stream() + .collect(groupingBy(ItemAttributeResource::getKey)); - final ItemAttributeResource firstResource = mapping.get("k1").get(0); - final ItemAttributeResource secondResource = mapping.get("k2").get(0); + final ItemAttributeResource firstResource = mapping.get("k1").get(0); + final ItemAttributeResource secondResource = mapping.get("k2").get(0); - final ItemAttribute firstAttribute = attributes.get(0); - final ItemAttribute secondAttribute = attributes.get(1); - shouldEqual(firstAttribute, firstResource); - shouldEqual(secondAttribute, secondResource); + final ItemAttribute firstAttribute = attributes.get(0); + final ItemAttribute secondAttribute = attributes.get(1); + shouldEqual(firstAttribute, firstResource); + shouldEqual(secondAttribute, secondResource); - } + } - private void shouldEqual(ItemAttribute itemAttribute, ItemAttributeResource resource) { - assertEquals(itemAttribute.getKey(), resource.getKey()); - assertEquals(itemAttribute.getValue(), resource.getValue()); - } + private void shouldEqual(ItemAttribute itemAttribute, ItemAttributeResource resource) { + assertEquals(itemAttribute.getKey(), resource.getKey()); + assertEquals(itemAttribute.getValue(), resource.getValue()); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceMetadataAttributeUpdaterTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceMetadataAttributeUpdaterTest.java index 735963e040..f09dadb2fe 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceMetadataAttributeUpdaterTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/launch/LaunchResourceMetadataAttributeUpdaterTest.java @@ -16,47 +16,48 @@ package com.epam.ta.reportportal.ws.converter.resource.handler.attribute.launch; +import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; + import com.epam.ta.reportportal.entity.ItemAttribute; import com.epam.ta.reportportal.ws.model.launch.LaunchResource; -import org.apache.commons.collections4.MapUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import java.util.List; import java.util.Map; import java.util.Set; - -import static com.epam.ta.reportportal.core.launch.cluster.pipeline.SaveLastRunAttributePartProvider.RP_CLUSTER_LAST_RUN_KEY; +import org.apache.commons.collections4.MapUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class LaunchResourceMetadataAttributeUpdaterTest { - private final LaunchResourceMetadataAttributeUpdater updater = new LaunchResourceMetadataAttributeUpdater(Set.of(RP_CLUSTER_LAST_RUN_KEY)); - - @Test - void shouldUpdateMetadataWhenAttributeMatches() { - final LaunchResource launchResource = new LaunchResource(); - final List<ItemAttribute> attributes = List.of(new ItemAttribute(RP_CLUSTER_LAST_RUN_KEY, "v1", false), - new ItemAttribute("k2", "v2", false) - ); - updater.handle(launchResource, attributes); - - final Map<String, Object> metadata = launchResource.getMetadata(); - Assertions.assertFalse(metadata.isEmpty()); - Assertions.assertEquals("v1", metadata.get(RP_CLUSTER_LAST_RUN_KEY)); - } - - @Test - void shouldNotUpdateMetadataWhenAttributeMatches() { - final LaunchResource launchResource = new LaunchResource(); - final List<ItemAttribute> attributes = List.of(new ItemAttribute("k1", "v1", false), - new ItemAttribute("k2", "v2", false) - ); - updater.handle(launchResource, attributes); - - Assertions.assertTrue(MapUtils.isEmpty(launchResource.getMetadata())); - } + private final LaunchResourceMetadataAttributeUpdater updater = new LaunchResourceMetadataAttributeUpdater( + Set.of(RP_CLUSTER_LAST_RUN_KEY)); + + @Test + void shouldUpdateMetadataWhenAttributeMatches() { + final LaunchResource launchResource = new LaunchResource(); + final List<ItemAttribute> attributes = List.of( + new ItemAttribute(RP_CLUSTER_LAST_RUN_KEY, "v1", false), + new ItemAttribute("k2", "v2", false) + ); + updater.handle(launchResource, attributes); + + final Map<String, Object> metadata = launchResource.getMetadata(); + Assertions.assertFalse(metadata.isEmpty()); + Assertions.assertEquals("v1", metadata.get(RP_CLUSTER_LAST_RUN_KEY)); + } + + @Test + void shouldNotUpdateMetadataWhenAttributeMatches() { + final LaunchResource launchResource = new LaunchResource(); + final List<ItemAttribute> attributes = List.of(new ItemAttribute("k1", "v1", false), + new ItemAttribute("k2", "v2", false) + ); + updater.handle(launchResource, attributes); + + Assertions.assertTrue(MapUtils.isEmpty(launchResource.getMetadata())); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcherTest.java b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcherTest.java index 27b2c956a9..f247e82583 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcherTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/converter/resource/handler/attribute/matcher/PredicateItemAttributeTypeMatcherTest.java @@ -21,38 +21,38 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * @author <a href="mailto:ivan_budayeu@epam.com">Ivan Budayeu</a> */ class PredicateItemAttributeTypeMatcherTest { - private final PredicateItemAttributeTypeMatcher systemAttributeMatcher = new PredicateItemAttributeTypeMatcher(ItemAttribute::isSystem, ItemAttributeType.SYSTEM); - private final PredicateItemAttributeTypeMatcher publicAttributeMatcher = new PredicateItemAttributeTypeMatcher(it -> !it.isSystem(), ItemAttributeType.PUBLIC); - - @Test - void publicShouldReturnTrue() { - final ItemAttribute publicAttribute = new ItemAttribute("k1", "v1", false); - Assertions.assertTrue(publicAttributeMatcher.matches(publicAttribute)); - } - - @Test - void publicShouldReturnFalse() { - final ItemAttribute systemAttribute = new ItemAttribute("k1", "v1", true); - Assertions.assertFalse(publicAttributeMatcher.matches(systemAttribute)); - } - - @Test - void systemShouldReturnTrue() { - final ItemAttribute systemAttribute = new ItemAttribute("k1", "v1", true); - Assertions.assertTrue(systemAttributeMatcher.matches(systemAttribute)); - } - - @Test - void systemShouldReturnFalse() { - final ItemAttribute publicAttribute = new ItemAttribute("k1", "v1", false); - Assertions.assertFalse(systemAttributeMatcher.matches(publicAttribute)); - } + private final PredicateItemAttributeTypeMatcher systemAttributeMatcher = new PredicateItemAttributeTypeMatcher( + ItemAttribute::isSystem, ItemAttributeType.SYSTEM); + private final PredicateItemAttributeTypeMatcher publicAttributeMatcher = new PredicateItemAttributeTypeMatcher( + it -> !it.isSystem(), ItemAttributeType.PUBLIC); + + @Test + void publicShouldReturnTrue() { + final ItemAttribute publicAttribute = new ItemAttribute("k1", "v1", false); + Assertions.assertTrue(publicAttributeMatcher.matches(publicAttribute)); + } + + @Test + void publicShouldReturnFalse() { + final ItemAttribute systemAttribute = new ItemAttribute("k1", "v1", true); + Assertions.assertFalse(publicAttributeMatcher.matches(systemAttribute)); + } + + @Test + void systemShouldReturnTrue() { + final ItemAttribute systemAttribute = new ItemAttribute("k1", "v1", true); + Assertions.assertTrue(systemAttributeMatcher.matches(systemAttribute)); + } + + @Test + void systemShouldReturnFalse() { + final ItemAttribute publicAttribute = new ItemAttribute("k1", "v1", false); + Assertions.assertFalse(systemAttributeMatcher.matches(publicAttribute)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImplTest.java index 007c1ba223..7653576593 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/handler/impl/QueryHandlerImplTest.java @@ -16,6 +16,11 @@ package com.epam.ta.reportportal.ws.handler.impl; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.dao.IntegrationRepository; @@ -34,72 +39,68 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - /** * @author Yauheni_Martynau */ @ExtendWith(MockitoExtension.class) class QueryHandlerImplTest { - @Mock - private ProjectRepository projectRepository; + @Mock + private ProjectRepository projectRepository; - @Mock - private IntegrationRepository integrationRepository; + @Mock + private IntegrationRepository integrationRepository; - @Mock - private TestItemRepository testItemRepository; + @Mock + private TestItemRepository testItemRepository; - @Mock - private LogRepository logRepository; + @Mock + private LogRepository logRepository; - @InjectMocks - private QueryHandlerImpl queryHandler; + @InjectMocks + private QueryHandlerImpl queryHandler; - @Test - void testFind_withLogRepositoryRequest() { + @Test + void testFind_withLogRepositoryRequest() { - //given: - Filter requestFilter = Filter.builder() - .withTarget(Log.class).withCondition(FilterCondition.builder().eq("id", "2").build()) - .build(); + //given: + Filter requestFilter = Filter.builder() + .withTarget(Log.class).withCondition(FilterCondition.builder().eq("id", "2").build()) + .build(); - QueryRQ queryRQ = new QueryRQ(); - queryRQ.setEntity(Log.class.getSimpleName()); - queryRQ.setFilter(requestFilter); + QueryRQ queryRQ = new QueryRQ(); + queryRQ.setEntity(Log.class.getSimpleName()); + queryRQ.setFilter(requestFilter); - //setup: - when(logRepository.findByFilter(requestFilter)).thenReturn(Lists.newArrayList()); + //setup: + when(logRepository.findByFilter(requestFilter)).thenReturn(Lists.newArrayList()); - //when: - queryHandler.find(queryRQ); + //when: + queryHandler.find(queryRQ); - //then: - ArgumentCaptor<Filter> captor = ArgumentCaptor.forClass(Filter.class); - verify(logRepository).findByFilter(captor.capture()); + //then: + ArgumentCaptor<Filter> captor = ArgumentCaptor.forClass(Filter.class); + verify(logRepository).findByFilter(captor.capture()); - Filter capturedFilter = captor.getValue(); + Filter capturedFilter = captor.getValue(); - assertEquals(requestFilter, capturedFilter); - } + assertEquals(requestFilter, capturedFilter); + } - @Test - void testFind_withNotFoundRepository() { + @Test + void testFind_withNotFoundRepository() { - //given: - Filter requestFilter = Filter.builder() - .withTarget(Launch.class).withCondition(FilterCondition.builder().eq("name", "name").build()) - .build(); + //given: + Filter requestFilter = Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq("name", "name").build()) + .build(); - QueryRQ queryRQ = new QueryRQ(); - queryRQ.setEntity(Launch.class.getSimpleName()); - queryRQ.setFilter(requestFilter); + QueryRQ queryRQ = new QueryRQ(); + queryRQ.setEntity(Launch.class.getSimpleName()); + queryRQ.setFilter(requestFilter); - //when: - assertThrows(ReportPortalException.class, () -> queryHandler.find(queryRQ)); - } + //when: + assertThrows(ReportPortalException.class, () -> queryHandler.find(queryRQ)); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListenerTest.java b/src/test/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListenerTest.java index c540bb3554..e86e86e793 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListenerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListenerTest.java @@ -1,5 +1,6 @@ package com.epam.ta.reportportal.ws.rabbit; +import static com.epam.ta.reportportal.ws.converter.converters.LogConverter.LOG_FULL_TO_LOG; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; @@ -29,8 +30,9 @@ import com.epam.ta.reportportal.entity.item.TestItem; import com.epam.ta.reportportal.entity.launch.Launch; import com.epam.ta.reportportal.entity.log.Log; +import com.epam.ta.reportportal.entity.log.LogFull; import com.epam.ta.reportportal.util.ProjectExtractor; -import com.epam.ta.reportportal.ws.converter.builders.LogBuilder; +import com.epam.ta.reportportal.ws.converter.builders.LogFullBuilder; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.StartTestItemRQ; @@ -239,12 +241,13 @@ void whenMessageReceived_andItemIsNotPresent_thenCreateLaunchLog() { when(launch.getId()).thenReturn(ID); when(launchRepository.findByUuid(LAUNCH_ID)).thenReturn(Optional.of(launch)); - Log log = new LogBuilder().addSaveLogRq(saveLogRQ).addLaunch(launch).addProjectId(ID).get(); + LogFull logFull = new LogFullBuilder().addSaveLogRq(saveLogRQ).addLaunch(launch).addProjectId(ID).get(); + final Log log = LOG_FULL_TO_LOG.apply(logFull); asyncReportingListener.onMessage(message); verify(logRepository).save(log); - verify(logService).saveLogMessageToElasticSearch(log, ID); + verify(logService).saveLogMessage(logFull, ID); verify(attachmentBinaryDataService).attachToLog( eq(binaryDataMetaInfo), any(AttachmentMetaInfo.class)); } @@ -277,7 +280,8 @@ void whenMessageReceived_andItemIsPresent_thenCreateItemLog() { TestItem testItem = mock(TestItem.class); when(testItemRepository.findByUuid(ITEM_ID)).thenReturn(Optional.of(testItem)); - Log log = new LogBuilder().addSaveLogRq(saveLogRQ).addTestItem(testItem).addProjectId(ID).get(); + LogFull logFull = new LogFullBuilder().addSaveLogRq(saveLogRQ).addTestItem(testItem).addProjectId(ID).get(); + final Log log = LOG_FULL_TO_LOG.apply(logFull); Launch launch = mock(Launch.class); when(launch.getId()).thenReturn(ID); @@ -286,7 +290,7 @@ void whenMessageReceived_andItemIsPresent_thenCreateItemLog() { asyncReportingListener.onMessage(message); verify(logRepository).save(log); - verify(logService).saveLogMessageToElasticSearch(log, ID); + verify(logService).saveLogMessage(logFull, ID); verify(attachmentBinaryDataService).attachToLog( eq(binaryDataMetaInfo), any(AttachmentMetaInfo.class)); } diff --git a/src/test/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumerTest.java b/src/test/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumerTest.java index a2c4a298d2..4410e8ea01 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumerTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/rabbit/QueryConsumerTest.java @@ -16,6 +16,10 @@ package com.epam.ta.reportportal.ws.rabbit; +import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import com.epam.ta.reportportal.commons.querygen.Filter; import com.epam.ta.reportportal.commons.querygen.FilterCondition; import com.epam.ta.reportportal.entity.launch.Launch; @@ -26,33 +30,29 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import static com.epam.ta.reportportal.commons.querygen.constant.GeneralCriteriaConstant.CRITERIA_ID; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) class QueryConsumerTest { - @Mock - private QueryHandler queryHandler; + @Mock + private QueryHandler queryHandler; - @InjectMocks - private QueryConsumer queryConsumer; + @InjectMocks + private QueryConsumer queryConsumer; - @Test - void find() { - QueryRQ queryRQ = new QueryRQ(); - queryRQ.setEntity("launch"); - queryRQ.setFilter(Filter.builder() - .withTarget(Launch.class) - .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "100").build()) - .build()); + @Test + void find() { + QueryRQ queryRQ = new QueryRQ(); + queryRQ.setEntity("launch"); + queryRQ.setFilter(Filter.builder() + .withTarget(Launch.class) + .withCondition(FilterCondition.builder().eq(CRITERIA_ID, "100").build()) + .build()); - queryConsumer.find(queryRQ); + queryConsumer.find(queryRQ); - verify(queryHandler, times(1)).find(queryRQ); - } + verify(queryHandler, times(1)).find(queryRQ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/validation/BusinessRuleTest.java b/src/test/java/com/epam/ta/reportportal/ws/validation/BusinessRuleTest.java index 6581451117..8671cc0bb8 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/validation/BusinessRuleTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/validation/BusinessRuleTest.java @@ -17,6 +17,8 @@ package com.epam.ta.reportportal.ws.validation; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.epam.ta.reportportal.commons.Predicates; import com.epam.ta.reportportal.commons.validation.BusinessRule; import com.epam.ta.reportportal.commons.validation.BusinessRuleViolationException; @@ -25,8 +27,6 @@ import com.epam.ta.reportportal.ws.model.ErrorType; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertThrows; - /** * Unit test for business rule logic * @@ -34,19 +34,21 @@ */ class BusinessRuleTest { - @Test - void testVerifyCustomError() { - assertThrows( - ReportPortalException.class, - () -> BusinessRule.expect("", Predicates.isNull()).verify(ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME, "") - ); - } + @Test + void testVerifyCustomError() { + assertThrows( + ReportPortalException.class, + () -> BusinessRule.expect("", Predicates.isNull()) + .verify(ErrorType.FINISH_TIME_EARLIER_THAN_START_TIME, "") + ); + } - @Test - void testVerifyBusinessError() { - assertThrows( - BusinessRuleViolationException.class, - () -> BusinessRule.expect("", Predicates.alwaysFalse(), Suppliers.stringSupplier("error")).verify() - ); - } + @Test + void testVerifyBusinessError() { + assertThrows( + BusinessRuleViolationException.class, + () -> BusinessRule.expect("", Predicates.alwaysFalse(), Suppliers.stringSupplier("error")) + .verify() + ); + } } \ No newline at end of file diff --git a/src/test/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidatorTest.java b/src/test/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidatorTest.java index 5a564c09cc..2d5b6e21c4 100644 --- a/src/test/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidatorTest.java +++ b/src/test/java/com/epam/ta/reportportal/ws/validation/JaskonRequiredPropertiesValidatorTest.java @@ -16,71 +16,72 @@ package com.epam.ta.reportportal.ws.validation; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; + import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.issue.Issue; import com.epam.ta.reportportal.ws.model.issue.IssueDefinition; import com.epam.ta.reportportal.ws.model.launch.StartLaunchRQ; -import org.junit.jupiter.api.Test; -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.Errors; - import java.util.Calendar; import java.util.Collections; import java.util.UUID; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import org.junit.jupiter.api.Test; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.Errors; /** * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ public class JaskonRequiredPropertiesValidatorTest { - @Test - public void testRequiredFields() { - StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); - startLaunchRQ.setDescription("some description"); - startLaunchRQ.setName("some launch name"); - startLaunchRQ.setAttributes(Collections.emptySet()); - JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); - Errors errors = new BeanPropertyBindingResult(startLaunchRQ, "startLaunchRq"); - validator.validate(startLaunchRQ, errors); - assertThat(errors.getAllErrors(), not(empty())); - assertThat(errors.getFieldError("startTime"), not(nullValue())); - } + @Test + public void testRequiredFields() { + StartLaunchRQ startLaunchRQ = new StartLaunchRQ(); + startLaunchRQ.setDescription("some description"); + startLaunchRQ.setName("some launch name"); + startLaunchRQ.setAttributes(Collections.emptySet()); + JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); + Errors errors = new BeanPropertyBindingResult(startLaunchRQ, "startLaunchRq"); + validator.validate(startLaunchRQ, errors); + assertThat(errors.getAllErrors(), not(empty())); + assertThat(errors.getFieldError("startTime"), not(nullValue())); + } - @Test - public void testInnerRequiredFields() { - IssueDefinition issueRQ = new IssueDefinition(); - JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); - Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); - validator.validate(issueRQ, errors); - assertThat(errors.getAllErrors(), not(empty())); - assertThat(errors.getFieldError("issue"), not(nullValue())); - } + @Test + public void testInnerRequiredFields() { + IssueDefinition issueRQ = new IssueDefinition(); + JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); + Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); + validator.validate(issueRQ, errors); + assertThat(errors.getAllErrors(), not(empty())); + assertThat(errors.getFieldError("issue"), not(nullValue())); + } - @Test - public void testInnerRequiredFields1() { - FinishTestItemRQ issueRQ = new FinishTestItemRQ(); - issueRQ.setLaunchUuid(UUID.randomUUID().toString()); - issueRQ.setEndTime(Calendar.getInstance().getTime()); - issueRQ.setStatus("PASSED"); - JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); - Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); - validator.validate(issueRQ, errors); - assertThat(errors.getAllErrors(), empty()); - } + @Test + public void testInnerRequiredFields1() { + FinishTestItemRQ issueRQ = new FinishTestItemRQ(); + issueRQ.setLaunchUuid(UUID.randomUUID().toString()); + issueRQ.setEndTime(Calendar.getInstance().getTime()); + issueRQ.setStatus("PASSED"); + JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); + Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); + validator.validate(issueRQ, errors); + assertThat(errors.getAllErrors(), empty()); + } - @Test - public void testInnerRequiredFields2() { - FinishTestItemRQ issueRQ = new FinishTestItemRQ(); - issueRQ.setEndTime(Calendar.getInstance().getTime()); - issueRQ.setStatus("PASSED"); - issueRQ.setIssue(new Issue()); - JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); - Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); - validator.validate(issueRQ, errors); - assertThat(errors.getAllErrors(), not(empty())); - } + @Test + public void testInnerRequiredFields2() { + FinishTestItemRQ issueRQ = new FinishTestItemRQ(); + issueRQ.setEndTime(Calendar.getInstance().getTime()); + issueRQ.setStatus("PASSED"); + issueRQ.setIssue(new Issue()); + JaskonRequiredPropertiesValidator validator = new JaskonRequiredPropertiesValidator(); + Errors errors = new BeanPropertyBindingResult(issueRQ, "issueRQ"); + validator.validate(issueRQ, errors); + assertThat(errors.getAllErrors(), not(empty())); + } } \ No newline at end of file diff --git a/src/test/resources/db/data-store/data-store-fill.sql b/src/test/resources/db/data-store/data-store-fill.sql index d062fc1f9f..c3c892cad4 100644 --- a/src/test/resources/db/data-store/data-store-fill.sql +++ b/src/test/resources/db/data-store/data-store-fill.sql @@ -1,10 +1,14 @@ -INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, last_modified, mode, status, has_retries, +INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, + last_modified, mode, status, has_retries, rerun, approximate_duration) -VALUES (1, 'uuid', 1, 1, 'launch', 'launch', now(), now(), now(), 'DEFAULT', 'FAILED', FALSE, FALSE, 0); +VALUES (1, 'uuid', 1, 1, 'launch', 'launch', now(), now(), now(), 'DEFAULT', 'FAILED', FALSE, FALSE, + 0); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, last_modified, path, unique_id, has_children, +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, + last_modified, path, unique_id, has_children, has_retries, has_stats, parent_id, retry_of, launch_id) -VALUES (1, 1, 'uuid', 'item', 'STEP', now(), 'desc', now(), '1', 'uniqueId', FALSE, FALSE, TRUE, NULL, NULL, 1); +VALUES (1, 1, 'uuid', 'item', 'STEP', now(), 'desc', now(), '1', 'uniqueId', FALSE, FALSE, TRUE, + NULL, NULL, 1); INSERT INTO log(id, uuid, log_time, log_message, item_id, last_modified, log_level, project_id) VALUES (1, 'uuid', now(), 'msg', 1, now(), 40000, 1); \ No newline at end of file diff --git a/src/test/resources/db/launch/launch-fill.sql b/src/test/resources/db/launch/launch-fill.sql index 2687f0ea2f..29530f9417 100644 --- a/src/test/resources/db/launch/launch-fill.sql +++ b/src/test/resources/db/launch/launch-fill.sql @@ -1,4 +1,5 @@ -INSERT INTO launch (id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, +INSERT INTO launch (id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status) VALUES (1, '4b02ef3a-56d6-443b-8cf7-27014bd53497', @@ -24,11 +25,14 @@ VALUES (1, now(), 'DEFAULT', 'FAILED'), - (3, 'befef834-b2ef-4acf-aea3-b5a5b15fd93c', 2, 2, 'empty launch', 'postman', now(), null, 1, now(), 'DEFAULT', + (3, 'befef834-b2ef-4acf-aea3-b5a5b15fd93c', 2, 2, 'empty launch', 'postman', now(), null, 1, + now(), 'DEFAULT', 'IN_PROGRESS'), - (4, '2e13b3df-298b-4052-beb8-426eedbc38ee', 1, 1, 'empty debug launch', 'postman', now(), null, 1, now(), + (4, '2e13b3df-298b-4052-beb8-426eedbc38ee', 1, 1, 'empty debug launch', 'postman', now(), + null, 1, now(), 'DEBUG', 'IN_PROGRESS'), - (5, 'e3adc64e-87cc-4781-b2d3-faa4ef1679dc', 2, 2, 'empty launch 2', 'postman', now(), null, 1, now(), 'DEFAULT', + (5, 'e3adc64e-87cc-4781-b2d3-faa4ef1679dc', 2, 2, 'empty launch 2', 'postman', now(), null, + 1, now(), 'DEFAULT', 'IN_PROGRESS'); INSERT INTO public.test_item (test_case_hash, item_id, diff --git a/src/test/resources/db/migration/V001003__integration_type.sql b/src/test/resources/db/migration/V001003__integration_type.sql index 1a5993323e..e88d88245a 100644 --- a/src/test/resources/db/migration/V001003__integration_type.sql +++ b/src/test/resources/db/migration/V001003__integration_type.sql @@ -1,3 +1,5 @@ -INSERT INTO integration_type (enabled, name, auth_flow, creation_date, group_type) VALUES (TRUE, 'rally', 'OAUTH', now(), 'BTS') ; +INSERT INTO integration_type (enabled, name, auth_flow, creation_date, group_type) +VALUES (TRUE, 'rally', 'OAUTH', now(), 'BTS'); -INSERT INTO integration_type (enabled, name, auth_flow, creation_date, group_type) VALUES (TRUE, 'jira', 'BASIC', now(), 'BTS'); \ No newline at end of file +INSERT INTO integration_type (enabled, name, auth_flow, creation_date, group_type) +VALUES (TRUE, 'jira', 'BASIC', now(), 'BTS'); \ No newline at end of file diff --git a/src/test/resources/db/migration/V0027__attachment_creation_date.up.sql b/src/test/resources/db/migration/V0027__attachment_creation_date.up.sql index 09ae930faa..cfc17b8475 100644 --- a/src/test/resources/db/migration/V0027__attachment_creation_date.up.sql +++ b/src/test/resources/db/migration/V0027__attachment_creation_date.up.sql @@ -1 +1,2 @@ -ALTER TABLE attachment ADD COLUMN creation_date TIMESTAMP; \ No newline at end of file +ALTER TABLE attachment + ADD COLUMN creation_date TIMESTAMP; \ No newline at end of file diff --git a/src/test/resources/db/migration/V0030__log_project_id.up.sql b/src/test/resources/db/migration/V0030__log_project_id.up.sql index e4c7a6bf9c..a19259e2fb 100644 --- a/src/test/resources/db/migration/V0030__log_project_id.up.sql +++ b/src/test/resources/db/migration/V0030__log_project_id.up.sql @@ -1 +1,2 @@ -ALTER TABLE log ADD COLUMN project_id BIGINT; \ No newline at end of file +ALTER TABLE log + ADD COLUMN project_id BIGINT; \ No newline at end of file diff --git a/src/test/resources/db/project-settings/project-settings-fill.sql b/src/test/resources/db/project-settings/project-settings-fill.sql index b719fd5816..5f39f3d259 100644 --- a/src/test/resources/db/project-settings/project-settings-fill.sql +++ b/src/test/resources/db/project-settings/project-settings-fill.sql @@ -1,10 +1,10 @@ -insert into issue_type (id, issue_group_id, locator, issue_name, abbreviation, hex_color) -values (6, 1, 'custom_ti', 'Custom to investigate', 'CTI', '#2f39bf'), +INSERT INTO issue_type (id, issue_group_id, locator, issue_name, abbreviation, hex_color) +VALUES (6, 1, 'custom_ti', 'Custom to investigate', 'CTI', '#2f39bf'), (7, 2, 'custom_ab', 'Custom automation bug', 'CAB', '#ccac39'), (8, 5, 'custom si', 'Custom system issue', 'CSI', '#08af2a'); -insert into issue_type_project(project_id, issue_type_id) -values (2, 6), +INSERT INTO issue_type_project(project_id, issue_type_id) +VALUES (2, 6), (2, 7), (2, 8); @@ -15,20 +15,20 @@ VALUES (1, 'default', 2), INSERT INTO public.filter (id, name, target, description) -VALUES (1, 'filter', 'Launch', null); +VALUES (1, 'filter', 'Launch', NULL); INSERT INTO public.filter_sort (id, filter_id, field, direction) VALUES (1, 1, 'name', 'ASC'); INSERT INTO public.filter_condition (id, filter_id, condition, value, search_criteria, negative) -VALUES (1, 1, 'CONTAINS', 'test', 'name', false); +VALUES (1, 1, 'CONTAINS', 'test', 'name', FALSE); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (2, 'overall statistics', null, 'overallStatistics', 20, '{"options": {}}'), - (3, 'launches table', null, 'launchesTable', 20, '{"options": {}}'); +VALUES (2, 'overall statistics', NULL, 'overallStatistics', 20, '{"options": {}}'), + (3, 'launches table', NULL, 'launchesTable', 20, '{"options": {}}'); -insert into content_field(id, field) -values (2, 'statistics$executions$total'), +INSERT INTO content_field(id, field) +VALUES (2, 'statistics$executions$total'), (2, 'statistics$executions$passed'), (2, 'statistics$executions$failed'), (2, 'statistics$executions$skipped'), @@ -62,4 +62,15 @@ insert into pattern_template(id, name, "value", type, enabled, project_id) values (1, 'some_name', 'value', 'STRING', true, 2), (2, 'simple_name', 'value', 'STRING', true, 2), (3, 'another_name', 'value', 'STRING', true, 1); -alter sequence pattern_template_id_seq restart with 4; \ No newline at end of file +alter sequence pattern_template_id_seq restart with 4; + +INSERT INTO public.sender_case (id, send_case, project_id, enabled, rule_name) +VALUES (1, 'ALWAYS', 2, TRUE, 'rule #1'), + (2, 'FAILED', 2, FALSE, 'rule #2'), + (3, 'TO_INVESTIGATE', 2, FALSE, 'rule #3'), + (4, 'MORE_10', 2, TRUE, 'rule #4'); + +ALTER SEQUENCE sender_case_id_seq RESTART WITH 5; + +INSERT INTO public.launch_names (sender_case_id, launch_name) +VALUES (1, 1); \ No newline at end of file diff --git a/src/test/resources/db/shareable/shareable-fill.sql b/src/test/resources/db/shareable/shareable-fill.sql index ad0f031691..3f9af7062c 100644 --- a/src/test/resources/db/shareable/shareable-fill.sql +++ b/src/test/resources/db/shareable/shareable-fill.sql @@ -1,7 +1,10 @@ -INSERT INTO public.users (id, login, password, email, attachment, attachment_thumbnail, role, type, expired, full_name, metadata) -VALUES (3, 'jaja_user', '7c381f9d81b0e438af4e7094c6cae203', 'jaja@mail.com', null, null, 'USER', 'INTERNAL', false, 'Jaja Juja', '{"metadata": {"last_login": 1546605767372}}'); +INSERT INTO public.users (id, login, password, email, attachment, attachment_thumbnail, role, type, + expired, full_name, metadata) +VALUES (3, 'jaja_user', '7c381f9d81b0e438af4e7094c6cae203', 'jaja@mail.com', null, null, 'USER', + 'INTERNAL', false, 'Jaja Juja', '{"metadata": {"last_login": 1546605767372}}'); -INSERT INTO public.project_user (user_id, project_id, project_role) VALUES (3, 1, 'MEMBER'); +INSERT INTO public.project_user (user_id, project_id, project_role) +VALUES (3, 1, 'MEMBER'); INSERT INTO public.owned_entity (id, owner, project_id) VALUES (1, 'superadmin', 1), @@ -23,53 +26,57 @@ VALUES (1, 'superadmin', 1), (17, 'default', 2), (18, 'default', 2); -INSERT INTO public.filter (id, name, target, description) VALUES -(1, 'Admin Filter', 'Launch', null), -(2, 'Admin Shared Filter', 'Launch', null), -(3, 'Default Filter', 'Launch', null), -(4, 'Default Shared Filter', 'Launch', null); +INSERT INTO public.filter (id, name, target, description) +VALUES (1, 'Admin Filter', 'Launch', null), + (2, 'Admin Shared Filter', 'Launch', null), + (3, 'Default Filter', 'Launch', null), + (4, 'Default Shared Filter', 'Launch', null); -INSERT INTO public.filter_sort (id, filter_id, field, direction) VALUES -(1, 1, 'name', 'ASC'), -(2, 2, 'name', 'DESC'), -(3, 3, 'name', 'ASC'), -(4, 4, 'name', 'DESC'); +INSERT INTO public.filter_sort (id, filter_id, field, direction) +VALUES (1, 1, 'name', 'ASC'), + (2, 2, 'name', 'DESC'), + (3, 3, 'name', 'ASC'), + (4, 4, 'name', 'DESC'); -INSERT INTO public.filter_condition (id, filter_id, condition, value, search_criteria, negative) VALUES -(1, 1, 'CONTAINS', 'asdf', 'name', false), -(2, 2, 'EQUALS', 'test', 'description', false), -(3, 3, 'EQUALS', 'juja', 'name', false), -(4, 4, 'EQUALS', 'qwerty', 'name', false); +INSERT INTO public.filter_condition (id, filter_id, condition, value, search_criteria, negative) +VALUES (1, 1, 'CONTAINS', 'asdf', 'name', false), + (2, 2, 'EQUALS', 'test', 'description', false), + (3, 3, 'EQUALS', 'juja', 'name', false), + (4, 4, 'EQUALS', 'qwerty', 'name', false); -INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) VALUES -(5, 'activity stream12', null, 'activityStream', 50, '{"options": {"user": "superadmin", "actionType": ["startLaunch", "finishLaunch"]}}'), -(7, 'INVESTIGATED PERCENTAGE OF LAUNCHES', null, 'investigatedTrend', 10, '{"options": {"timeline": "DAY"}}'), -(6, 'LAUNCH STATISTICS', null, 'launchStatistics', 10, '{"options": {"timeline": "WEEK"}}'), -(8, 'TEST CASES GROWTH TREND CHART', null, 'casesTrend', 10, '{"options": {}}'), -(9, 'LAUNCHES DURATION CHART', null, 'launchesDurationChart', 10, '{"options": {}}'), -(12, 'ACTIVITY STREAM', null, 'activityStream', 10, '{"options": {"user": "default", "actionType": ["startLaunch", "finishLaunch", "deleteLaunch"]}}'), -(10, 'FAILED CASES TREND CHART', null, 'bugTrend', 10, '{"options": {}}'), -(11, 'LAUNCH STATISTICS', null, 'launchStatistics', 10, '{"options": {"timeline": "WEEK"}}'); +INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) +VALUES (5, 'activity stream12', null, 'activityStream', 50, + '{"options": {"user": "superadmin", "actionType": ["startLaunch", "finishLaunch"]}}'), + (7, 'INVESTIGATED PERCENTAGE OF LAUNCHES', null, 'investigatedTrend', 10, + '{"options": {"timeline": "DAY"}}'), + (6, 'LAUNCH STATISTICS', null, 'launchStatistics', 10, '{"options": {"timeline": "WEEK"}}'), + (8, 'TEST CASES GROWTH TREND CHART', null, 'casesTrend', 10, '{"options": {}}'), + (9, 'LAUNCHES DURATION CHART', null, 'launchesDurationChart', 10, '{"options": {}}'), + (12, 'ACTIVITY STREAM', null, 'activityStream', 10, + '{"options": {"user": "default", "actionType": ["startLaunch", "finishLaunch", "deleteLaunch"]}}'), + (10, 'FAILED CASES TREND CHART', null, 'bugTrend', 10, '{"options": {}}'), + (11, 'LAUNCH STATISTICS', null, 'launchStatistics', 10, '{"options": {"timeline": "WEEK"}}'); insert into content_field(id, field) values (10, 'statistics$executions$failed'); -INSERT INTO public.widget_filter (widget_id, filter_id) VALUES -(6, 1), -(7, 2), -(8, 2), -(10, 3), -(11, 3); +INSERT INTO public.widget_filter (widget_id, filter_id) +VALUES (6, 1), + (7, 2), + (8, 2), + (10, 3), + (11, 3); -INSERT INTO public.dashboard (id, name, description, creation_date) VALUES -(13, 'test admin dashboard', 'admin shared dashboard', '2019-01-10 13:01:06.083000'), -(14, 'test admin private dashboard', 'admin dashboard', '2019-01-10 13:01:19.259000'), -(15, 'test jaja shared dashboard', 'jaja dashboard', '2019-01-10 13:01:51.417000'), -(16, 'test jaja private dashboard', 'jaja dashboard', '2019-01-10 13:01:59.015000'), -(17, 'test default shared dashboard', 'default dashboard', '2019-01-10 13:02:20.397000'), -(18, 'test default private dashboard', 'default dashboard', '2019-01-10 13:02:27.659000'); +INSERT INTO public.dashboard (id, name, description, creation_date) +VALUES (13, 'test admin dashboard', 'admin shared dashboard', '2019-01-10 13:01:06.083000'), + (14, 'test admin private dashboard', 'admin dashboard', '2019-01-10 13:01:19.259000'), + (15, 'test jaja shared dashboard', 'jaja dashboard', '2019-01-10 13:01:51.417000'), + (16, 'test jaja private dashboard', 'jaja dashboard', '2019-01-10 13:01:59.015000'), + (17, 'test default shared dashboard', 'default dashboard', '2019-01-10 13:02:20.397000'), + (18, 'test default private dashboard', 'default dashboard', '2019-01-10 13:02:27.659000'); -INSERT INTO public.dashboard_widget (dashboard_id, widget_id, widget_name, widget_owner, widget_type, widget_width, widget_height, +INSERT INTO public.dashboard_widget (dashboard_id, widget_id, widget_name, widget_owner, + widget_type, widget_width, widget_height, widget_position_x, widget_position_y) VALUES (13, 5, 'activity stream12', 'superadmin', 'activityStream', 5, 5, 0, 0), diff --git a/src/test/resources/db/test-item/item-change-status-from-failed.sql b/src/test/resources/db/test-item/item-change-status-from-failed.sql index 553c308079..92f31233f9 100644 --- a/src/test/resources/db/test-item/item-change-status-from-failed.sql +++ b/src/test/resources/db/test-item/item-change-status-from-failed.sql @@ -1,17 +1,21 @@ -- Passed launch with 4 step items -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into item_attribute(id, key, value, item_id, launch_id, system) values (1, 'skippedIssue', 'true', null, 1, true); +insert into item_attribute(id, key, value, item_id, launch_id, system) +values (1, 'skippedIssue', 'true', null, 1, true); -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid2', 'test item 1', 'TEST', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid3', 'step item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1.2', 1, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -20,7 +24,8 @@ set status = 'PASSED', end_time = now() where result_id = 2; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid4', 'step item 2', 'STEP', now(), 'desc', 'uuid3', now(), '1.3', 1, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -35,12 +40,14 @@ set status = 'PASSED', where result_id = 1; -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid5', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid5', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (5, 5, 'uuid6', 'step item 3', 'STEP', now(), 'desc', 'uuid5', now(), '4.5', 4, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); @@ -49,8 +56,9 @@ set status = 'PASSED', end_time = now() where result_id = 5; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid8', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid8', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -60,7 +68,8 @@ where result_id = 6; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (6, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid9', 'step item 7', 'STEP', now(), 'desc', 'uuid7', now(), '4.7', 4, 1); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); diff --git a/src/test/resources/db/test-item/item-change-status-from-interrupted.sql b/src/test/resources/db/test-item/item-change-status-from-interrupted.sql index 1754a78b0f..5b0a31da87 100644 --- a/src/test/resources/db/test-item/item-change-status-from-interrupted.sql +++ b/src/test/resources/db/test-item/item-change-status-from-interrupted.sql @@ -1,17 +1,21 @@ -- Passed launch with 4 step items -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid1', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into item_attribute(id, key, value, item_id, launch_id, system) values (1, 'skippedIssue', 'true', null, 1, true); +insert into item_attribute(id, key, value, item_id, launch_id, system) +values (1, 'skippedIssue', 'true', null, 1, true); -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid', 'test item 1', 'TEST', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'step item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1.2', 1, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -20,7 +24,8 @@ set status = 'PASSED', end_time = now() where result_id = 2; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid3', 'step item 2', 'STEP', now(), 'desc', 'uuid3', now(), '1.3', 1, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -35,12 +40,14 @@ set status = 'PASSED', where result_id = 1; -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (5, 5, 'uuid5', 'step item 3', 'STEP', now(), 'desc', 'uuid5', now(), '4.5', 4, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); @@ -49,7 +56,8 @@ set status = 'PASSED', end_time = now() where result_id = 5; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (6, 6, 'uuid6', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); @@ -58,7 +66,8 @@ set status = 'INTERRUPTED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'step item 7', 'STEP', now(), 'desc', 'uuid7', now(), '4.7', 4, 1); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); diff --git a/src/test/resources/db/test-item/item-change-status-from-passed.sql b/src/test/resources/db/test-item/item-change-status-from-passed.sql index 33352e9cd5..154417bb43 100644 --- a/src/test/resources/db/test-item/item-change-status-from-passed.sql +++ b/src/test/resources/db/test-item/item-change-status-from-passed.sql @@ -1,17 +1,21 @@ -- Passed launch with 4 step items -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'PASSED', false); -insert into item_attribute(id, key, value, item_id, launch_id, system) values (1, 'skippedIssue', 'true', null, 1, true); +insert into item_attribute(id, key, value, item_id, launch_id, system) +values (1, 'skippedIssue', 'true', null, 1, true); -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid1', 'test item 1', 'TEST', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'step item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1.2', 1, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -20,7 +24,8 @@ set status = 'PASSED', end_time = now() where result_id = 2; -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid3', 'step item 2', 'STEP', now(), 'desc', 'uuid3', now(), '1.3', 1, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -35,12 +40,14 @@ set status = 'PASSED', where result_id = 1; -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (5, 5, 'uuid5', 'step item 3', 'STEP', now(), 'desc', 'uuid5', now(), '4.5', 4, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); @@ -49,7 +56,8 @@ set status = 'PASSED', end_time = now() where result_id = 5; -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (6, 6, 'uuid6', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); @@ -58,7 +66,8 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'step item 7', 'STEP', now(), 'desc', 'uuid7', now(), '4.7', 4, 1); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); @@ -73,16 +82,21 @@ set status = 'PASSED', where result_id = 4; -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (2, 'l2_uuid', 1, 1, 'test launch without skipped issue', 'desc', now(), null, 1, now(), 'DEFAULT', 'PASSED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (2, 'l2_uuid', 1, 1, 'test launch without skipped issue', 'desc', now(), null, 1, now(), + 'DEFAULT', 'PASSED', false); -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (8, 8, 'uuid_s_8', 'test suite 1', 'SUITE', now(), 'desc', 'uuid4', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9, 'uuid_s_9', 'step item under suite', 'STEP', now(), 'desc', 'uuid7', now(), '8.9', 8, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid_s_9', 'step item under suite', 'STEP', now(), 'desc', 'uuid7', now(), '8.9', 8, + 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -96,11 +110,15 @@ set status = 'PASSED', where result_id = 8; -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (3, 'l3_uuid', 1, 1, 'test launch to finish', 'desc', now(), null, 1, now(), 'DEFAULT', 'PASSED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (3, 'l3_uuid', 1, 1, 'test launch to finish', 'desc', now(), null, 1, now(), 'DEFAULT', + 'PASSED', false); -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10, 'uuid_s_2_8', 'test suite 2_1', 'SUITE', now(), 'desc', 'uuid4', now(), '10', null, 3); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid_s_2_8', 'test suite 2_1', 'SUITE', now(), 'desc', 'uuid4', now(), '10', null, + 3); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results @@ -108,7 +126,9 @@ set status = 'PASSED', end_time = now() where result_id = 10; -insert into test_item(test_case_hash, item_id, uuid,name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (11, 11, 'uuid_s_2_9', 'step item under suite 2_1', 'STEP', now(), 'desc', 'uuid7', now(), '10.11', 10, 3); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (11, 11, 'uuid_s_2_9', 'step item under suite 2_1', 'STEP', now(), 'desc', 'uuid7', now(), + '10.11', 10, 3); insert into test_item_results(result_id, status) values (11, 'IN_PROGRESS'); \ No newline at end of file diff --git a/src/test/resources/db/test-item/item-change-status-from-skipped.sql b/src/test/resources/db/test-item/item-change-status-from-skipped.sql index 44a3b45758..3fd4e60e19 100644 --- a/src/test/resources/db/test-item/item-change-status-from-skipped.sql +++ b/src/test/resources/db/test-item/item-change-status-from-skipped.sql @@ -1,17 +1,21 @@ -- Passed launch with 4 step items -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into item_attribute(id, key, value, item_id, launch_id, system) values (1, 'skippedIssue', 'true', null, 1, true); +insert into item_attribute(id, key, value, item_id, launch_id, system) +values (1, 'skippedIssue', 'true', null, 1, true); -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid1', 'test item 1', 'TEST', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'step item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1.2', 1, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -20,8 +24,9 @@ set status = 'PASSED', end_time = now() where result_id = 2; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'step item 2', 'STEP', now(), 'desc', 'uuid3', now(), '1.3', 1, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'step item 2', 'STEP', now(), 'desc', 'uuid3', now(), '1.3', 1, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -35,13 +40,15 @@ set status = 'PASSED', where result_id = 1; -- Test level item with 2 step items -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 1', 'TEST', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'step item 3', 'STEP', now(), 'desc', 'uuid5', now(), '4.5', 4, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'step item 3', 'STEP', now(), 'desc', 'uuid5', now(), '4.5', 4, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -49,8 +56,9 @@ set status = 'PASSED', end_time = now() where result_id = 5; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'step item 4', 'STEP', now(), 'desc', 'uuid6', now(), '4.6', 4, 1); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -58,7 +66,8 @@ set status = 'SKIPPED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'step item 7', 'STEP', now(), 'desc', 'uuid7', now(), '4.7', 4, 1); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); diff --git a/src/test/resources/db/user/user-customer.sql b/src/test/resources/db/user/user-customer.sql index dddbedc617..a4c23e1951 100644 --- a/src/test/resources/db/user/user-customer.sql +++ b/src/test/resources/db/user/user-customer.sql @@ -1,5 +1,7 @@ INSERT INTO users (login, password, email, role, type, full_name, expired, metadata) -VALUES ('default_customer', '5d39d85bddde885f6579f8121e11eba2', 'customeremail@domain.com', 'USER', 'INTERNAL', 'tester', FALSE, +VALUES ('default_customer', '5d39d85bddde885f6579f8121e11eba2', 'customeremail@domain.com', 'USER', + 'INTERNAL', 'tester', FALSE, '{"metadata": {"last_login": 0}}'); -INSERT INTO project_user (user_id, project_id, project_role) VALUES ((SELECT currval(pg_get_serial_sequence('users', 'id'))), 2, 'CUSTOMER'); +INSERT INTO project_user (user_id, project_id, project_role) +VALUES ((SELECT currval(pg_get_serial_sequence('users', 'id'))), 2, 'CUSTOMER'); diff --git a/src/test/resources/db/user/user-fill.sql b/src/test/resources/db/user/user-fill.sql index d55fb2798e..2dceea1356 100644 --- a/src/test/resources/db/user/user-fill.sql +++ b/src/test/resources/db/user/user-fill.sql @@ -1,5 +1,10 @@ -INSERT INTO user_creation_bid (uuid, email, default_project_id, role, inviting_user_id) -VALUES ('e5f98deb-8966-4b2d-ba2f-35bc69d30c06', 'test@domain.com', 2, 'MEMBER', 1); +INSERT INTO user_creation_bid (uuid, email, project_name, role, metadata, inviting_user_id) +VALUES ('e5f98deb-8966-4b2d-ba2f-35bc69d30c06', 'test@domain.com', 'default_personal', 'MEMBER', +'{ + "metadata": { + "type": "internal" + } + }', 1); INSERT INTO restore_password_bid (uuid, last_modified, email) VALUES ('e5f98deb-8966-4b2d-ba2f-35bc69d30c06', now(), 'defaultemail@domain.com'); @@ -7,13 +12,6 @@ VALUES ('e5f98deb-8966-4b2d-ba2f-35bc69d30c06', now(), 'defaultemail@domain.com' INSERT INTO integration (project_id, type, enabled, params, creator, creation_date, name) VALUES (2, 2, TRUE, NULL, 'superadmin', now(), 'integration name'); -INSERT INTO public.oauth_access_token (id, token_id, token, authentication_id, username, user_id, client_id, authentication, refresh_token) -VALUES (3, '1089a992-a931-4b5c-8194-09c925168b37', - E'\\xACED0005737200436F72672E737072696E676672616D65776F726B2E73656375726974792E6F61757468322E636F6D6D6F6E2E44656661756C744F4175746832416363657373546F6B656E0CB29E361B24FACE0200064C00156164646974696F6E616C496E666F726D6174696F6E74000F4C6A6176612F7574696C2F4D61703B4C000A65787069726174696F6E7400104C6A6176612F7574696C2F446174653B4C000C72656672657368546F6B656E74003F4C6F72672F737072696E676672616D65776F726B2F73656375726974792F6F61757468322F636F6D6D6F6E2F4F417574683252656672657368546F6B656E3B4C000573636F706574000F4C6A6176612F7574696C2F5365743B4C0009746F6B656E547970657400124C6A6176612F6C616E672F537472696E673B4C000576616C756571007E000578707372001E6A6176612E7574696C2E436F6C6C656374696F6E7324456D7074794D6170593614855ADCE7D002000078707070737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C65536574801D92D18F9B80550200007872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C0001637400164C6A6176612F7574696C2F436F6C6C656374696F6E3B7870737200176A6176612E7574696C2E4C696E6B656448617368536574D86CD75A95DD2A1E020000787200116A6176612E7574696C2E48617368536574BA44859596B8B7340300007870770C000000103F400000000000017400036170697874000662656172657274002431303839613939322D613933312D346235632D383139342D303963393235313638623337', - 'ec119aafb40d36d6757f5b3ffccf8b32', 'default', 2, 'api', - E'\\xACED0005737200416F72672E737072696E676672616D65776F726B2E73656375726974792E6F61757468322E70726F76696465722E4F417574683241757468656E7469636174696F6EBD400B02166252130200024C000D73746F7265645265717565737474003C4C6F72672F737072696E676672616D65776F726B2F73656375726974792F6F61757468322F70726F76696465722F4F4175746832526571756573743B4C00127573657241757468656E7469636174696F6E7400324C6F72672F737072696E676672616D65776F726B2F73656375726974792F636F72652F41757468656E7469636174696F6E3B787200476F72672E737072696E676672616D65776F726B2E73656375726974792E61757468656E7469636174696F6E2E416273747261637441757468656E7469636174696F6E546F6B656ED3AA287E6E47640E0200035A000D61757468656E746963617465644C000B617574686F7269746965737400164C6A6176612F7574696C2F436F6C6C656374696F6E3B4C000764657461696C737400124C6A6176612F6C616E672F4F626A6563743B787000737200266A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C654C697374FC0F2531B5EC8E100200014C00046C6973747400104C6A6176612F7574696C2F4C6973743B7872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C00016371007E00047870737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D03000149000473697A65787000000001770400000001737200426F72672E737072696E676672616D65776F726B2E73656375726974792E636F72652E617574686F726974792E53696D706C654772616E746564417574686F7269747900000000000002080200014C0004726F6C657400124C6A6176612F6C616E672F537472696E673B7870740009524F4C455F555345527871007E000C707372003A6F72672E737072696E676672616D65776F726B2E73656375726974792E6F61757468322E70726F76696465722E4F41757468325265717565737400000000000000010200075A0008617070726F7665644C000B617574686F72697469657371007E00044C000A657874656E73696F6E7374000F4C6A6176612F7574696C2F4D61703B4C000B726564697265637455726971007E000E4C00077265667265736874003B4C6F72672F737072696E676672616D65776F726B2F73656375726974792F6F61757468322F70726F76696465722F546F6B656E526571756573743B4C000B7265736F7572636549647374000F4C6A6176612F7574696C2F5365743B4C000D726573706F6E7365547970657371007E0014787200386F72672E737072696E676672616D65776F726B2E73656375726974792E6F61757468322E70726F76696465722E426173655265717565737436287A3EA37169BD0200034C0008636C69656E74496471007E000E4C001172657175657374506172616D657465727371007E00124C000573636F706571007E00147870740003617069737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C654D6170F1A5A8FE74F507420200014C00016D71007E00127870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F40000000000006770800000008000000047400056772616E7474000870617373776F726474000A6772616E745F7479706570740009636C69656E745F696471007E0017740008757365726E616D6574000764656661756C7478737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F6469666961626C65536574801D92D18F9B80550200007871007E0009737200176A6176612E7574696C2E4C696E6B656448617368536574D86CD75A95DD2A1E020000787200116A6176612E7574696C2E48617368536574BA44859596B8B7340300007870770C000000103F4000000000000171007E001778017371007E0025770C000000103F40000000000000787371007E001A3F40000000000000770800000010000000007870707371007E0025770C000000103F40000000000000787371007E0025770C000000103F40000000000000787372004F6F72672E737072696E676672616D65776F726B2E73656375726974792E61757468656E7469636174696F6E2E557365726E616D6550617373776F726441757468656E7469636174696F6E546F6B656E00000000000002080200024C000B63726564656E7469616C7371007E00054C00097072696E636970616C71007E00057871007E0003017371007E00077371007E000B0000000177040000000171007E000F7871007E002E707400034E2F4173720031636F6D2E6570616D2E74612E7265706F7274706F7274616C2E636F6D6D6F6E732E5265706F7274506F7274616C557365729177CA61D787FB2E0200044C0005656D61696C71007E000E4C000E70726F6A65637444657461696C7371007E00124C00067573657249647400104C6A6176612F6C616E672F4C6F6E673B4C000875736572526F6C6574002F4C636F6D2F6570616D2F74612F7265706F7274706F7274616C2F656E746974792F757365722F55736572526F6C653B787200326F72672E737072696E676672616D65776F726B2E73656375726974792E636F72652E7573657264657461696C732E5573657200000000000002080200075A00116163636F756E744E6F6E457870697265645A00106163636F756E744E6F6E4C6F636B65645A001563726564656E7469616C734E6F6E457870697265645A0007656E61626C65644C000B617574686F72697469657371007E00144C000870617373776F726471007E000E4C0008757365726E616D6571007E000E7870010101017371007E0022737200116A6176612E7574696C2E54726565536574DD98509395ED875B0300007870737200466F72672E737072696E676672616D65776F726B2E73656375726974792E636F72652E7573657264657461696C732E5573657224417574686F72697479436F6D70617261746F720000000000000208020000787077040000000171007E000F78740020336664653662623035343133383765346562646164663763326666333131323371007E002174001764656661756C74656D61696C40646F6D61696E2E636F6D7371007E001A3F400000000000017708000000020000000174001064656661756C745F706572736F6E616C73720040636F6D2E6570616D2E74612E7265706F7274706F7274616C2E636F6D6D6F6E732E5265706F7274506F7274616C557365722450726F6A65637444657461696C731F175AB834A625AD0200034C000970726F6A656374496471007E00314C000B70726F6A6563744E616D6571007E000E4C000B70726F6A656374526F6C657400354C636F6D2F6570616D2F74612F7265706F7274706F7274616C2F656E746974792F70726F6A6563742F50726F6A656374526F6C653B78707372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000000000000571007E003D7E720033636F6D2E6570616D2E74612E7265706F7274706F7274616C2E656E746974792E70726F6A6563742E50726F6A656374526F6C6500000000000000001200007872000E6A6176612E6C616E672E456E756D0000000000000000120000787074000F50524F4A4543545F4D414E41474552787371007E004100000000000000027E72002D636F6D2E6570616D2E74612E7265706F7274706F7274616C2E656E746974792E757365722E55736572526F6C6500000000000000001200007871007E004574000455534552', - NULL); - INSERT INTO api_keys( id, name, hash, created_at, user_id) VALUES (1, 'test', '1E2CEACB608044C8C900C7A5FB43ED593BC97DBC559D0F03D6FC59D5EB58303F', now(), 1); \ No newline at end of file diff --git a/src/test/resources/db/widget/bug-trend.sql b/src/test/resources/db/widget/bug-trend.sql index fc520d13e1..8e390e533d 100644 --- a/src/test/resources/db/widget/bug-trend.sql +++ b/src/test/resources/db/widget/bug-trend.sql @@ -1,8 +1,10 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,7 +25,8 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,8 +86,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -88,8 +98,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -97,8 +108,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/cases-trend.sql b/src/test/resources/db/widget/cases-trend.sql index 6f6e97518a..6570a2ba35 100644 --- a/src/test/resources/db/widget/cases-trend.sql +++ b/src/test/resources/db/widget/cases-trend.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,7 +74,8 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); @@ -77,8 +86,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8,'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -88,8 +98,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9,'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -97,8 +108,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10,'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/flaky-test-cases.sql b/src/test/resources/db/widget/flaky-test-cases.sql index baaab8788a..563c79e13f 100644 --- a/src/test/resources/db/widget/flaky-test-cases.sql +++ b/src/test/resources/db/widget/flaky-test-cases.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7,'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,8 +86,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -88,8 +98,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -97,20 +108,34 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results set status = 'FAILED', end_time = now() where result_id = 10; + +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (11, 11, 'uuid11', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '11', null, 2); +insert into test_item_results(result_id, status) +values (11, 'IN_PROGRESS'); +update test_item_results +set status = 'FAILED', + end_time = now() +where result_id = 11; + insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (10, 1, 'to investigate', false, true); -- Third launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', + false); -- Filter and widget INSERT INTO public.owned_entity (id, owner, project_id) @@ -120,7 +145,11 @@ VALUES (1, 'superadmin', 1), (4, 'superadmin', 1); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (1, 'flaky test cases', null, 'flakyTestCases', 10, '{"options": {"launchNameFilter": "test launch"}}'), - (2, 'flaky test cases', null, 'flakyTestCases', 10, '{"options": {"launchNameFilter": "not_exist"}}'), - (3, 'flaky test cases', null, 'flakyTestCases', 10, '{"options": {"launchNameFilter": "empty launch"}}'), - (4, 'flaky test cases', null, 'flakyTestCases', 10, '{"options": {"launchNameFilter": "test launch", "includeMethods": true}}'); +VALUES (1, 'flaky test cases', null, 'flakyTestCases', 10, + '{"options": {"launchNameFilter": "test launch"}}'), + (2, 'flaky test cases', null, 'flakyTestCases', 10, + '{"options": {"launchNameFilter": "not_exist"}}'), + (3, 'flaky test cases', null, 'flakyTestCases', 10, + '{"options": {"launchNameFilter": "empty launch"}}'), + (4, 'flaky test cases', null, 'flakyTestCases', 10, + '{"options": {"launchNameFilter": "test launch", "includeMethods": true}}'); diff --git a/src/test/resources/db/widget/investigated-trend.sql b/src/test/resources/db/widget/investigated-trend.sql index f972dc1273..7cd1493e98 100644 --- a/src/test/resources/db/widget/investigated-trend.sql +++ b/src/test/resources/db/widget/investigated-trend.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,7 +13,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -22,7 +25,8 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -33,7 +37,8 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); @@ -42,7 +47,8 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); @@ -54,10 +60,12 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); @@ -66,7 +74,8 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); @@ -77,7 +86,8 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); @@ -88,7 +98,8 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); @@ -97,7 +108,8 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); @@ -125,7 +137,8 @@ VALUES (1, 1, 'CONTAINS', 'test', 'name', false); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) VALUES (2, 'investigated trend', null, 'investigatedTrend', 10, '{"options": {}}'), - (3, 'investigated trend', null, 'investigatedTrend', 10, '{"options": {"timeline": "WEEK"}}'); + (3, 'investigated trend', null, 'investigatedTrend', 10, + '{"options": {"timeline": "WEEK"}}'); insert into widget_filter(widget_id, filter_id) values (2, 1), diff --git a/src/test/resources/db/widget/launch-statistics.sql b/src/test/resources/db/widget/launch-statistics.sql index 2c5b2aaf21..60d2cbd2c0 100644 --- a/src/test/resources/db/widget/launch-statistics.sql +++ b/src/test/resources/db/widget/launch-statistics.sql @@ -1,8 +1,10 @@ -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -10,7 +12,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -21,8 +24,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -32,8 +36,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -41,8 +46,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/launches-comparison-chart.sql b/src/test/resources/db/widget/launches-comparison-chart.sql index 3f4d028ad9..e7e1dcf603 100644 --- a/src/test/resources/db/widget/launches-comparison-chart.sql +++ b/src/test/resources/db/widget/launches-comparison-chart.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,7 +37,8 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7,'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,7 +86,8 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); @@ -88,8 +98,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9,'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -97,7 +108,8 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); @@ -128,8 +140,10 @@ VALUES (1, 1, 'CONTAINS', 'test', 'name', false), (4, 4, 'EQUALS', 'mot_exist', 'name', false); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (2, 'launch comparison', null, 'launchesComparisonChart', 20, '{"options": {"launchNameFilter": "test launch"}}'), - (3, 'launch comparison', null, 'launchesComparisonChart', 20, '{"options": {"launchNameFilter": "test launch"}}'); +VALUES (2, 'launch comparison', null, 'launchesComparisonChart', 20, + '{"options": {"launchNameFilter": "test launch"}}'), + (3, 'launch comparison', null, 'launchesComparisonChart', 20, + '{"options": {"launchNameFilter": "test launch"}}'); insert into content_field(id, field) values (2, 'statistics$executions$total'), diff --git a/src/test/resources/db/widget/launches-duration-chart.sql b/src/test/resources/db/widget/launches-duration-chart.sql index c59ca8f7ad..7ce324da0a 100644 --- a/src/test/resources/db/widget/launches-duration-chart.sql +++ b/src/test/resources/db/widget/launches-duration-chart.sql @@ -1,10 +1,14 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (1, 'uuid', 1, 1, 'test launch', 'desc', now() - interval '9 minute', now(), 1, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (1, 'uuid', 1, 1, 'test launch', 'desc', now() - interval '9 minute', now(), 1, now(), + 'DEFAULT', 'FAILED', false); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (2, 'uuid2', 1, 1, 'test launch', 'desc', now() - interval '11 minute', now(), 2, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (2, 'uuid2', 1, 1, 'test launch', 'desc', now() - interval '11 minute', now(), 2, now(), + 'DEFAULT', 'FAILED', false); -- Filters and widgets INSERT INTO public.owned_entity (id, owner, project_id) diff --git a/src/test/resources/db/widget/launches-table.sql b/src/test/resources/db/widget/launches-table.sql index 1d59fbcec5..6b2935539d 100644 --- a/src/test/resources/db/widget/launches-table.sql +++ b/src/test/resources/db/widget/launches-table.sql @@ -1,12 +1,16 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into item_attribute(key, value, launch_id) VALUES ('key', 'value', 2); -insert into item_attribute(key, value, launch_id) VALUES ('key1', 'value1', 2); +insert into item_attribute(key, value, launch_id) +VALUES ('key', 'value', 2); +insert into item_attribute(key, value, launch_id) +VALUES ('key1', 'value1', 2); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -14,8 +18,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7,'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -25,8 +30,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8,'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -36,8 +42,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9,'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -45,8 +52,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10,'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/most-time-consuming.sql b/src/test/resources/db/widget/most-time-consuming.sql index 35ce4a3440..d746ef9ddd 100644 --- a/src/test/resources/db/widget/most-time-consuming.sql +++ b/src/test/resources/db/widget/most-time-consuming.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -12,8 +14,9 @@ set status = 'PASSED', duration = 165.0 where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -24,8 +27,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -36,8 +40,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -46,8 +51,9 @@ set status = 'PASSED', duration = 87.0 where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -59,8 +65,10 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (2, 'uuid1', 1, 1, 'empty launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (2, 'uuid1', 1, 1, 'empty launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', + false); -- Filter and widgets INSERT INTO public.owned_entity (id, owner, project_id) @@ -84,9 +92,12 @@ VALUES (1, 1, 'CONTAINS', 'test', 'name', false), (2, 2, 'EQUALS', 'mot_exist', 'name', false); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (3, 'most time consuming', null, 'mostTimeConsuming', 20, '{"options": {"launchNameFilter": "test launch"}}'), - (4, 'most time consuming', null, 'mostTimeConsuming', 20, '{"options": {"launchNameFilter": "empty launch"}}'), - (5, 'most time consuming', null, 'mostTimeConsuming', 20, '{"options": {"launchNameFilter": "not exist"}}'), +VALUES (3, 'most time consuming', null, 'mostTimeConsuming', 20, + '{"options": {"launchNameFilter": "test launch"}}'), + (4, 'most time consuming', null, 'mostTimeConsuming', 20, + '{"options": {"launchNameFilter": "empty launch"}}'), + (5, 'most time consuming', null, 'mostTimeConsuming', 20, + '{"options": {"launchNameFilter": "not exist"}}'), (6, 'most time consuming', null, 'mostTimeConsuming', 20, '{"options": {"launchNameFilter": "test launch", "includeMethods": true}}'); diff --git a/src/test/resources/db/widget/not-passed.sql b/src/test/resources/db/widget/not-passed.sql index 7b812928b4..4946da68c5 100644 --- a/src/test/resources/db/widget/not-passed.sql +++ b/src/test/resources/db/widget/not-passed.sql @@ -1,8 +1,10 @@ -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -10,7 +12,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -21,8 +24,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -32,7 +36,8 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); @@ -41,8 +46,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/old-line-chart.sql b/src/test/resources/db/widget/old-line-chart.sql index 3be685f012..4095bac6ef 100644 --- a/src/test/resources/db/widget/old-line-chart.sql +++ b/src/test/resources/db/widget/old-line-chart.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,7 +13,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,7 +37,8 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/overall-statistics.sql b/src/test/resources/db/widget/overall-statistics.sql index 3efec2045b..16fc8ea1ad 100644 --- a/src/test/resources/db/widget/overall-statistics.sql +++ b/src/test/resources/db/widget/overall-statistics.sql @@ -1,8 +1,10 @@ -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -10,7 +12,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -21,8 +24,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -32,8 +36,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -41,8 +46,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/passing-rate-per-launch.sql b/src/test/resources/db/widget/passing-rate-per-launch.sql index 6db0eaec2c..d21c0cb9f8 100644 --- a/src/test/resources/db/widget/passing-rate-per-launch.sql +++ b/src/test/resources/db/widget/passing-rate-per-launch.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,10 +60,12 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7,'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,8 +86,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8,'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -88,7 +98,8 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); @@ -97,8 +108,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10,'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results @@ -109,8 +121,10 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (10, 1, 'to investigate', false, true); -- Third launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', + false); -- Filter and widget INSERT INTO public.owned_entity (id, owner, project_id) diff --git a/src/test/resources/db/widget/passing-rate-summary.sql b/src/test/resources/db/widget/passing-rate-summary.sql index bba8808a15..63cb3e8e78 100644 --- a/src/test/resources/db/widget/passing-rate-summary.sql +++ b/src/test/resources/db/widget/passing-rate-summary.sql @@ -1,8 +1,10 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,7 +86,8 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); @@ -88,7 +98,8 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); @@ -97,8 +108,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results diff --git a/src/test/resources/db/widget/product-status.sql b/src/test/resources/db/widget/product-status.sql index f06b0eff35..e554a5fe8b 100644 --- a/src/test/resources/db/widget/product-status.sql +++ b/src/test/resources/db/widget/product-status.sql @@ -1,11 +1,13 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); insert into item_attribute(id, key, value, item_id, launch_id, system) values (1, 'key', 'val', null, 1, false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); @@ -14,7 +16,8 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); @@ -25,7 +28,8 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); @@ -36,7 +40,8 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); @@ -45,7 +50,8 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); @@ -57,10 +63,12 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); @@ -69,7 +77,8 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); @@ -80,7 +89,8 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); @@ -91,7 +101,8 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); @@ -100,7 +111,8 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); @@ -138,8 +150,10 @@ VALUES (1, 1, 'CONTAINS', 'test', 'name', false), (3, 1, 'CONTAINS', 'test', 'name', false); INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (4, 'product status', null, 'productStatus', 10, '{"options": {"strategy": "launch", "customColumns": {"column": "key"}}}'), - (5, 'product status', null, 'productStatus', 10, '{"options": {"strategy": "launch", "customColumns": {"column": "key"}}}'), +VALUES (4, 'product status', null, 'productStatus', 10, + '{"options": {"strategy": "launch", "customColumns": {"column": "key"}}}'), + (5, 'product status', null, 'productStatus', 10, + '{"options": {"strategy": "launch", "customColumns": {"column": "key"}}}'), (6, 'cases trend', null, 'casesTrend', 10, '{"options": {}}'), (7, 'cases trend', null, 'casesTrend', 10, '{"options": {"timeline": "notPresent"}}'), (8, 'cases trend', null, 'casesTrend', 10, '{"options": {"timeline": "WEEK"}}'); diff --git a/src/test/resources/db/widget/top-test-cases.sql b/src/test/resources/db/widget/top-test-cases.sql index 4fec70f950..bdb02b5326 100644 --- a/src/test/resources/db/widget/top-test-cases.sql +++ b/src/test/resources/db/widget/top-test-cases.sql @@ -1,9 +1,11 @@ -- First launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (1, 'uuid', 1, 1, 'test launch', 'desc', now(), null, 1, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (1, 1,'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', null, 1); insert into test_item_results(result_id, status) values (1, 'IN_PROGRESS'); update test_item_results @@ -11,8 +13,9 @@ set status = 'PASSED', end_time = now() where result_id = 1; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (2, 2,'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', null, 1); insert into test_item_results(result_id, status) values (2, 'IN_PROGRESS'); update test_item_results @@ -22,8 +25,9 @@ where result_id = 2; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (2, 2, 'automation bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (3, 3,'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', null, 1); insert into test_item_results(result_id, status) values (3, 'IN_PROGRESS'); update test_item_results @@ -33,8 +37,9 @@ where result_id = 3; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (3, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (4, 4,'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', null, 1); insert into test_item_results(result_id, status) values (4, 'IN_PROGRESS'); update test_item_results @@ -42,8 +47,9 @@ set status = 'PASSED', end_time = now() where result_id = 4; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (5, 5,'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', null, 1); insert into test_item_results(result_id, status) values (5, 'IN_PROGRESS'); update test_item_results @@ -54,11 +60,13 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (5, 1, 'to investigate', false, true); -- Second launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) values (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (6, 6,'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', null, 2); insert into test_item_results(result_id, status) values (6, 'IN_PROGRESS'); update test_item_results @@ -66,8 +74,9 @@ set status = 'PASSED', end_time = now() where result_id = 6; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (7, 7,'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', null, 2); insert into test_item_results(result_id, status) values (7, 'IN_PROGRESS'); update test_item_results @@ -77,8 +86,9 @@ where result_id = 7; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (7, 1, 'unknown bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (8, 8,'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', null, 2); insert into test_item_results(result_id, status) values (8, 'IN_PROGRESS'); update test_item_results @@ -88,8 +98,9 @@ where result_id = 8; insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) values (8, 3, 'product bug', false, true); -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (9, 9,'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', null, 2); insert into test_item_results(result_id, status) values (9, 'IN_PROGRESS'); update test_item_results @@ -97,8 +108,9 @@ set status = 'SKIPPED', end_time = now() where result_id = 9; -insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) -values (10, 10,'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); +insert into test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) +values (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', null, 2); insert into test_item_results(result_id, status) values (10, 'IN_PROGRESS'); update test_item_results @@ -109,8 +121,10 @@ insert into issue(issue_id, issue_type, issue_description, auto_analyzed, ignore values (10, 1, 'to investigate', false, true); -- Third launch -insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) -values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', false); +insert into launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) +values (3, 'uuid3', 1, 1, 'empty launch', 'desc', now(), null, 2, now(), 'DEFAULT', 'FAILED', + false); -- Filter and widget INSERT INTO public.owned_entity (id, owner, project_id) @@ -121,10 +135,14 @@ VALUES (1, 'superadmin', 1), INSERT INTO public.widget (id, name, description, widget_type, items_count, widget_options) -VALUES (1, 'top test cases', null, 'topTestCases', 20, '{"options": {"launchNameFilter": "test launch"}}'), - (2, 'top test cases', null, 'topTestCases', 20, '{"options": {"launchNameFilter": "empty launch"}}'), - (3, 'top test cases', null, 'topTestCases', 20, '{"options": {"launchNameFilter": "not exist launch"}}'), - (4, 'top test cases', null, 'topTestCases', 20, '{"options": {"launchNameFilter": "test launch", "includeMethods": true}}'); +VALUES (1, 'top test cases', null, 'topTestCases', 20, + '{"options": {"launchNameFilter": "test launch"}}'), + (2, 'top test cases', null, 'topTestCases', 20, + '{"options": {"launchNameFilter": "empty launch"}}'), + (3, 'top test cases', null, 'topTestCases', 20, + '{"options": {"launchNameFilter": "not exist launch"}}'), + (4, 'top test cases', null, 'topTestCases', 20, + '{"options": {"launchNameFilter": "test launch", "includeMethods": true}}'); insert into content_field(id, field) values (1, 'statistics$executions$failed'), diff --git a/src/test/resources/db/widget/unique-bug-table.sql b/src/test/resources/db/widget/unique-bug-table.sql index 753761e23a..7b6ae02a77 100644 --- a/src/test/resources/db/widget/unique-bug-table.sql +++ b/src/test/resources/db/widget/unique-bug-table.sql @@ -1,8 +1,10 @@ -- First launch -INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) VALUES (1, 'uuid', 1, 1, 'test launch', 'desc', now(), NULL, 1, now(), 'DEFAULT', 'FAILED', FALSE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (1, 1, 'uuid1', 'test item 1', 'STEP', now(), 'desc', 'uuid1', now(), '1', NULL, 1); INSERT INTO test_item_results(result_id, status) VALUES (1, 'IN_PROGRESS'); @@ -11,7 +13,8 @@ SET status = 'PASSED', end_time = now() WHERE result_id = 1; -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (2, 2, 'uuid2', 'test item 2', 'STEP', now(), 'desc', 'uuid2', now(), '2', NULL, 1); INSERT INTO test_item_results(result_id, status) VALUES (2, 'IN_PROGRESS'); @@ -22,14 +25,16 @@ WHERE result_id = 2; INSERT INTO issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) VALUES (2, 2, 'automation bug', FALSE, TRUE); INSERT INTO ticket(id, ticket_id, submitter, bts_url, submit_date, url, bts_project) -VALUES (1, 'ticket1', 'superadmin', 'http:/example.com', now(), 'http:/example.com/ticket1', 'superadmin_bts'); +VALUES (1, 'ticket1', 'superadmin', 'http:/example.com', now(), 'http:/example.com/ticket1', + 'superadmin_bts'); INSERT INTO issue_ticket(issue_id, ticket_id) VALUES (2, 1); INSERT INTO item_attribute(key, value, item_id, launch_id, system) VALUES (NULL, 'test', 2, NULL, FALSE), (NULL, 'value', 2, NULL, FALSE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (3, 3, 'uuid3', 'test item 3', 'STEP', now(), 'desc', 'uuid3', now(), '3', NULL, 1); INSERT INTO test_item_results(result_id, status) VALUES (3, 'IN_PROGRESS'); @@ -40,7 +45,8 @@ WHERE result_id = 3; INSERT INTO issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) VALUES (3, 3, 'product bug', FALSE, TRUE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (4, 4, 'uuid4', 'test item 4', 'STEP', now(), 'desc', 'uuid4', now(), '4', NULL, 1); INSERT INTO test_item_results(result_id, status) VALUES (4, 'IN_PROGRESS'); @@ -49,7 +55,8 @@ SET status = 'PASSED', end_time = now() WHERE result_id = 4; -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (5, 5, 'uuid5', 'test item 5', 'STEP', now(), 'desc', 'uuid5', now(), '5', NULL, 1); INSERT INTO test_item_results(result_id, status) VALUES (5, 'IN_PROGRESS'); @@ -61,10 +68,12 @@ INSERT INTO issue(issue_id, issue_type, issue_description, auto_analyzed, ignore VALUES (5, 1, 'to investigate', FALSE, TRUE); -- Second launch -INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, last_modified, mode, status, has_retries) +INSERT INTO launch(id, uuid, project_id, user_id, name, description, start_time, end_time, number, + last_modified, mode, status, has_retries) VALUES (2, 'uuid2', 1, 1, 'test launch', 'desc', now(), NULL, 2, now(), 'DEFAULT', 'FAILED', FALSE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (6, 6, 'uuid6', 'test item 1', 'STEP', now(), 'desc', 'uuid6', now(), '6', NULL, 2); INSERT INTO test_item_results(result_id, status) VALUES (6, 'IN_PROGRESS'); @@ -73,7 +82,8 @@ SET status = 'PASSED', end_time = now() WHERE result_id = 6; -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (7, 7, 'uuid7', 'test item 2', 'STEP', now(), 'desc', 'uuid7', now(), '7', NULL, 2); INSERT INTO test_item_results(result_id, status) VALUES (7, 'IN_PROGRESS'); @@ -84,7 +94,8 @@ WHERE result_id = 7; INSERT INTO issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) VALUES (7, 1, 'unknown bug', FALSE, TRUE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (8, 8, 'uuid8', 'test item 3', 'STEP', now(), 'desc', 'uuid8', now(), '8', NULL, 2); INSERT INTO test_item_results(result_id, status) VALUES (8, 'IN_PROGRESS'); @@ -95,7 +106,8 @@ WHERE result_id = 8; INSERT INTO issue(issue_id, issue_type, issue_description, auto_analyzed, ignore_analyzer) VALUES (8, 3, 'product bug', FALSE, TRUE); -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (9, 9, 'uuid9', 'test item 4', 'STEP', now(), 'desc', 'uuid9', now(), '9', NULL, 2); INSERT INTO test_item_results(result_id, status) VALUES (9, 'IN_PROGRESS'); @@ -104,7 +116,8 @@ SET status = 'SKIPPED', end_time = now() WHERE result_id = 9; -INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, last_modified, path, parent_id, launch_id) +INSERT INTO test_item(test_case_hash, item_id, uuid, name, type, start_time, description, unique_id, + last_modified, path, parent_id, launch_id) VALUES (10, 10, 'uuid10', 'test item 5', 'STEP', now(), 'desc', 'uuid10', now(), '10', NULL, 2); INSERT INTO test_item_results(result_id, status) VALUES (10, 'IN_PROGRESS'); diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index e3f22441eb..3065ff9ea5 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -1,16 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> <configuration> - <include resource="org/springframework/boot/logging/logback/base.xml"/> - <logger name="org.springframework" level="ERROR"/> - <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> - <encoder> - <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n</pattern> - </encoder> - </appender> + <include resource="org/springframework/boot/logging/logback/base.xml"/> + <logger name="org.springframework" level="ERROR"/> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - + %msg%n + </pattern> + </encoder> + </appender> - <logger name="org.springframework.security" level="info"/> + <logger name="org.springframework.security" level="info"/> - <root level="info"> - <appender-ref ref="STDOUT"/> - </root> + <root level="info"> + <appender-ref ref="STDOUT"/> + </root> </configuration> \ No newline at end of file From 6f65e2d58ff7b78a31e84ea1763de978845d9ac2 Mon Sep 17 00:00:00 2001 From: Pavel Bortnik <pavel_bortnik@epam.com> Date: Fri, 1 Mar 2024 11:54:56 +0300 Subject: [PATCH 15/25] 5.11.0 || Update gradle wrapper jar --- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f93135c49b765f8051ef9d0a6055ff8e46073d8 100644 GIT binary patch literal 63721 zcmb5Wb9gP!wgnp7wrv|bwr$&XvSZt}Z6`anZSUAlc9NHKf9JdJ;NJVr`=eI(_pMp0 zy1VAAG3FfAOI`{X1O)&90s;U4K;XLp008~hCjbEC_fbYfS%6kTR+JtXK>nW$ZR+`W ze|#J8f4A@M|F5BpfUJb5h>|j$jOe}0<b<>oE!`Zf6fM>C<V>R?!y@zU(cL8NsKk`a z6tx5mAk<liamrzlCS@BsX~|&`RS-HU8cGq`t>djD;J=LcJ;;Aw8p!v#ouk>mUDZF@ zK>yvw%+bKu+T{N<MgC_~H%9||dlSch>k@LZ;zkYy0HBKw06_IWcM<!q!PNfx0T}}e zTRJ0a11G0!b#QO&CEQP4n)k!|A)#qSG|8;N24)yY|3OH|n9Ef#Qn-}F#h?W3i%43c z)2szbS#t|1^laxjK<9Y@_Ix3>Ho*0HKpTsEFZhn<oTMi&w}vW*Ra?K_!_)1rk7w^0 zcz%y-9{{$<M=0I0eaFor!J){*JHz%a;XWx9WpR5@-ICoSDBGt4RNpQ|Al>5qCHH9j z)|XpN&{`!0a>Vl+PmdQc)Yg4A(AG-z!+@Q#eHr&g<9D?7E)_aEB?s_rx>UE9TUq|? z;(ggJt>9l?C|zoO@5)tu?<y?2z)*Z;1quxvz;2Wr$0J)*8MlO}_`_m{D`H0p@e^(M z$iAC}1xU~1A4L(ddtDLl_Pr6{Hx8(|zsON}%665gG;b|X+4q@!y;YHT4o3!{_{jPB z>EV0x_7T17q4fF-q3{yZ^ipUbKcRZ4Qftd!xO(#UGhb2y>?*@{xq%`(-`2T^vc=#< zx!+@4pRdk&*1ht2OWk^Z5IAQ0YTAXLkL{(D*$gENaD)7A%^XXrCchN&<gtMWk{spc zdf)IQ%Esm7d(=p(gnM#+I?kJb&Lb5@<u)2i>z2x+*>o2FwPFjWpeaL=!tzv#JOW#( z$B)Nel<+$bkH1KZv3&-}=SiG~w2sbDbAWarg%5>YbC|}*d9hBjBkR(@tyM0T)FO$# zPtRXukGPnOd)~z=?avu+4Co@wF}1T)-uh5jI<1$HLtyDrVak{gw`mcH@Q-@wg{v^c zRzu}hMKFHV<8w}o*yg6p@Sq%=gkd~;`_VGTS?L@yVu`xuGy+dH6YOwcP6ZE`_0rK% zAx5!FjDuss`FQ3eF|mhrWkjux(Pny^k$u_)dyCSEbAsecHsq#8B3n3kDU(zW5yE|( zgc>sFQywFj5}U*qtF9Y(bi*;>B7WJykcAXF86@)z|0-Vm<fczTCmKxlM?(K(U1MI{ zH7CsNY39I?b2iW&6QmO%p`j~N;r{IyO6k!4?8&O+JtB37&qWiLadcH|I)VEU4X_&G z2Ff&+i<CegULNGA;Rqo82kZIenL`+2Sql2b=gdn7-sCd|*$dW%v3%JHM_jz-$G*h( z2Zhp66mL0wC-)~7Dg~G4tT5AYOjgU1YJq|3QV~+nZV4#kZI8ONh{_OOoJD(-6)TQN zW~`V4m}~|uOv@KO-ydJ-Zh&N$+FY<g0*jjHHbxmR>@jt!EPoLA6>r)?@DIobIZ5Sx zsc@OC{b|3%vaMbyeM|O^UxEYlEMHK4r)V-{r)_yz`w1*xV0|lh-LQOP`OP`Pk1aW( z8DSlG<ofVg|3LaJ-=P0V))`RIkE+lq+qJ{`jPVl(|5Va1SGyg3MTkZ3a5}sBX&c*A ztSA~lX)HnZl`w$}6pc6PwMwbP#y;;c$+yzscOU^s%U^DuE7fk%u_oE_r4U9DlvWzf zB&zu$+)hR%%$d2sDve|n{X>N>Ts|n*xj+%If~+E_B<wY#42?CSY)Lp9f}%hd8G2BV zYz5{>xK)~5T#w6Q1WEKt{!Xtbd`J;`2a>8boRo;7u2M&iOop4qcy<)z023=oghSFV zST;?S;ye+dRQe>ygiJ6HCv4;~3DHtJ({fWeE~$H@mKn@Oh6Z(_sO>01JwH5oA4nvK zr5<Xf@p4l8GDDqq9Ca=)oYjzaL8(efxR9(LX_X`~m?l6@BVW;!8T+Uyif6_AH70S3 z1&@6Mj!ceBBfVQ`!9u3Zf{wVpf0C(t(aC=1R{{IVv+00AMAS(+n-xbkL&B4F#nFqZ ztPDBX@p?jtnq^cL=+U%~e$BEw+yxI)sZyO4JhtoSg*p=}x1?BGLbn0LMY>Sr^g+LC zLt(i&ecdmqsIJGNOSUyUpglvhhrY8lGkzO=0USEKNL%8zHshS>Qziu|`eyWP^5xL4 zRP122_dCJl>hZc~?58w~><cp^hJ_ZV5fj>`P_s18VoU|7(|Eit0-lZRgLTZKNq5{k zE?V=`7=R&ro(X%LTS*f+#H-mGo_j3dm@F_krAYegDLk6UV{`UKE;{<k$0*s;%bL~F z;<2lwblZB7HV^gmjYfnL$(oz3yiwuVBNdItsJS*edKT4)myLcW$QJUM;r94>YSsn$ z(yz{v1@p|p!0>g04!eRSrSVb>MQYPr8_MA|MpoGzqyd*$@4j|)cD_%^Hrd>SorF>@ zBX+V<@vEB5PRLGR(uP9&U&5=(HVc?6B58NJT_igiAH*q~Wb`dDZpJSKfy5#Aag4IX zj~uv74EQ_Q_1qaXWI!7Vf@ZrdUhZFE;L&P_Xr8l@GMkhc#=plV0+g(ki>+7fO%?Jb zl+b<?C%WXJNEX{LzvH<usRTrr8A!~O>Ty7q{w^pTb{>(Xf2q1BVdq?#f=!geqssXp z4pMu*q;iiHmA*IjOj4`4S&|8@gSw*^{|PT}Aw~}ZXU`6=vZ<Hcy3%$%v9V&0Kee&a zKV!#7+J;9|6x<uodo*>B=GGeMm}V6W46|pU&58~P+?LUs%n@J}CSrICkeng6YJ^M? zS(W?K4nOtoBe4tvBXs@@`i<!ZAMR~@rqD5uMjjRS2DHf>?4G$S2W&;$z8VBSM;Mn9 zxcaEiQ9=v<fz_-ouh|d?S}QqE(0qsl4bj8_Oo|Bt%%h=cX$JXg7?LJ&<ET0ro2;%t z1-1gS%DOru2m?YDj1D3wKn1f3YvfFowv0`#z<)Q7Eu0mY1aD;Bp(<0D*dvtLJmX0i zAI;vT=wP6!8*)iKc4+k{>S|bIJ>*tf9AH~m&U%2+Dim<)E=<ebn)#5-YItTnbgMqQ zt=Y>}KORp+cZ^!@wI`h1NVBXu{@%hB2Cq(dXx_aQ9x3mr*fwL5!ZryQqi|KFJuzvP zK1)nrKZ7U+B{1ZmJub?4)Ln^J6k!i0t~VO#=q1{?T)%OV?MN}k5M{}vjyZu#M0_*u z8jwZKJ#Df~1jcLXZL7bnCEhB6IzQZ-GcoQJ!16I*39iazoVGugcKA{lhiHg4Ta2fD zk1Utyc<n(<e1-Rj>5%QzZ$s3;p0N+N8VX{sd!~l*Ta3|t>lhI&G`sr6L~G5Lul`>m z{!^INm?J|&7X=;{XveF!(b*=?9NAp4y&r&N3(GKcW4rS(Ejk|Lzs1PrxPI_owB-`H zg3(Rruh^&)`TKA6+_!n>RdI6pw>Vt1_j&+bKIaMTYLiqhZ#y_=J8`TK{Jd<7l9&sY z^^`hmi7^14s16B6)1O;vJWOF$=$B5ONW;;2&|pUvJlmeUS&F;DbSHCrEb0QBDR|my zIs+pE0Y^`q<Mo02TIpLU)qh7WQ?@rM6U&!Z;VW(ggXdTSsIrFphI+dpATgu%)3IHs z@+Xj*BwLyZ=r@R=;kqR6lCAdnF<CWp%t6J7J#JoVQ!Q2LM-rk#T_J^oRW%%3=2#t< zlx+Py@hbE`=>JTyH-_mP=)Y+u^LHcuZhsM3+P||?+W#V!_6E-8boP#R-*na4!o-Q1 zVthtYhK{mDhF(&7Okzo9dTi03X(AE{8cH$JIg%MEQc<ZbLh@dc$w|qk{r@1?l>a`S zy@8{Fjft~~BdzWC(di#X{ny;!yYGK9b@=b|zcKZ{vv4D8i+`ilOPl;PJl{!&5-0!w z<G-5=7&<vS8W=eX+1c0_*cwY)*qR90*}8t;u!-Ye>^fOl#|}vVg%=n)@_e1BrP)`A zKPgs`O0EO}Y2KWLuo`iGaKu1k#YR6BMySxQf2V++Wo{6EH<oD|H%>mK>A~Q5o73yM z-RbxC7Qdh0Cz!nG+7BRZE>~FLI-?&W_rJUl-8FDIaXoNBL)@1hwKa^wOr1($*5h~T zF;%f^%<$p8Y_yu(JEg=c_O!aZ#)Gjh$n(hfJAp$C2he555W5zdrBqjFmo|VY+el;o z=*D_w|GXG|p0**hQ7~9-n|y5k%B}TAF0iarDM!q-jYbR^us(>&y;n^2l0C%@2B}KM zyeRT9)oMt97Agvc4sEKUEy%M<cvw&A<E0smes0HD4KT3M{WaOQQ;89w>pXr2vz*lb zh*L}}iG>-pqDRw7ud{=FvTD?}<cu3Tk)KD+t)3BG<`{7$)a-(xssJsd76$3kXZ|K+ zux7WJ7n@%B)`GvtXt2vB^wx3Cq%hbMjsz#YIUp6%4@(wA$XOe1;039$$Hc7QvIpbU zLS8D9A2JK!>xjD)w{`KzjNom-$jS^;iw0+7n<H%EYFc(Oy%QoCT$qyKODp6T3?dHk z!A)db&e@dFRGDaEZ1f6Uhkq#S5W3t3q@<p|gafXRD$(FZPe|Di#nme60l3B9fVDQI z7v|md<AFmDM_>XSnt1R@G|VqoRh<xeTuMLt3A;kkH;cO*#r^ytgz}n?7coM19}rK` z);^|be>E%12<OWj>nm+PH?9`(4rM0kfrZzIK9JU=^$YNyLvAIoxl#Q)xxDz!^0@zZ zSCs$nfcxK_vRYM34O<1}Q<iD$7sC+}q<B7R-C|JDpp;azgo0#wbVy`Lz$zBEbO-~2 z>HZ|hp4`ioX3x8(UV(FU$J@o%tw3t4k1QPmlEpZa2IujG&(roX_q*%e`Hq|);0;@k z0z=fZiFckp#JzW0p+2A+D$PC~IsakhJJkG(c;CqAgFfU0Z`u$PzG~-9I1oPHrC<wq zp!=`znU^{;qwI4(IwPTBbeO&*i}Y=rKz<}0qd2sSuD;n+Mp~oxu2u^U_@*f$2SH4& zl?ba0Bgc;6q%NBUleYBwY{7zE^Vfp-*+^4E--SmUnP*kpPGgQ7i#F(|?Htpi_BGIr zb@Gxu5=<~CQJoX};=}ZoAqI?aQ`aURT7|_bL85cc5*32Ec(l3BkkWJ!;u(fz)0rjQ zM$>w&)@s^Dc~^)#<wKTL<XKhL5mN0<#J&V|X6YXFoTAHh1v3e?`1qzOHJxAfrJ&Ia z>HPW0Ra}J^=|h7Fs*<8|b13ZzG6MP*Q1dkoZ6&A^!}|hbjM{2HpqlSXv_UUg1U4gn z3Q)2VjU^ti1myod<e*tXJ``;<uRxWgHj9DL9reuUk;3Yai3$ZVxc$Lik!QkFkY_p- zQ0zfew$syu%`J??OaA$e3yhROoyi??MOs)*6Y|FoRjo5YG8>v+tjhSZp%D978m~p& z43uZUrraHs80Mq&vcetqfQpQP?m!CFj)44t8Z}k`E798wxg&~aCm+DBoI+nKq}&j^ zlPY3W$)K;KtEajks1`G?-@me7C>{PiiBu+41#yU_c(dITaqE?IQ(DBu+c^Ux!>pCj zLC|HJGU*v+!it1(;3e`6igkH(VA)-S+k(*yqxM<DMa${DuB@U~n2TvsN>gUah3$@C zz`7hEM47xr>j8^g`%*f=6S5n>z%Bt_Fg{Tvmr+MIsCx=0gsu_sF`q2hlkEmisz#Fy zj_0;zUWr;Gz}$BS%Y`meb(=$d%@Crs(<S5im8rZJ+hXaeF4?)$Bxlh$wotZoqo;9C zoV$lbzz-{=kDm#H-UEvsDLF6Q650PW_m^)`Fnl2k7$|cT<4p%DP+QQ%Pm<dng5Tlm zJY!}F9=K|jqEaN6rLUGWH!wZ0U(TSP7a_ulN!0{(D76G_DCCMYc~&1UiwGoGVvr{o zKJ*3=vWF1EmCF?ngO(A#QHO73AHw39x4#7x|2*uRJP=H^WAL{ITtOufKQPefaR-dw z;G$VL`0sIgw-zB%E@}zvSQFs9-~l@jy~i@_j=aHRkdEWSDI;LT_XD0ffYvUye7<si z2Fb>OoJ|}m#<7=-A~PQbyN$x%2iXP2@e*nO0b7AwfH8cCUa*Wfu@b)D_>I*%uE4O3 z(lfnB`-Xf<Eah_TH0`p#iJ%bwIruYbtv4=iev1%ADQ5<nqfk9TiY>*L<pJwX*6 z6rk6>fC)E}e?%X2kK7DItK6Tf<+M^mX0Ijf_!IP>7c8IZX%8_#0060P{QMuV^B<Nc z0Y@_z8xvb+5qBdKduI!~zgMP`<EJEn8Bv1e-k1xUTQqH`&-$;LRKPb?p@^XRcl%SW z7A(?4O_9bX%W97*cKg9^@&`$1Rhl479TL49uifNE-$%}|e=@U3QRq(u*`T|i!vY;= zLFYU{oP~b!`V{F3i<~?v4T-GsVj-c>9i<^E`_Qf0pv9(P%_<ZnXV3#<!Itln<wgcO z_ag@&>s8D`qvDE9LK9u-jB}J2S`(mCO&XHTS04Z5Ez*vl^T%!^$<HtTbQGA?-M`Fa zN~3r+{;f4I^wTt)Y$;V0A?b}t39$3`u-!SmQRz2~BgR0Y22AtoiqyTce$gRQ#;)xn z(H=h1rzHb3B0D>~EH8M-UdwhegL>3IQ*)(MtuH2Xt1p!fS4o~*rR?WLxlA!sjc2(O znjJn~wQ!Fp9s2e^IWP1C<4%sFF}T4omr}7+4asciyo3DntTgWIzhQpQirM$9{EbQd z3jz9vS@{<x6RjX4HShz$XJL7Gv9^MIhKL19l!vXDKtut8g2a8N<h+4&Yt&WgZG-0p z_>aOqTQHI|l#aUV@2Q^Wko4T0T04Me4!2nsdrA8QY1%fnAYb~d2GDz@lAtfcHq(P7 zaMBAGo}+NcE-K*@9y;Vt3*(aCaMKXBB*BJcD_Qnx<UAAx@pFpd`WS-_yK7SJSHbCM zJ+sycj{FkEU&9Ysa-wV2!;2(ImdDdIZgJ}`9j;jTiYPXEDq*CO`T4-t*|XS#9~HNC zu96BV=Ry2qi)VUChoa}C_CB44h;*&oc0EWPU$hYH8{zPphs-sTrb;$I`Tk25Ef6wI z)-7g@DMK6f){DP<6&$RnaJ4vp86eii6XT#?kKzCG^Hnm1S^@(5e!g%30A&B?^OgGt zSI<_}azj?Z*h(zPW=Yo#YqH4KJ|wab#BOfNtKQV48`7O!MvH)0FqQ@{NoPp6N4$3X z1K#yg(se^X=dYqMag+$(^NRillP<Mw#+WO8vuGkT>pt75r?GeAQ}*|>pYJE=uZb73 zC>sv)18)q#EGrTG6io*}JLuB_jP3AU1Uiu$D7r|2<a!(dEKJOdD7OJ~`mJ#&3lVWo z2(|vK+K6Dp{tAw<@IDkF-OU~{Fey=i5LyAY`xe{ZP)J-QHDxPH%5%%ni&>_zlIGb9 zjhst#ni)Y`$)!fc#reM*$~iaYoz~_Cy7J3ZTiPm)E?%`fbk`3Tu-F#`{i!l5pNEn5 zO-Tw-=TojYhzT{J=?SZj=Z8#|eoF>434b-DXiU<dJw*iNTYgDXXO3%H4$mrD2+2if zR#sZlF&7^<X^ey&*l`pd(b870Yl;d^q~$DJ4j>si<i1L1H7=S6VPERSA>gnxXNaR3 zm_}4iWU$gt2Mw5NvZ5(Vp<B5%4ml4%u2XX{cb%`vs{9^lq|NV~2Us}ADnGUgJZqX- zvwS;i%5bY0rx<UeBWyPSiTAfxZ8Te<Y^2=Q6Uyjb@`B9@uPO^RqSGRQ8L=vx?~S*{ zt!O7dY09tk+Q(K@^7dsqbRFj3D?R)D=uSPhZfFr)&^PL7B^!(GLR_d(Kw!yNd&IP$ znV)B>F`?X*f2UZDs1TEa1oZCif?Jdgr{>O~7}-$|BZ7I(IKW`{f;@|IZFX*R8&iT= zoWstN8&R;}@2Ka%d3vrLtR|O??ben;k8QbS-WB0VgiCz;<$pBmIZdN!aalyCS<xwK zC7(yN8jDThv(|6XTqj5k)nXJHl?i2Q&>Em)crpS9dcD^Y@XT1a3+zpi-`D}e#HV<} z$Y(G&o~PvL-xSVD5D?JqF3?B9rxGWeb=oEGJ3vRp5xfBPlngh1O$yI95EL+T8{GC@ z98i1H9KhZGFl|;`)_=QpM6H?eDPpw~^(aFQWwyXZ8_EEE4#@QeT_URray*mEOGsGc z6|sdXtq!hVZo=d#+9^@lm&L5|q&-GDCyUx#YQiccq;spOBe3V+VKdjJA=IL=Zn%P} zNk=_8u}VhzFf{UYZV0`lUwcD&)9AFx0@Fc6LD9A6Rd1=ga>Mi0)_QxM2ddCVRmZ0d z+J=uXc(?5JLX3=)e)Jm$HS2yF`44IKhwRnm2*669_J=<i2xqPYPe_t`z^~U4bI&mS zeK8h(VJQzW*&0F;1J5rkP14OFRVV|<ULvN%7sx(;Rti9xZLhau-~!P2{WfUAn2q*` zd|=*_Vb!;8;KGMfl41$VF7fE>2LlwuF5$1tAo@ROSU@-y+;Foy2IEl2^V1N;fk~YR z?&EP8#t&m0B=?aJeuz~lH<ij*LuuHi5!4Rd8ZU2wg>jAzRBX>&x=A;gIvb>MD{XEV zV%l-+9N-)i;YH%nKP?>f`=?#`>B(`*t`aiPLoQM(a6(qs4p5KFjDBN?8JGrf3z8>= zi7sD)c)Nm~x{e<^jy4nTx${P~cwz_*a>%0_;ULou<DyN^`2@H+<{3q_pZ|fCRGf^h zvtT4FGJj|vS-l9;nX`=;6AMdLY77qfRlAH(xzJbez);$Wc|j0JS86%Riccga7l&Q^ z7DDh5jhBvJ0eBnJZoBnclA)#bn$D1A`JT3aY&tu3wlfU}!It+X%B_(|pGP1-6at%6 z9G;Q{hFp?BH`-HYKrn-(5-7%bIR8)}bl%^bc}8y}>3kHCAD7EYkw@l$8TN#LO9jC( z1B<i{*|v`>eFW`k+bu5e8Ns^a8dPcjEVHM;r6UX+cN=Uy7HU)j-myRU0wHd$<r<rS z?gfFH3ULExuxO;h09`>A1fNI~`4;I~`zC)3ul#8#^rXVSO*m}Ag>c%_;nj=Nv$rCZ z*~L@C@OZg%Q^m)lc-kcX&a*a5`y&DaRxh6O*dfhLfF+fU5wKs(1v*!TkZidw*)YBP za@r`3+^IHRFeO%!ai%rxy;R;;V^Fr=OJlpBX;(b*3+SIw<j-Y9ZSgmH9DO&6{}V;z z4IG_J97!1eDmMg22|)ETAc%aKH#bAM9(9CS1?uKgKtu$Phh55R&4VPI?P<FMz>}7= zIq$*Thr(Zft-RlY)D3e8V;BmD&HOfX+E$H#Y@B3?UL5L~_fA-@*IB-!gItK7PIgG9 zgWuGZK_nuZjHVT_Fv(XxtU%)58;W39vzTI2n&)&4Dmq7&JX6G>XFaAR{7_3QB6zsT z?$L8c*WdN~nZGiscY%5KljQARN;`w$gho=p006z;n(qIQ*Zu<``TMO3n0{ARL@gYh zoRwS*|Niw~cR!?hE{m*y@F`1)vx-JRfqET=dJ5_(076st(=lFfjtKHoYg`k3oNmo_ zNbQEw8&sO5jAYmkD|Zaz_yUb0rC})U<yhPFxA*<jTKd}k{c~z90FpaZKIj}7mLZZR zVlskQe<0xI9>!rCHOl}JhbYIDLzLvrZVw0~JO`d*6f;X&?V=#T@ND*cv^I;`sFeq4 z##H5;gpZTb^0Hz@3C*~u0AqqNZ-r%rN3KD~%Gw`0XsIq$(^MEb<~H(2*5G^<2(*aI z%7}WB+TRlMIrEK<z8Y-G_4JTi0dxbex2YwD(&eIklPGFZaWLB&GD=ZnUD^~B#;k{< zjP^KiL#JbSns`pE$?*&<=bFPwu*}^i6&=HjW3#5UHflvIkmn+HmO8$)V)qRxk*3l@ zOO9ib60_+Zpll9hiP2eYZBRUKjvXd)MdN}}smA0!UK^qy;<^pk_jf6elpJ`B)>#s0 z93xn*Ohb=kWFc)BNHG4I(~RPn-R8#0lqyBBz5OM6o5|>x9LK@%HaM}}Y5goCQRt2C z{j*2TtT4ne!Z}vh89mjwiSXG=%DURar~=kGNNaO_+Nkb+tRi~Rkf!7a$*QlavziD( z83s4GmQ^Wf*0Bd04f#0H<rzc{Zw2|AZqo(GiNDwicoG{misd0-Mku7fEh(b%bV@{& zro_rCgoAMr<vEX067x&DjEdA&lB?SNTC@l2#eL4j&Fx~(S<U2Qj$}%g_p>X@ua_d8 z23~z*53ePD6@xwZ(vdl0DLc=>cPIOPOdca&MyR^jhhKrdQO?_jJh`xV3GKz&2lvP8 zEOwW6L*ufvK;TN{=S&R@pzV^U=Q<n5LbrjaQ=f5@7_~`mTQ9mj1lTX|puGXCkhc-% zDqQ!ov(P;Fh`r;zNT#tw6ShQ_Wb=wsd)-t85jQ<PT~cSb(KG~zb^;j9%nmc1=u1J= znM6vCx;p+afnlGOK^Z(FtJX%b2Laq9%EC)v3-}QHS=dL;;3Z|eP=v~{8Igl4x<in+ zs+~^lyBk3)zB{QIT=g<UC4Dvc@uY$A(I$Qm(r%M)rb;eRGv~cUyVvsbhIKxiBZOdE z&4GjvPs^czPS?~yx=kmokn<?z^Iu|gjSZTs;5%U;1OKb!`@bg*{}`ix5nQLgVzWB= zOBPuGVWiiKw%d`msf^&W1_DTJ7XVcxDttFKPMJj@Q@p^`V#d*Pi+Mxn7SS91D^8en zZty#+i)vgc%xXIPl}6Ud+}N0#zLvf5`S$Ta{!?R<CC_N_2bR$mN%T1dmbl^kFBBTw z1ujzzCe&Kp;{r{`peY9BJL9Pe30)VP%6+b7BRXtX7mFD)e?pfD#2CL!17n(PpRUO` z?Yjz)8OniiQ=hFAxt9*96eH5w{w=1|n0X<i`5k*Km^JQNZ!JF0bM74Zvj&6~ZAXtn zgG9^ASe$T762j2Jcgl0`Y(Mo@H6OZ<lK6bTs)vl;gOmx8Db2@XVoT@)D;P*RE2{Pu zkq|sNVFWHy%(o0jW-8h@<pE7_$58cKk*4~kS1*H4Ot~s|!`6&RJxm(c3R*s0mV_8; zn2FG~1NRH*S@8AcCakja5ctO6KJ`a7lcApLvK|cc`*cNA(|7?@ShdEJko*Iz0dJa* za(Cjc=YoMHSiGhp!^zXOoFUjrW@)@~Kuoe2$0wLZF+12d?*qAHgQiPS_>Nk^Ec}5H z+2~JvEVA{`uMAr)?Kf|aW>33`)UL@bnfIUQc~L;TsTQ6>r-<^rB8uoNOJ>HWgqMI8 zSW}pZmp_;z_2O5_RD|fGyTxaxk53Hg_3Khc<8AUzV|ZeK{fp|Ne933=1&_^Dbv5^u zB9n=*)k*tjHDRJ@$bp9mrh}qFn*s}npMl5BMDC%Hs0M0g-hW~P*3CNG06G!MOPEQ_ zi}Qs-6M8aMt;sL$vlmVBR^+Ry<64jrm1EI1%#j?c?4b*7>)a{aDw#TfTYKq+SjEFA z(aJ&z_0?0JB83D-i3Vh+o|XV4UP+YJ$9Boid2^M2en@APw&wx7vU~t$r2V`F|7Qfo z>WKgI@eNBZ-+Og<{u2ZiG%>YvH2L3fNpV9J;WLJoBZda)01Rn;o@){01{7E#ke(7U zHK>S#qZ(N=aoae*4X!0A{)nu0R_sKpi1{)u>GVjC+b5Jyl6#AoQ-1_3UDovNSo`T> z?c-@7XX*2GMy?k?{g)7?Sv;SJkmxYPJPs!&QqB12ejq`Lee^-cDveVWL^CTUldb(G zjDGe(O4P=S{4fF=#~oAu>LG>wrU^z<Zw*_46AZG)LPZf(N{7;dl4f;=ChNJ&((0HR z>_?3yt24FOx>}{^lCGh8?vtvY$^hbZ)9I0E3r3NOlb9I?F-Yc=r$*~l`4N^xzlV~N zl~#oc>U)Yjl0BxV>O*Kr@lKT{Z09OXt2GlvE38nfs+DD7exl|&vT;)>VFXJVZp9Np zDK}aO;R3~ag$X*|hRVY3OPax|PG`@_ESc8E!mHRByJbZQR<iP3ONA)u3T^sr$hJu) z!;4BKQQ3Ke*v_=`LpX`s9^P!rY`x6m`OB{xdu)~9l-PrYu_eSHL`$3Jn77r}HXM<V zt(63|ZNf?J_G2$D@(>S38V2F__7MW~sgh!a>98Q2%lUNFO=^x<M$kfz5r<ep4<gy2 zqj#v58_1DTD9KgRF!$T?T|hpgQFqS{y9=z}$c192Is9kheW211%6d$Lv95L2Dj6<Y zb#^>U52|?D=IK#QjwBky-C>zO<IBf}7iok}7&M@d#5zo!yo-N`Xt*z8pz#W=a}edt zZG-pIp+-`FRdYN5kGiz~5pI5v{UL@+ll7;0f%sl_#Rz#s#c=hclIZch%vfdNL6kTn zr*OojJocIA;LUP<Ni!nCp8^IKsKOF;%d~A3Zec1Z)onv06oLt;&zK*gg)?kMAG~wt z$?%9ZDd#C*i@r2pEnc3pbg`;ZSgHhk8hnJ=MZQDKa})LR^M<VYo_<&7>WlsiiM&1n z;!&1((Xn1$9K}xabq~222gYvx3hnZPg}VMF_GV~5ocE=-v>V=T&RsLBo&`)DOyIj* zLV{h)JU_y*7SdRtDajP_Y+rBkNN*1_TXiKwHH2&p51d(#zv~s#HwbNy?<+(=9WBvo zw2hkk2Dj%kTFhY+$T+W-b7@qD!bkfN#Z2ng@Pd=i3-i?xYfs5Z*1hO?kd7Sp^9`;Y zM2jeGg<-nJD1er@Pc_cSY7wo5dzQX44=%6rn}P_SRbpzsA{6B+!$3B0#;}qwO37G^ zL(V_5JK`XT?OH<!?|M@&0-Z{-IE8Y%j&9{KOrqhAFsdE>Vk|{_$vQ|oNEpab*BO4F zUTNQ7RUhnRsU`TK#~`)$icsvKh~(pl=3p6m98@k3P#~upd=k*u20SNcb{l^<aLnRI zIQFl^{&&$2$-fmuufLTX(f?#w5i)Qxk+5|#v30U=ws193a(1+^HT!10f0I0&?f$MZ z7Axt<A%ClkjrclcTIHY>1rUa)>qO997)pYRWMncC8A&&MHlbW?7i^7M`+B$hH~Y|J zd>FYOGQ;j>Zc2e7R{KK7)0>>nn_jYJy&o@sK!4G>-rLKM8Hv)f;hi1D2fAc$+six2 zyVZ@wZ6x|fJ!4KrpCJY=!Mq0;)X)OoS~{<zp2fNOj3=!d#J-DZOZZGDsQytEg`t+g z3s*%5CrGI0LC#hm)1QTr3)Q~mP=>Lkh6u8J<B0%4?J^Iw+=WHCe(yhjohQDag#Q-y zuxp6&sgx+NVPxq!=P=H(FOhwRd2_*m=|$Mcn3vF&f(Fz>`eK%u0WtKh6B>GW_)PVc zl}-k`p09qwGtZ@VbYJC!>29V?Dr>>vk?)o(x?!z*9DJ||9qG-&G~#kXxbw{KKYy}J zQKa-dPt<oy^t}rwUk4E{A=4M9sOFfr7Ds9yI!q0r@t|+qU_|sPwWo~)0N*{XeSJ2j zt||$@K&w$2s%KuI4R}Av!VN4FKqSw8V4~H!Grt8-#>~M~E}V?PhW0R26xdA%<ogsP zN|DDB6`HT`^}UE=1A}Thaak~Emv(0YF@z$Cl+aE_pyty?6u<ojo%}e0uS=bI+~z8+ zN@qxB>1T*%ra6SguGu50YHngOTIv)@N|YttEXo#OZfgtP7;H?EeZZxo<}3YlYxtBq znJ!W<Tk7rKF4_TgJoZCW5Z^!*fTJ-Zk)y;)2fnZbAE(sksf_kg&-X&Eg#6@NPIv)e zPk4oG=#<n+u~!?2Waj@D(b4RIBp>FR^tmGf0Py}N?kZ(#=VtpC@%xJkDmfcCoBTxq zr_|5gP?u1@vJZbxPZ|G0AW4=tpb84gM2DpJU||(b8kMOV1S3|(yuwZJ&rIiFW(U;5 zUtAW`O6F6Zy+eZ1EDuP~AAHlSY-+A_eI5Gx)%*uro5tljy}kCZU*_d7)oJ>oQSZ3* zneTn`{gnNC&uJd)0aMBzAg021?YJ~b(fmkwZAd696a=0NzBAqBN54KuNDwa*no(^O z6p05bioXUR^uXjpTol*ppHp%1v9e)vkoUAUJyBx3lw0UO39b0?^{}yb!$yca(@DUn zCquRF?t=Zb9`Ed3AI6|L{eX~ijVH`VzSMheKoP7LSSf4g>md>`yi!TkoG5P>Ofp+n z(v~rW+(5L96L{vBb<M(xcH!jFDY91P;>^g51B=(o)?%%xhvT*A5btOpw(TKh^g^4c zw>0%X!_0`{iN%RbVk+A^f{w-4-SSf*fu@FhruNL##F~sF<TNlh3Zu<wDObc>24O~u zyYF<3el2b$$wZ_|uW#@Ak+VAGk#e|kS8nL1g>2B-SNMjMp^8;-FfeofY2fphFHO!{ z*!o4oTb{4e;S<|JEs<1_hPsmAlVNk?_5-Fp5KKU&d#FiNW~Y+pVFk@Cua1I{T+1|+ zHx6rFMor)7L)krbilqsWwy@T+g3DiH5MyVf8Wy}XbE<yUx>aoFIDr~y;@r&I>FMW{ z?Q+(IgyebZ)-i4jNoXQhq4Muy9Fv+OxU;9_Jmn+<`mEC#%2Q_2bpcgzcinygNI!&^ z=V$)o2&Yz04~+&pPWWn`rrWxJ&}8k<h1nlJpEW7DYjzCm^(#wnSe&>hR)6B(--!9Q zubo}h+1T)>a@c)H^i``@<^j?|r4*{<Pxu7~B&!$dLmL9Ys=1M8gJeDpJrYz<2V9nr zTvmS4mM<@Hxmfnk<1RI6FD*TtRhU+s9@>;tQf78(xn0g39IoZw0(CwY1f<%F>kEaJ zp9u|IeMY5mRdAlw*+gSN^5$Q)ShM<~E=(c8QM+T-Qk)FyKz#<J1rUcxa8T8CP^@o- z9LUqXz6y%L)dYBeo?hHD`m4vf;Ko!GhH#gWIg{IB<GEyusoLX^qjW_iBFR#|P|H$t z1PVdv4xB@M4hvXb%aZB@j?)`0DTujf<&yn?+Ww^h>Sw0EJ*edYcuOtO#~Cx^(M7w5 z3)rl#L)rF|(Vun2LkFr!rg8Q@=r>9p>(t3Gf_auiJ2Xx9HmxYTa|=MH_SUlYL`mz9 zTTS$`%;D-|Jt}AP1&k7PcnfFNTH0A-*FmxstjBDiZX?}%u%Yq94$fUT&z6od+(Uk> zuqsld#G(b$G8tus=M!<V>N#oPd|PVFX)?M?tCD0tS%2IGTfh}3YA3f&UM)W$_GNV8 zQo+a(ml2Km4o6O%gKTCSDNq+#zCTIQ1<zRinbW1<P#|UQotg93waYH2w1*h*jWPj6 z^zMSH#dD)R!pp{n89hOchS-cu?Yi0ISv7!)1hAHH{1T%@r!ud3;HLw5<Vb67p@OE@ zP1TDxu7L{<vN=z>*`TIJh~k6Gp;htHBFnne))rlFdGqwC6dx2+La1&Mnko*352k0y z+tQcwndQlX`nc6nb$A9?<-o|r*%aWXV#=6PQic0Ok_D;q>wbv&j7cKc!w4~KF#-{6 z(S%6Za)WpGIWf7jZ3svNG5OLs0>vCL9{V7cgO%zevIVMH{WgP*^D9ws&OqA{yr|m| zKD4*07dGXshJHd#e%x%J+qmS^lS|0Bp?{drv;{@{l9ArPO&?Q5=?OO9=}h$oVe#3b z3Yofj&Cb}WC$PxmRRS)H%&$1-)z7jELS}!u!zQ?A^Y{Tv4QVt*vd@uj-^t2fYRzQj zfxGR>-q|o$3sGn^#VzZ!QQx?h9`njeJry}@x?|k0-GTTA4y3t2E`3DZ!A~D?GiJup z)8%PK2^9OVRlP(24P^4_<|D=H^7}WlWu#LgsdHzB%cPy|f8dD3|A^mh4WXxhLTVu_ z@abE{6Saz|Y{rXYPd4$tfPYo}ef(oQWZ=4Bct-=_9`#Qgp4ma$n$`tOwq#&E18$B; z@Bp)bn3&rEi0>fWWZ@7k5WazfoX`SCO4jQWwVuo+$PmSZn^Hz?O(-tW@*DGxuf)V1 zO_xm&;NVCaHD4dqt(-MlszI3F-p?0!-e$fbiCeuaw66h^TTDLWuaV<@C-`=Xe5WL) zwooG7h>4&*)p3pKMS3O!4>-4jQUN}iAMQ)2*70?hP~)TzzR?-f@?Aqy$$1Iy8VGG$ zMM?8;j!pUX7QQD$gRc_#+=raAS577ga-w?jd`vCiN5lu)dEUkkUPl9!?{$IJNxQys z*E4e$eF&n&+AMRQR2gcaFEjAy*r)G!s(P6D&TfoApMFC_*Ftx0|D0@E-=B7tezU@d zZ{hGiN;YLIoSeRS;9o%dEua4b%4R3;$SugDjP$x;Z!M!@QibuSBb)HY!3zJ7M;^jw zlx6AD50FD&p3JyP*>o+t9YWW8(7P2t!VQQ21pHJOcG_SXQD;(5aX#M6x##5H_<Vgo zXaA`|b1qI$OB^nkP*k8;>Re>6lPyDCjxr*R(+HE%c&QN+b^tbT<D}=?S8O%T8tX+C zcq<H{RI|G2B9m%Rvp=d?PUf-1CZ*M)qUmtvLRWz*mFB-QNI1$Q(ryDe(K%5UcMcw> zXBJk?p)zhJj#<NYmRaIG#%{yKso~Jl);(QZ{BXnYyStuZE8Z;ST(ba;;Cf6`eaY~e zro&T_@|5eV&LV-Vdlye+OlA8HSGS?PEP0tn!gk^nHiROTHF+mL6DBZ*<LBy0zzNW0 z?K`Dd6_+8u^4Tx%YqyDRx3oaO`51F%4~hz9FS=g55uAbZ9<uEXv*DeH(f5XqNd{@0 zp<n?$CoIPaZ{u=WOkQK=>I?&Y2n&~XiytG9!1ox;bw5Rbj~)7c(MFBb4>IiRATdhg zmiEFlj@S_hwYYI(ki{}&<;_7(Z0Qkf<vz98R4^QE*0+j0Yt5Bq_8W~pIEsdB>q>am z&LtL=2qc7rWguk3BtE4zL41@#S;NN*-jWw|7Kx7H7~_%7fPt;TIX}Ubo>;Rmj94V> zN<mGWxPciFI#UK&1{)&R+tKETKKJppI5eS&4QOQDb2gC@9#amL!Z4`6_?sgG50#TO zUE{XN@zEh;wAcp{%1UraASTco@__6>B1=;-9AR7s`Pxn}t_6^3ahlq53e&!Lh85uG zec0vJY_6e`tg7LgfrJ3k!DjR)Bi#L@DHIrZ`sK=<5O0Ip!fxGf*OgGSpP@Hbbe&$9 z;ZI}8lEoC2_7;%L2=w?tb%1oL0V+=Z`7b=P&lNGY;yVBazXRYu;+cQ<d^ZC}lYirx z)hZjd3qKHeGus^Y+enhww8u%4lE|(|Z6qnX?I}@3Q1b~uMX2mD2SFAFYnI`H<@TW6 z_W((t!X&)`@PpH2wi2iW=uqjmv(p=oqs&Y%b9;Nf0OWslW9*Nb&oWZEt+0AVS&R~u z_Wf#$fP|$gQ9fiHWGF1iGfW}Wb;*#iU5QAsVTwY*RhU@;t!16`ZZ<f|b==EnUgA$9 z4GDXmcVu4RoyBc?5+IzLNU`y7!@x5Q-0Qn*X9{dMTclVEa<*>DKvm*7NCxu&i;zub zAJ<l&f69)KP9=Oa-e|<}G6{v&t3Gsy-GA$_$uw;4(^(<e6x2^i-<E!;86)%4VjM%- z<_j^P(DEMAyY~*<c=R4aPSMdD=QV?HQb>h#11%?w>E2rf2e~C4+rAb-&$^vsdACs7 z@|<k_fU+PhC9U|KK^m>Ra!OfVM(ke{vyiqh7puf&Yp6cd6{DptUteYfIRWG3pI+5< zBVBI_xkBAc<(p<um#S5<Wtzr=ckJ6;=I>cb$!Y%dTW(b;B;2pOI-(QCsLv@U-D1XJ z(Gk8Q3l7Ws46Aktuj>|s{$6zA&xCPuXL-kB`CgYMs}4IeyG*P51IDwW?8UNQd+$i~ zlxOPtSi5L|gJcF@DwmJA5Ju8HEJ>o{{upwIpb!f{2(vLNBw`7xMbvcw<^{Fj@E~1( z?w`iIMieunS#>nXlmUcSMU+D3rX28f?s7z;X=se6bo8;5vM|O^(D6{A9*ChnGH!RG zP##3>LDC3jZPE4PH32<r6$U<HX=R_L2D`8>AxrqPk|yIIrq~`aL-=}`okhNu9aT%q z1b<WnlSbT*V4<ymTCe0MD#5~7Whz|=;>)7iJ)CN=V#Ly84N_r7U^SH2FGdE5FpTO2 z630TF$P>GNMu8`rOytb(lB2};`;P4YNwW1<5d3Q~AX#P0aX}R2b2)`rgkp#zTxcGj zAV^cvFbhP|JgWrq_e`~exr~sIR$6p5V?o4Wym3kQ3HA+;Pr$bQ0(PmADVO%MKL!^q z?zAM8j1l4jrq|5X+V!8S*2<l)&qsCusW$QhU{vI`y!|$e;d+{bf(RH@<)nJ517c7s zDim)TBb^~cK*c)35Gg|q1$&KAYNncsQOHJ|nu#)~+T76>Wl@=7*pPgciTVK6kS1Ge zMsd_u6DFK$jTnvVtE;qa+8(1sGBu~n&F%dh(&c(Zs4Fc#A=gG^^%^AyH}1^?|8quj zl@Z47h$){PlEL<j^JXcV*jDSt#inW`1Gn}CBm-N=8TRh<K)!JpM`mq>JgYZCIHHL= z{U8O>Tw4x3<1{?$8>k-P<}1y9DmAZP_;(3Y*{<b??kNj&VqPGa79d@(m$2L68%nd! z{_JjeX;XQdwTu-^XN2zhv1k+fQHndX43k}u83t_z&A52ZBFI*?6D8Q{uBSWGwQ#nR zSnaCVwkuW{YP1TLJ@kJx_A>Sk^H^A=_iSJ@+s5ktgwTXz_2$~W9>VVZsfwCm@s0sQ zeB50_yu@uS+e7QoPvdCwDz{prjo(AFwR%C?z`EL{1`|coJHQTk^nX=tvs1<0arUOJ z!^`*x&&BvTYmemyZ)2p~{%eYX=JVR?DYr(rNgqRMA5<s3FN;{WX^H?!5dAC7_ToT& z049v%;5~bT4K%9GqC;d+sXL`9S9+;oZpLE#7knG~OKbHmpUA?yU6n&99^Z!ZI?xYz z{BGz0U$>E1PR1Iw=prk=L2ldy3r3Vg@27IZx43+ywyzr-X*p*d@tZV+!U#~$-q=8c zgdSuh#r?b4GhEGNai)ayHQpk>5(%j5c@C1K3(W1pb~HeHpaqijJZa-e6vq_8t-^M^ zBJxq|MqZc?pjXPIH}70a5vt!IUh;l}<>VX<-Qcv^u@5(@@M2CHSe_hD$VG-eiV^V( zj7*9T0?di?P$FaD6oo?)<)QT>Npf6Og!GO^GmPV(Km0!=<c9QK{JSBnxbTl~S4d3F zZhX~`iBZf``YC!s;R3x;^$k-@k$#)|!OTN1novAwmG;&P2)PD!FyXg4r(4gHh?ySe z7<%V?@*d*j&#%W*MAHm*B6GjS8B_74D&Msq691~iVscJ{Zps}t4Abjxm(LlYOjt<z z0=dj7A`k(bp)&5Hm__k9JT(e0PyOe3?@>+dE&bk#SNI+C9RGQ|{~O*VC+tXK3!n`5 zHfl6>lwf_aEVV3`0T!aHNZLsj$paS$=LL(?b!Czaa5bbSuZ6#$_@LK<(7yrrl+80| z{tOFd=|ta2Z`^ssozD9BINn45NxUeCQis?-BKmU*Kt=FY-NJ+)8S1ecuFtN-M?&42 zl2$G>u!iNhAk*HoJ^4v^9#ORYp5t^wDj6|lx~5w45#E5wVqI1JQ~9l?nPp1YINf++ zMAdSif~_ETv@Er(EFBI^@L4BULFW>)NI+ejHFP*<T<d*k5U>T}UhWNN`I)RRS8za? z*@`1>9ZB}An%aT5K=_2iQmfE;GcBVHLF!$`I99o5GO`O%O_zLr9AG18>&^HkG(;=V z%}c!OBQ~?MX(9h~tajX{=x)+!cbM7$YzTlmsPOdp2L-?GoW`@{lY9U3f;OUo*BwRB z8A+nv(br0-SH#VxGy#ZrgnGD(=@;HME;yd46EgWJ`EL%oXc&lFpc@Y}^>G(W>h_v_ zlN!`idhX+OjL+~T?19sroAFVGfa5tX-D49w$1g2g_-T|EpHL6}K_aX4$K=LTvwtlF zL*z}j{f+Uoe7{-px3_5iKPA<_7W=>Izkk)!l9ez2w%vi(?Y;i8AxRNLSOGDzNoqoI zP!1uAl}r=_871(G?y`i&)-7{u=%nxk<TF^9;4ekh$qpT49mIUTo!QB3IxD^Xo8$2N z0jCW$vUnPpla#O+%Oja`23x?g8&sst<rR<!i-fJAT!pW4qQWcl7>7CZ_Qh#!|ITec zwQn`33GTUM`;D2POWnkqngqJhJRlM>CTONzTG}>^Q0wUunQyn|TAiHzyX2_%ATx%P z%7gW)%4rA9^)M<_%k@`Y?RbC<29sWU&5;@|9thf2#zf8z12$hRcZ!CSb>kUp=4N#y zl3hE#y6>kkA8VY2`W`g5Ip?2qC_BY$>R`iGQLhz2-S>x(RuWv)SPaGdl^)gGw7tjR zH@;jwk!jIaCgSg_*9iF|a);sRUTq30(8I(obh^|}S~}P4U^BIGYqcz;MPpC~Y@k_m zaw4WG1_vz2GdCAX!$_a%GHK**@IrHSkGoN>)e}>yzUTm52on`hYot7cB=oA-h1u|R ztH$11t?54Qg2L+i33FPFKKRm1aOjKST{l1*(nps`>sv%VqeVMWjl5+Gh+9);hIP8? zA<Q7k-wX5MjEY4*mC%%h!I%wsiVeW4+`u*(F}G%hLu4v_No<?+)c0h3mM0wvOcTzb z6mLpttd1pgh;LPDfUyEl9?m3fSr8}4WkXDbERL<t;7gDrg+uTPTiBati$g>@$?}Sc z3qIRpba+y5yf{R6G(u8Z^vkg0Fu&D-7?1s=QZU`Ub{-!Y`I?AGf1VNuc^L3v>)>i# z{DV9W$)>34<d17om!!)9&{`T5uHYJXV$G;?A+9420_wrs59Q5xU_?zk<S-MZw#YF! z)5TK_({W1E10+oWfpH?yLthllM<4BAQSN*>wnzAXUiV^ZpYKw>UElrN_5Xj6{r_3| z$X5PK`e5$7>~9Dj7gK5ash(dvs`vwfk}&RD`>04;j62zoXESkFBklYaKm5seyiX(P z<ID{omUfJz++3+6M6A3|He)%RuG>qQ-;XxlV*yg?Dhlx%xt!b0N3GHp@(p$A;8|%# zZ5m2KL|{on4nr>2_s9Yh=r5ScQ0;aMF)G$-9-Ca6%wA`Pa)i?NGFA|#Yi?{X-4ZO_ z^}%7%vkzvUHa$-^Y#aA+aiR5sa%S|Ebyn`EV<3Pc?ax_f>@sBZF1S<H?5z{)#QL{V zr*a_q>;7y$CXd5t5=WGsTKBk8$OfH4v|0?0I=Yp}7c=WBSCg!{0n)XmiU;lfx)<uN zPvr+1FFDIM@A4#y;a<?S=xTH`XYK!+^->**zZaYqmDJelxk$)nZyx5`x$6R|fz(;u zEje5Dtm|a%zK!!tk3{i9$I2b{vXNFy%Bf{50X!x{98+BsDr_u9i>G5%*sqEX|06J0 z^IY{UcEbj6LDwuMh7cH`H@9sVt1l1#8kEQ(LyT@&+K}(ReE`ux8gb0r6L_#bDUo^P z3Ka2l<H7(tNv_ycRF43oWEx{?2ychJaXYk!nafC$;QPt)Dhl%pHY&kHF=u*jMxFxR z8hs|e%r39oE}ts%zE`x;@(JZF%`*hV&TQs;k7&^PC%_|U=Z^yM6XVPX3WWp6H|w9J z45Q%jM?z_P7Kg74lHMQ_-ZVr_NbHvg3EMK85#qK7Y#v#ov_?2?Wu|DHo1}82@XlNo z*7dav>Ro52Hdtl_%+pwVs14=q`{d^L58PsU@AMf(hENumaxM{7iAT5sYmWh@hQCO^ zK&}ijo=`VqZ#a3vE?`7QW0ZREL17ZvDfdqKGD?0D4fg{7v%|Yj&_jcKJAB)>=*RS* zto8p6@k%;&^ZF>hvXm&$PCuEp{uqw3VPG$9VMdW5$w-fy2CNNT>E;>ejBgy-m_6`& z97L1p{%srn@O_JQgFpa_#f(_)eb#YS>o>q3(*uB;uZb605(iqM$=NK{nHY=+X2*G) zO3-_Xh%aG}fHWe*==58zBwp<ewOv=l7F;`(EW(2I^P`O~+>%&`mg<U+`XEp_tI#7M zlHXq!JFASK8=TxtsItown-vYtx@G%cb7t%FpgERtlejdO-?8O0py|EQiBWNJ#diHb z8h^Y>e<8uq8;xIxOd=P%9EK!34^E9sk|(Zq1QSz-JVeP12Fp)-`F|KY$LPwUE?rku zY@OJ)Z9A!ojfzfeyJ9;zv2EM7ZQB)AR5xGa-tMn^bl)FmoIiVyJ@!~@%{}qXXD&Ns zPnfe5U+&ohKefILu_1mPfLGuapX@btta5C#gPB2cjk5m4T}Nfi+Vfka!Yd(L?-c~5 z#ZK4VeQEXNPc4r$K00F<wRh*06<c<Cw!0P4***aS+tgLJ2H$n=v+UM@P`jG9HJHW0 zeqBot9>g>g#_W!YZ)cJ?JTS<&68_$#cZT-ME`}tcwqg3#``3M3UPvn+pi}(VNNx6y zFIMVb6OwYU(2`at$gHba*qrMVUl8xk5z-z~fb@Q3Y_+aXuEKH}L+>eW__!IAd@V}L zkw#s%H0v2k5-=vh$^vPCuAi22Luu3uKTf6fPo?*nvj$9(u)4$6tvF-%IM+3pt*cgs z_?wW}J7VAA{_~!?))?s6{M=KPpVhg4fNuU*|3THp@_(q!b*hdl{fjRVFWtu^1dV(f z6iOux9hi&+UK=|%M*~|aqFK{Urfl!TA}UWY#`w(0P!KMe1Si<jiK`FCX|r(xrQ!0U zNF-2!m|??dd%b!3w5!;b;@Y>{8|o))Gy6d7;!JQYhgMYmXl?3FfOM2nQGN@~Ap6(G z3+d_5y<nkN(o+zEYZBPE7qE4X4RTq~xP<0UuT}eq);wA`P~5mS&}Ni6sX$kQ!#Y14 zw<=&7Ca^#oAVnvbz-T-b@50=C)>@=nkpKAhRqf{qQ~k7Z$v&l&@m7Ppt#FSNzKPZM z8LhihcE6i=<(#87E|Wr~HKvVWhkll4iSK$^mUHaxgy8*K$_Zj;zJ`L$naPj+^3zTi z-3NTaaKnD5FPY-~?Tq6QHnmDDRxu0mh0D|zD~Y=vv_qig5r-cIbCpxlju&8Sya)@{ zsmv6XUSi)@(?PvItkiZEeN*)AE~I_?#+Ja-r8$(XiXei2d@Hi7<U!}O-C%Wp93|!6 z_maftKQVDsmc-oSX^Wf5%~c*ohRjQuXO7WUoJr4mKQ1O_S_G_rS=b~3S&JLLEOKDV z{3LUpGl1vt1pkI#r_j=V*y<p!g}(O0?op0V5}i0e<PEWYB8x5J4<%9#9y9X9M*bUx zicdfReJ#lhlVUp=<yC<tza847t{vKR$R*ci-p`+Gl}ts*E09J&7%h92yemiDYmk~} zTm@z(hV@tXo`0Xdz4V~IJu7i|)?jOn6Nt~0dUv^z2PHbxR-jssAHfY`%7{ql=vzVB zs_4Na@y!!YjTV?bkxAK(=I=549YO&vP5F{dsX_6-68_n)LiIx2IwV=E#EmY<Yodu6 z9z7+@5zk>Rx8+rZZb?ZLa{;@*EHeRQ-YDadz~M*YCM4&F-r;E#M+@CSJMJ0oU|PQ^ z=E!HBJDMQ2TN*Y(Ag(ynAL8%^v;=~q?s4plA_hig&5Z0x_^Oab!T)@6kRN$)qEJ6E zNuQjg|G7iwU(N8pI@_6==0CL;lRh<Er=!!1>1dQF#wePhmu@hADFd3B5KIH#dx(2A zp~K&;Xw}F_N6CU~0)<woWpm{<(lL~%8t8hZ?O>QpQk7s$a+LcTOj1%=WXI(U=Dv!6 z{#<#-)2+gCyyv=Jw?Ab#PV<kuPJ4UouiQa>kxPDeH|sAxyG`|Ys}A$PW4TdBv%zDz z^?lwrxWR<%Vzc8Sgt|?FL6ej_*e&rhqJZ3Y>k=X(^dytycR;XDU16}Pc9Vn0>_@H+ zQ;a`GSMEG64=JRAOg%~L)x*w{2re6DVprNp+FcNra4VdNjiaF0M^*<Z21jxz28!z4 z)+Qw^>>Cd<OYjfTeBDpnxINod_ps<v{(V~~r+~z4oEIjOYCK|$#(JnCT7;!!Y}f=y zFNsGLXIqR_Lc24Epk`I91kx04#KNLQB=sN}`>Pkt(m150rCue?FVdL0nFL$V%5y6N z%eLr5%YN7D06k5ji5*p4v$UMM)G??Q%RB27IvH7vYr_^3>1D-M66#MN8tWGw>WED} z5AhlsanO=STFYFs)Il_0i)l)f<8qn|$DW7ZXhf5xI;m+7M5-%P63XFQrG9>DMqHc} zsgNU9nR`b}E^mL5=@7<1_R~j@q_2U^3h|+`7YH-?C=vme1C3m`Fe0HC>pjt6f_XMh zy~-i-8R46QNYneL4t@)<0VU7({aUO?aH`z4V2+kxgH5pYD5)wCh75JqQY)jIPN=U6 z+qi8cGiOtXG2tXm;_CfpH9ESCz#i5B(42}rBJJF$jh<1sbpj^8&L;gzGHb8M{of+} zzF^8VgML2O9nxBW7AvdEt90vp+#kZxWf@A)o<TP7Iv6D<p-`geitU42O0|5*#cI2& zD#rHm-Vc3+vP+a)$@(=16*wM+J-aXvee~$jPN+y)1J;9JyU$}nCH;?MkiD^?^{YXd z()hszm1?+Vl-hdUHRO1qu43l7<f-+JFAVi;sMe)sVUTGeF5*U18gVs~b3a#HICwn? zOc3D$MdBtKd+A-2`!?hp+dNtbrf)b+gMTQ^qA%J;1l0Bf$I4T>9f9}vKJy9NDBjBW zSt=Hcs=YWCwnfY1UYx*+msp{g!w0HC<_SM!VL1(I2PE?CS}r(eh?{I)mQixmo5^p# zV?2R!R@3GV6hwTCrfHiK#3Orj>I!GS2kYhk1S;aFBD_}u2v;0HYFq}Iz1Z(I4oca4 zxquja8$+8JW_EagDHf$a1OTk5S97umGSDaj)gH=fLs9>_=XvVj^Xj9a#gLdk=&3tl zf<JQN-rLl3?(b@3I(eFE1!7*!5QjuNkUcQB*{SCO?Dz6>mK9MNnIX9v{?%xdw7568 zNrZ|roYs(vC4pHB5RJ8>)^*OuyNC>x7ad)tB_}3SgQ96+-JT^Qi<`xi=)_=$Skwv~ zdqeT9Pa`LYvCAn&rMa2aCDV(TMI#PA5g#RtV|CWpgDYRA^|55LLN^u<JFRGA?x);o z`Z~}R6`4W#%h(d)aQ>Nh*gOU>Z=a06qJ;$C9z8;n-Pq=qZnc1zUwJ@t)L;&NN+E5m zRkQ(SeM8=l-aoAKGKD>!@?mWTW&~)uF2PYUJ;tB^my`r9n|Ly~0c%diYzqs9W#<S` z2%`mn3A&KL|FUYx1DDYTb2GMnO1WEyfJ-eVoSqd~=r!kw@InSGE<>FTjy?h&X3TnH zXqA{QI82sdjPO->f=^K^f>N`+B`q9&rN0bOXO79S&a9XX8zund(kW7O76f4dcWhIu zER`XSMSFbSL>b;Rp#`CuGJ&p$s~G|76){d?xSA5wVg##_O0DrmyEYppyBr%fyWbbv zp`K84JwRNP$d-pJ!Qk|(RMr?*!wi1if-9G#0p>>1QXKXWFy)eB3ai)l3601q8!9JC zvU#ZWWDNKq9g6fYs?JQ)Q4C_cgTy3FhgKb8s&m)DdmL5zhNK#8wWg!J*7G7Qhe9VU zha?^AQTDpYcuN!B+<Y^i3NB&h=8l2*^8*j@dwN-$SX`JG4?X#EO)n_d+Mm*qNtLvW z1{=j+)$5S8QKKaCKpO>#1dE*X{<#!M%zfUQbj=zL<r~1!%Q56_&?RVt*j39RdBbdU zvt>E{dW0XeQ7-oIsGY6RbkP2re@Q{}r_$iiH0xU%iN*ST`A)-EH6eaZB$GA#v)cLi z*MpA(3bYk$oBDKAzu^kJoSUsDd|856DApz={3u8sbQV@JnRkp2nC|)m;#T=DvIL-O zI4vh;g7824l}*`_p@MT4+d`JZ<NgM|d-wED*_BDR=X2CYG0s+@tH~}mHA<v@@*LLa zcTk2OQd|qCF;Irq7ZT2t<bCnFzjKHMYi_FEX5uA1sMB~b=-gExnk*fx9Jolk@GBaP zo2{A-B!6SMvS~u~??*1DY*%B^{i&5Xid$7&jHLv;Csgpyh12H&Wr+sb8jR356U$OH z#keINf2882?;$z(=9b`_o!xWZsvxb)AId~zQ-ypi#22f~snWv+_Q$md&MYLZH1*5& zgU2`BbMmltaER}JO!m5!`^u~)I>2%6NQh=N9bmgJ#q!hK@_<`HQq3}Z8Ij>3%~<*= zcv=!oT#5xmeGI92lqm9sGVE%#X$ls;St|F#u!?5Y7syhx6q#MVRa&lBmmn%$C0QzU z);*ldgwwCmzM3ug<bwv^{e8k-I_Ia))Ca<<K85KO7s<Z8_qINV*w7o<JN><pez`8$ z*U(_%(Oddx;Dy@<By6!p<ae@SHe5;+DISJZbTAq-U`Q`A1)YLa`3xqvnU#=JMDwvc zT=fd_B(g|SbuM?{hEp2{k!4hh2k1}qTl{TSl*cD|duWT^U1%zqX9UbNuTdGS)?ic- zFWu0OzODT7)oL^9a3Iy*#7Rk@72_$KGruLmz}W@8{rhO(Lndv7z61c>lr}!Z2G+?& zf%Dpo&mD%2ZcNFiN-Z0f;c_Q;A%f@>26f?{d1kxIJD}LxsQkB47SAdwinfMILZdN3 zfj^HmTzS3Ku5BxY>ANutS8WPQ-G>v4^_Qndy==P3pDm+Xc?>rUHl-4+^%Sp5atOja z2oP}ftw-rqnb}+khR3CrRg^ibi6?QYk1*i^;kQGirQ<G&YKu_KEA~r2_|MY6U!vEc zYq^WKw2*I=^(R7(!~~v`>=uB9Sd1NTfT-Rbv;hqnY4neE5H1YUrjS2m+2&@uXiAo- zrKUX|Ohg7(6F(AoP~tj;NZlV#xsfo-5reuQHB$&EIAhyZk;bL;k9ouDmJNBAun;H& zn;Of1z_Qj`x&M;5X;{s~iGzBQTY^kv-k{ksbE*Dl%Qf%N@hQCfY~iUw!=F-*$cpf2 z3wix|aL<TqR7Y;}gRV7Q6u)-qpm%oMjSmV6D=p0OrNXwr5;y^b5cF7C7&Mp&D`?Ob z8ESq3ScyN7w@J>BV0b;W@z^%7S{>9Z^T^fLOI68_;l@+Qzaxo`nAI8emTV@rRhEKZ z?*z_{oGdI~R*#<2{bkz$G~^Qef}$*4OYTgtL$e9q!FY7EqxJ2`zk6SQc}M(k(_MaV zSLJnTXw&@djco1~a(vhBl^&w=$fa9{Sru>7g8SHahv$&Bl(D@(Zwxo_3r=;VH|uc5 zi1Ny)J!<(KN-EcQ(xlw%PNwK8U>4$9nVOhj(y0l9X^vP1TA>r_7WtSExIOsz`nDOP zs}d>Vxb2Vo2e5x8p(n~Y5ggAyvib>d)6?)|E@{FIz?G3PVGLf7-;BxaP;c?7ddH$z zA+{~k^V=bZuXafOv!RPsE1GrR3J2TH<Ny`yVx$sah_BnMO|Vl_4M%y|BVBOcD(&Tf zIi%w5mBkQA-m8WhIS+m)@HEq^i=}^RPX#BvtKJYieRDhM9CpMXBxjmn?hoV<pKsfM zQ3`)(<)?1Do&LG^9T4w<TIx#Djhk>9uB=Z67gok+u`V#}BR86hB1xl}H4v`F+mRfr zYhortD%@IGfh!JB(NUNSDh+qDz?4ztEgCz&bIG-Wg7w-ua4ChgQR_c+z8dT3<1?uX z*G(DKy_LTl*Ea!%v!RhpCXW1WJO6F`bgS-SB;Xw9<cxOL&fF^435YAz<*2lIsx>#! z<*K}=#wVu9$`Yo|e!z-CPYH!nj7s9dEPr-E`DXUBu0n!xX~&|%#G=BeM?X@shQQMf zMvr2!y7p_gD5-!Lnm|a@z8Of^EKboZsTMk%5VsJEm>Vs<fWSaAAk=E0a4xz;CoE+n zvV|`k(cS-gI#<~znD&6(Dyi8%>J4W7Kv{<|#4f-qDE$D-W>gWT%<wM^e7+vR+ZVxu zJA%k!wV1jm=-?CPfHci1I%oS6_$rRC_i%Dy1_C}}(R>z-!qXnDHhOvLk=?^a1*|0j z{pW{M0{#1VcR5;F!!fIl<yJC4LQf<m+NFcvrhH-9Oq`TslF!sxh9CTya<1|Z@Sf8S z#)!cL{VHJYkWIKNj^M2D@K4#yCJQKlT2}zO7tRTvNED*cmVv~6G8g$V6W>LVNh_Gj zbnW(_j?0c2q$EHIi@fSMR{OUKBcLr{Y&$hrM8XhPByyZa<R$b|!F4rBVu<@_&`m0` zvC-aJ+X!p>Xy|dd&{hYQRJ9@Fn%h3p7*VQolBIV@Eq`=y%5BU~3RPa^$a?ixp^cCg z+}Q*X+CW9~TL29@OOng(#OAOd!)e$d%sr}^KBJ-?-X&|4HTmtemxmp?cT3uA?md4% zT8yZ0U;6Rg6JHy3fJae{6TMGS?ZUX6+gGTT{Q{)SI85$5FD{g-eR%O0KMpWPY`4@O zx!hen1*8^E(*}{m^V_?}(b5k3hYo=T+$&M32+B`}81~KKZhY;2H{7O-M@vbCzuX0n zW-&HXeyr1%I3$@ns-V1~Lb@wIpkmx|8I~ob1Of7i6BTNysEwI}=!nU%q7(V_^+d*G z7G;07m(CRTJup!`cdYi93r^+LY+`M*>aMuHJm(A8_O8C#A*$!Xvddgpjx5)?_EB*q zgE8o5O>e~9IiSC@WtZpF{4Bj2J5eZ>uUzY%TgWF7wdDE!fSQIAWCP)V{;HsU3ap?4 znRsiiDbtN7i9hapO;(|Ew>Ip2TZSvK9Z^N21%J?OiA_&eP1{(Pu_=%JjKy|HOardq ze?zK^<n_C~sSO$T&zHJ&gqMJm2ooswNa9fe;pI&q8BGtsLvsv{E`UcDopP-qDeO>K zA%sj<KGR#nku^U`P7U%dm^(-)^vJ8a7zEx#hISA%f9a1Ybx@Dr&>F64*Wufad%H<) z^|t>e*h+Z1#l=5wHexzt9HNDNXgM=-OPWKd^5p!~%SIl>Fo&7BvNpbf8{NXmH)o{r zO=aBJ;meX1^{O%q;kqdw*5k<?!FYD}X~SRg{bAptI6CT~WZcECii<d{!~H9SptJA{ z(IMO5d`_qI=h*DGo=n0v@_q*TN1Rb~B&ITpk8DJlRXa*ROudIg-K94et8*W|ahl(A z2RLvW1}v%VuO9`Ef9t?PKUXTW2f&D}3vrtNJ87$D?Y9if%$|t@;m`i#_BSRV)jj(n z<)v7wOK4@tW$UKKWR0fsc^c<~vm5M`u2vnP<@`C7-1h}V)vH?GIQ6kut>!Y7%t_30 zy{nGRVc&5qt?dBwLs+^Sfp;f`YVMSB#C>z^a9@fpZ!xb|b-JEz1LBX7ci)V@W+k<d z?qR|O?7_P?Q6<qQfw{t}<omxO-y4wzz13f^3s3)!sA+n!=}0n9^jL6z6UFtDDE}Mp z!BsppJn%YvdkxcpH0L^o3RScOB1lQrKBaMr+6<a345~U+wL$oOCB}VtK17ZH;V1Ue zdj4e4ug6v=rEE8!n9=MxEf@easRS`JT*=LVd(P_|@2%P^bJF0dJak~<TFSD+7ZH;0 zk0}Z5&3UxSBxu~{Rz*8BKG13&fcf@9dyUN>vQ89KWA0T~L<vZ;GW*aTR}HF1-jedY z#-MsfGyBFAcQAdcd`Yx-bcvlJbsoc$%4C5;EuOf%FC1$=NHxR@P$wjlROtPJ?~8@j z{p*zq)|ri!j1uu-Pw*x?ETPT6(jkMz{tB)03YK+l%8c_vwo>j$aCcfW#nD5bt&Y_< z-q{4ZXDqVg?|0o)j1%l0^_it0WF*LCn-+)c!2y5yS7aZIN$>0LqNnkujV*YVes(v$ zY@_-!Q;!ZyJ}Bg|G-~w@or&u0RO?vlt5*9~yeoPV_UWrO2J54b4#{D(D>jF(R88u2 zo#B^@iF_%S>{iXSol8jpmsZuJ?+;epg>k=$d`?GSegAVp3n$`GVDvK${N*#L_1`44 z{w0fL{2%)0|E+qgZtjX}itZz^KJt4Y;*8uSK}Ft38+3>j|K(PxIXXR-t4VopXo#9# zt|F{LWr-?34y`$nLBVV_*UEgA6AUI65dYIbqpNq9cl&uLJ0~L}<=ESlOm?Y-S@L*d z<7vt}`)TW#f%Rp$Q}6@3=j$7Tze@_uZ<ObsOT=LjG!@YPQ+Y%TP2q;%&e6bD0<;#D zn1mKO23ndd^;;2ec_vb`0m}1R5{A-e6@I<Gaf6P$y+!C|ZytXPFNr}*6sJD;{rbI+ zRwg~nC(gjZ<H0G$h5d*YGLSy%7k#zcB&IGLVazVInCg9bgF6KKKSeDarF+`2IFlWj z%#J~%w5&}@qlKlZ9XX8WVB)+9_$hOD{jg_1meULyOnTAY(X(RGDVFl%IWWYYn*#Gf zs5wy97!DZR>O@aMn<|si{?S}~maII`VTjs&?}jQ4_cut9$)PEqMukwoXobzaKx^MV z2fQwl+;LSZ$qy%Tys0oo^K=jOw$!YwCv^e<e%~cuMqeXJnyNEIpgKcP&BSGZ3-V#G zgnyc%fsRb47ImAxDT<IihCipil@oTF)0wHSZ%ab4RM$MVn<5Pqo=k;p=s1{wkr4K3 zPn=Vq->i4NBVauL)tN%=wz9M{uf{IB(BxK|lT*pFkmN<Z(NFM5`sDgUq1$L^2{X$m zQ<@5WTkRGfqF>K_1tV`nb%jH=a0~VNq2RCKY(rG7jz!-D^k)Ec)yS%17pE#o6&eY+ z^qN(hQT$}5F(=4lgNQhlxj?nB4N6ntUY<e6n(3tLO%M0YHj0diWfkmtmb0?9X&BDU zs6Tl5CHz~g>6(?+R#B?W3hY_a*)hnr4PA|v<bL3cOEhhyT5k=(qGlmAL3eDw%3aS) z+mMt2HXmQhxUE+tIpq`0N<C;yWn7~iBEGnslqQO0EY^z~!M$i!^_m>J<6p`K3Z5Hy z{{8(|ux~NLUW=!?9Qe&WXMTAkQnLXg(g=I@(VG3{HE13OaUT|DljyWXPs2FE@?`iU z4GQlM&Q=T<4&v@Fe<+TuXiZQT3G~v<S1*NrZ8z<H*IRys?O`Oqz|}FcV<W%7zks=K zjhgy^OR8^T{XcG5A)q#Ixd7)hWJZgOgp%s-!KiICJ<7)nHG%9IeF-=|(W+fGO(~eL zUZW|&`a8*ZnEW_JOqB-k$82w~>Z&^POfmI1K2h6t4eD}Gk5XFGpbj1n_g*{qmD6Xy z`6<o)fI|_!EcP+Bw?+2|y3t!@@OewwE@am14Pw<&ymmicd%g=pQX-4Dl6iXM5Mi<r zx3XG;>Vv|lLZtLmrnv*{Q%xxtcWVj3K4M%$bdBk_a&ar{{GWyu#ljM;dII;*jP;QH z#+^o-A4np{@|Mz+LphTD0`FTyxYq#wY)*&Ls5o{0z9yg2K+K7ZN>j1>N&;r+Z`vI| zDzG1LJZ+sE?m?>x{5LJx^)g&pGEpY=fQ-4}{x=ru;}FL$inHemOg%|R*ZXPodU}Kh zFEd5#+8rGq$Y<_?k-}r5zgQ3jRV=ooHiF|@z_#D4pKVEmn5CGV(9VKCyG|sT9nc=U zEoT67<jXapz33SQGdVleW*J=p6l-iq5HGgGZNX3gcnDtqDqT6Lxf&Cy#Ap6*__@(N zI9l&1+PZ(2&t7;rjbr<N3;GXPQmR+Jb=l@GOikZr!v7KeKwAmIz6g%ucSA?oWgocV zk;d7L7JWl9$p0E+2q4zN?=f=Aph6SF??-{0uw#y<{6dXC$UJvvFots-eZ*CWmiR<m z^L^@#CZ2{u<>R`C->KY8Wp-fEcjjFm^;Cg(ls|*ABVHq8clBE(;~K^b+S>6uj70g? z&{XQ5U&!Z$SO7zfP+y^8XBbiu*Cv-yJG|l-oe*!s5$@Lh_KpxYL2sx`<G0?@o|1&5 z++RB?zrCfT7`A&iZHeO}uiAn(9Y;?H+|QxaD&F$T&wYPv^@%QzORq4V7h)QaA?IS+ zFB!z6yTuA4F{2w*bnO?o`KM7U>B|V=dETN>5K+C+CU~a_3cI8{vbu$TNVdGf15*>D zz@f{zIlorkY>TRh7mKuAlN9A0>N>SV`X)+bEHms=mfYTMWt_AJtz_h+JMmrgH?mZt zm=lfdF`t^J*XLg7v+iS)XZROygK=CS@CvUaJo&w2W!Wb@aa?~Drtf`JV^cCMjngVZ zv&xaIBEo8EYWuML+vxCpjjY^s1-ahXJzAV6hTw%ZIy!FjI}aJ+{rE&u#>rs)vzuxz z+$5z=7W?zH2>Eb32dvgHYZtCAf!=OLY-pb4>Ae79rd68E2LkVPj-|jFeyqtBCCwiW zkB@kO_(3wFq)7qwV}bA=zD!*@UhT`geq}ITo%@O(Z5Y80nEX~;0-8kO{oB6|(4fQh z);73T!>3@{ZobPwRv*W?7<u$fR#FIIDQ|?d;-=4~nL_DQNR_L(s2gGB|Bi%bXbI)! ztn@6?NW&ORN!+hVmb|xpUMHeP-Y*-8YoeQ$=7K(Sd>m0Ml9GmJBCJd&6E?hdj9lV= z4flNfsc(J*DyPv?RCOx!MSvk(M952PJ-G|JeVxWVjN~SN<fFWRb2=9964Bd}-9L0# za&bfyJOi!#T%8p@)e{#M*HC~_RDcB;kF@?XCf0o$;#0Tz<%{^IxQ6b()`kCzGw`pn zvVV06qCVS*7lZ)(o7Gp6ekOkuzzxs?O%%&Yp1+cWnn|fKYX<Z-8@MV#wqF)qqV5*o zSnWk1rIdh6FPQo!-hS8qsY!O5JD<AlIn95(ae6Jd?fWIAFM+L&sw_o{)ZY*mza^{a zFgSda?4Av^CAF7cj@(}R6JgOpyFKsFTD;d44h4&<Jz-_1F5J{G+LW?&6IhxYcs@xb zl@w&aT)k@tK}w%(8c;t<C(7s<T@#tgO(Q)4E9>S6n-_Ge3Q;TGE;EQvZg86%wZ`MB zSMQua(i*R8a75!6$QRO^(o7sGoomb+Y{OMy;m~Oa`;P9Yqo><o$qrN{Uy#{EYZAYV zhkQ~i`~tBVbX%VYXh`B$bAR$*>?bJAhqXxLr7_3g_n>f#UVtxG!^F#1+y@os6x(sg z^28bsQ@8rw%Gxk-stAEPRbv^}5sLe=VMbkc@J<s@rA3iE(48`CbnWn(=&3DF#J=}a z4FTXYopd?mZI}}1ZlC8~VV`QLNWV;~TVEZ~uaDc-&}W%0xomagCDhH<gooe&naXnn z<tUH-X!YNVZ5{|0$(F_l%}+PcEZ$(<;b4&E&i=){rcO+Hkk=zdTK^Ffd=*LS^6eUA zUbs7^NXMxkl#^HyJ=dcJiSCooRo<stw%BQ{lj}<*D~N?4*Cut%z#~2r#dSIApv9<Q zjHtNwb#+f5agUh9@-@^){GvYFJ5KG7zCVqj%Df~m{m3x+{p&MW3!dR+pvL^5ZRmC0 zC309}MqA9m^d9B_Vk}86VV~U#6&}A3g}?sHV+qTd>jimqjvmd!3E7+QnL>|(^3!R} zD-l1l7*Amu@j+PWLGHXXaFG0Ct2Q=}5YNUxEQHCAU7gA$sSC<5OGylNnQUa>>l%sM zyu}z6i&({U@x^hln**o6r2s-(C-L50tQvz|zHTqW!ir?w&V23tuYEDJVV#5pE|OJu z7^R!A$iM$YCe?8n67l*J-okwfZ+ZTkGvZ)tVPfR;|3gyFjF<h<Cj<zZh5#4y5>)8V zyXXN=!*bpyRg9#~Bg1+U<pnWYhrolu{FPCsV0iobLA4JkV_p&4r@K1M;NHG>DYCt0 ztp4&?t1X0q>uz;an<Pmca*5{xy^4kc>n$OrZs{5*r`(oNvw=$7O#rD|Wuv*wIi)4b zGtq4%BX+kkagv3F9Id6~-c+1&?zny%w5j&nk9SQfo0k4LhdSU_kWGW7axkfpgR`8* z!?UTG*Zi_baA1^0<wK9e#G~fPDt@KdN$SZ|%nA9j-17!`BH9vUH0o`1P&6J*h<;ef zVW;53QYa7AXJdrlTA-n?%wp6d3?_b6<x05IZ{WEejqFp)B0lVPV-bRe>eda8S|@&F z{)Rad0kiLjB|=}XFJhD(S3ssKlveFFmkN{Vl^_nb!o5M!RC=m)V&v2%e?ZoRC@h3> zJ(?pvToFd`*Zc@HFPL#=otWKwtuuQ_dT-Hr{S%pQX<6dqVJ8;f(o)4~VM_kEQkMR+ zs1SCVi~k>M`u1u2xc}>#D!V&6nOOh-E$O&SzYrjJdZpaDv1!R-QGA141WjQe2s0J~ zQ;AXG)F+K#K8_5HVqRoRM%^EduqOnS(j2)|ctA6Q^=|s_WJYU;Z%5bHp08HPL`YF2 zR)Ad1z{zh`=sDs<zGHk8(=f(sFR?;R<HJ%pYo-KSa+@gOo;(hTO4p7NJfbujY~Kee zGHQPHC}zX0H$dR?nrR`jLKzUvcA{-a5@SQ^UbQXYN=CS}aw?OAqkUt?H8F&>^&V}J z%$Z$!jd7BY5AkT?j`eqMs%!Gm@T8)4w3GYEX~IwgE~`d|@T{WYHkudy(47brgHXx& zBL1yFG6!!!VOSmDxBpefy2{L_u5yTwja&HA!mYA#wg#bc-m%~8aRR|~AvMnind@zs zy>wkShe5&*un^zvSOdlVu%kHsEo>@puMQ`b1}(|)l~E{5)f7gC=E$fP(FC2=F<^|A zxeIm?{EE!3sO!Gr7e{w)Dx(uU#3WrFZ>ibmKSQ1tY?*-Nh1TDHLe+k*;{Rp!Bmd_m zb#^kh`Y*8l|9Cz2e{;RL%_lg{#^Ar+NH|3z*Zye>!alpt{z;4dFAw^^H!6ING*EFc z_yqhr8d!;%nHX9AKhFQZBGrSzfzYCi%C!(Q5*~hX>)0N`vbhZ@N|i;_972WSx*>LH z87?en(;2_`{_JHF`Sv6Wlps;dCcj+8IJ8ca6`DsOQCMb<Z@pezuQ&fWzt;cz#SUWI zcqV2XJ90lftQ?~%HDz)~)GJXKcKN}4st=)aT3chrg_EA{?3LcT)!JaRZ}=sv*>3n# z3)_w%FuJ3>fjeOOtWyq)ag|PmgQbC-s}KRHG~enBcIwqIiGW8R8jFeBNY9|YswRY5 zjGUxdGgUD26wOpwM#8a!Nuqg68*dG@VM~SbOroL_On0N6QdT9?)NeB3@0FCC?Z|E0 z6TPZj<t(m7DtKHBH@$**2Zo{c79USiF>(AsPtwCw>*{eDEE}Gby>0q{*lI+g2e&<d zeHwJP(&NSri;iaCB`Kw+7PmoLhp%WLBbMtYj3S7->(YQrsY&uGM{O~}(oM@YWmb*F zA0^rr5~UD^qmNljq$F#ARXRZ1igP`MQx4aS6*MS;Ot(1L5jF2NJ;de!NujUYg$dr# z=TEL_zTj2@>ZZN(NYCeVX2==~=aT)R30gETO{G&GM4XN<+!&W&(WcDP%oL8PyIVUC zs5AvMgh6qr-2?^unB@mXK*Dbil^y-GTC+>&N5HkzXtozVf93m~xOUHn8`HpX=$_v2 z61H;Z1qK9o;>->tb8y%#4H)765W4E>TQ1o0PFj)uTOPEvv&}%(_<LSzDTRe;Ie+2@ ztS!_=d%s5$G(s@--l3N6rQ)s8U_l;8K^1JNd@9$&rF%j>mG0ISmyhnQV33Z$#&yd{ zc{>8V8XK$3u8}04CmAQ#I@XvtmB*s4t8va?-IY4@CN>;)mLb_4!&P3XSw4pA_NzDb zORn!blT-aHk1%Jpi>T~oGLuh{DB)JIGZ9KOsciWs2N7mM1JWM+lna4vkDL?Q)z_Ct z`!mi0jtr+4*L&N7jk&LodVO#6?_qRGVaucqVB8*us6i3BTa<Q)$L85GR#EfdqV+R= zf3l>^^EI0x%EREQSXV@f!lak6Wf1cNZ8>*artIJ(ADO*=<-an`3zB4d*oO*8D1K!f z*<txU<LU~pP7SiW&ptI|Ssyh1rN!%<&LcD}5;B1lVw_<Fz9i;*7Icnh+iR{wkbxFv zHQ>A@P1bZCNtU=p!742MrAj%&5v%Xp_dSX@4YCw%F|%Dk=u|1BOmo)HsVz)nD5USa zR~??e61sO(;PR)iaxK{M%QM_rIua9C^4ppVS$qCT9j2%?*em?`4Z;4@>I(c%M&#cH z>4}*;ej<4cKkbCAjjDsyKS8rIm90O)Jjgyxj5^venBx&7B!xLmzxW3jhj7sR(^3Fz z84EY|p1NauwXUr;FfZjdaAfh%ivyp+^!jBjJuAaKa!yCq=?T_)R!>16?{~<b2tOP~ z47Nm=L%=a2H5%-;PoTI9Zf8Q{gX)6FgL99Sq~HCCHEEWym2icXnIe}8P_;ArgG0CO zf`4Rr(ciS_AIGt|OsCGh)=l12V2IHdqu&-WW<-O!NRu$)_PXwf_YA1=lIto-SBdBp zc;mWJN=QE`GD!ww=QztESZcD3U_Jx*+2x>p)FQ3LDoMyG%hL#pR!f@P%*;#90rs_y z@9}@r1BmM-SJ#DeuqCQk=J?ixDSwL*wh|G#us;dd{H}3*-Y7Tv5m=<O-p8_PlVR?L zh4I(^CY;zbW$TKH9!Xrci9D`~7Tt_MnPoyJiw3E%9=)V8`no!#&SD?Z3i8z<VyM}0 zABD#E*H)<&R|%HW;*e1VGvE8RGjpVF<el}tkQ-ZH>bQJMcH+_S`zVtf;!0kt*(zwJ zs+kedTm!A}cMiM!qv(c$o5K%}Yd0|nOd0iLjus&;s0Acvoi-PFrWm?+q9f^FslxGi z6ywB`QpL$rJzWDg(4)C4+!2cLE}UPCTBLa*_=c#*$b2PWrRN46$y~yST3a2$7hEH= zNjux+wna^AzQ=KEa_5#9Ph=G1{S0#hh1L3hQ`@HrVnCx{!fw_a0N5xV(iPdKZ-HOM za)LdgK}1ww*C_>V7hbQnTzjURJL`S%`6nTHcg<XB+ozL*{rR!_$M~K9Ao~6H!H^=h zwoacr(!lN?6COXY0RI?8^Y3)nD5dew#%KWle2X)4QJ|3aSbkvB3|XvJ4T7PtDp@RC zL=FRTdKkZak;Ble+c&|%U<4_;=Pv@V_7`H`L@;$HHik1Cov%9Y?v|ejzhoH-_ORGg z?z#NpZ8<kuALb{N_e(NeGkem>S+dB6b_;PY1FsrdE8(2K6<T$5h-ID+y%Pgc&YiJj zQSx)n1qnTmVVNMYY68M{^SPS)&CE>FN>37!62j_cBlui{jO^$dPkGHV>pXvW0EiOA z<TH9~Xay1oO$zQ#3a3<TF-+#*^SkQT;5{#&5>qW`YaSUBWg_v^Y5tPJfWLcLpsA8T zG)<v7DAcVy#7Wn65S?qZDrUX35PlA`Aoi+&wVKj813Fm5$JK2HOhK_!#&jYh-6-UE z?+!tn`6hPZXOsq_tvt7v))8yvK|C^QB-3YDBn&zFRg<%>!x>pKMpt!lv3&KV!-um= zKCir6`bEL_LCFx4Z5bAFXW$g3Cq`?Q%)3q0r852XI*Der*JNuKUZ`C{cCuu8R8nkt z%pnF>R$uY8L+D!V{s^9>IC+bmt<05h**>49R*#vpM*4i0qRB2uPbg8{{s#9yC;Z18 zD7|4m<9qneQ84uX|J&f-g8a|nFKFt34@Bt{CU`v(SYbbn95Q67*)_Esl_;v291s=9 z+#2F2apZU4Tq=x+?V}CjwD(P=U~d<=mfEFuyPB`Ey82V9G#Sk8H_Ob_RnP3s?)S_3 zr%}Pb?;lt_)Nf>@zX~D~TBr;-LS<1I##8z`;0ZCvI_QbXNh8Iv)$LS=*gHr;<k-Rm zCOX3iwRBMS%2HbhB&55bKxXVrjksHaE!$yhFQVOkB9&b;RXWYu12Q{oZxRnIOVr=+ zV;u%|w58=ulh(mY=94oS*pT{cO%ppm(zvJWm<qAqWJ+tsD$mc#zQ-$!O_aUVS(xv& zlic&3<NOINl%vfa(YE-09OenqqI00N?`6YZ&y5jRWu1$*;ND0xgkIT8GGJ<pZ_BqS zfzf6E9oArEF5xqlU<TZaFS?_~jIlVR?u(-sg0I7Ln4&`lfjy*Sukl^_TcEsDm~(l} z+s}VbwTMn&y0~O&Noc7}EK>}dgb=w5$3k2la1keIm|=7<-JD>)U%=Avl0Vj@+&vxn zt-)`vJxJr88D&!}2^{GPXc^nmRf#}nb$4MMkBA21GzB`-Or`-3lq^O^svO7Vs~FdM zv`NvzyG+0T!P8l_&8gH|pzE{N(gv_tgDU7SWeiI-iHC#0Ai%Ixn4&nt{5y3(GQs)i z&uA;~_0shP$0Wh0VooIeyC|lak__#KVJfxa7*mYmZ22@(<^W}FdKjd*U1CqSjNKW% z*z$5$=t^+;Ui=MoDW~A7;)Mj%ibX1_p4gu>RC}Z_pl`U*{_z@+HN?AF{_<AT&sf>W z?M_X@o%w8fgFIJ$fIzBeK=v#*`mtY$HC3tqw7q^GCT!P$I%=2N4FY7j9nG8aIm$c9 zeKTxVKN!UJ{#W)zxW|Q^K!3s;(*7Gbn;e@pQBCDS(I|Y0euK#dSQ_W^)sv5pa%<^o zyu}3d?Lx`)3-n5Sy9r#`I{+t6x%I%G(iewGbvor&I^{lhu-!#}*Q3^itvY<Y65Bs! z6}9J&T3Jmx%Jeo0UA1RUWfC4^3~`bOw#&=(RdYfoBOtonl9x?Q%%ud_8xGfac}V3S z_t?8@P9D{AMY+HQj#M?0#<Loprwk<zPs3>(^UWXgvthH52zLy&T+B)Pw;5>4D6>74 zO_EBS)>l!zLTVkX@NDqyN2cXTwsUVao7$HcqV2%t$YzdAC&T)dwzExa3*kt9d(}al zA~M}=%2NVNUjZiO7c>04YH)sRelXJYpWSn^aC$|Ji|E13a^-v2MB!Nc*b+=KY7MCm zqIteKfNkONq}uM;PB?vvgQvfKLPMB8u5+Am=d#<Ofl>>g+o&Ys<k|1Ag^|(Lcq#YS zJ3m+ShjMEKKXbb?#zc6~_{8T^k&I4kx<j?2OLnw(e9?2R%ab*KIh|OcYkV*-ppCU+ z&<4=VL>b>dX9EC8q?D$pJH!MTA<fJX`-o>qa=DS5$cb+;hEvjwVfF{4;M{5U&^_+r zvZdu_rildI!*|*A$TzJ&apQWV@p{!W`=?t(o0{?9y&vM)V)ycGSlI3`;ps(vf2PUq zX745#`cmT*ra7XECC0gKkpu2eyhFEUb?;4@X7weEnLjXj_F~?<g~DII^Bcx&poTYi zLVuwObActGKn>OzL1U1L0|s6M+kIhmi%`n5vvDALMagi4`wM<y{<R6>c=JV{XiO+^ z?s9i7;GgrRW{Mx)d7rj)?(;|b-`iBNPqdwtt%32se@?w4<^KU&585_kZ=`Wy^oLu9 z?DQAh5z%q;UkP48jgMFH<isTC5e=i>Tf#m<K<awZyB<dC!4ZWVVj?0l^>j?#z|=w= z(q6~17Vn}P)J3M?O)x))%a5+>TFW3No~TgP;f}K$#icBh;rSS+R|}l鯊%1Et zwk~hMkhq;MOw^Q5`7oC{CUUyTw9x>^%*FHx^qJw(LB+E0WBX@{Ghw;)6aA-KyYg8p z7XDveQOpEr;B4je@2~usI5BlFadedX^ma{b{ypd|RNYqo#~d*mj&y`^iojR}s%~vF z(H!u`yx68D1Tj(3(m;Q+Ma}s2n#;O~bcB1`lYk%Irx60&-nWIUBr2x&@}@76+*zJ5 ze&4?q8?m%L9c6h=J$WBzbiTf1Z-0Eb5$IZs>lvm$>1n_Mezp*qw_pr8<8$6f)5f<@ zyV#tzMCs51nTv_5ca`x`yfE5YA^*%O_H<xfnQ6>?;tWYdM_kHPubA%vy47i=9>Bq) zRQ&0UwLQHeswmB1yP)+Bi<gYuF=;5%P5fb($ua)vN{<dTS}pc$-noYj&~P(-vz}$v zu3jpy02nRu2m5&K8!o)7k}0wq<;X00@Xx7A<mINk!<+VpN#`s2^mC5Ofe4$`&tl#* z>R;S+Vc-5TX84KUA;8VY9}yEj0eESSO`7HQ4lO<y)w_Q~B}%2$aGK(6Ummn<`kl%; z`ex#21X!9UBm3Vc-U~%seDuubCS=6He};CM149#aL;PRFuT<U<#xD2*e6V!HB9TS@ z-1@gJDr5k3GW(TMRP`M0C}32Sp)@iN+m7Q7FVkR-!Q93t0T{<wiGM)0t%$WJc@v;> z4(CyA8y1G7_C;6kd4U3K-aNOK!sHE}KL_-^EDl(vB42P$2Km7<xlD85HX*0-hkMZF zkjr5ZvT-#;Mth(cu<tj#atu~`yerH!&_Rq;m6S6;E=E^t8E;_e)$<aCEe^z9S}-Gm zR}d6r*AN)OHk0vR$wldVl&!rNQoW*!$WBpDRw`=6+$-g54384TvT>$WGqNy=%fqB+ zSLdrlcbEH=T@W8V4(TgoXZ*G1_aq$K^@ek=TVhoKRjw;HyI&coln|uRr5mMOy2GXP zwr*F^Y|!Sjr2YQXX(Fp^*`Wk905K%$bd03R<H!tySet(EP)5Lj`0&gFCZ@coqtHFV zq;TC+Ud)isOY`?v*vYVa0u2u<OuzeQhQx-th#lEeb|E85m0u7j#xz<Q(27O50YNZG z_X!_ZeKj36XsF4fNkWJ-X&&`{PiP|d5I{)ntoL7!_lyc3!C3?s@K?fxx2uj~W~|6a z@37XYDSt)e<cy5Hg6yFElSnilL`l_9#54dfOVI=v!_cyZ8P0}j&eAUCbFyagF03t) ziN>4(igl0&7IIm*#f`A!DCarW9$h$z`kYk9MjjqN&5-DsH@8xh63!fTNPxWsFQhNv z#|3RjnP$Thdb#Ys7M+v|>AHm0BVTw)EH}>x@_f4zca&3tXJhTZ8pO}aN?(dHo)44Z z_5j+YP=jMlFqwvf3lq!57-SAuRV2_gJ*wsR_!Y4Z(trO}0wmB9%f#jNDHPdQGHFR; zZXzS-$`;7DQ5vF~oSgP3bNV$6Z(rwo6W(U07b1n3UHqml>{=6&-4PALATsH@Bh^W? z)ob%oAPaiw{?9HfMzpGb)@Kys^J$CN{uf*HX?)z=g`J(uK1YO^8~s1(ZIbG%Et(|q z$D@_QqltVZu9Py4R0Ld8!U|#`5~^M=b>fnHthzKBRr=i+w@0Vr^l|W;=zFT#PJ?*a zbC}G#It}rQP^Ait^W&aa6B;+0gNvz4cWUMzpv(1gvfw-X4xJ2Sv;mt;zb2Tsn|kSS zo*U9N?I{=-;a-OybL4r;PolCfiaL=y@o9{%`>+&FI#D^uy#>)R@b^1ue&AKKwuI*` zx%+6r48EIX6nF4o;>)zhV_8(IEX})NGU6Vs(yslrx{5fII}o3SMHW7wG<xJ7RkURX zL?-%U*5SbEvYh>tK9oIO4OM&@@ECtXSICLcPXoS|{;=_yj>hh*%hP27yZwOmj4&Lh z*Nd@OMkd!aKReoqNOkp5cW*lC)&C$P?+H3*%8)6HcpBg&IhGP^77XPZpc%WKYLX$T zsSQ$|ntaVVOoRat$6lvZO(G-QM5s#N4j*|N_;8cc2v_k4n6zx9c1L4JL*83F-C1Cn zaJhd;>rHXB%%ZN=3_o3&Qd2YOxrK~&?1=UuN9QhL$~OY-Qyg&})#ez*8Np<qwhY!r zPGi5Uv36_KU&P;Ysny7Yn7Aq*w^YJk+j;r5!{54y2KTRW=n4P9Q$RrUV@IzXwTG1s zzW93%6>QW_*<cOtWE@YNsI)L#ntpV!%&tkEA2b<G(kTCfol|w3coc&So$?P2SFmWk zBWp7V`+IlUb`e$B*<dRPJ-ehhZQ$M{k7#onRlEE~dw{L=-9ElX-V5A(;-ZBE+Yf{^ z{+-Mf7yUbWUdboXPA1sh*z~xCt^6m6c{6_JCok9HQbYRhr51?*l;sOM;AIxuJ4Q$p z`CgAJ+<9O64PUJ^k}^%FQclq}Wk!;S2TZ^{;?u15<et5AgcPi>a&kD&ANjedxT0Ar z<6r{eaVz3`d~+N~vkMaV8{F?RBVemN(jD@S8qO~L{rUw#=2a$V(7rLE+kGUZ<%pdr z?$DP|Vg#gZ9S}w((O2NbxzQ^zTot=89!0^~hE{|c9q1hVzv0?YC5s42Yx($;hAp*E zyoGuRyphQY{Q2ee0Xx`1&lv(l-SeC$NEyS~8iil3_aNlnqF_G|;zt#F%1;J)jnPT& z@iU0S;wHJ2$f!juqEzPZeZkjcQ+Pa@eE<F$7REzl$4Vg!h~1-QZGdPJ^bJ@K4OS*c zP-fR4iXy^QA;#1=y2VI*LRPhjykLV({@6o-twx$xfBE}QnTt6vqFElm=UM-(NfZCi z=lx&9)JZKEFO|hbLCVw#&(sbpFfqulk`VBkNi?$lD5(B0WM5ff*mCA1f5%740p~O| ztQOb8UFr=BBea^EKn!z+v}nk*YvS7NtKQ8K+R4>RSLKsWf=`{R@yv7AuRh&ALRTAy z8=g&nxsSJCe!QLchJ=}6|LshnX<g_y(YX??7D<ya@4%V<9h+|Ic_N&p+^6cL1%rRw zI`_<$r7i-QeU%G7oxJ6b$}<GVE+7g7j;H#VPbD7FMNK~{pfkqz8k&Qk100>IK)SNd zRkJNiqHwKK{SO;N5m5wdL&qK`v|d?5<4!(FAsDxR>Ky#0#t$8XCMptvNo?|SY?d8b z`*8dVBlXTUanlh6n)!EHf2<Z;<pqvCOZ=A2H>&PDG8sXNAt6~u-_1EjPI1|<=33T8 zEnA00E!`4Ave0d&VVh0e>)Dc}=FfAFxpsC1u9ATfQ`-Cu;mhc8Z>2;uyXtqpLb7(P zd2F9<3cXS<T6BO6%Wff4)w8RK^!PZ}fJ&%B?D(O0phg;sxkMq1g;&s2yVy|dlo7$& zut6p%Pt5t7R%%o@lpz7mamy48(tCjGd57eFCrjgxV_IjQOo{Eq=LdqW@am;MINbXP zIQr$cxXwNaQ_H6v`p4(aUBXrmz}**&%<Zzfbtj+pDbBMu#7x_{KfkOxH1}OCyx<aM zu@SXrn_{seG?|N7mo)o<BmjNPRWwBLiQLKA5vhgn!8ZTe76=gv#-hh7?ex$Xtz9>} znMg?{&8_YFTGRQZEPU-XPq55%51}RJpw@LO_|)CFAt62-_!u_Uq$csc+7|3+TV_!h z+2a7Yh^5AA{q^m|=KSJL+w-EWDBc&I_I1vOr^}P8i?cKMhGy$CP0XKrQzCheG$}G# zuglf8*PAFO8%xop7KSwI8||liTaQ9NCAFarr~psQt)g*pC@9bORZ>m`_GA`_K@~&% zijH0z;T$fd;-Liw8%EKZas>BH8nYTqsK7F;>>@YsE=Rqo?_8}UO-S#|6~CAW0Oz1} z3F(1=+#wrBJh4H)9jTQ_$~@#9|Bc1Pd3rAIA_&vOpvvbgDJOM(yNPhJJq2%PCcMaI zrbe~toYzvkZYQ{ea(Wiyu#4WB#RRN%bMe=SOk!CbJZv^m?Flo5p{W8|0i3`hI3Np# zvCZqY%o258CI=SGb+A3yJe~J<XAm<h+@x%=dk!>H^i{uU`#U#fvSC~rWTq+K`E%J@ zasU07&pB6A4w3b?d?q<ZUdN`d9`jSQ6}@hE_t>}2=0rA#SA7D`X+zg@&zm^iA*HVi z009#PUH<%lk4z~p^l0S{lCJk1Uxi=F4e_DwlfHA`X`rv(|JqWKAA5nH+u4Da+E_p+ zVmH@lg^n4ixs~*@gm_dgQ&eDmE1mnw5wBz9Yg?QdZwF|an67Xd*x!He)Gc8&2!urh z4_uXzbYz-aX)X1>&iUjGp;P1u8&7TID<T*k)hrSs$ZMYU#eY?f%J<TYM`ZV5WD$80 zG6we^sim<v0ffzyR3HV@k#_?T5yB1?r-E~gnJ!jx=#l~KWX=|*TsGqUMbMy7&Dlm$ zkg`~ug9}A)NTCqAmF?i{?tn%$xnbe}sXgn0Ns#1Tz9yxnXess97ti7|9c?mVx|E|M zsw|@!R#sWRksSuwE0qkq{xVpVBsF7Y5`nBxFc=Vb@S*=tu3_rkiM*j^3$OH{X3IB$ zsB0-+Fdr>0bTH-jCL&Xk8b&<MC!nk<L_l*|?aq$M0{!H9`RQ21GGD+c^BcX*2|SYI zugFZ`gqDwwr<(%$82O_6nOWDm!eA(RGpBfa<+B;MKzgz`W@E7E&XQR*%r|=RjJ(AQ z1GcBC!v)wKu_J~RfHh}+ZjQp_Xx>;;6p2op_=y^m@Nq*0{#o!!A;wNAFG@0%Z9rHo zcJs?Th>Ny6+hI`+1XoU*ED$Yf@9f91m9Y=#N(HJP^Y@ZEYR6I?oM{>&Wq4|v0IB(p zqX#Z<_3X(&{H+{3Tr|sFy}~=bv+l=P;|sBz$wk-n^R`G3p0(p>p=5ahpaD7>r|>pm zv;V`_IR@tvZreIuv2EM7ZQHhO+qUgw#kOs%*ekY^n|=1#x9&c;Ro&I~{rG-#_3ZB1 z?|9}IFdbP}^DneP*T-JaoYHt~r@EfvnPE5<mj|3vYvi%XA!0DTe17}~aG2h7eq*~r z9|l2u19&ExDJOsRZ$@8=z;;HhZw$_SviSm}uAwc_ow2rT=iX2K1>EKUwIxjPbsr$% zfWW83pgWST7*B(o=kmo)74$8UU)v0{@4DI+ci&%=#90}!CZz|rnH+Mz=HN~97G3~@ z;v5(9_2%eca(9iu@J@aqaMS6*$TM<otkyEUfDAtMmVO5=3I}?EG6T26ue>w!S>H(b z4(*B!|H|8&EuB%mITr~O?vV<E-8Z6S)k5lzkIaVLJC566nZk>Ef%(Gr)6E=>H~1VR z&1YOXluJSG1!?TnT)_*YmJ*o_Q@om~(GdrhI{$Fsx_zrkupc#y{DK1WOUR>tk>ZE) ziOLoBkhZZ?0Uf}cm>GsA>Rd6V8@JF)J*EQlQ<=JD@m<)hyElXR0`pTku*3MU`HJn| zIf7$)RlK^pW-$87U;431;<klhG5_ER>Ye4Ie+l~_B3*bH1>*yKzn23cH0u(i5pXV! z4K?{3oF7ZavmmtTq((wtml)m6i)8X6ot_mrE-QJCW}Yn!(3~aUHYG=^fA<^~`e3yc z-NWTb{gR;DOUcK#zPbN^D*e=2eR^_!(!RKkiwMW@@yYtEoOp4XjOGgzi`;=8<Yusf zN5l6kO$1L;ws<m1`Zh#?`63unV{T(2V21gcCYV&FhZqe6Nass1MK|Z4KyXbkzmY5} zZ?_?UexvC&zoC0o1N+Vde1)9v5Lgfss-n~Y`wrFPCpU&f2y~X5VS8!)_$jxG?x+Q> zi3`Ccw1%L*y(FDj=C7Ro-V?q)-%p?Ob2ZElu`eZ99n14-ZkEV#y5C+{Pq87Gu3&>g zFy~Wk7^6v*)4pF3@F@rE__k3ikx(hzN3@e*^0=KNA6|jC^B5nf(XaoQaZN?Xi}Rn3 z$8&m*KmWvPaUQ(V<#J+S&zO|8P-#!f%7G+n_%sXp9=J%Z4&9OkWXeuZN}ssgQ#Tcj z8p6ErJQJWZ+fXLCco=RN8D{W%+*kko*2-LEb))xcHwNl~Xmir>kmAxW?eW50Osw3# zki8Fl$#fvw*7rqd?%E?}ZX4`c5-R&w!Y0#EBbelVXSng+kUfeUiqofPehl}$ormli zg%r)}?<O#LIQ<x^r>%=?_pHb9`Cq9Z|B`L8b>(!+8HSX?`5+5mm81AFXfnAt1*R3F z%b2RPIacKAddx%JfQ8l{3U|vK@W7KB$CdLqn@wP^?azRks@x8z59#$Q*7q!KilY-P zHUbs(IFYRGG1{~@RF;Lqyho$~7^hNC`NL3kn^Td%A7dRgr_&`2k=t+}D-o9&C!y^? z6MsQ=tc3g0xkK(O%DzR9nbNB(r@L;1zQrs8mzx&4dz}?3KNYozOW5;=w18U6$G4U2 z#2^qRLT*Mo4bV1Oeo1PKQ2WQS2Y-hv&S|C7`xh6=Pj7MNLC5K-zokZ67S)C;(F0Dd zloDK2_o1$Fmza>EMj3X9je7e%Q`$39Dk~GoOj89-6q9|_WJlSl!!+*{R=t<I5W)Q1 zkAGZ6mVbAZdwNx+cM^(`G%H7T29zgao{aSHP_2`opHKbyoo@LZV-ND6*ct<1X->Gp z8u|MuSwm^t7K^nUe+^0G3dkGZr3@(X+T<R{A2|{q4h1HZkio;YA1t6>L5eah)K^Tn zXEtHmR9UIaEYgD5Nhh(s*fcG_lh-mfy5iUF3xxpRZ0q3nZ=1qAtUa?(LnT9I&~uxX z`pV?+=|-Gl(kz?w!zIieXT}o}7@`QO>;u$Z!QB${a08_bW0_o@&9cjJUXzVyNGCm8 zm=W+$H!;_Kzp6WQqxUI;JlPY&`V}9C$8HZ^m?NvI*JT@~BM<?RV=J&{dty%0kuvcV zvDY*i(P?K=6~(~xZAsj_c^PMb&#Z`Y|Lurd8fSVQU$p5WH?x?Xpj)rsBdv*QxJ##A zM=~|M*Y>=()T()Ii#+*$y@lTZBkmMMda><ZXF}$122DAC4inciHEXN*L_tT(?E|%+ zt7Py*&-=;dUzJ7C=EUZz8ph9x9vB|ACLKw@s&c^<^F0YA3k;p}2F-(+6L*|cO&Kx| zGV=>7s#O(1YZR+zTG@&<R7(G2<E$<wduz9!FnD8M=}U%cAl$d*6}Sq3Sm>}!EXFG{ zEWPSDI5bFi;NT>Yj*FjH((=oe%t%xYmE~AGaOc4#9K_XsVpl<4SP@E!TgC0qpe1oi zNpxU2b0(lEMcoibQ-G^cxO?ySVW26HoBNa;n0}CWL*{k)oBu1>F18X061$SP{Gu67 z-v-Fa=Fl^u3lnGY^o5v)Bux}<gD3`?Qhv)PX)U=^-kffCXQ$p2csKZNM5x8!RMUOX zrn9?t`{WKqC0A+hrI3CS?R@viwL~gPCU^BRur-hw0CEwaK7f#%S}_w7_H%2lZVcgk zQL;J=ry;kmi}ZUr-!!m`rCH2ERpwJ6Q|G`5r-Xy0r?6;<g{<5%zr{9CmP^vf>bNZ~ z5pL+7F_Esoun8^5>z8NFoIdb$sNS&xT8_|`GTe8zSXQzs4r^<Z>g0kZjg(b0b<J|) z&kyXHVzP24v$IxevEHN?k6>Jvz`g<70u9Z3fQILX1Lj@;@+##bP|FAOl)U^9U>0rx zGi)M1(Hce)LAvQO-pW!MN$;#ZMX?VE(22lTlJrk#pB0FJNqVwC+*%${Gt#r_tH9I_ z;+#)#8cWAl?d@R+O+}@1A^hAR1s3UcW{G+>;X4utD2d9X(jF555}!TVN-hByV6t+A zdFR^aE@GNNgSxxixS2p=on4(+*+f<8xrwAObC)D5)4!z7)}m<cS(iD4<A0N$g+SqA zl%O;ERC__&2rvP%TMdpBGey$+i_(aSuJSoOVG@%hWSWo?*uZz-46eyt;fOY4@j*cs z(Nlf$ie?ANAv6K4_-a2q*kk+$A3)y-+s^rqkRC|T=Yj2fF?eZ}!9uZg3msy525K;C zG$r&@M9n%7`Sgm&aIl}13Vz%ip9hGWt!og5bdx1qTG)j2nL>Tpb7&ofF3u&9&wPS< zB62WHLGMhmrmOAgmJ+|c>qEWTD#jd~lHNgT0?t-p{T<Fhnjc^O*n1^SI<&BNNFb%X zHxbuJadh!4YtYH|wpEljX5ubnIb*m`KO@(XQ|K!ErMf$l_=~Nst8I^_;~LFMY;jPd z>=~#E<K9VH{%))?p1uEh9GO_D_^6?&!kOhc5(&300G7)A4!13Ozm(lvh<tIpVpv;w z$Zq4R)GbGst(09X1uL^1TcWYOO$_QS5|?mAC8?<QY1GusEAbgtUMGPRN?~sU>McB| z=AoDKOL+qXCfk~F)-Rv**V}}gWFl>liXOl7Uec_8v)(S#av99PX1sQIVZ9eNLkhq$ zt|qu0b?GW_uo}TbU8!jYn8iJeIP)r@;!Ze_7mj{AUV$GEz6bDSDO=D!&C9!M@*S2! zfGyA|EPlXGMjkH6x7OMF?gKL7{GvGfED=Jte^p=91FpCu)#{whAMw`vSLa`K#atdN zThnL+7!ZNmP{rc=Z>%$meH;Qi1=m1E3Lq2D_O1-X5C;!I0L>zur@tPAC<By>9*7<! z3r5ih2IB%6&?*r6Z<C9~bdv;$Jz)vwe<Nu0(L5l%QJ@HdxjvyfFnvb*!a}9oGNK6E zqHxM7juWe=SSnY{v&Q7EoMOb}E}wD)CsC?77@`e0AQsRgp-@%+t|BGqN=<`p&67Ay z|1Ca)Xw?J?`0+tpDJa4VbOI+nCoMRhc94J)*YTm*Cvm6NKcmS0S8lEaP@BDlDO2j! z3B#9mbQbob%QSF`NGB1uJE%GFPC5TQVb=AS_#@8Xn3od@{x#f5jU7spPqbI@;gM2n zy<$hk+Hy??zt_V4Zq9&R;7&^l#vS@`iD+}{y4jLIDKXTJNC<QY9H?-HD>Je<e@N~V zM8{whHc_Y)oJRTaE@}6XBK;XqJh6DOZ%b~};oF1$Ja8>h)`;eec}1`nkRP(%iv-`N zZ@ip-g|7l6Hz%j%gcAM}6<zu1Fy2Y69l>-nrC8oA$BkOTz^?dakvX?`^=ZkYh%vUE z9+&)K1UTK=ahYiaNn&G5nHUY5niLGus@p5E2@RwZufRvF{@$hW{;{3QhjvEHMvduO z#Wf-@oYU4ht?#uP{N3utVzV49mEc9>*TV_W2TVC`6+oI)zAjy$KJrr=*q##&kobiQ z1vNbya&OVjK`<C+)|Y=S6qD0g+yj}rJu+*{Nv+8EH`6C*w=QvJZy_0aJA=(RR*FuE z=Ve*%{0>2pdRr<aX@8G=KRVz8TtomBSpcq@r(_ajX~o2yoaeZ}oez2h)8-QBk)?}3 z07=L4P3BU4*%bpPu*ZY*FM)E8NlN*R9eF#VQ}7$t%LL}o3#|L+gi2ok?oW7%M=|~p zC5<%;sq@8S<pakq(618P52%D<(#5rYl@k)nhPsY1k)aFy(uH>M?LuK6BgrLN7H_3m z!qpNKg~87XgCwb#I=Q&0rI*l$wM!qTkXrx1ko5q-f;=R2fImRMwt5Qs{P*p^z@9ex z`2#v(qE&F%MXlHpdO#QEZyZftn4f05ab^f2vjxuFaat2}jke{j?5GrF=WYBR?gS(^ z9SBiNi}anzBDBRc+QqizTTQuJrzm^bNA~A{j%ugXP7McZqJ}65l10({wk++$=e8O{ zxWjG!Qp#5OmI#XRQQM?n6?1ztl6^D40hDJr?4$Wc&O<sMJO3^;cmzln7W^zYPW<c) z|Nn)@|5@a8iRp(7<VO~{rdqT_5uSV!nd9F~6^REIQGA!cD-9=NGWybr;?0kXWZrN^ z3+v>_{*OfMfxe)V0=e{|N?J#fgE>j9jA<EEh|%C%>ajze$iN!*yeF%jJU#G1c@@rm zolGW!j?W6Q8pP=lkctNFdfgUMg92wlM4E$aks1??M$~WQfzzzXtS)wKrr2sJeCN4X zY(X^H_c^PzfcO8Bq(Q*p4c_v@F$Y8cH<tNdh?t1Gk+qA{Pne*ng|&%*k<pK?D`Q}5 zVD>LrH$`pJ2}=#*8%JYdqsqnGqEdBQMpl!Ot04tUGSXTQdsX&GDtjbWD=prcCT9(+ z&UM%lW%Q3yrl1yiYs;LxzIy>2G}EPY6|sBhL&X&RAQrSAV4Tlh2nITR?{6xO9ujGu zr*)^E`>o!c=gT*_@6S&>0POxcXYNQd&HMw6<|#{eSute2C3{&h?Ah|cw56-AP^f8l zT^kvZY$YiH8j)sk7_=;gx)vx-PW`hbSBXJGCTkpt;ap(}G2GY=2bbjABU5)ty%G#x zAi07{Bjhv}>OD#5zh#$0w;-vvC@^}<H!J~9x8ns3P(-h{dr(SdVxo7mkj}AsjC5HV zo6g6-m3quL?mvNQgld&;Wk&NDE-R7EZ)*~rtG<Lq_zyu{lXW&{xOyIFvsws8eo>F! z#X$@)zIs1L^E;2xDAwEjaXhTBw2<{&JkF*`;c3<1U@A4MaLPe{M5DGGkL}#{cHL%* zYMG+-Fm0#qzPL#V)TvQVI|?_M>=zVJr9>(<nvsf&9hvsWr%#7CsQ**Fe-0<7veWn* zbd^GxM~>6ib*#z8q@mYKXDP`k&A4A};xMK0h=yrMp~JW{L?mE~ph&1Y1a#4%SO)@{ zK2juwynUOC)U*hVlJU17%llUxAJFuKZh3K0gU`a<X-1W{<+F6zY3jg>P)pc~b<Vo8 zn2YAtCd;B0Avz@7p^Po{xMRCQYS{JVW8Z`GH$zG=#SS&KZ2A$u^x!Isx6mLPi?<ZN z*{kt-YdG0}`9!9hbnjn<=b=7lTPuWEpF+k^SZAjar2B<DQb{uEO;vTv3FqIDI3!LU zvasv6BD^}y#db_7<6NwPQSk6X)=~uy$Zd95xS~u)s@;O!EALmaQ@kYB`EY75*h2)s z-R#8r)o{~&P%kZgz*(Kw!pn_O3rshJwHWRYI|!$r!a4#|kLw{Kz&k3CZ#RtrYB!Yu z*A++a?kRokM)%Uo3N_uT!~ugsw#&4oIID7K+!k+)I;<)Si^E{(i)cD@HTao5;+q!0 zbwB*KzCL0ZC~g-PH7MbBVgTO07?^K#9=bcG8FQEIE=(6id^)U|^hS5OYQT5$J-!Sa zBvfO%E+b9eID~Xvvo@#oSJO3E?jiXTQ<upuXRYN+dqAs$<{%yP2cnwB9G5^{RErN2 z5a`n%B*&Qd&SoW|&P~{87+q;P_bbKnMD-j91aHnUm-Ol<>E~mM!i1mi!~LTf>1Wp< zuG+ah<cN%^mGc@zm->p^gH8g8-M$u{HUWh0m^9Rg@cQ{&DAO{PTMudV6c?ka7+AO& z746QylZ&Oj`1aqfu?l&zGtJnpEQOt;OAFq19MXTcI~`ZcoZmyMrIKDFRIDi`FH)w; z8+*8tdevMDv*VtQi|e}CnB_JWs>fhLOH-+Os2Lh!&)Oh2utl{*AwR)QVLS49iTp{6 z;|172Jl!Ml17unF+pd+Ff@jIE-{Oxv)5|pOm@CkHW?{l}b@1>Pe!l}VccX#xp@xgJ zyE<&ep<?&Ja!<vf;^Rc_Ext&<l)$GW^vhyI+JCe2O3`LUd|)s%0qsYi2%EvJz-tM3 zKY=mZW?7k^N!wTSw*{;yb$3mRD9vNKYL6QIU4KGF{JZXpqeFF?UNh<Hsu=#~nZ?*` z8?`-sY#3wWljoYqahkg_LR+fxC=Ok@srcz_lf5JG(Aw?<nC(WNHZ^iNeqvbZ784f| zUF|zFa%ZSkIT}iZS*J5%>$=*vT=}7vtvif0B?9xw_3Gej7mN*dOHdQPtW5kA5_zGD zpA4tV2*0E^OUimSsV#?Tg#oiQ<Gc63Xnq8{B?9(QSV36W&7QYB_fY=P6DiK#CwX}S zgr8jyAKT1k<~JoNlpe8K#uDWD6A;w{rqu&jtmBFgY_BM6uK=HK6yOqhbD)4G&d4Zx zgx}5JZQcjx2iiz|qys{K@f>>%4D@1F5@AHwT8Kgen$bSMHD3sXCkq8^(uo7CWk`mT zuslYq`6Yz;L%wJh$3l1%SZv#QnG3=NZ=BK4yzk#HAPbqXa92;3K5?0kn4TQ`%E%X} z&>Lbt!!QclYKd6+J7Nl@xv!uD%)*bY-;p`y^ZCC<%LEHUi$l5biu!sT3TGGSTPA21 zT8@B&a0lJH<Is)g$je?v)zrGnVnN*a?`1A_B7jSFYFL!G^YdU54T8BJ`&=Grt0wbK zm=GTh#mq0;L&QL~1)M*45{rzjOV&&Ibr2i!Ltb})&Q3g>Vn1I$I3I1I{W9fJAYc+8 zVj8>HvD}&O`TqU2AAb={?eT;0hyL(R{|h23=4fDSZKC32;wWxsV<K&5XXRr5uQ}LF z+0CB-DJWvs=zyhUDM(~V3gV_A(2WHskwSfbLhWS!Vr~&q4bY$lqS1mvz2zv7a&eyv zq27v0&hua?e7Hjc)2G9WDUS0kzHi?zAo?IsP=#m-cTywmevo}cL`cE(<Xi1(J>j`P z3J3{M$PwdH!ro*Cn!D&=jnFR>BNGR<<|I8CI@+@658Dy(lhqbhXfPTVecY@L8%`3Q z1Fux2w?2C3th60jI~%OC9BtpNF$QPqcG+Pz96qZJ71_`0o0w_q7|h&O>`6U+^BA&5 zXd5Zp1Xkw~>M%RixTm&OqpNl8Q+ue=92Op_>T~_9UON?ZM2c0aGm=^A4ejrXj3dV9 zhh_bCt-b9`uOX#cFLj!vhZ#lS8Tc47OH>*)y#{O9?AT~KR9LntM|#l#Dlm^8{nZdk zjMl#>ZM%#^nK2TPzLcKxqx24P7R1FPlBy7LSBrRvx>fE$9AJ;7{PQm~^LBX^k#6Zq zw*Z(zJC|`!6_)EFR}8|n8&&Rbj8y028~P~sFXBFRt+tmqH-S3<%N;C&WGH!f3{7cm zy_fCAb9@HqaXa1Y5vFbxWf%#zg6SI$C+Uz5=CTO}e|2fjWkZ;Dx|84Ow~bkI=LW+U zuq;KSv9VMboRvs<muUdEos4J@28PT^*5txvGZbKDaszyz$QdH{051B8A}wS50ihLR z^}*xLvwA_M{Vi%9v2EHPcjW2dClsn~)MPlr{(wj9a}gF+Q-M)HC}0<xaSL~ZQN-$F z7pVo2NF$PZ!~7c5`YO~K2nWlk*2_#MS>9)}2PAO|b(JCEC_A0wq{uEj|3x@}*=bOd zwr{TgeCGG>HT<@Zeq8y}vTpwDg#UBvD)BEs@1KP$^3$sh&_joQPn{hjBXmLPJ{tC) z*HS`*2+VtJO{|e$mM^|q<Nl<aNnR+M;uGuLoy^|5_yMTrUl*Jc;J-xFCNFUlNS9`1 z>v1R*8i(m1`%)}g=SU#T#0KlTM2RSvYUc1fP+va|4;5}Bfz98UvDCpq7}+SMV&;nX zQw~N6qOX{P55{#LQkrZk(e5YGzr|(B;Q;ju;2a`q+S9bsEH@i1{_Y0;hWYn1-79jl z5c&bytD*k)GqrVcHn6t-7kinadiD>B{Tl`ZY@`g|b~pvHh5!gKP4({rp?D0aFd_cN zhHRo4dd5^S6ViN(>(28qZT6E>??aRhc($kP`>@<+lIKS5HdhjVU;>f7<4))E*5|g{ z&d1}<wI2Yxf4k?!umu<cm>D|vpuV^eRj5j|xx9nwaCxXFG?Qbjn~_WSy=N}P0W>MP zG-F%70lX5Xr$a)2i6?i|iMyM|;Jtf*hO?=Jxj12oz&>P=1#h~lf%#fc73M2_(SUM- zf&qnjS80|_Y0lDgl&I?*eMumUklLe_=Td!9G@eR*tcPOgIShJipp3{A10u(4eT~DY zHezEj8V+7m!knn7)W!-5QI3=IvC<r`G1r;-#=KH#^bDsbD^<>^as5+TW1@Ern@yX| z7Nn~xVx&fGSr+L%4iohtS3w^{-H1A_5=r&x8}R!YZvp<2T^YFvj8G_vm}5q;^UOJf ztl=X3iL;;^^a#`t{Ae-%5Oq{?M#s6Npj+L(n-*LMI-yMR{)qki!~{5z{&`-iL}lgW zxo+tnvICK=lImjV$<vu==Ri_*yyu6*srp=+w%VMI++>Z|O_c<d`u5Z43azu#^&ypv z2XQf<KjK;)X-?wB*Sewpf;vW`6)cGyqY0^Kmt<sX6AgDavh{KfTqndPyGjf#w5CPH zd5wvsmzb)a>Yj_PlEYCzu-XBz&XC-JVxUh9;6*z4fuBG+H{voCC;`~GYV|hj%j_&I zDZCj>Q_0RCwFauYoVMiUSB+*Mx`tg)bWmM^SwMA+?lBg12QUF_x2b)b?qb88K-YUd z0dO}3k#QirBV<5%jL$#wlf!60dizu;tsp(7XLdI=eQs?P`tOZYMjVq&jE)qK*6B^$ zBe>VvH5TO>s>izhwJJ$<`a8fakTL!yM^Zfr2hV9`f}}VVUXK39p@G|xYRz{fTI+Yq z20d=)iwjuG9RB$%$^&8#(c0_j0t_C~^|n+c`Apu|x7~;#cS-s=X1|C*YxX3ailh<R zTW0JnWEDqjPC~D*L>g_|0`g!E&GZJEr?bh#T<kIti^!4|N+ecge$#dzW2oYeVA6W^ zTf=2ts!v<D6N@P&^Yk^QSZQdun$SpPGW!lb8i(GI;CLFfP&>pb8siR=JxWKc{#w7g zWznLwi;zLFmM1g8V5-P#RsM@iX>TK$xsWuujcsVR^7TQ@!+vCD<>Bk9tdCo7Mzgq5 zv8<xjOE`)Xl$&nfKK_(a*GxWq=IP<8*TsiQ<?73@Fo<n&f=T#zZE61~c1WExC#Z*C zBR?0KIU<_708sM|Ni}WhSK@G4$2@TsRGI0k6P~Edb~#f7+1%73{4^^R;XGADxxf+k zSKP@Qw?N!!n%j~Ps{Av<y>d>dK9x8C@Qoh01u@3h0X_`SZ<H1Jt*l+r%vhj38gu7( zi%Y(Yu(yCRu7j&QPtzY&|NIVK<{aX%!5|>luTb@5o;{4{{eF!-4405x8X7hewZWpz z2qEi4UTiXTvsa(0X7kQH{3VMF>W|6;6iTrrYD2fMggFA&-CBEfSqPlQDxqsa>{e2M z(R5PJ7uOooFc|9GU0ELA%m4&4Ja#cQpNw8i8ACAoK6?-px+oBl_yKmenZut#Xumjz zk8p^OV2KY&?5MUwGrB<d@yk90?8kfe*7#9+-#&)Q0>Oo?ki`Sxo#?-Q4gw*Sh0k`@ zFTaYK2;}%Zk-68`#5DXU$2#=%YL#S&<HGFJsB^*5Aw|=c;4ki9<qCK7e%Vj(VHL~6 z&DTbldm(&0B0fTx|5re(!MJSE^QU1#`&m2qUm7Nf|9k}h=kY)0pa1#ZNlE^hgpfxc z$@}d>MTN8bF+!J2VT6x^XBci6O)Q#JfW{<sb5)HkTF~_Sa_M^vi<UXTocVSE>YMz) zOBM>t2rSj)n#0a3cjvu}r|k3od6W(SN}V-cL?bi<J46HHYSLL&OeFRm%u#)=VN9PH zxaTYq?JHLwz2fTT`H!RbdHX@6n6p6?mn|3kIU%%1k}C2(3hi^IDh(udokZ1xF-p+u z0u<3zht=l5wn_zAAWK?U0XT-L6xs5k3ZJ=V1H`#dpB4>*Iz-8uOcCcsX0L>ZXjLqk zZu2uHq5B|Kt>e+=pPKu=1P@1r9WLgYFq_TNV1p9pu0erHGd!+bBp!qGi+~4<N?Fq) zn=ndP#eVyN4)AOmF>A(RsYN@CyXNrC&hxGmW)u5m35Om<gLIl43|ftfxD;4@0U%W{ zfCt<dp}9hk8dzvf-#}P{$rRcsI2FbF%>WwX`I+0yByglO`}HC4nGE^_HUs^&A(uaM zKPj^=qI{&ayOq#z=p&pnx@@k&I1JI>cttJcu@Ihljt?6p^6{|ds`0MoQwp+I{3l6` zB<9S((RpLG^>=Kic`1LnhpW2=Gu!x`m~=y;A`Qk!-w`IN;S8S930#vBVMv2vCKi}u z6<-VPrU0AnE&vzwV(CFC0gnZYcpa-l5T0ZS$P6(?9AM;`Aj~XDvt;Jua=jIgF=Fm? zdp=M$>`phx%+Gu};;-&7T|B1AcC#L4@mW5SV_^1BRbo6;2PWe$r+npRV`yc;T1mo& z+~_?7rA<BY)cqU~+}^_%&5(AuHg02IxD?AG?j^Zhn%1`rT{GFYPZA>+(Um&o@Tddl zL_hxvWk~a)yY}%j`Y+200D%9$bWHy&;(yj{jpi?Rtz{J66ANw)UyPOm;t6FzY3$hx zcn)Ir79nhFvNa7^a{SHN7XH*|Vlsx`CddPnA&Qvh8aNhEA;mPV<ryWQl0P?MiPwBL z+vex2kKClH;6k1Et=IFG!&SyN$8+S#_UnR?aFa6Eq|~rBS)8W_vwKAj+o^X)(9027 z*WrGQ$Ej`dD5*y_K^!R^&+N3W?cTJmXL9S<fpm^mH*?0O@w{qI>v;Ah=k<*u!Zq^7 z<=xs*iQTQOMMcg|(NA_auh@x`3#_LFt=)}%SQppP{E>mu_LgquAWvh<>L7tf9+~rO znwUDS52u)OtY<~!d$;m9+87aO+&`#2ICl@Y>&F{jI=H(K+@3M1$rr=*H^dye#~TyD z!){#Pyfn+|ugUu}G;a~!&&0aqQ59U@UT3|_JuBlYUpT$2+11;}JBJ`{+lQN9T@QFY z5+`t;6(TS0F?OlBTE!@7D`8#URDNqx2t6`GZ{ZgXeS@v%-eJzZOHz18aS|svxII$a zZeFjrJ*$IwX$f-Rz<J3Ld3QGgbbgt9L|A^RC+}TLgII?Lz8a4l887}}cuTMGGhsX* z9&mmFqP?djyuRYNLb|y#gPeE?&x5*{yL4yV`z1bx{$hup<=h=EzEhKN_egi{3sPw} z!?<6KVR?6VYA;nDAIyA2AKd4Ab>r_G>xbu@euGl)B7pC&S+CmDJBg$BoV~jxSO#>y z33`bupN#LDoW0feZe0%q8un0rYN|eRAnwDHQ6e_)xBTbtoZtTA=Fvk){q}9Os~6mQ zKB80VI_&6iSq`LnK7*kfHZoeX6?WE}8yjuDn=2#JG$+;-TOA1%^=DnXx%w{b=w}tS zQbU3XxtOI8E(!%`64r2`zog;5<0b4i)xBmGP^jiDZ2%HNSxIf3@wKs~uk4%3Mxz;~ zts_S~E4>W+YwI<-*-$U8*^HKDEa8oLbmqGg?3vewnaNg%Mm)W=)lcC_J+1ov^u*N3 zXJ?!BrH-+wGYziJq2Y#vyry6Z>NPgkEk+Ke`^DvNRdb>Q2Nlr#v%O@<5hbflI6EKE z9dWc0-ORk^T}jP!nkJ1imyjdVX@GrjOs%cpgA8-c&FH&$(4od#x6Y&=LiJZPINVyW z0snY$8JW@>tc2}DlrD3StQmA0Twck~@>8dSix9CyQOALcREdxoM$Sw*l!}bXKq9&r zysMWR@%OY24@e`?+#xV2bk{T^C_xSo8v2ZI=lBI*l{RciPwuE>L5<W5z;@6p;6;|O z%1xS<PrHS@9bs_>@uhz@{!l)rtVlWC>)6(G)1~n=Q|S!{E9~6*f<w%m`;Qd>dpa*n z!()-8EpTdj=zr_Lswi;#{TxbtH$8*G=UM`I+icz7sr_SdnHXrv=?iEOF1UL+*6O;% zPw>t^kb<Y!37E>W9X@oEXx<97%lBm-9?O_7L!DeD)Me#rwE5<?Y(}PPRapoJOytLr zH%=!UQ}Y5J_(3KVTFf%D7DXvmTFStSsvMk1_bhZw*QC=UXI9MplG;au>4t~UBu9VZ zl_I1tBB~>jm@bw<SOr`xU7_Kg$PU){Os_I8cve<UKbUg-U~fB$8f2Y<)c>0Aljz8! zXBB6ATG6i<ky6{p$)@{!N}M!yKr)m#;X?<H(Z75&7#=qg5yAe!nNXMBxO$uuu4{+; zB;Z$SC9Hkye>ByKIxs!qr%pz%wgqbg(l{65DP4#v(vqhhL{0b#0C8mq`bnqZ1OwFV z7mlZZJFMACm>h9v^2J9+^_zc1<NQ`E;}bmano=+KqF=1iDw+>=JjL#qM5ZHaThH&n zXPTsR8(+)cj&>Un{6v*z?@VTLr{TmZ@-fY%*o2G}*G}#!bmqpoo*<pdMvH^(qd~4b z&U$~Fo(WzrnMy~ykcI{stgLy~unZF&M1>Ay@U!JI^Q@7gj;Kg-HIrLj4}#ec<Vnys z#0P7P+6h@<uM?dbofaPCeGw4^GKj)BhZ;UWJ+<6Nx^ge1;*1yP2rFzRz&wW{MTEr2 zHXxRizPbhoG%+`mqNb$aK0~}2_bn~FMY2@vFZ0AA!pFio4f|r;(+@Q1=`h#RqX!CO zrKiCBy`_GlRuCrdEk+*L2qw)Xi3a$4Yu;T-ek#YzAVQMsU=A4R@x`B#O+Rf$w;qdW z?}xS=&C)dEt1bY5wPQ*Qhbfh3qM{iKuWW?ZRgK1yH>4~D2~X6vo;ghep-@&yOivYP zC19L0D`jjKy1Yi-SGPAn94(768<MS&a!S%v@?~BDz5em7uiJCVng8mCX4kKzoQ6PZ z2Tk0a6O=C#;z%H(u6zVb=|H2_?Mkm8Gc%N0k^Pp7o_nH69Yyq@mT_v(ZVS($NBa&F z6xwW+#+_X3s)pC4l=DX;IIvOLHG0qBsgo?lu%3&9euMN`&SyK73Bo<x@&AHA*=am& z1@no;r9Z{@*~p)rGlS`fyJCBB`|!&7#=qvn{2=@K-S4-@S0u|BDv=7_-i!Ic_QmBs zjXb>Tcf$urAf{)1)9W58P`6MA{YG%O?|07!g9(b`8PXG1B1Sh0?HQmeJtP0M$O$hI z{5G`&9XzYhh|y@qsF1GnHN|~^ru~HVf#)lOTSrv=S<uFZ_;?KwDx~9UUr?%y@ex}8 z_9H~!Xc3m^qNrtT@3y|;1c?=J#VjGm2#~m8gbETU8K{z_hDYEnF$+2Q2Oc9Mp&ga4 z#Mhq}0`Jk@q}^00F79AOKffu=y|_%9nA^(yl2kj(9G$y+k?BKg2^S**>@DyR$UKQk zjdEPFDz{uHM&UM;=mG!xKvp;xAGHOBo~>_=WFTmh$chpC7c`~7?36h)7$fF~Ii}8q zF|YXxH-Z?d+Q+27Rs3X9S&K3N+)OBxMHn1u(vlrUC6ckBY@@jl+mgr#KQUKo#VeFm zFwNYgv0<%~Wn}KeLeD9e1$S>jhOq&(e*I@L<=I5b(?G(zpqI*WBqf|Zge0&aoDUsC zngMRA_Kt0>La+Erl=Uv_J^p(z=!?XHpenzn$%EA`JIq#yYF?JLDMYiPfM(&Csr#f{ zdd+LJL1by?xz|D8+(fgzRs~(N1k9DSyK@LJygwaYX8dZl0W!I&c^K?7)z{2is;OkE zd$VK-(uH#AUaZrp=1z;O*n=b?QJkxu`Xsw&7yrX0?(CX=I-C#T;yi8a<{E~?vr3W> zQrpPqOW2M+AnZ&p{hqmHZU-;Q(7<pG4gt)B4$6wsrn;hWv_Oig17Y?jJ&7E4<tmZn zOCP%0<fYi!jPBWOw9w}#K7$n=jY!?ZAO-w*mO9|G92xj4(OrW0?2j);##sDv4x>?- zP8L|Q0RM<y7372ia7WA3T&finv`tA1B}OSEw3SiAZho>~sB0w1w53f&Kd*y}ofx@c z5Y6B8qGel+uT1JMot$nT1!Tim6{>oZzJXdyA+4euOLME?5Fd_85Uk%#E*ln%y{u8Q z$|?|R@Hpb~yTVK-Yr_S#%NUy7EBfYGAg>b({J|5b+j-PBpPy$Ns`PaJin4JdRfOaS zE|<<io8>HjH%NuJgsd2wOlv>~y=np%=2)$M9LS|>P)zJ+Fei5vYo_N~B0XCn+GM76 z)Xz3tg*FRVFgIl9zpESgdpWAavvVViGlU8|UFY{{gVJskg*I!ZjWyk~OW-Td4(mZ6 zB&SQreAAMqwp}rjy`HsG<WwCuHn5_unq_y9e#cRc8<%lnA}KbA9;x1=pR7&&N!F-G zjdr@AW->({l2&q5Y52<@AULVAu~rWI$UbFuZs>Sc*x+XI<+ez%$U)|a^unjpiW0l0 zj1!<ZReHVMm7dlC$9b#yLY{IPu{3a%?*mdb?Ln7M9kK-6dElH{UJFdM&-U|~tV)|A zbcx=;RI5^&eB34O5VoIsgM>K0(b6$8LOjzRqQ~K&dfbMIE=TF}XFAi)$+h}5SD3lo z%%Qd>p9se=VtQG{kQ;N`sI)G^u|DN#7{aoEd<IbwTtn<2Y5Nlu3=6HqY@ID|;XJ`> zkksYP%_X$Rq08);-s6o>CGJ<}v`qs%eYf+J%DQ^2k68C%nvikRsN?$ap--f+vCS`K z#&~)f7!N^;sdUXu54gl3L=LN>FB^tuK=y2e#|hWiWUls__n@L|>xH{%8lIJTd5`w? zSwZbnS;W~DawT4OwSJVdAylbY+u5S+ZH{4hAi2&}Iv~W(UvHg(1GTZRPz`@{SOqzy z(8g&Dz=$PfRV=6FgxN~zo+G8OoPI&d-thcGVR*_^(R8COTM@bq?fDwY{}WhsQS1AK zF6R1t8!RdFmfocpJ6?9Yv~;WYi~XPgs(|>{5})j!<TEFe=Er$+pf$t`J5iiJseKY6 zOKcLAm!-S>AR!voO7y9&cMPo#80A(`za@t>cx<0;qxM<p_$AQsg0LlIt|lbiT;}c3 zw^mT}aw%3C?rkh$t46uo%m3)>@S*m(jYP)dMXr*?q0E`oL;12}VAep179uEr8c<=D zr5?A*C{eJ`z9Ee;E$8)ME<J+@MZh2qBdMetA0Ap@SWv(BczRx8QLfufLwM}8P0mCM zqL)NPc0jmFO8S}^g)dV@LX%jnUO0Nfp9J$lfwZiNA(bY@QLPrgG(eM{>CqatHkbHH z&Y+ho0B$31MIB-xm&;xyaFCtg<{m~M-Q<p|>DbY)fQ>Q*Xibb~8ytxZQ?QMf9!%cV zU0_X1@b4d+Pg#R!`OJ~DOrQz3@cpi<UUDp%7N@Va%&%d{hBCU%M}b3(4mHNaXl%^x zy!Jj<1JK)G8qrZwHKQaxXMHgDJ>Gy~XSKjZQQ|^4J1puvwKeScrH8o{bscBsowomu z^f12kTvje`yEI3eEXDHJ6L+O{Jv$HVj%IKb<P1JL_~J>|J{IvD*l6IG8WUgDJ*UGz z3!C%>?=dlfSJ>4U88)V+`U-!9r^@AxJBx8R;)J4Fn@`~k>8>v0M9xp90OJElWP&R5 zM#v*vtT}*Gm1<v7k$Q8)e+>^)Bv!s7<Pmunc}KvQIoTurYA$VFfn68@NS2!fMC<J7 zU5k+UNB7w2H5=t<P?=shL{5Ib0NG240C`@MTdpWV847hZ=*V+;L(?h<*^25EoClgz zyD7a#m?)n<0d;}sfn7Zdh>2T3PB0yVIjJW)H7a)ilkAvoaH?)jjb`MP>2z{%Y?}83 zUIwBKn`-MSg)=?R)1Q0z3b>dHE^)D8LFs}6ASG1|da<c-!XQ(Z6e^nFF6CW&kh!QD zJBO*^4S)F;_i)EMF6B*oE&=d8{@I29Wcz|o39n|gU$iV{0mmf~bE{AKN63AsId2PB zg*_mqkTRn*8K3S&kIzHn;I0dhO)-->Dly_^lOSy&zIIhm*HXm1?VS=_iacG);_I9c zUQH1>i#*?oPIwBMJkzi_*>HoUe}_4o>2(SHWzqQ=;TyhAHS;Enr7!#8;sdlty&(>d zl%5cjri8`2X^Ds`jnw7>A`X|bl=U8n+3LKLy(1dAu8`g@9=5iw$R0qk)w8Vh_Dt^U zIglK}sn^)W7aB(Q<l{uKGQ*rm=eJZ(-a1nFbLMjzjPyq^Zl*<ly16J->>HvrX=rxB z+*L)3DiqpQ_%~|m=44LcD4-bxO3OO*LPjsh%p(k?&<Y@4%3KJjIC&Ci<sWjP2Dfw= zuyvM4SPH14EA{O`2rzE>jvLp0py57oMH|*IMa(<|{m1(0S|x)?R-mqJ=I;_YUZA>J z62v*eSK;5w!h8J+6Z2~oyGdZ68waWfy09?4fU&m7%u~zi?YPHPgK6LDwphgaYu%0j zurtw)AYOpYKgHBrkX189mlJ`q)w-f|6>IER{5Lk97%P~<Lp)MD3iR}ejbGt7Rtt!H zbM>a-JyCRFjejW@L>n4vt6#hq;!|m;hNE||LK3nw1{bJOy+eBJjK=QqNjI;Q6;Rp5 z&035pZDUZ#%Oa;&_7x0T<7!RW`#YBOj}F380Bq?MjjEhrvlCATPdkCTTl+2efTX$k zH&0zR1n^`C3ef~^sXzJK-)52(T}uTG%OF8yDhT76L~|^+hZ2hiSM*QA9*D5odI1>& z9kV9<p~_g)xTTw=X;R>jC~twA5MwyOx(lsGD_ggYmztXPD`2=_V|ks_FOx!_J8!zM zTzh^cc+=VNZ&(OdN<cEfx!)Rv#OxA~Op%fRB@%V*lRYTee=t2@R^;Yw?#mEg+C=Q= zojy#mB^&>=y4Juw)@8-85lwf_#VMN!Ed(eQiRiLB2^2e`4dp286h@v@`O%_b)Y~A; zv}r6U?zs&@uD_+(_4bwoy7*uozNvp?bXFoB8?l8yG0qsm1JYzIvB_OH4_2G*IIOwT zVl%HX1562vLVcxM_RG*~w_`FbIc!(T=3>r528#%mwwMK}uEhJ()3ME<NoNRheH>by zQQjzqjWkwfI~;Fuj(Lj=Ug0y`>~C7`w&wzjK(rPw+Hpd~EvQ-ufQOiB4OMpyUKJhw zqEt~jle9d7S~LI~$6Z->J~QJ{Vdn3!c}g9}*KG^Kzr^(7V<ce%+9mXv^Yaa3Jhd!0 zVk?95!P$`MAquqor+9D#c(4q*0U*gkAX5okY6G!AZg^p?IbWVd!~IAXj%<mibcw^E z0M3HMVXuXDmhDXxE;Vjmfy%F+0X%+{&lK~`;T7cS`cLHThTCpHZupIqw|&Aqppk3r z-&np;eZoZM2&XOVoZ;>I5Gk(mHLL{itj_hG?&K4Ws0+T4gLfi3eu$N=`s36geNC?c zm<tGIMBC*Y4;VwmbLfiAj7y{1&1Jb>!~}vG6lx9Uf^5M;bWntF<-{p^bruy~f?sk9 zcETAPQZLoJ8JzMMg<-=ju4keY@SY%Wo?u9Gx=j&dfa6LIAB|IrbORLV1-H==Z1zCM zeZcOYpm5><v|;Qz(!vWawg1_tKdRVrHI_W5DOUncaXPaZDhIYYS>U2fU7V*h;%n`8 zN95Qh<STRuU64jVjbmKjdqZSJY%8zw4$Tfj@Wvru9*X0H8*3HTGDxdEq_neggWPUu z?xft@*y1f4!?2gYA)>fD994={1*<2vKLCNF)feKOGk`R#K~G=;rfq}|)s20&MCa65 zUM?xF5!&e0lF%|U!#rD@I{~OsS_?=;s_MQ_b_s=PuWdC)q|UQ&ea)DMRh5>fpQjXe z<T?`@;|?};a~ft^83ljDfAQ3!94d~hNv5n{)4AwKJATa`zA71ee}fN!jaN8Z#4EjL z-f$?vQg}|9Xo{%n!=1Mx&dq=e%YrtN37{wyLgfqAgdwo({~~Q__5WR5p+@9NOz51F zn`CL;9K(yDAz%jg^1P_Hc`Bi##Ur7V7Egt@oIK-E#LjT)$}{W%w45C#V=-fOXxI=t z^7_J*h#~Pik#Js#zy5ys39=Vz5a6#V82w{&CtitoXAwOl8~H^TQXd+vIaX<UxmEZ+ zVA?E;a0GBuKV>%9#*x=7{iRCtBKT#H>#v%>77|{4_slZ)XCY{s3<vj3F!Lf~Ms<;i zbhaGgzo{F~=cvK)<7sgUCyNidX;S2p_?WD^=yZOmYaGxQQ-~@!!w5=kxBhe-MppxS zf%rYJdpz6$k?w>j_r{tdpvb#|r|sbS^dU1x70$eJMU!h{Y7Kd{dl}9&vxQl6Jt1a` zHQZrWyY0?!vqf@u-fxU_@+}u(%Wm>0<h|8_^}%F!#OlpyrbcO<dw!GUDNyxENZ?*z zXa;m>I#KP48tiAPYY!T<suq7MlJU4p2C@*^!}?Z}Bs+ffZEdwIV~rhP4EI#LVSE#E zKAv&oq@=|P;@PtQ@(J{wnUWAbS17e!I7@`^bq|U&TSNB%V@)WhqU`zr*SYoRa15`t zq@?ryhS#AfQ#j8*PNC?6U-qg<^sQ_jI^Oh8HLIjwIVAJWx<QIp$*(EZ9$rxFs<o(f z&qU=|nW^RP$x<u*s5N|2WXF}vN|`Y{xjc0I<5vRQ@T4U1{aj`*N<gWmUnEJdAd=LM zS<sS>dW(o|KtVI|EUB9V`CBBN<Jb6P#IAaNVgj&r>aBLVih7+yMVF|GSoIQD0Jfb{ z!OXq;(>Z?O`1gap(L~bUcp>Lc@Jl-})^=6P%<~~9ywY=$iu8pJ0m*hOPzr~q`23eX zgbs;VOxxENe0UMVeN*>uCn9Gk!4siN-e>x)pIKAbQ<D_NGuAv_X}p9rcKdkJ-CY72 zY;M@t?NA)MG(kc+%pPv#HrW@CR&+GK&%ZfgLEA^}da`PjtxP`2he{N2tMkOQBzSdU zqbmpW3;gHqz$`asO$luCw6=w|wgSS|BN5dhU^m;NTBn4zBEe1bKmQJTcIjeq=_4;- z<%Lk#6J$}CB#|%0(w^Q++N0xCR7{uhNVvN{SCZ__oxC7+<4L39n=PVh0~(Pz$Z2kz zsD-eU@YACA>z!G)TcqIJ0`JBBaX>1-4_XO_-HCS^vr2vjv#7KltDZdyQ{tlWh4$Gm zB>|O1cBDC)yG(sbnc*@w6e%e}r*|IhpXckx&;sQCwGdKH+3oSG-2)Bf#x`@<4ETAr z0My%7RFh6ZLi<P3fz)VD6=F(UIjNi&4<Piytn-i3OvEhi7O_1<!4Bb=elUisJ5+JC zX3<Z{mUVV<bu6}1{$m+MIUKl?IZ(DneHsoYb;kLtxDj9+Q`hKxkGfO!F3`9no26-x zqe3&#LrJ-tqEc7B*%q?Pp5?r>Z_;X6Mu1YmXx7C$lSZ^}1h;j`EZd6@%JNUe=btBE z%s=Xmo1Ps?8G`}9+6>iaB8bgjUdXT?=trMu|4yLX^m0Dg{m7rpKNJey|EwHI+nN1e zL^>qN%5Fg)dGs4DO~uwIdXImN)QJ*Jhpj7$fq_^`{3fwpztL@WBB}OwQ#Epo-mqMO zsM$UgpFiG&d#)lzEQ{3Q;)&zTw;SzGOah-Dpm{!q7<8*)Ti_;xvV2TYXa}=faXZy? z3y?~GY@kl)>G&EvEijk9y1S`*=zBJSB1iet>0;x1Ai)*`^{pj0JMs)KAM=@UyOGtO z3y0BouW$N&TnwU6!%<gf6*u=C<iEed;KBwJxLRtV%EsYYZE^_I&am&FwOQIrs&rNv zsJkfwCitU8wV%PAV4*8&C!5{qUgyYY#T}|<>zS%nIrnANvZF&vB1~P5_d`x-giHuG zPJ;>XkVoghm#kZXRf>qxxEix;2;D1CC~NrbO6NBX!`&_$iXwP~P*c($EVV|669kDO zKoTLZNF4Cskh!Jz5ga9uZ`3o%7Pv`d^;a=cXI|>y;zC3rYPFLQkF*nv(r>SQvD*## z(Vo%^9g`%XwS0t#94zPq;mYGLKu4LU3;txF26?V~A0xZbU4Lmy`)>SoQX^m7fd^*E z+%{R4eN!rIk~K)M&UEzxp9dbY;_I^<z6SRx&;ge+MnfR=LP4lbl*GlbJMl=;M7>c} zOc{wlIrN_P(PPqi51k_$>Lt|X6A^|CGYgKAmoI#Li?;Wq%q~q*L7ehZkUrMxW67Jl zhsb~+U?33QS>eqyN{(odAkbopo=Q$Az?L+NZW>j;#~@wCDX?=L5SI|OxI~7!Pli;e zELMFcZ<bg~PJE<rY>tJY3!|=Gr2L4>z8yQ-{To>(f80*#;6`4IAiqUw`=Pg$%C?#1 z_g@hIGerILSU>=P>z{gM|DS91A4cT@PEIB^hSop!uhMo#2G;+tQSpDO_6nOnPWSLU zS;a9m^DFMXR4?*X=<qwp0>}d7l;nXuHk&0|m`NQn%d?8|Ab3A9l9Jh5s120ibWBdB z$5YwsK3;wvp!Kn@)Qae{ef`0#NwlRpQ}k^r>yos_Ne1;xyKLO?4)t_G4eK<Q62tM^ zi3!pz7{^fEGTr8{(f#W&Re=O*i3#l1dMP2CM@R9Dz7(}LH_=oT4s2({F6)NqjLkfn zWyb9}W9)`Eu!Z8~Tk)-$ftsw64V9oQ!&L>~wkUS2A&@_;)K0-03XGBzU+5f+uMDxC z(s8!8!RvdC#@`~fx$r)TKdLD6fWEVdEYtV#{ncT-ZMX~eI#UeQ-+H(Z43vVn%Yj9X zLdu9>o%wnWdvzA-#d6Z~vzj-}V3FQ5;axDIZ;i(95IIU=GQ4WuU{tl-{gk!5{l4_d zvvb&uE{%!iFwpymz{wh?bKr1*qzeZb5f6e<hIoTpEPx(5QYd%^TYj)|S%=LSr!JTs zz!;*wB%3?qZoTm|(U@GJ+#WuaK@<xquK@r4JW{I|?LhkR#^Q(lZ<%iY8sqr4Yy6*A zRP{^`YZZkjC>6m_ozRF&zux2mlK=v_(_s^R6b5l<OklUMWKH5m9CK)GA(}BNrnAhY z)mdhvSSE{gE9<H_hJ>u?_W4W3#<$zeG~Pd)^!4tzhs}-Sx$FJP>)ZGF(hVTH|C3(U zs0PO&*<Bq@X!wy{g3X=$ULK*~ws9t@GTdzNv=8$q3p#^9{iAshe2<iFXWu|*=#t*^ zHiMowYBuE7!#m)z7kwaYz#Uc(_5ibIU;zg~@927U0DWlH<0UlQF4CPh*e--2*e>h_ zNA-&qZpTP$$LtIgfiCn07}XDbK#HIXdmv8zdz4TY;ifNIH-0jy(gMSByG2<C3EzZ8 zhJn#!of$=`Z!hW|DTzs`N(xHpzG~5_y<$0J`1RsK1TZ1v{7!~LCAC@6G637W!~rk| zLx+h*<9F&&V-5Ie2REOa1?BIx`oEMIjt$k+8IcS%|EII70E=pQ-+-W`(g+CBps;jE zhtk~$2oej@U6M;lmo$jPN{1kgAl)GCrAtadSp-2s|A(twE-P34{pWf1IZMp@&U{nf zIWy<|G__isvfkx&jFyQpKg<vGx_3kCalUAl^%NntK#6(2lW1e<U)CGbFQUPSU&Hih zN~SsTvwJ7vUK%oWe<^FW<$VJlS91FR+Ang7i@BCO7_QPS9$yRY9L+a`GWU$_BS$My z%KO<mCE#1|s27xKI4jobQyI#G#shn67pXsz&cAj4?7POazD<?>EF~Th#eb_TueZC` zE?3I>UTMpKQ})=C;6p!?G)M6w^u*A57bD?2X`m3X^6;&4%i_m(uGJ3Z5h`nwxM<)H z$I5m?wN>O~8`BGnZ=y^p6;0+%_0K}Dcg|K;+fEi|qoBqvHj(M&aHGqNF48~XqhtU? z^ogwBzRlOfpAJ+Rw7IED8lRbTdBdyEK$gPUpUG}j-M42xDj_&qEAQEtbs>D#dRd7Y z<&TpSZ(quQDHiCFn&0xsrz~4`4tz!CdL8m~HxZM_agu@IrBpyeL1Ft}V$HX_ZqDPm z-f89)pjuEzGdq-PRu`b1m+qBGY{zr_>{6Ss>F|<HR3fdmQIEk)2Sh}0yO~96C1H<% z?QzVeMOyeG53X0w(8tYWACBt{TjL#WIIj{m`My#tMB;vJ{a~L+FxMlWMgTKK^KR0o zJ;X}EooSp!+2+G$e0wWSL-uZ;icHwY>xHZlJj9dt5HD$u`1*WZe)qEIuDSR)%z+|n zatVlhQ?$w#XRS7xUrFE;Y8vMGhQS5*T{ZnY=q1P?w5g$OKJ#M&e??tAmPWHMj3xhS ziGxapy?kn@$~2%ZY;M8Bc@%$pkl%Rvj!?o%agBvpQ-Q61n9kznC4ttrRNQ4%GFR5u zyv%Yo9~yxQJWJSf<lJl-iWu&1UwGnK(pvra?!Ge}y|x}g-8E3%rQnB2p@S*aS0l>j z?#HY$y=O<nlXsK9%dUnfsdN1u-Swe<-W_b&r&^uHFD7qA9zLa8;*KhGP$Wd1TRU3& ztEwlUTD>~F|2pZs22pu|_&Ajd<gZcA$Jk5{2YpKm>+D(Mt!nPUG{|1nlvP`=R#kKH zO*s$r_%ss5h1YO7k0bHJ2CXN)Y<zvl5N}16U~{2_GuG6q#_|JfMPqxfGtP5?Y4Mg| zyuvVEU!;&g*bD4Uw&V&*(NB>d6C<gbrz78@@`&t*Y)2+zhDQ!r1~__bZ$!MIY{hdK zBvhOU_=wf9=WDc_17is97>Hn~W!R=SqkWe=&nAZu(Q1G!xgcUilM@YVei@2@a`8he z9@pM`)VB*=e7-MWgLlXlc)t;fF&-AwM{E-EX}pViFn0I0CNw2bNEnN2dj!^4(^zS3 zobUm1uQnpqk_4q{pl*n06=TfK_C>UgurKFjRXsK_LEn};=79`TB12tv6KzwSu*-C8 z;=~ohDLZylHQ|Mpx-?yql>|e=vI1Z!epyUpAcDCp4T|*RV&X`Q$0ogNwy6mFALo^@ z9=&(9txO8V@E!@6^(W0{*~CT>+-MA~vnJULBxCTUW>X5>r7*eXYUT0B6+w@lzw%n> z_VjJ<2qf|(d6jYq2(x$(ZDf!yVkfnbvNmb5c|hhZ^2TV_LBz`9w!e_V*W_(MiA7|= z&EeIIkw*+$Xd!)j<aFr1R~xS}s~%p?Tvbh^pTwhKxj)!tQV8+Fl)bzUj`73ZqG~f+ zWSqF|`Gl$F?L)li$PwFjgAh#|DN8z!3tX5Sk_}`_4}-ZspoOseDU{j7Ti8%*vj}b6 z!IL&Z(PW4r+7(`f(&N9n^0NAMH0{AUeVSnnjZI%3h9AB_P13b({Q?6h@ewu{vztxi zi*&5Pl_mU)Ysqz^vmyhLIWWvN)Hw=`Cx$Vrwrqq?{hpCEd*k5Ph0hP@wEBG#s4-aR zr>8<@_<}A5;~A_>3JT*kX^@}cDoLd>Qj<`Se^wdUa(j0dp+Tl8EptwBm{9OGsdFEq zM`!pjf(Lm(`$e3<VugKu#}L&f$tPP-i|8Q%zt8Y0zy98R@0)>FLOjqA5LnN5o!}z{ zNf}rJuZh@yUtq&ErjHeGzX4(!luV!jB&;FAP|!R_QHYw#^Z1LwTePAKJ6X&IDNO#; z)#I@Xnnzyij~C@UH~X51JCgQeF0&hTXnuoElz#m{heZRexWc<T<>0k4<>0+ClX7%0 zEBqCCld1tD9Zwkr4{?Nor19#E5-YKfB8d?qgR82-Ow2^AuNevly2*tHA|sK!ybYkX zm-sLQH72P&{vEAW6+z~O5d0qd=xW~rua~5a?ymYFSD@8&gV)E5@RNNBAj^C99+Z5Z zR@Pq55mbCQbz+Mn$<DWdXQ3R#5&V?~bks;#i}6WLoWplVhIsF#fA%#X=}+{bA9=wr zM^>d_CMW<-+?TU960agEk1J<>d>0K=pF19yN))a~4>m^G&tc*xR+yMD*S=yip-q=H zIlredHpsJV8H(32@Zxc@bX6a21dUV95Th--8pE6C&3F>pk=yv$yd6@Haw;$v4+Fcb zRwn{Qo@0`7aPa2LQOP}j9v>sjO<JEcz!71PwCy&w1EL#RH@3db^Ta;FM00H0|Mp0R zTpn{$THw|Y^1IL=kOtj&J`-2ec-4zB&kyxvlF+QM;i6t6y+_@6dbj@S^owU3pQ_HH z9V4D!R*q77p6}D`1gWi#=H#L`<?!BK(-r>o5K<lY0`DON8bR;qp%j?!ikO3v{CO;C zr0hoVGpgX&#zAv@v~t0WKK3UWhFI@!4za_cZypgom@RlHWXjhb*zkH>qvn|`FLizX zB+@<Q$;$QqzF2GLY>-u4Lw|jsvz{p^>n8Vo8H2peIqJJnMN}A)q6%$Tmig7eu^}K2 zrh$X?T|ZMsoh{6pdw1G$_T<`Ds-G=jc;qcGdK4{?dN2-XxjDNbb(7pk|3JUVCU4y; z)?LXR>f+AAu)JEiti_Zy#z5{RgsC}R(@jl%9YZ>zu~hKQ*AxbvhC378-I@{~#%Y`Z zy=a=9YpewPIC+gkEUUwtUL7|RU7=!^Aa}Mk^6uxOgRGA#JXjWLsjFUnix|Mau{hDT z7mn*z1m5g`vP(#tjT0Zy4eAY(br&!RiiXE=ZI!{sE1#^#%x^Z7t1U)b<;%Y}Q9=5v z;wp<LcU26iy~^KE9SueUhM9hSw5kFoch;KoAlT!eZTy6~rH?gNli?L&L}beKU`4T0 z({~FKWDwz-RkBOo`jHu$QZ~kQ5hqg(17SNo!H8^sKoQ@sO@9*??XWU5dC7fKZfAM^ z2&bW;u5NQsiN78LoRoCLadg3L1V;2%Am2iq%z(Q$=@X7Rr39Bjk?oA-7B^0IaaHoZ z3%j;&y}ZdKT?VLFIiCAzK=`ZWp2^>DCEZ@OE36TWT=|gxigT@VaW9BvHS05;_P(#s z8z<ixvefPSW(R``v-ey(C3!C1-J|HQHNtMWDk@k-%_AI{727f2fp)E3nzP2zne83t z(KHQ3Yp(UnUc1B>I4XFQys}q)<X?lz9;PIDH}W2ejg(xq4^Dln*?prNo2!$AYL(&x zQ^n*upjhh><`tkX$WnSarn{3e!s}4(J!=Yf>+Y>cP3f;vr63f2{|S^`_pWc)^5_!R z*(x-fuBxL51@xe!lnDBKi}Br$c$BMZ3%f2Sa6kLabiBS{pq*yj;q|k(86x`PiC{p6 z_bxCW{>Q2BA8~Ggz&0jkrcU+-$ANBsOop*ms>34K9lNYil@}jC;?cYP(m^P}nR6FV zk(M%48Z&%2Rx$A&FhOEirEhY0(dn;-k(qkTU)sFQ`+-ih+s@A8g?r8Pw+}2;35WYf zi}VO`jS`p(tc)$X$a>-#WXoW!phhatC*$}|rk>|wUU71eUJG^$c6_jwX?iSHM@6__ zvV|6%U*$sSXJu9SX?2%M^kK|}a2QJ8AhF{fuX<l$E^Sy6fzZeBWpXwtZtJ*+^5CvK zm5o@)Vb`rsjDy{;ty&^h;yuf(Qr~Ixfg8~=YlY3#vkGe-He?J$+-qAU_lqZP;hegA zk*AEh4ihR~5Jo#08klD@qHx90U57vSVf9#s#`LJAUz(qMmmvGKi`3#h#kmAJjG9h6 zQ)B)8jyj(255#*8@2i<tO5B5CO)}P|yt3DVt)qJDZd`sE+o{(_Ii^q?>rHZxXsI~O zGKX45!K7p*MCPEQ=gp?eu&#AW*pR{lhQR##P_*{c_DjMGL|3T3-bSJ(o$|M{ytU}> zAV>wq*uE*qFo9KvnA^@juy{x<-u*#2NvkV={Ly}ysKYB-k`K3@K#^S1Bb$8Y#0L0# z`6IkSG&|Z$ODy|VLS+y5pFJx&8tvPmMd8c9FhCyiU8~k6FwkakUd^(_ml8`rnl>JS zZV){9G*)xBqPz^LDqRwyS6w86#D^~xP4($150M)SOZRe9sn=>V#aG0Iy(_^Yc<Qa{ zc=f(3k0FXE4g8yHjnttlIF~$;u0A21@bchm@(lE%*(K8|UX&n%>PpIz8QYM-#s+n% z@Jd?xQq?Xk6=<3xSY7XYP$$yd&Spu{A#uafiIfy8gRC`o0nk{ezEDjb=q_qRAlR1d zFq^*9Gn)yTG4b}R{!+3hWQ+u3GT~8nwl2S1lpw`s<ATc7q8AYRlt3+=;0YO5Kh=m6 zcJQSxR8f1@n@G{FQOYA>0X_qpxv)g+JIkVKl${sYf_nV~B>Em>M;RlqGb5WVil(89 zs<BCtUSSVUPQs2-L)cP6#hn*j_NRz!rNALK#^L&c9rXdhSPT_+NmK*)Z5xF$xiJ=3 z8+Mc<!WJ?e3I&g_14W8h)QxMzSB66MIj*RP^*N)W9*O3{I9!<#lwG5$#G;69c_Ici z`@Ou~cYuw(AE3NQtoUi`%GvRnV9k1A0~o8pga`->=ld@|#;dq1*vQGz=7--Br-|l) zZ%Xh@v8>B7P?~}?Cg$q9_={59l%m~O&*a6TKsCMAzG&vD>k2WDzJ6!tc!V)+oxF;h zJH;apM=wO?r_+*#;ulohuP=E>^zon}a$<j`_j%GZX3(oc_SxO~-G*=c4ZAbD8%BzP zd)Pi)VtGNDLDj>NnlcQ{1$SO*i=jnGVcQa^>QOILc)e6;eNTI>os=eaJ{*^DE+~jc zS}TYeOykDmJ=6O%>m`i*>&pO_S;qMySJIyP=}4E&J%#1zju$RpVAkZbEl+p%?ZP^C z*$$2b4t%a(e+%>a>d_f_<<lO{*K50r$dT8<<B_m+L}7)kTP?9nuT8`~rXnwmPpNu& z_<Hj7^*-8j&~7D0OWBmB6J|2NeYzm{G=39Rh<aW*6|DbSdXI^GaeRfwgIs@eF%-$X z>JjxI#J1x;=hPd1zFPx=6T$;;X1TD*2(edZ3f46zaAoW>L53vS_J*N8TMB|n+;LD| zC=GkQPpyDY#Am4l49chDv*gojhRj_?63&&8#doW`INATAo(qY#{q}%nf@eTIXmtU< zdB<7YWfyCmBs|c)cK>1)v&M#!yNj#4d$~pVfDWQc_ke1?fw{T1Nce_b`v|Vp5ig(H zJvRD^+p<xU1eMV2Dp)d&jL}1T-4yJBks?w&E4)Bl#ayf5z?e)=tGbQS;h3(gA$e=k z6KY(=q)^im5{@d1i=Ix4={^<VU*;0T*7?%g*~`NlJ)S&FWzzYph<0?QcO=pLP8?e$ z*FaH6Y-^O^gO|=h>s46^hLX;=e2!2e;w9y1D@!D$c@Jc&%%%IL=<b6daWfefB)Aj< zmFAkvPGmuOH|UXs98|Izd34i4mjd%!t1Qfh2QG#C`?Q72>+xzw55&2?darw=9g~>P z9>?Kdc$r?6c$m%x2S$sdpPl>GQZ{rC9mPS63*<SW1ss4Nyr-0;)>qjCVa?OIBj!fW zm|g?>CVfG<LKn)qVK&7vOUVLdB{HCz?|MJr^jJ<qMG*a<=xVmP)}?vXFtiYfxJQ@S z#a>XNjOfcyqImXR_(tXS(F{FcoNzKvG5R$IgGaxC@)i(e+$ME}vPVIhd|mx2IIE+f zM?9opQHIVgBWu)^A|RzXw!^??S!x)SZOwZaJkGjc<_}2l^eSBm!eAJG9T>EC6I_sy z?bxzDIAn&K5*mX)$RQzDA?s)-no-XF(g*yl4%+GBf`##bDXJ==AQk*xmnatI;SsLp zP9XTHq5mmS=iWu~9E<z?vk<wVk?axOB(w*1mgxPEOC4Q_bKOg8aZS|<Jy7e5qZiZy zi_|O~v^<Tb8jU^hW(}=ov(p@txag^UbHjwTdt5JHG|siOz_cTtZE_L!P;3VdkA;2O zLo^GkBN2HNqX9mQqP?;}M=Weu;f8w@!h2(}g9(ObqEVL=EgisIBV{7fu4ome13nCE zdwW~^rkG^r1c_Jwl>S>b%Q=1aMa|ya^vj$@qz9S!ih{T8_PD%Sf_QrNKwgrXw9ldm zHRVR98*{C?_XNpJn{<p15xt>abA!oix_mowRMu^2lV-LPi;0+?-F(>^5#OHX-fPED zCu^l7u3E%STI}c4{J2!)9S<WqRBxZXWrLfD3v(g<)+j7~DBJ!D1`Yc*cLPVUN6i!o z<WHr{5RdXyi7LHb^NKbKUg}tH*PPH!`V-!@Sd!s(E-vzsn6!5N&eAaqoX%HxTMM{P zIJeCXkWwFSIEY&)8%SeRPki$2eJ?TcIF$5@j`=f}32hbX8_y10W!UQZL+acoY3HWL z^6U9-tleDkD!6JsRBj>UlGP_@!d?5W^QJXOI-Ea`hFMKjR7TluLvzC-ozCPn1`Tpy z!vlv@_Z58ILX6>nDjTp-1LlFMx~-%GA`aJvG$?8*Ihn;mH37eK**rmOEwqegf-Ccx zrIX4;{c~RK>XuTXxYo5kMiWMy)!IC{*DHG@E$hx?RwP@+wuad(P1{@%tRkyJRqD)3 zMHHHZ4boqDn>-=DgR5VlhQTpfVy182Gk;A_S8A1-;U1RR>+$62>(MUx@Nox$vTjHq z%QR=j!6Gdyb5wu7y(YUktwMuW5<@jl?m4cv4BODiT5o8qVdC0MBqGr@-YBIwnpZAY znX9(_uQjP}JJ=!~Ve9#5I~rUnN|P_3D$LqZcvBnywYhjlMSFHm`;u9GPla{5Q<X)1 z%$Q)YQ_xs_u@fVbNBxjMBTpgM&=XlBlp}w#R&41H+3NH%W*0}&d|5rv#al8&><AlF z8HoEcIWb_>D7(7*6Tb3Svr8;(nuAd81q$*uq6HC_&~je*Ca7hP4sJp0av{M8480wF zxASi7Qv+~@2U%Nu1Ud;s-G4CTVWIPyx!sg&8ZG0<u*j8bI(fE4R+~6W9t@%ANP1F@ zp$eJoBlfrurBBjoT#vaVVYUuEOoWffDHI4t?-V4p5pZZ3DkD`0^rkb1n)as8WP>Wq zG_}i3C(6_1>q3w!EH7$Kwq8uBp2F2N7}l65mk1p*9v0&+;th=_E-W)E;w}P(j⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8f<yhFr_4W{*sa2b)64y#l+N#ywviYKA zHs^$|vSmQ9h25pfc|F}ni`8kid}w)OD+3UEhP%9Dlwy33NMgJ*oN!k%?qfbTx#r!J zY-dPtmtNT~GY1Wt*spshItZ8i4R+jh2L%btp^)9t=mbb(EpeeR#tnR}gtoxxvFD|m zhb}`&kCesZUqA7FVifG~RXu8NP->uX!I}#8g+(wxzQwUT#Xb2(t<I|Vdp4<hf#R}E zO$m~GhlyfnIij1YM1#7L8*;8lzFA>bY1+EUhG<XbGlkEvuzFKy+tnOPm$r=L#YRzV zwl2E?nbHJTp_m!TZ`;N8RAqq@pSx_H9#jNyRdy^@&BAm<aBE+@>KoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}<Hop~&Xqn<t%=;~lIDY-u92ye&Z%8~1AbQ5!`jhH%qI zx(5`}Haa*r;yTwa;Iry8BUl6}+9-EGitaF$Aq_C?<%Xbp{$*-bSPHf$IdY92oxi$9 zcggG$CBdW=NKdNvJ@yJUY`u+>v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF<nu9$;OS+a41|h`ofOZC21#Y@_xv+k3^Ljg zEP^3r*gL6M9RW3lIubK}wzMJ3Vq#cPO<cz7xXnc!R;|M8d|v`nL0G&xB&n;gb?&kd z#fHl)FBAfL#Kd5aQG;&jsz|6*t@OWoiXQ1Qs^e+x9z47f=xOXd8X%iV!R%6NpDAQ2 zTW=KVlc2NZatQ2fBO>8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f<nT83VyE*=trSIMwSK+ z4z|GFEwin?jV;*T(G2VW4|oi4V$|b?I7v{*;m?4!2KEM4VBj1m$Qrmh{2}a>6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x<u`s6FSLLTv<|cn{|Pp5g+jgo+oN!0JAnt({C-&Q&xt&X`rRaf=9UHOa<(4N zfldWS^e<RZds8PXAUYACtOvF|eLw<Vj~BBG`@{geDFA=A=_Ck#1^*lKsG6XUA_1@M zoBr4<KCuuKk`3G@{&%Sre^J!KjgXRO0MHWfIlj?6Nl?i8wO?T>8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq<h|F<+{0IyH zi8D-XK*RiZ>;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~<a5^&n0jI1r5GnDy`M#F|h(qiMKHrd*pVsPffa+}n9r&yvC)xjiO5V)D0jSV- zGGG|~f~m<FCo&&kY6Y0iR%(jt514*XxER=je_N@~Rw;NXK<|(S7GRz;_L~O|?EJRP zzEl0Kks34-UgZF@NftnKd<^I$K_P>HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#v<R9RxTU-1O0|)yvA4xba;H&`N3f&14aD_soWPVR}ep`@)E(vu3 zg+~Bz&teka`w8=Ja~S`ahL2bA^D*6KQ5+`#qlg3T%XFrkbl~4(ejf_wBkMZ1i+KP8 z00S5Rd}okl9{h}KZ(|NNa{T{z1?aDD2_Ewt0=3{h!$WTV6A%3M@xSczn`QhM8DRK3 zVgI-y{Oy6kEY8q4IhtAi<boY%ILQqtp!`V34lt$V&$-R4ftA$S;AfcY{Zw*wfIWkO zN%HJ)*Zw68;IpdP8#sgQ9Ski076v-mF^6ATl(pNMM1g`517i@FK>kTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|<!Bd8Mzh5$(Z*X{#@KZSM#9zVz<vk}ZGJI*_HMvjW>5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O<nja==1v+{2K<RX!qLBMf>;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc literal 0 HcmV?d00001 From 0c426d5c4885afcd23d735724a9edf865e0a8d0a Mon Sep 17 00:00:00 2001 From: Pavel Bortnik <pavel_bortnik@epam.com> Date: Fri, 1 Mar 2024 12:52:37 +0300 Subject: [PATCH 16/25] 5.11.0 || Fix unit tests --- build.gradle | 2 +- .../core/analyzer/auto/indexer/BatchLogIndexer.java | 2 +- .../ta/reportportal/core/imprt/XmlImportStrategyTest.java | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 1ff5d40461..366629fa49 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ plugins { import org.owasp.dependencycheck.reporting.ReportGenerator apply from: 'project-properties.gradle' -apply from: "$scriptsUrl/build-docker.gradle" +//apply from: "$scriptsUrl/build-docker.gradle" apply from: "$scriptsUrl/build-commons.gradle" apply from: "$scriptsUrl/build-info.gradle" apply from: "$scriptsUrl/release-service.gradle" diff --git a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java index 7a98614b1d..606b69f7d8 100644 --- a/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java +++ b/src/main/java/com/epam/ta/reportportal/core/analyzer/auto/indexer/BatchLogIndexer.java @@ -99,7 +99,7 @@ private Long indexPartition(List<Long> itemIds, AnalyzerConfig analyzerConfig, L private Long countLogs(List<IndexLaunch> indexLaunch) { return indexLaunch.stream() .flatMap(launch -> launch.getTestItems().stream()) - .mapToLong(item -> item.getLogs().size()) + .mapToLong(item -> item.getLogs() != null ? item.getLogs().size() : 0) .sum(); } diff --git a/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java b/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java index 8dc2699d08..cc024c378a 100644 --- a/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/imprt/XmlImportStrategyTest.java @@ -26,6 +26,7 @@ import java.nio.file.Path; import java.time.Instant; import java.util.Date; +import java.util.HashSet; import java.util.Optional; import java.util.Set; import javax.inject.Provider; @@ -106,7 +107,12 @@ void whenImportLaunch_thenProcessXmlFile(@TempDir Path tempDir) throws Exception void whenImportLaunch_andIsSkippedIssue_thenProcessXmlFileWithSkippedTrue(@TempDir Path tempDir) throws Exception { LaunchImportRQ rq = new LaunchImportRQ(); - rq.setAttributes(Set.of(new ItemAttributesRQ(AbstractImportStrategy.SKIPPED_IS_NOT_ISSUE, "true"))); + ItemAttributesRQ attributesRQ = + new ItemAttributesRQ(AbstractImportStrategy.SKIPPED_IS_NOT_ISSUE, "true"); + attributesRQ.setSystem(true); + Set<ItemAttributesRQ> attributes = new HashSet<>(); + attributes.add(attributesRQ); + rq.setAttributes(attributes); File xmlFile = createFile(tempDir); From 4d0e3e9db36b996810a107a5631d979065adafe0 Mon Sep 17 00:00:00 2001 From: Andrei Piankouski <andrei_piankouski@epam.com> Date: Mon, 25 Mar 2024 13:05:33 +0300 Subject: [PATCH 17/25] EPMRPP-89755 || Sort parameters in alphabetical order --- .../ws/rabbit/AsyncReportingListener.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java index 54e9a9bfe3..69d550646f 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java +++ b/src/main/java/com/epam/ta/reportportal/ws/rabbit/AsyncReportingListener.java @@ -312,15 +312,17 @@ private void createItemLog(SaveLogRQ request, TestItem item, BinaryDataMetaInfo Launch effectiveLaunch = testItemService.getEffectiveLaunch(item); logService.saveLogMessage(logFull, effectiveLaunch.getId()); - if (Objects.nonNull(request.getFile())) {saveAttachment(request.getFile().getName(), metaInfo, - logFull.getId(), - projectId, - effectiveLaunch.getId(), - item.getItemId(), - effectiveLaunch.getUuid(), - logFull.getUuid() - ); - }} + if (Objects.nonNull(request.getFile())) { + saveAttachment(request.getFile().getName(), metaInfo, + logFull.getId(), + projectId, + effectiveLaunch.getId(), + item.getItemId(), + effectiveLaunch.getUuid(), + logFull.getUuid() + ); + } + } private void createLaunchLog(SaveLogRQ request, Launch launch, BinaryDataMetaInfo metaInfo, Long projectId) { @@ -331,9 +333,12 @@ private void createLaunchLog(SaveLogRQ request, Launch launch, BinaryDataMetaInf logFull.setId(log.getId()); logService.saveLogMessage(logFull, launch.getId()); - saveAttachment(request.getFile().getName(), metaInfo, logFull.getId(), projectId, launch.getId(), - null, launch.getUuid(), - logFull.getUuid()); + if (Objects.nonNull(request.getFile())) { + saveAttachment(request.getFile().getName(), metaInfo, logFull.getId(), projectId, + launch.getId(), + null, launch.getUuid(), + logFull.getUuid()); + } } private void saveAttachment(String fileName, BinaryDataMetaInfo metaInfo, Long logId, From 6b0ec09e355ff187953b9a8eebb54a4404f802c4 Mon Sep 17 00:00:00 2001 From: Andrei Piankouski <andrei_piankouski@epam.com> Date: Tue, 26 Mar 2024 12:01:00 +0300 Subject: [PATCH 18/25] EPMRPP-89932 || Add possibility to configure autocomplete suggestions when inviting users --- .../ws/controller/ProjectController.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java index ee505599a1..c210c6b16b 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java @@ -44,6 +44,7 @@ import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.project.ProjectInfo; import com.epam.ta.reportportal.entity.user.User; +import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.DeleteBulkRQ; @@ -69,6 +70,7 @@ import java.io.IOException; import java.io.OutputStream; import java.security.Principal; +import java.util.Collections; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; @@ -76,6 +78,7 @@ import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -112,6 +115,8 @@ public class ProjectController { private final UpdatePreferenceHandler updatePreference; private final GetJasperReportHandler<ProjectInfo> jasperReportHandler; + private final boolean isUserSuggestions; + @Autowired public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler getProjectHandler, GetProjectInfoHandler projectInfoHandler, @@ -120,7 +125,8 @@ public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler ge GetUserHandler getUserHandler, GetPreferenceHandler getPreference, UpdatePreferenceHandler updatePreference, @Qualifier("projectJasperReportHandler") - GetJasperReportHandler<ProjectInfo> jasperReportHandler) { + GetJasperReportHandler<ProjectInfo> jasperReportHandler, + @Value("${rp.environment.variable.user.suggestions:true}") boolean isUserSuggestions) { this.projectExtractor = projectExtractor; this.getProjectHandler = getProjectHandler; this.projectInfoHandler = projectInfoHandler; @@ -131,6 +137,7 @@ public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler ge this.getPreference = getPreference; this.updatePreference = updatePreference; this.jasperReportHandler = jasperReportHandler; + this.isUserSuggestions = isUserSuggestions; } @Transactional @@ -276,6 +283,9 @@ public List<String> getProjectUsers(@PathVariable String projectName, public Iterable<SearchUserResource> searchForUser(@PathVariable String projectName, @RequestParam(value = "term") String term, Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { + if (!user.getUserRole().equals(UserRole.ADMINISTRATOR) && !isUserSuggestions) { + return Collections.emptyList(); + } return getProjectHandler.getUserNames(term, projectExtractor.extractProjectDetails(user, projectName), pageable); } From 53f8a9065b1344dd9d80c9c293e89268fa5de8c6 Mon Sep 17 00:00:00 2001 From: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:09:29 +0300 Subject: [PATCH 19/25] EPMRPP-89924 || Security vulnerabilities fix (#1958) --- build.gradle | 27 +++++++---- .../core/integration/plugin/PluginLoader.java | 6 +-- .../plugin/impl/PluginLoaderImpl.java | 7 ++- .../plugin/Pf4jPluginManager.java | 7 +-- .../plugin/ReportPortalExtensionFactory.java | 12 ++--- .../plugin/impl/PluginLoaderTest.java | 4 +- .../plugin/Pf4jPluginManagerTest.java | 45 +++++++++---------- 7 files changed, 58 insertions(+), 50 deletions(-) diff --git a/build.gradle b/build.gradle index 366629fa49..78c6d0cbd9 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ ext['spring-boot.version'] = '2.5.15' dependencyManagement { imports { - mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.11.6' : 'com.epam.reportportal:commons-bom:5.11.6') + mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.11.6' : 'com.github.reportportal:commons-bom:8603a03b4f') mavenBom('io.zonky.test.postgres:embedded-postgres-binaries-bom:12.9.0') } } @@ -74,12 +74,12 @@ dependencies { implementation 'com.epam.reportportal:plugin-api' } else { implementation 'com.epam.reportportal:commons-events' - implementation 'com.epam.reportportal:commons-dao' + implementation 'com.github.reportportal:commons-dao:586c730aaf' implementation 'com.epam.reportportal:commons-rules' implementation 'com.epam.reportportal:commons-model' implementation 'com.epam.reportportal:commons' implementation 'com.epam.reportportal:commons-fonts' - implementation 'com.epam.reportportal:plugin-api' + implementation 'com.github.reportportal:plugin-api:399273afd2' } implementation 'org.springframework.boot:spring-boot-starter-aop' @@ -90,13 +90,19 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-amqp' implementation 'org.springframework.boot:spring-boot-starter-batch' + //Fix CVE-2023-34050 + implementation 'org.springframework.amqp:spring-amqp:2.4.17' + + //Fix CVE-2023-40827, CVE-2023-40828, CVE-2023-40826 + implementation 'org.springframework:spring-webmvc:5.3.32' + implementation 'org.springframework:spring-web:5.3.32' implementation 'com.opencsv:opencsv:5.8' - // Fix CVE-2021-41079, CVE-2022-23181, CVE-2021-33037, CVE-2021-30640, CVE-2022-42252 - implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.82' - implementation 'org.apache.tomcat.embed:tomcat-embed-el:9.0.82' - implementation 'org.apache.tomcat.embed:tomcat-embed-websocket:9.0.82' + // Fix CVE-2023-46589, CVE-2024-24549 + implementation 'org.apache.tomcat.embed:tomcat-embed-core:9.0.86' + implementation 'org.apache.tomcat.embed:tomcat-embed-el:9.0.86' + implementation 'org.apache.tomcat.embed:tomcat-embed-websocket:9.0.86' // //https://nvd.nist.gov/vuln/detail/CVE-2020-5411 @@ -139,10 +145,15 @@ dependencies { implementation 'org.codehaus.jettison:jettison:1.5.4' // Fix CVE-2020-15522 implementation 'org.bouncycastle:bcprov-jdk15on:1.70' - implementation 'org.apache.commons:commons-compress:1.25.0' + // Fix CVE-2024-25710, CVE-2024-26308 + implementation 'org.apache.commons:commons-compress:1.26.0' implementation 'org.yaml:snakeyaml:1.33' implementation 'org.hibernate:hibernate-core:5.6.15.Final' + //Fix CVE-2023-6378, CVE-2023-6481, CVE-2023-6378, CVE-2023-6481 + implementation 'ch.qos.logback:logback-classic:1.2.13' + implementation 'ch.qos.logback:logback-core:1.2.13' + // Metrics implementation 'io.micrometer:micrometer-registry-prometheus:1.8.13' diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java index 602a523b32..a70683cc2c 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/PluginLoader.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; -import org.pf4j.PluginException; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginWrapper; /** @@ -35,9 +35,9 @@ public interface PluginLoader { * * @param pluginPath Plugin's path * @return {@link PluginInfo} with {@link PluginInfo#getId()} and {@link PluginInfo#getVersion()} - * @throws PluginException if there is an issue in loading the plugin or the plugin is not found in the specified path + * @throws PluginRuntimeException if there is an issue in loading the plugin or the plugin is not found in the specified path */ - PluginInfo extractPluginInfo(Path pluginPath) throws PluginException; + PluginInfo extractPluginInfo(Path pluginPath) throws PluginRuntimeException; /** * Creates the {@link IntegrationTypeDetails} object based on the params of the plugin diff --git a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderImpl.java b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderImpl.java index f165d7241e..a0cb905392 100644 --- a/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderImpl.java @@ -48,7 +48,7 @@ import org.apache.commons.lang3.StringUtils; import org.pf4j.PluginDescriptor; import org.pf4j.PluginDescriptorFinder; -import org.pf4j.PluginException; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -87,7 +87,7 @@ public PluginLoaderImpl(DataStore dataStore, IntegrationTypeRepository integrati @Override @NotNull - public PluginInfo extractPluginInfo(Path pluginPath) throws PluginException { + public PluginInfo extractPluginInfo(Path pluginPath) throws PluginRuntimeException { PluginDescriptor pluginDescriptor = pluginDescriptorFinder.find(pluginPath); return new PluginInfo(pluginDescriptor.getPluginId(), pluginDescriptor.getVersion()); } @@ -99,8 +99,7 @@ public IntegrationTypeDetails resolvePluginDetails(PluginInfo pluginInfo) { .flatMap(it -> ofNullable(it.getDetails())).flatMap( typeDetails -> IntegrationTypeProperties.VERSION.getValue(typeDetails.getDetails()) .map(String::valueOf)).ifPresent( - version -> BusinessRule.expect(version, v -> !v.equalsIgnoreCase( - pluginInfo.getVersion())) + version -> BusinessRule.expect(version, v -> !v.equalsIgnoreCase(pluginInfo.getVersion())) .verify( ErrorType.PLUGIN_UPLOAD_ERROR, Suppliers.formattedSupplier( "Plugin with ID = '{}' of the same VERSION = '{}' " diff --git a/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java b/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java index 07b539354e..23fbbcb3f4 100644 --- a/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java +++ b/src/main/java/com/epam/ta/reportportal/plugin/Pf4jPluginManager.java @@ -50,11 +50,12 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import org.apache.commons.digester.plugins.PluginException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; -import org.pf4j.PluginException; import org.pf4j.PluginManager; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.slf4j.Logger; @@ -385,7 +386,7 @@ private PluginInfo resolvePluginInfo(final String fileName, InputStream fileStre BusinessRule.expect(validatePluginMetaInfo(newPluginInfo), equalTo(Boolean.TRUE)) .verify(ErrorType.PLUGIN_UPLOAD_ERROR, "Plugin version should be specified."); return newPluginInfo; - } catch (PluginException e) { + } catch (PluginRuntimeException e) { removeUploadingPlugin(fileName); throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, e.getMessage()); } @@ -746,7 +747,7 @@ private PluginState loadPreviousPlugin(PluginWrapper previousPlugin, previousPlugin.getPluginId()) .get() ))); - } catch (PluginException e) { + } catch (PluginRuntimeException e) { throw new ReportPortalException(ErrorType.PLUGIN_UPLOAD_ERROR, Suppliers.formattedSupplier("Unable to reload previousPlugin with id = '{}': '{}'", previousPlugin.getPluginId(), diff --git a/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java b/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java index ec6db33aaa..2af01a5b83 100644 --- a/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java +++ b/src/main/java/com/epam/ta/reportportal/plugin/ReportPortalExtensionFactory.java @@ -44,18 +44,18 @@ public ReportPortalExtensionFactory(String resourcesDir, PluginManager pluginMan } @Override - public Object create(Class<?> extensionClass) { + public <T> T create(Class<T> extensionClass) { PluginWrapper pluginWrapper = pluginManager.whichPlugin(extensionClass); if (beanFactory.containsSingleton(pluginWrapper.getPluginId())) { - return beanFactory.getSingleton(pluginWrapper.getPluginId()); + return extensionClass.cast(beanFactory.getSingleton(pluginWrapper.getPluginId())); } else { - return createExtension(extensionClass, pluginWrapper); + return extensionClass.cast(createExtension(extensionClass, pluginWrapper)); } } - private Object createExtension(Class<?> extensionClass, PluginWrapper pluginWrapper) { + private <T> T createExtension(Class<T> extensionClass, PluginWrapper pluginWrapper) { Map<String, Object> initParams = getInitParams(pluginWrapper); - Object plugin = createPlugin(extensionClass, initParams); + T plugin = createPlugin(extensionClass, initParams); beanFactory.autowireBean(plugin); beanFactory.initializeBean(plugin, pluginWrapper.getDescriptor().getPluginId()); beanFactory.registerSingleton(pluginWrapper.getDescriptor().getPluginId(), plugin); @@ -66,7 +66,7 @@ private Object createExtension(Class<?> extensionClass, PluginWrapper pluginWrap return plugin; } - private Object createPlugin(Class<?> extensionClass, Map<String, Object> initParams) { + private <T> T createPlugin(Class<T> extensionClass, Map<String, Object> initParams) { try { return extensionClass.getDeclaredConstructor(Map.class).newInstance(initParams); } catch (Exception ex) { diff --git a/src/test/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderTest.java b/src/test/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderTest.java index 8672c4505b..e4e4af6125 100644 --- a/src/test/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/integration/plugin/impl/PluginLoaderTest.java @@ -36,8 +36,8 @@ import org.junit.jupiter.api.Test; import org.pf4j.PluginDescriptor; import org.pf4j.PluginDescriptorFinder; -import org.pf4j.PluginException; import org.pf4j.PluginManager; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginWrapper; /** @@ -72,7 +72,7 @@ class PluginLoaderTest { ); @Test - void shouldExtractPluginIdWhenExists() throws PluginException { + void shouldExtractPluginIdWhenExists() throws PluginRuntimeException { Path path = Paths.get("dir", FILE_NAME); diff --git a/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java b/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java index fd9aeef652..7b612afc80 100644 --- a/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java +++ b/src/test/java/com/epam/ta/reportportal/plugin/Pf4jPluginManagerTest.java @@ -44,7 +44,7 @@ import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.pf4j.PluginException; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginManager; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; @@ -65,24 +65,19 @@ class Pf4jPluginManagerTest { public static final String NEW_JIRA_PLUGIN_VERSION = "1.0"; private final PluginLoader pluginLoader = mock(PluginLoader.class); - private final IntegrationTypeRepository integrationTypeRepository = mock( - IntegrationTypeRepository.class); + private final IntegrationTypeRepository integrationTypeRepository = + mock(IntegrationTypeRepository.class); private final AutowireCapableBeanFactory beanFactory = mock(AutowireCapableBeanFactory.class); private final PluginManager pluginManager = mock(PluginManager.class); private final PluginWrapper previousPlugin = mock(PluginWrapper.class); private final PluginWrapper newPlugin = mock(PluginWrapper.class); - private final ApplicationEventPublisher applicationEventPublisher = mock( - ApplicationEventPublisher.class); + private final ApplicationEventPublisher applicationEventPublisher = + mock(ApplicationEventPublisher.class); - private final Pf4jPluginManager pluginBox = new Pf4jPluginManager(PLUGINS_PATH, - PLUGINS_TEMP_PATH, - RESOURCES_PATH, - pluginLoader, - integrationTypeRepository, - pluginManager, - beanFactory, - applicationEventPublisher - ); + private final Pf4jPluginManager pluginBox = + new Pf4jPluginManager(PLUGINS_PATH, PLUGINS_TEMP_PATH, RESOURCES_PATH, pluginLoader, + integrationTypeRepository, pluginManager, beanFactory, applicationEventPublisher + ); private final InputStream fileStream = mock(InputStream.class); @@ -98,7 +93,7 @@ void cleanUp() throws IOException { } @Test - void uploadPlugin() throws PluginException, IOException { + void uploadPlugin() throws PluginRuntimeException, IOException { PluginInfo pluginInfo = getPluginInfo(); when(pluginLoader.extractPluginInfo( @@ -130,7 +125,7 @@ void uploadPlugin() throws PluginException, IOException { } @Test - void uploadPluginWithExistingFile() throws PluginException, IOException { + void uploadPluginWithExistingFile() throws PluginRuntimeException, IOException { File tempFile = File.createTempFile(NEW_PLUGIN_FILE_NAME, ".jar", new File(PLUGINS_TEMP_PATH)); tempFile.deleteOnExit(); PluginInfo pluginInfo = getPluginInfo(); @@ -158,7 +153,7 @@ void uploadPluginWithExistingFile() throws PluginException, IOException { } @Test - void uploadPluginWithLoadingError() throws PluginException { + void uploadPluginWithLoadingError() throws PluginRuntimeException { PluginInfo pluginInfo = getPluginInfo(); when(pluginLoader.extractPluginInfo( @@ -179,11 +174,12 @@ void uploadPluginWithLoadingError() throws PluginException { ); assertEquals( "Error during plugin uploading: 'Failed to load new plugin from file = 'plugin.jar''", - exception.getMessage()); + exception.getMessage() + ); } @Test - void uploadPluginWithoutExtensionClasses() throws PluginException { + void uploadPluginWithoutExtensionClasses() throws PluginRuntimeException { PluginInfo pluginInfo = getPluginInfo(); when(pluginLoader.extractPluginInfo( @@ -210,11 +206,11 @@ void uploadPluginWithoutExtensionClasses() throws PluginException { } @Test - void uploadPluginWithPluginException() throws PluginException { + void uploadPluginWithPluginException() throws PluginRuntimeException { when(pluginLoader.extractPluginInfo( - Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenThrow(new PluginException( - "Manifest not found")); + Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenThrow( + new PluginRuntimeException("Manifest not found")); final ReportPortalException exception = assertThrows(ReportPortalException.class, () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) @@ -223,7 +219,7 @@ void uploadPluginWithPluginException() throws PluginException { } @Test - void uploadPluginWithoutVersion() throws PluginException { + void uploadPluginWithoutVersion() throws PluginRuntimeException { when(pluginLoader.extractPluginInfo( Paths.get(PLUGINS_TEMP_PATH, NEW_PLUGIN_FILE_NAME))).thenReturn( @@ -233,7 +229,8 @@ void uploadPluginWithoutVersion() throws PluginException { () -> pluginBox.uploadPlugin(NEW_PLUGIN_FILE_NAME, fileStream) ); assertEquals("Error during plugin uploading: 'Plugin version should be specified.'", - exception.getMessage()); + exception.getMessage() + ); } @Test From fbc5e2902bc0238bf6f21f3e491bdf151722c25f Mon Sep 17 00:00:00 2001 From: Ivan Kustau <86599591+IvanKustau@users.noreply.github.com> Date: Mon, 1 Apr 2024 11:21:04 +0300 Subject: [PATCH 20/25] =?UTF-8?q?EPMRPP-89958=20||=20Remove=20update=20of?= =?UTF-8?q?=20parent=20test=20item=20if=20it=20has=20status=20an=E2=80=A6?= =?UTF-8?q?=20(#1960)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/impl/status/ChangeStatusHandlerImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java index 9d4eef2b72..3700988023 100644 --- a/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/item/impl/status/ChangeStatusHandlerImpl.java @@ -19,6 +19,7 @@ import static com.epam.ta.reportportal.entity.enums.StatusEnum.FAILED; import static com.epam.ta.reportportal.entity.enums.StatusEnum.INFO; import static com.epam.ta.reportportal.entity.enums.StatusEnum.PASSED; +import static com.epam.ta.reportportal.entity.enums.StatusEnum.SKIPPED; import static com.epam.ta.reportportal.entity.enums.StatusEnum.WARN; import static com.epam.ta.reportportal.ws.converter.converters.TestItemConverter.TO_ACTIVITY_RESOURCE; import static java.util.Optional.ofNullable; @@ -93,6 +94,7 @@ private boolean isParentStatusUpdateRequired(TestItem parent) { return parent.getItemResults().getStatus() != StatusEnum.IN_PROGRESS && parent.getItemResults().getStatus() != PASSED && parent.getItemResults().getStatus() != FAILED + && parent.getItemResults().getStatus() != SKIPPED && !testItemRepository.hasItemsInStatusByParent(parent.getItemId(), parent.getPath(), StatusEnum.IN_PROGRESS.name()); } From 00435ff94ffb7d8080be67ba5b1c9f72c7916b13 Mon Sep 17 00:00:00 2001 From: Andrei Piankouski <andrei_piankouski@epam.com> Date: Mon, 1 Apr 2024 13:32:40 +0300 Subject: [PATCH 21/25] EPMRPP-89932 || Add possibility to configure autocomplete suggestions when inviting users --- .../project/impl/GetProjectHandlerImpl.java | 18 +++++++++++++++--- .../ws/controller/ProjectController.java | 12 +----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java index 976ea58141..cdaf32bf96 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java @@ -43,6 +43,7 @@ import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -77,14 +78,18 @@ public class GetProjectHandlerImpl implements GetProjectHandler { private final ProjectConverter projectConverter; + private final boolean isUserSuggestions; + @Autowired public GetProjectHandlerImpl(ProjectRepository projectRepository, UserRepository userRepository, @Qualifier("projectJasperReportHandler") GetJasperReportHandler<ProjectInfo> jasperReportHandler, - ProjectConverter projectConverter) { + ProjectConverter projectConverter, + @Value("${rp.environment.variable.user.suggestions:true}") boolean isUserSuggestions) { this.projectRepository = projectRepository; this.userRepository = userRepository; this.jasperReportHandler = jasperReportHandler; this.projectConverter = projectConverter; + this.isUserSuggestions = isUserSuggestions; } @Override @@ -150,7 +155,8 @@ private void checkBusinessRuleLessThan1Symbol(String value) { public Iterable<SearchUserResource> getUserNames(String value, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable) { checkBusinessRuleLessThan1Symbol(value); - final CompositeFilterCondition userCondition = getUserSearchCondition(value); + final CompositeFilterCondition userCondition = + isUserSuggestions ? getUserSearchSuggestCondition(value) : getUserSearchCondition(value); final Filter filter = Filter.builder() .withTarget(User.class) @@ -162,13 +168,19 @@ public Iterable<SearchUserResource> getUserNames(String value, ReportPortalUser. .apply(userRepository.findByFilterExcludingProjects(filter, pageable)); } - private CompositeFilterCondition getUserSearchCondition(String value) { + private CompositeFilterCondition getUserSearchSuggestCondition(String value) { return new CompositeFilterCondition(List.of(new FilterCondition(Operator.OR, Condition.CONTAINS, false, value, CRITERIA_USER), new FilterCondition(Operator.OR, Condition.CONTAINS, false, value, CRITERIA_FULL_NAME), new FilterCondition(Operator.OR, Condition.CONTAINS, false, value, CRITERIA_EMAIL) ), Operator.AND); } + private CompositeFilterCondition getUserSearchCondition(String value) { + return new CompositeFilterCondition(List.of( + new FilterCondition(Operator.OR, Condition.EQUALS, false, value, CRITERIA_EMAIL) + ), Operator.AND); + } + @Override public List<String> getAllProjectNames() { return projectRepository.findAllProjectNames(); diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java index c210c6b16b..ee505599a1 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java @@ -44,7 +44,6 @@ import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.project.ProjectInfo; import com.epam.ta.reportportal.entity.user.User; -import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.util.ProjectExtractor; import com.epam.ta.reportportal.ws.model.DeleteBulkRQ; @@ -70,7 +69,6 @@ import java.io.IOException; import java.io.OutputStream; import java.security.Principal; -import java.util.Collections; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; @@ -78,7 +76,6 @@ import org.jooq.Operator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -115,8 +112,6 @@ public class ProjectController { private final UpdatePreferenceHandler updatePreference; private final GetJasperReportHandler<ProjectInfo> jasperReportHandler; - private final boolean isUserSuggestions; - @Autowired public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler getProjectHandler, GetProjectInfoHandler projectInfoHandler, @@ -125,8 +120,7 @@ public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler ge GetUserHandler getUserHandler, GetPreferenceHandler getPreference, UpdatePreferenceHandler updatePreference, @Qualifier("projectJasperReportHandler") - GetJasperReportHandler<ProjectInfo> jasperReportHandler, - @Value("${rp.environment.variable.user.suggestions:true}") boolean isUserSuggestions) { + GetJasperReportHandler<ProjectInfo> jasperReportHandler) { this.projectExtractor = projectExtractor; this.getProjectHandler = getProjectHandler; this.projectInfoHandler = projectInfoHandler; @@ -137,7 +131,6 @@ public ProjectController(ProjectExtractor projectExtractor, GetProjectHandler ge this.getPreference = getPreference; this.updatePreference = updatePreference; this.jasperReportHandler = jasperReportHandler; - this.isUserSuggestions = isUserSuggestions; } @Transactional @@ -283,9 +276,6 @@ public List<String> getProjectUsers(@PathVariable String projectName, public Iterable<SearchUserResource> searchForUser(@PathVariable String projectName, @RequestParam(value = "term") String term, Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - if (!user.getUserRole().equals(UserRole.ADMINISTRATOR) && !isUserSuggestions) { - return Collections.emptyList(); - } return getProjectHandler.getUserNames(term, projectExtractor.extractProjectDetails(user, projectName), pageable); } From d328565c56c375e0997a42c0f6ba0423cabc98b9 Mon Sep 17 00:00:00 2001 From: Andrei Piankouski <andrei_piankouski@epam.com> Date: Tue, 2 Apr 2024 15:53:47 +0300 Subject: [PATCH 22/25] Fix test --- .../project/impl/GetProjectHandlerImpl.java | 25 +++++++++---------- .../impl/GetProjectHandlerImplTest.java | 8 ++++-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java index cdaf32bf96..cbf178eb97 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java @@ -78,19 +78,18 @@ public class GetProjectHandlerImpl implements GetProjectHandler { private final ProjectConverter projectConverter; - private final boolean isUserSuggestions; - - @Autowired - public GetProjectHandlerImpl(ProjectRepository projectRepository, UserRepository userRepository, - @Qualifier("projectJasperReportHandler") GetJasperReportHandler<ProjectInfo> jasperReportHandler, - ProjectConverter projectConverter, - @Value("${rp.environment.variable.user.suggestions:true}") boolean isUserSuggestions) { - this.projectRepository = projectRepository; - this.userRepository = userRepository; - this.jasperReportHandler = jasperReportHandler; - this.projectConverter = projectConverter; - this.isUserSuggestions = isUserSuggestions; - } + @Value("${rp.environment.variable.user.suggestions:true}") + boolean isUserSuggestions; + + @Autowired + public GetProjectHandlerImpl(ProjectRepository projectRepository, UserRepository userRepository, + @Qualifier("projectJasperReportHandler") GetJasperReportHandler<ProjectInfo> jasperReportHandler, + ProjectConverter projectConverter) { + this.projectRepository = projectRepository; + this.userRepository = userRepository; + this.jasperReportHandler = jasperReportHandler; + this.projectConverter = projectConverter; + } @Override public Iterable<UserResource> getProjectUsers(String projectName, Filter filter, Pageable pageable) { diff --git a/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java index 9b371960d5..909d47e89f 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java @@ -30,8 +30,10 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.PageRequest; +import org.springframework.test.context.TestPropertySource; import java.util.Optional; @@ -45,13 +47,15 @@ * @author <a href="mailto:ihar_kahadouski@epam.com">Ihar Kahadouski</a> */ @ExtendWith(MockitoExtension.class) +@TestPropertySource(properties = {"rp.environment.variable.user.suggestions=true"}) class GetProjectHandlerImplTest { @Mock private ProjectRepository projectRepository; - @InjectMocks - private GetProjectHandlerImpl handler; + @Spy + @InjectMocks + private GetProjectHandlerImpl handler; @Test void getUsersOnNotExistProject() { From b78ea18f5a0a295d50e733c9e0567d4bdcec6e20 Mon Sep 17 00:00:00 2001 From: Andrei Piankouski <andrei_piankouski@epam.com> Date: Fri, 5 Apr 2024 12:39:30 +0300 Subject: [PATCH 23/25] EPMRPP-90309 || Empty content is returned for Admin user via API when searching for users --- .../ta/reportportal/core/project/GetProjectHandler.java | 3 ++- .../core/project/impl/GetProjectHandlerImpl.java | 7 +++++-- .../ta/reportportal/ws/controller/ProjectController.java | 2 +- .../core/project/impl/GetProjectHandlerImplTest.java | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java index 81ee3dc926..0a70aec7ab 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/GetProjectHandler.java @@ -21,6 +21,7 @@ import com.epam.ta.reportportal.commons.querygen.Queryable; import com.epam.ta.reportportal.entity.jasper.ReportFormat; import com.epam.ta.reportportal.entity.project.Project; +import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.ws.model.project.ProjectResource; import com.epam.ta.reportportal.ws.model.user.SearchUserResource; import com.epam.ta.reportportal.ws.model.user.UserResource; @@ -87,7 +88,7 @@ public interface GetProjectHandler { * @param pageable {@link Pageable} Page Details * @return List of found user resources */ - Iterable<SearchUserResource> getUserNames(String value, + Iterable<SearchUserResource> getUserNames(String value, UserRole userRole, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable); /** diff --git a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java index cbf178eb97..dcfc761244 100644 --- a/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java +++ b/src/main/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImpl.java @@ -29,6 +29,7 @@ import com.epam.ta.reportportal.entity.project.Project; import com.epam.ta.reportportal.entity.project.ProjectInfo; import com.epam.ta.reportportal.entity.user.User; +import com.epam.ta.reportportal.entity.user.UserRole; import com.epam.ta.reportportal.exception.ReportPortalException; import com.epam.ta.reportportal.ws.converter.PagedResourcesAssembler; import com.epam.ta.reportportal.ws.converter.converters.ProjectConverter; @@ -151,11 +152,13 @@ private void checkBusinessRuleLessThan1Symbol(String value) { } @Override - public Iterable<SearchUserResource> getUserNames(String value, ReportPortalUser.ProjectDetails projectDetails, Pageable pageable) { + public Iterable<SearchUserResource> getUserNames(String value, UserRole userRole, + ReportPortalUser.ProjectDetails projectDetails, Pageable pageable) { checkBusinessRuleLessThan1Symbol(value); final CompositeFilterCondition userCondition = - isUserSuggestions ? getUserSearchSuggestCondition(value) : getUserSearchCondition(value); + (userRole.equals(UserRole.ADMINISTRATOR) || isUserSuggestions) + ? getUserSearchSuggestCondition(value) : getUserSearchCondition(value); final Filter filter = Filter.builder() .withTarget(User.class) diff --git a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java index ee505599a1..fc35a243d7 100644 --- a/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java +++ b/src/main/java/com/epam/ta/reportportal/ws/controller/ProjectController.java @@ -276,7 +276,7 @@ public List<String> getProjectUsers(@PathVariable String projectName, public Iterable<SearchUserResource> searchForUser(@PathVariable String projectName, @RequestParam(value = "term") String term, Pageable pageable, @AuthenticationPrincipal ReportPortalUser user) { - return getProjectHandler.getUserNames(term, + return getProjectHandler.getUserNames(term, user.getUserRole(), projectExtractor.extractProjectDetails(user, projectName), pageable); } diff --git a/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java b/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java index 909d47e89f..b490fcf802 100644 --- a/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java +++ b/src/test/java/com/epam/ta/reportportal/core/project/impl/GetProjectHandlerImplTest.java @@ -125,7 +125,7 @@ void getUserNamesByIncorrectTerm() { @Test void getUserNamesNegative() { - ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.getUserNames("", + ReportPortalException exception = assertThrows(ReportPortalException.class, () -> handler.getUserNames("", UserRole.ADMINISTRATOR, new ReportPortalUser.ProjectDetails(1L, "superadmin_personal", ProjectRole.PROJECT_MANAGER), PageRequest.of(0, 10))); assertEquals("Incorrect filtering parameters. Length of the filtering string '' is less than 1 symbol", exception.getMessage()); From 9d71a7ffb0dae78d1ba6f914daa900a7bb9dfaab Mon Sep 17 00:00:00 2001 From: Ivan_Kustau <Ivan_Kustau@epam.com> Date: Wed, 10 Apr 2024 13:43:21 +0300 Subject: [PATCH 24/25] Update release versions --- .github/workflows/release.yml | 2 +- build.gradle | 12 ++++++------ gradle.properties | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef232831f9..8fe675b7ea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: env: GH_USER_NAME: github.actor - RELEASE_VERSION: 5.11.0 + RELEASE_VERSION: 5.11.1 REPOSITORY_URL: 'https://maven.pkg.github.com/' jobs: diff --git a/build.gradle b/build.gradle index 78c6d0cbd9..a3275c90b4 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ ext['spring-boot.version'] = '2.5.15' dependencyManagement { imports { - mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.11.6' : 'com.github.reportportal:commons-bom:8603a03b4f') + mavenBom(releaseMode ? 'com.epam.reportportal:commons-bom:' + '5.11.7' : 'com.epam.reportportal:commons-bom:5.11.7') mavenBom('io.zonky.test.postgres:embedded-postgres-binaries-bom:12.9.0') } } @@ -71,15 +71,15 @@ dependencies { implementation 'com.epam.reportportal:commons-model' implementation 'com.epam.reportportal:commons' implementation 'com.epam.reportportal:commons-fonts' - implementation 'com.epam.reportportal:plugin-api' + implementation 'com.epam.reportportal:plugin-api:5.11.1' } else { implementation 'com.epam.reportportal:commons-events' - implementation 'com.github.reportportal:commons-dao:586c730aaf' + implementation 'com.epam.reportportal:commons-dao' implementation 'com.epam.reportportal:commons-rules' implementation 'com.epam.reportportal:commons-model' implementation 'com.epam.reportportal:commons' implementation 'com.epam.reportportal:commons-fonts' - implementation 'com.github.reportportal:plugin-api:399273afd2' + implementation 'com.epam.reportportal:plugin-api:5.11.1' } implementation 'org.springframework.boot:spring-boot-starter-aop' @@ -94,8 +94,8 @@ dependencies { implementation 'org.springframework.amqp:spring-amqp:2.4.17' //Fix CVE-2023-40827, CVE-2023-40828, CVE-2023-40826 - implementation 'org.springframework:spring-webmvc:5.3.32' - implementation 'org.springframework:spring-web:5.3.32' + implementation 'org.springframework:spring-webmvc:5.3.33' + implementation 'org.springframework:spring-web:5.3.33' implementation 'com.opencsv:opencsv:5.8' diff --git a/gradle.properties b/gradle.properties index 489863e567..54e45f0fc4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.11.0 +version=5.11.1 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom From 9f4b2ccf2de63a573b991d581a2451bcf5b601c3 Mon Sep 17 00:00:00 2001 From: "reportportal.io" <support@reportportal.io> Date: Thu, 18 Apr 2024 11:33:31 +0000 Subject: [PATCH 25/25] [Gradle Release Plugin] - new version commit: '5.11.2'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 54e45f0fc4..b2c6c1f5a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=5.11.1 +version=5.11.2 description=EPAM Report portal. Main API Service dockerPrepareEnvironment= dockerJavaOpts=-Xmx1g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom