From 38b7175b61d4b9c3481e38f332be942ea9d33222 Mon Sep 17 00:00:00 2001 From: song-tianyang Date: Mon, 27 Feb 2023 16:58:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --story=1011161 --user=宋天阳 测试计划报告性能优化 https://www.tapd.cn/55049933/s/1346616 --- ...FailureApiDTO.java => TestPlanApiDTO.java} | 2 +- ...narioDTO.java => TestPlanScenarioDTO.java} | 2 +- .../api/dto/plan/ApiPlanReportDTO.java | 20 +- .../api/dto/plan/ApiPlanReportRequest.java | 4 + .../api/dto/plan/ApiReportResultDTO.java | 17 + .../dto/plan/TestPlanExecuteReportDTO.java | 8 +- .../api/jmeter/KafkaListenerTask.java | 6 +- .../api/jmeter/MsApiBackendListener.java | 6 +- .../ext/ExtApiScenarioReportResultMapper.java | 2 + .../ext/ExtApiScenarioReportResultMapper.xml | 9 + .../plan/ext/ExtTestPlanApiCaseMapper.java | 6 +- .../plan/ext/ExtTestPlanApiCaseMapper.xml | 15 +- .../ext/ExtTestPlanScenarioCaseMapper.java | 6 +- .../ext/ExtTestPlanScenarioCaseMapper.xml | 6 +- .../plan/ShareTestPlanApiCaseController.java | 10 +- .../ShareTestPlanScenarioCaseController.java | 11 +- .../plan/TestPlanApiCaseController.java | 16 +- .../plan/TestPlanScenarioCaseController.java | 27 +- .../listener/ApiExecutionQueueListener.java | 2 +- .../service/ApiExecutionQueueService.java | 33 +- .../service/RemakeReportService.java | 8 +- .../ApiDefinitionExecResultService.java | 13 +- .../service/plan/TestPlanApiCaseService.java | 32 +- .../plan/TestPlanScenarioCaseService.java | 200 ++--- .../scenario/ApiScenarioReportService.java | 11 + .../ApiScenarioReportStructureService.java | 2 +- .../constants/TestPlanReportStatus.java | 2 +- .../plan/service/PerfQueueService.java | 31 +- .../mapper/ext/ExtTestPlanApiCaseMapper.java | 9 + .../mapper/ext/ExtTestPlanApiCaseMapper.xml | 10 + .../mapper/ext/ExtTestPlanLoadCaseMapper.java | 15 + .../mapper/ext/ExtTestPlanLoadCaseMapper.xml | 13 + .../base/mapper/ext/ExtTestPlanMapper.java | 2 + .../base/mapper/ext/ExtTestPlanMapper.xml | 4 + .../ext/ExtTestPlanScenarioCaseMapper.java | 11 +- .../ext/ExtTestPlanScenarioCaseMapper.xml | 10 + .../mapper/ext/ExtTestPlanTestCaseMapper.java | 12 +- .../mapper/ext/ExtTestPlanTestCaseMapper.xml | 23 + .../mapper/ext/ExtTestPlanUiCaseMapper.java | 15 + .../mapper/ext/ExtTestPlanUiCaseMapper.xml | 13 + .../io/metersphere/config/DatabaseConfig.java | 34 + .../controller/ShareController.java | 19 +- .../controller/TestPlanController.java | 14 +- ...FailureApiDTO.java => TestPlanApiDTO.java} | 2 +- .../dto/TestPlanCaseReportResultDTO.java | 25 + .../dto/TestPlanExecuteReportDTO.java | 22 - .../dto/TestPlanReportBuildResultDTO.java | 5 - ...narioDTO.java => TestPlanScenarioDTO.java} | 2 +- .../listener/ExecReportListener.java | 28 +- .../plan/dto/ApiPlanReportDTO.java | 20 +- .../plan/dto/ApiReportResultDTO.java | 17 + .../metersphere/plan/dto/CaseExecResult.java | 17 + ...xtReportDTO.java => ExecutionModeDTO.java} | 2 +- .../dto/TestCaseRelevanceCasesRequest.java | 24 + .../plan/dto/TestCaseRelevanceVo.java | 13 + .../plan/dto/TestPlanSimpleReportDTO.java | 16 +- .../plan/enums/FunctionCaseExecResult.java | 23 + .../plan/enums/TestCaseReleevanceType.java | 19 + .../request/api/ApiPlanReportRequest.java | 8 +- .../service/TestCaseSyncStatusService.java | 269 ++++++ .../plan/service/TestPlanMessageService.java | 10 +- .../plan/service/TestPlanReportService.java | 831 +++++++----------- .../plan/service/TestPlanService.java | 386 ++++---- .../plan/service/TestPlanTestCaseService.java | 72 +- .../api/PlanTestPlanApiCaseService.java | 28 +- .../api/PlanTestPlanScenarioCaseService.java | 31 +- .../PlanTestPlanLoadCaseService.java | 19 +- .../ui/PlanTestPlanUiScenarioCaseService.java | 20 +- .../plan/utils/TestCaseSyncStatusUtil.java | 264 ++++++ .../plan/utils/TestPlanReportUtil.java | 154 ++++ .../io/metersphere/service/IssuesService.java | 71 +- .../utils/BatchProcessingUtil.java | 50 ++ .../resources/i18n/messages_en_US.properties | 6 +- .../resources/i18n/messages_zh_CN.properties | 7 +- .../resources/i18n/messages_zh_TW.properties | 8 +- .../report/detail/TestPlanReportContent.vue | 288 +++--- 76 files changed, 2202 insertions(+), 1266 deletions(-) rename api-test/backend/src/main/java/io/metersphere/api/dto/automation/{TestPlanFailureApiDTO.java => TestPlanApiDTO.java} (83%) rename api-test/backend/src/main/java/io/metersphere/api/dto/automation/{TestPlanFailureScenarioDTO.java => TestPlanScenarioDTO.java} (79%) create mode 100644 api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiReportResultDTO.java create mode 100644 test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.java create mode 100644 test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml create mode 100644 test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.java create mode 100644 test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.xml create mode 100644 test-track/backend/src/main/java/io/metersphere/config/DatabaseConfig.java rename test-track/backend/src/main/java/io/metersphere/dto/{TestPlanFailureApiDTO.java => TestPlanApiDTO.java} (79%) create mode 100644 test-track/backend/src/main/java/io/metersphere/dto/TestPlanCaseReportResultDTO.java delete mode 100644 test-track/backend/src/main/java/io/metersphere/dto/TestPlanExecuteReportDTO.java rename test-track/backend/src/main/java/io/metersphere/dto/{TestPlanFailureScenarioDTO.java => TestPlanScenarioDTO.java} (83%) create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/dto/ApiReportResultDTO.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/dto/CaseExecResult.java rename test-track/backend/src/main/java/io/metersphere/plan/dto/{TestPlanExtReportDTO.java => ExecutionModeDTO.java} (84%) create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceCasesRequest.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceVo.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/enums/FunctionCaseExecResult.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/enums/TestCaseReleevanceType.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/service/TestCaseSyncStatusService.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/utils/TestCaseSyncStatusUtil.java create mode 100644 test-track/backend/src/main/java/io/metersphere/plan/utils/TestPlanReportUtil.java create mode 100644 test-track/backend/src/main/java/io/metersphere/utils/BatchProcessingUtil.java diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureApiDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanApiDTO.java similarity index 83% rename from api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureApiDTO.java rename to api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanApiDTO.java index 28e79f2e4b..1f91881dd4 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureApiDTO.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanApiDTO.java @@ -8,7 +8,7 @@ import lombok.Setter; @Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) -public class TestPlanFailureApiDTO extends TestPlanApiCaseDTO { +public class TestPlanApiDTO extends TestPlanApiCaseDTO { private String response; private String reportId; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureScenarioDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanScenarioDTO.java similarity index 79% rename from api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureScenarioDTO.java rename to api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanScenarioDTO.java index dca89a3ba8..95c04f7d0c 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanFailureScenarioDTO.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/automation/TestPlanScenarioDTO.java @@ -7,6 +7,6 @@ import lombok.Setter; @Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) -public class TestPlanFailureScenarioDTO extends ApiScenarioDTO { +public class TestPlanScenarioDTO extends ApiScenarioDTO { private ApiScenarioReportResult response; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportDTO.java index a262f42110..0911006e9d 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportDTO.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportDTO.java @@ -1,8 +1,8 @@ package io.metersphere.api.dto.plan; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; -import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; +import io.metersphere.api.dto.automation.TestPlanApiDTO; +import io.metersphere.api.dto.automation.TestPlanScenarioDTO; import lombok.Getter; import lombok.Setter; @@ -11,13 +11,13 @@ import java.util.List; @Setter @Getter public class ApiPlanReportDTO { - private List apiAllCases; - private List apiFailureCases; - private List errorReportCases; - private List unExecuteCases; + private List apiAllCases; + private List apiFailureCases; + private List errorReportCases; + private List unExecuteCases; - private List scenarioAllCases; - private List scenarioFailureCases; - private List errorReportScenarios; - private List unExecuteScenarios; + private List scenarioAllCases; + private List scenarioFailureCases; + private List errorReportScenarios; + private List unExecuteScenarios; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportRequest.java b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportRequest.java index e020756ca5..1a1530a443 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportRequest.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiPlanReportRequest.java @@ -5,8 +5,12 @@ import io.metersphere.request.PlanSubReportRequest; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Setter @Getter public class ApiPlanReportRequest extends PlanSubReportRequest { + List apiReportIdList; + List scenarioReportIdList; private TestPlanExecuteReportDTO testPlanExecuteReportDTO; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiReportResultDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiReportResultDTO.java new file mode 100644 index 0000000000..bd41c29288 --- /dev/null +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/ApiReportResultDTO.java @@ -0,0 +1,17 @@ +package io.metersphere.api.dto.plan; + + +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Setter +@Getter +public class ApiReportResultDTO { + // 接口报告结果 + Map apiReportResultMap; + + // 场景报告结果 + Map scenarioReportResultMap; +} diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/TestPlanExecuteReportDTO.java b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/TestPlanExecuteReportDTO.java index b6dff611b3..12b839df07 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/plan/TestPlanExecuteReportDTO.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/plan/TestPlanExecuteReportDTO.java @@ -1,7 +1,7 @@ package io.metersphere.api.dto.plan; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; -import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; +import io.metersphere.api.dto.automation.TestPlanApiDTO; +import io.metersphere.api.dto.automation.TestPlanScenarioDTO; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -16,6 +16,6 @@ import java.util.Map; public class TestPlanExecuteReportDTO { private Map testPlanApiCaseIdAndReportIdMap; private Map testPlanScenarioIdAndReportIdMap; - private Map apiCaseInfoDTOMap; - private Map scenarioInfoDTOMap; + private Map apiCaseInfoDTOMap; + private Map scenarioInfoDTOMap; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java index 188e322011..bbf083bb63 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/KafkaListenerTask.java @@ -91,10 +91,8 @@ public class KafkaListenerTask implements Runnable { // 全局并发队列 PoolExecBlockingQueueUtil.offer(testResult.getReportId()); // 更新测试计划报告 - if (StringUtils.isNotEmpty(testResult.getTestPlanReportId())) { - LoggerUtil.info("Check Processing Test Plan report status:" + testResult.getQueueId() + "," + testResult.getTestId(), testResult.getReportId()); - apiExecutionQueueService.testPlanReportTestEnded(testResult.getTestPlanReportId()); - } + LoggerUtil.info("Check Processing Test Plan report status:" + testResult.getQueueId() + "," + testResult.getTestId(), testResult.getReportId()); + apiExecutionQueueService.checkTestPlanCaseTestEnd(testResult.getTestId(), testResult.getRunMode(), testResult.getTestPlanReportId()); }); } } catch (Exception e) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java index 8eb1c7b162..34dbb54417 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsApiBackendListener.java @@ -115,10 +115,8 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen apiExecutionQueueService.queueNext(dto); } // 更新测试计划报告 - if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) { - LoggerUtil.info("Check Processing Test Plan report status:" + dto.getQueueId() + "," + dto.getTestId()); - apiExecutionQueueService.testPlanReportTestEnded(dto.getTestPlanReportId()); - } + LoggerUtil.info("Check Processing Test Plan report status:" + dto.getQueueId() + "," + dto.getTestId()); + apiExecutionQueueService.checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId()); LoggerUtil.info("TEST-END处理结果集完成", dto.getReportId()); JvmUtil.memoryInfo(); diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.java b/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.java index eefaaf0ac2..0929e5294e 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.java +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.java @@ -15,4 +15,6 @@ public interface ExtApiScenarioReportResultMapper { List selectDistinctStatusByReportId(String reportId); int deleteByProjectId(String projectId); + + List selectIdAndStatusByReportIdList(@Param("ids") List scenarioReportIdList); } diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.xml b/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.xml index 7f307d58bb..21081d3215 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.xml +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioReportResultMapper.xml @@ -38,4 +38,13 @@ FROM api_scenario_report_result WHERE report_id = #{0} + + + diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.java b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.java index 228f9f83b2..48fb0fa8cb 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.java +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.java @@ -1,8 +1,8 @@ package io.metersphere.base.mapper.plan.ext; import io.metersphere.api.dto.QueryReferenceRequest; +import io.metersphere.api.dto.automation.TestPlanApiDTO; import io.metersphere.api.dto.automation.TestPlanDTO; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; import io.metersphere.api.dto.definition.ApiTestCaseRequest; import io.metersphere.api.dto.definition.TestPlanApiCaseDTO; import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO; @@ -39,9 +39,9 @@ public interface ExtTestPlanApiCaseMapper { List selectForPlanReport(String planId); - List getFailureList(@Param("planId") String planId, @Param("status") String status); + List getFailureList(@Param("planId") String planId, @Param("status") String status); - List getFailureListByIds(@Param("ids") Collection caseIdList, @Param("status") String status); + List getFailureListByIds(@Param("ids") Collection caseIdList, @Param("status") String status); List selectPlanIds(); diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.xml b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.xml index 1940b53198..7b8b36247f 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.xml +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanApiCaseMapper.xml @@ -366,7 +366,7 @@ != 'Trash' ) - select t.id, c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_id, @@ -388,7 +388,7 @@ where t.test_plan_id = #{planId} ORDER BY t.order DESC - select t.id, c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_id, @@ -544,15 +544,4 @@ #{v} - - diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.java b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.java index e010a2d17a..faf48e9128 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.java +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.java @@ -1,7 +1,7 @@ package io.metersphere.base.mapper.plan.ext; import io.metersphere.api.dto.automation.ApiScenarioDTO; -import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; +import io.metersphere.api.dto.automation.TestPlanScenarioDTO; import io.metersphere.api.dto.automation.TestPlanScenarioRequest; import io.metersphere.api.dto.plan.TestPlanApiScenarioInfoDTO; import io.metersphere.base.domain.TestPlanApiScenario; @@ -32,9 +32,9 @@ public interface ExtTestPlanScenarioCaseMapper { List selectForPlanReport(String planId); - List getFailureList(@Param("planId") String planId, @Param("status") String status); + List getFailureList(@Param("planId") String planId, @Param("status") String status); - List getFailureListByIds(@Param("ids") Collection ids, @Param("status") String status); + List getFailureListByIds(@Param("ids") Collection ids, @Param("status") String status); List getUnderwaySteps(@Param("ids") List underwayIds); diff --git a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.xml b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.xml index e6d132cf03..f66baef08b 100644 --- a/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.xml +++ b/api-test/backend/src/main/java/io/metersphere/base/mapper/plan/ext/ExtTestPlanScenarioCaseMapper.xml @@ -299,7 +299,7 @@ != 'Trash' ) - select t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal, c.status,c.step_total, c.step_total, c.project_id, @@ -323,9 +323,9 @@ ORDER BY t.order DESC - select - t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal, + t.id, t.last_result, t.report_id, c.id AS caseId,c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal, c.status,c.step_total, c.step_total, c.project_id, c.num, c.custom_num from diff --git a/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanApiCaseController.java b/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanApiCaseController.java index bf8fee2c9b..3a93de0ddd 100644 --- a/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanApiCaseController.java +++ b/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanApiCaseController.java @@ -1,6 +1,6 @@ package io.metersphere.controller.plan; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; +import io.metersphere.api.dto.automation.TestPlanApiDTO; import io.metersphere.service.ShareInfoService; import io.metersphere.service.plan.TestPlanApiCaseService; import jakarta.annotation.Resource; @@ -21,25 +21,25 @@ public class ShareTestPlanApiCaseController { TestPlanApiCaseService testPlanApiCaseService; @GetMapping("/list/failure/{shareId}/{planId}") - public List getApiFailureList(@PathVariable String shareId, @PathVariable String planId) { + public List getApiFailureList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanApiCaseService.getFailureCases(planId); } @GetMapping("/list/errorReport/{shareId}/{planId}") - public List getErrorReportApiCaseList(@PathVariable String shareId, @PathVariable String planId) { + public List getErrorReportApiCaseList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanApiCaseService.getErrorReportCases(planId); } @GetMapping("/list/unExecute/{shareId}/{planId}") - public List getUnExecuteCases(@PathVariable String shareId, @PathVariable String planId) { + public List getUnExecuteCases(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanApiCaseService.getUnExecuteCases(planId); } @GetMapping("/list/all/{shareId}/{planId}") - public List getApiAllList(@PathVariable String shareId, @PathVariable String planId) { + public List getApiAllList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanApiCaseService.getAllCases(planId); } diff --git a/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanScenarioCaseController.java b/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanScenarioCaseController.java index 10da57600d..f02ba920c4 100644 --- a/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanScenarioCaseController.java +++ b/api-test/backend/src/main/java/io/metersphere/controller/plan/ShareTestPlanScenarioCaseController.java @@ -1,7 +1,8 @@ package io.metersphere.controller.plan; import io.metersphere.api.dto.automation.ApiScenarioReportResult; -import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; +import io.metersphere.api.dto.automation.TestPlanScenarioDTO; +import io.metersphere.api.dto.automation.TestPlanScenarioDTO; import io.metersphere.service.ShareInfoService; import io.metersphere.service.plan.TestPlanScenarioCaseService; import io.metersphere.service.scenario.ApiScenarioReportService; @@ -25,25 +26,25 @@ public class ShareTestPlanScenarioCaseController { private ApiScenarioReportService apiReportService; @GetMapping("/list/failure/{shareId}/{planId}") - public List getScenarioFailureList(@PathVariable String shareId, @PathVariable String planId) { + public List getScenarioFailureList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanScenarioCaseService.getFailureCases(planId); } @GetMapping("/list/all/{shareId}/{planId}") - public List getScenarioAllList(@PathVariable String shareId, @PathVariable String planId) { + public List getScenarioAllList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanScenarioCaseService.getAllCases(planId); } @GetMapping("/list/errorReport/{shareId}/{planId}") - public List getScenarioErrorReportList(@PathVariable String shareId, @PathVariable String planId) { + public List getScenarioErrorReportList(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanScenarioCaseService.getErrorReportCases(planId); } @GetMapping("/list/unExecute/{shareId}/{planId}") - public List getUnExecuteScenarioCases(@PathVariable String shareId, @PathVariable String planId) { + public List getUnExecuteScenarioCases(@PathVariable String shareId, @PathVariable String planId) { shareInfoService.validate(shareId); return testPlanScenarioCaseService.getUnExecuteCases(planId); } diff --git a/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanApiCaseController.java b/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanApiCaseController.java index 159e1d3369..8701fb51b3 100644 --- a/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanApiCaseController.java +++ b/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanApiCaseController.java @@ -3,8 +3,8 @@ package io.metersphere.controller.plan; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.QueryReferenceRequest; +import io.metersphere.api.dto.automation.TestPlanApiDTO; import io.metersphere.api.dto.automation.TestPlanDTO; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest; import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs; @@ -19,10 +19,10 @@ import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.request.ResetOrderRequest; import io.metersphere.service.plan.TestPlanApiCaseService; +import jakarta.annotation.Resource; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,22 +41,22 @@ public class TestPlanApiCaseController { } @GetMapping("/list/failure/{planId}") - public List getFailureList(@PathVariable String planId) { + public List getFailureList(@PathVariable String planId) { return testPlanApiCaseService.getFailureCases(planId); } @GetMapping("/list/errorReport/{planId}") - public List getErrorReportList(@PathVariable String planId) { + public List getErrorReportList(@PathVariable String planId) { return testPlanApiCaseService.getErrorReportCases(planId); } @GetMapping("/list/unExecute/{planId}") - public List getUnExecuteCases(@PathVariable String planId) { + public List getUnExecuteCases(@PathVariable String planId) { return testPlanApiCaseService.getUnExecuteCases(planId); } @GetMapping("/list/all/{planId}") - public List getAllList(@PathVariable String planId) { + public List getAllList(@PathVariable String planId) { return testPlanApiCaseService.getAllCases(planId); } @@ -170,7 +170,7 @@ public class TestPlanApiCaseController { } @PostMapping("/failure/list") - public List getFailureListByIds(@RequestBody Set planApiCaseIds) { + public List getFailureListByIds(@RequestBody Set planApiCaseIds) { return testPlanApiCaseService.getFailureListByIds(planApiCaseIds); } @@ -190,7 +190,7 @@ public class TestPlanApiCaseController { } @PostMapping("/build/response") - public List buildResponse(@RequestBody List cases) { + public List buildResponse(@RequestBody List cases) { testPlanApiCaseService.buildApiResponse(cases); return cases; } diff --git a/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanScenarioCaseController.java b/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanScenarioCaseController.java index 318ea00877..463c5ca27f 100644 --- a/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanScenarioCaseController.java +++ b/api-test/backend/src/main/java/io/metersphere/controller/plan/TestPlanScenarioCaseController.java @@ -4,11 +4,8 @@ import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.ApiCaseRelevanceRequest; import io.metersphere.api.dto.RelevanceScenarioRequest; -import io.metersphere.api.dto.plan.TestPlanScenarioCaseBatchRequest; import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.plan.*; -import io.metersphere.service.scenario.ApiScenarioService; -import io.metersphere.service.plan.TestPlanScenarioCaseService; import io.metersphere.base.domain.TestPlanReport; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.OperLogConstants; @@ -21,9 +18,11 @@ import io.metersphere.dto.PlanReportCaseDTO; import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.request.ResetOrderRequest; +import io.metersphere.service.plan.TestPlanScenarioCaseService; +import io.metersphere.service.scenario.ApiScenarioService; +import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,22 +42,22 @@ public class TestPlanScenarioCaseController { } @GetMapping("/list/failure/{planId}") - public List getFailureList(@PathVariable String planId) { + public List getFailureList(@PathVariable String planId) { return testPlanScenarioCaseService.getFailureCases(planId); } @GetMapping("/list/error-report/{planId}") - public List getErrorReportList(@PathVariable String planId) { + public List getErrorReportList(@PathVariable String planId) { return testPlanScenarioCaseService.getErrorReportCases(planId); } @GetMapping("/list/pending/{planId}") - public List getUnExecuteCases(@PathVariable String planId) { + public List getUnExecuteCases(@PathVariable String planId) { return testPlanScenarioCaseService.getUnExecuteCases(planId); } @GetMapping("/list/all/{planId}") - public List getAllList(@PathVariable String planId) { + public List getAllList(@PathVariable String planId) { return testPlanScenarioCaseService.getAllCases(planId); } @@ -185,8 +184,8 @@ public class TestPlanScenarioCaseController { return testPlanScenarioCaseService.buildApiReport(request); } - @PostMapping("/plan/execute/report") - public ApiPlanReportDTO buildExecuteApiReport(@RequestBody ApiPlanReportRequest request) { + @PostMapping("/select/result/by/reportId") + public ApiReportResultDTO selectReportResultById(@RequestBody ApiPlanReportRequest request) { return testPlanScenarioCaseService.buildExecuteApiReport(request); } @@ -195,9 +194,9 @@ public class TestPlanScenarioCaseController { return testPlanScenarioCaseService.isExecuting(planId); } - @PostMapping("/failure/list") - public List getFailureListByIds(@RequestBody Set planApiCaseIds) { - return testPlanScenarioCaseService.getFailureListByIds(planApiCaseIds); + @PostMapping("/all/list") + public List getListByIds(@RequestBody Set planApiCaseIds) { + return testPlanScenarioCaseService.getListByIds(planApiCaseIds); } @PostMapping("/env/generate") @@ -221,7 +220,7 @@ public class TestPlanScenarioCaseController { } @PostMapping("/build/response") - public List buildResponse(@RequestBody List cases) { + public List buildResponse(@RequestBody List cases) { testPlanScenarioCaseService.buildScenarioResponse(cases); return cases; } diff --git a/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java b/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java index ef7829cf1c..e1ae1420bc 100644 --- a/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java +++ b/api-test/backend/src/main/java/io/metersphere/listener/ApiExecutionQueueListener.java @@ -1,7 +1,7 @@ package io.metersphere.listener; -import io.metersphere.service.ApiExecutionQueueService; import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.service.ApiExecutionQueueService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; diff --git a/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java b/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java index 2416f0f720..7781fda161 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/ApiExecutionQueueService.java @@ -213,10 +213,7 @@ public class ApiExecutionQueueService { if (isError) { ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); example.createCriteria().andQueueIdEqualTo(dto.getQueueId()); - - if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) { - testPlanReportTestEnded(dto.getTestPlanReportId()); - } + checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId()); // 更新未执行的报告状态 List details = executionQueueDetailMapper.selectByExample(example); List reportIds = details.stream().map(ApiExecutionQueueDetail::getReportId).collect(Collectors.toList()); @@ -272,9 +269,23 @@ public class ApiExecutionQueueService { return queue; } - public void testPlanReportTestEnded(String testPlanReportId) { - // 检查测试计划中其他队列是否结束 - kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId); + private void testPlanCaseTestEnd(String testId, String runMode) { + //不是整体测试计划执行的用例,发送testID给测试跟踪模块,用于做单接口执行后续操作处理 + if (StringUtils.isNotEmpty(testId) && StringUtils.equalsAnyIgnoreCase(runMode, + ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), + ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) { + kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testId, UUID.randomUUID().toString()); + } + } + + public void checkTestPlanCaseTestEnd(String testId, String runMode, String testPlanReportId) { + if (StringUtils.isEmpty(testPlanReportId)) { + //不是整体测试计划执行的用例,发送testID给测试跟踪模块,用于做单接口执行后续操作处理 + this.testPlanCaseTestEnd(testId, runMode); + } else { + // 由测试计划检查测试计划中其他队列是否结束 + kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId); + } } public void queueNext(ResultDTO dto) { @@ -443,7 +454,7 @@ public class ApiExecutionQueueService { // 更新测试计划报告 if (StringUtils.isNotEmpty(item.getReportId())) { LoggerUtil.info("Handling test plan reports that are not in the execution queue:【" + item.getReportId() + "】"); - testPlanReportTestEnded(item.getReportId()); + checkTestPlanCaseTestEnd(null, null, item.getReportId()); } }); } @@ -452,7 +463,7 @@ public class ApiExecutionQueueService { if (CollectionUtils.isNotEmpty(testPlanReports)) { testPlanReports.forEach(reportId -> { LoggerUtil.info("Compensation Test Plan Report:【" + reportId + "】"); - testPlanReportTestEnded(reportId); + checkTestPlanCaseTestEnd(null, null, reportId); }); } // 清除异常队列/一般是服务突然停止产生 @@ -473,7 +484,7 @@ public class ApiExecutionQueueService { ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(detail.getQueueId()); // 更新测试计划报告 if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) { - testPlanReportTestEnded(queue.getReportId()); + checkTestPlanCaseTestEnd(null, null, queue.getReportId()); } } }); @@ -499,7 +510,7 @@ public class ApiExecutionQueueService { ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(queueId); // 更新测试计划报告 if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) { - testPlanReportTestEnded(queue.getReportId()); + checkTestPlanCaseTestEnd(null, null, queue.getReportId()); queueMapper.deleteByPrimaryKey(queueId); } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java b/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java index 371ae59737..fdd402e188 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/RemakeReportService.java @@ -35,13 +35,11 @@ public class RemakeReportService { CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto); } // 更新测试计划报告 - if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) { - LoggerUtil.info("Check Processing Test Plan report status:" + dto.getQueueId() + "," + dto.getTestId(), dto.getReportId()); - CommonBeanFactory.getBean(ApiExecutionQueueService.class).testPlanReportTestEnded(dto.getTestPlanReportId()); - } + LoggerUtil.info("Check Processing Test Plan report status.queueId:" + dto.getQueueId() + ",runMode:" + dto.getRunMode() + ",testId:" + dto.getTestId(), dto.getReportId()); + CommonBeanFactory.getBean(ApiExecutionQueueService.class).checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId()); } catch (Exception e) { LoggerUtil.error("回退报告异常", request.getReportId(), e); - }finally { + } finally { redisTemplateService.delete(JmxFileUtil.getExecuteScriptKey(request.getReportId(), request.getTestId())); redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId())); } diff --git a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionExecResultService.java b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionExecResultService.java index 2e2687a114..18824cfb25 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionExecResultService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionExecResultService.java @@ -22,6 +22,7 @@ import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.ServiceUtils; import io.metersphere.utils.LoggerUtil; +import jakarta.annotation.Resource; import org.apache.commons.beanutils.BeanMap; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; @@ -33,7 +34,6 @@ import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import jakarta.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @@ -489,4 +489,15 @@ public class ApiDefinitionExecResultService { public ApiDefinitionExecResultWithBLOBs getLastResult(String testId) { return extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId); } + + public Map selectResultByIdList(List reportIdList) { + Map returnMap = new HashMap<>(); + if (CollectionUtils.isNotEmpty(reportIdList)) { + List apiDefinitionExecResultList = extApiDefinitionExecResultMapper.selectStatusByIdList(reportIdList); + if (CollectionUtils.isNotEmpty(apiDefinitionExecResultList)) { + returnMap = apiDefinitionExecResultList.stream().collect(Collectors.toMap(ApiDefinitionExecResult::getId, ApiDefinitionExecResult::getStatus, (k1, k2) -> k1)); + } + } + return returnMap; + } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java index 26e8894239..66559e4d12 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java @@ -7,8 +7,8 @@ import io.metersphere.api.dto.ApiCaseRelevanceRequest; import io.metersphere.api.dto.ApiReportEnvConfigDTO; import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.QueryReferenceRequest; +import io.metersphere.api.dto.automation.TestPlanApiDTO; import io.metersphere.api.dto.automation.TestPlanDTO; -import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest; import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO; @@ -39,6 +39,7 @@ import io.metersphere.service.definition.ApiDefinitionService; import io.metersphere.service.definition.ApiModuleService; import io.metersphere.service.definition.ApiTestCaseService; import io.metersphere.service.plan.remote.TestPlanService; +import jakarta.annotation.Resource; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; @@ -49,7 +50,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import jakarta.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @@ -392,20 +392,20 @@ public class TestPlanApiCaseService { } - public List getFailureCases(String planId) { - List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name()); + public List getFailureCases(String planId) { + List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name()); return buildCases(apiTestCases); } - public List getAllCases(String planId) { - List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null); + public List getAllCases(String planId) { + List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null); return buildCases(apiTestCases); } - public void buildApiResponse(List cases) { + public void buildApiResponse(List cases) { if (!org.apache.commons.collections.CollectionUtils.isEmpty(cases)) { List reportIds = new ArrayList<>(); - for (TestPlanFailureApiDTO apiCase : cases) { + for (TestPlanApiDTO apiCase : cases) { if (StringUtils.isEmpty(apiCase.getReportId())) { ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(apiCase.getId(), "API_PLAN"); if (result != null && StringUtils.isNotBlank(result.getContent())) { @@ -464,7 +464,7 @@ public class TestPlanApiCaseService { } } - public List buildCases(List apiTestCases) { + public List buildCases(List apiTestCases) { if (CollectionUtils.isEmpty(apiTestCases)) { return apiTestCases; } @@ -479,9 +479,9 @@ public class TestPlanApiCaseService { * * @param apiTestCases */ - private void buildPrincipal(List apiTestCases) { + private void buildPrincipal(List apiTestCases) { List apiIds = apiTestCases.stream() - .map(TestPlanFailureApiDTO::getApiDefinitionId) + .map(TestPlanApiDTO::getApiDefinitionId) .collect(Collectors.toList()); Map userIdMap = apiDefinitionService.selectByIds(apiIds) @@ -503,13 +503,13 @@ public class TestPlanApiCaseService { ServiceUtils.updateOrderField(request, TestPlanApiCase.class, testPlanApiCaseMapper::selectByPrimaryKey, extTestPlanApiCaseMapper::getPreOrder, extTestPlanApiCaseMapper::getLastOrder, testPlanApiCaseMapper::updateByPrimaryKeySelective); } - public List getErrorReportCases(String planId) { - List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name()); + public List getErrorReportCases(String planId) { + List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name()); return buildCases(apiTestCases); } - public List getUnExecuteCases(String planId) { - List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name()); + public List getUnExecuteCases(String planId) { + List apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name()); return buildCases(apiTestCases); } @@ -717,7 +717,7 @@ public class TestPlanApiCaseService { return !testPlanApiCaseList.stream().map(TestPlanApiCaseInfoDTO::getApiCaseId).collect(Collectors.toList()).isEmpty(); } - public List getFailureListByIds(Set planApiCaseIds) { + public List getFailureListByIds(Set planApiCaseIds) { return extTestPlanApiCaseMapper.getFailureListByIds(planApiCaseIds, null); } diff --git a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanScenarioCaseService.java b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanScenarioCaseService.java index d76ad7d5ab..2d3a17a553 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanScenarioCaseService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanScenarioCaseService.java @@ -6,15 +6,16 @@ import io.metersphere.api.dto.ApiCaseRelevanceRequest; import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.RelevanceScenarioRequest; import io.metersphere.api.dto.ScenarioEnv; -import io.metersphere.api.dto.automation.ApiScenarioReportResult; import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.plan.*; import io.metersphere.api.exec.scenario.ApiScenarioEnvService; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.base.domain.ApiScenarioReportResult; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.ApiTestEnvironmentMapper; import io.metersphere.base.mapper.ext.ExtApiScenarioModuleMapper; +import io.metersphere.base.mapper.ext.ExtApiScenarioReportResultMapper; import io.metersphere.base.mapper.plan.TestPlanApiScenarioMapper; import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiScenarioMapper; import io.metersphere.base.mapper.plan.ext.ExtTestPlanScenarioCaseMapper; @@ -41,10 +42,12 @@ import io.metersphere.service.definition.ApiDefinitionExecResultService; import io.metersphere.service.plan.remote.TestPlanService; import io.metersphere.service.scenario.ApiScenarioModuleService; import io.metersphere.service.scenario.ApiScenarioReportService; +import io.metersphere.service.scenario.ApiScenarioReportStructureService; import io.metersphere.service.scenario.ApiScenarioService; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; @@ -103,6 +106,11 @@ public class TestPlanScenarioCaseService { private TestPlanService testPlanService; @Resource private JMeterService jMeterService; + @Resource + private ExtApiScenarioReportResultMapper extApiScenarioReportResultMapper; + @Lazy + @Resource + private ApiScenarioReportStructureService apiScenarioReportStructureService; public List list(TestPlanScenarioRequest request) { request.setProjectId(null); @@ -557,17 +565,17 @@ public class TestPlanScenarioCaseService { return envMap; } - public List getAllCases(String planId) { - List apiTestCases = + public List getAllCases(String planId) { + List apiTestCases = extTestPlanScenarioCaseMapper.getFailureList(planId, null); return buildCases(apiTestCases); } - public List getAllCases(Map idMap, Map scenarioInfoDTOMap) { + public List getAllCases(Map idMap, Map scenarioInfoDTOMap) { Map reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values()); Map savedReportMap = new HashMap<>(idMap); - List apiTestCases = new ArrayList<>(); - for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) { + List apiTestCases = new ArrayList<>(); + for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) { String reportId = savedReportMap.get(dto.getId()); savedReportMap.remove(dto.getId()); dto.setReportId(reportId); @@ -585,13 +593,13 @@ public class TestPlanScenarioCaseService { } - public List getFailureCases(String planId) { - List apiTestCases = + public List getFailureCases(String planId) { + List apiTestCases = extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name()); return buildCases(apiTestCases); } - public List buildCases(List apiTestCases) { + public List buildCases(List apiTestCases) { if (CollectionUtils.isEmpty(apiTestCases)) { return apiTestCases; } @@ -633,23 +641,34 @@ public class TestPlanScenarioCaseService { testPlanApiScenarioMapper::updateByPrimaryKeySelective); } - public List getErrorReportCases(String planId) { - List apiTestCases = + public List getErrorReportCases(String planId) { + List apiTestCases = extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name()); return buildCases(apiTestCases); } - public List getUnExecuteCases(String planId) { - List apiTestCases = + public List getUnExecuteCases(String planId) { + List apiTestCases = extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name()); return buildCases(apiTestCases); } public TestPlanScenarioStepCountSimpleDTO getStepCount(List planReportCaseDTOS) { TestPlanScenarioStepCountDTO stepCount = new TestPlanScenarioStepCountDTO(); + + List scenarioReportIdList = new ArrayList<>(); for (PlanReportCaseDTO item : planReportCaseDTOS) { - calculateScenarioResultDTO(item, stepCount); + if (StringUtils.isBlank(item.getReportId())) { + stepCount.getUnderwayIds().add(item.getCaseId()); + } else { + if (!scenarioReportIdList.contains(item.getReportId())) { + scenarioReportIdList.add(item.getReportId()); + } + } } + //统计各种状态的步骤 + calculateScenarioResultDTO(scenarioReportIdList, stepCount); + int underwayStepsCounts = getUnderwayStepsCounts(stepCount.getUnderwayIds()); TestPlanScenarioStepCountSimpleDTO stepResult = new TestPlanScenarioStepCountSimpleDTO(); stepResult.setStepCount(stepCount); @@ -665,24 +684,33 @@ public class TestPlanScenarioCaseService { return 0; } - private void calculateScenarioResultDTO(PlanReportCaseDTO item, + private void calculateScenarioResultDTO(List scenarioReportIdList, TestPlanScenarioStepCountDTO stepCount) { - if (StringUtils.isNotBlank(item.getReportId())) { - ApiScenarioReportResult apiScenarioReportResult = apiScenarioReportService.get(item.getReportId(), false); - if (apiScenarioReportResult != null) { - String content = apiScenarioReportResult.getContent(); - if (StringUtils.isNotBlank(content)) { - Map map = JSON.parseMap(content); - stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + (Integer) map.get("scenarioStepTotal")); - stepCount.setScenarioStepSuccess(stepCount.getScenarioStepSuccess() + (Integer) map.get("scenarioStepSuccess")); - stepCount.setScenarioStepError(stepCount.getScenarioStepError() + (Integer) map.get("scenarioStepError")); - stepCount.setScenarioStepErrorReport(stepCount.getScenarioStepErrorReport() + (Integer) map.get("scenarioStepErrorReport")); - stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + (map.get("pending") == null ? 0 : (Integer) map.get("pending"))); + if (CollectionUtils.isNotEmpty(scenarioReportIdList)) { + List resultList = extApiScenarioReportResultMapper.selectIdAndStatusByReportIdList(scenarioReportIdList); + resultList = apiScenarioReportStructureService.filterProcessResult(resultList); + stepCount.setScenarioStepTotal(resultList.size()); + int successStep = 0; + int fakeErrorStep = 0; + int errorStep = 0; + int unexecuteStep = 0; + for (ApiScenarioReportResult result : resultList) { + if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.ERROR.name())) { + errorStep++; + } else if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.SUCCESS.name())) { + successStep++; + } else if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.FAKE_ERROR.name())) { + fakeErrorStep++; + } else if (!StringUtils.equalsAnyIgnoreCase(result.getStatus(), ApiReportStatus.RUNNING.name(), ApiReportStatus.RERUNNING.name())) { + unexecuteStep++; } } - } else { - stepCount.getUnderwayIds().add(item.getCaseId()); + stepCount.setScenarioStepSuccess(successStep); + stepCount.setScenarioStepError(errorStep); + stepCount.setScenarioStepErrorReport(fakeErrorStep); + stepCount.setScenarioStepUnExecute(unexecuteStep); } + } public void relevanceByTestIds(List ids, String planId) { @@ -802,8 +830,8 @@ public class TestPlanScenarioCaseService { String planId = request.getPlanId(); Boolean saveResponse = request.getSaveResponse(); if (ServiceUtils.checkConfigEnable(config, "api")) { - List apiAllCases = null; - List scenarioAllCases = null; + List apiAllCases = null; + List scenarioAllCases = null; if (checkReportConfig(config, "api", "all")) { // 接口 apiAllCases = testPlanApiCaseService.getAllCases(planId); @@ -825,7 +853,7 @@ public class TestPlanScenarioCaseService { return report; } - public void buildScenarioResponse(List cases) { + public void buildScenarioResponse(List cases) { if (!CollectionUtils.isEmpty(cases)) { cases.forEach((item) -> { item.setResponse(apiScenarioReportService.get(item.getReportId(), true)); @@ -833,12 +861,12 @@ public class TestPlanScenarioCaseService { } } - private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List apiAllCases, Map reportConfig) { + private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List apiAllCases, Map reportConfig) { if (!CollectionUtils.isEmpty(apiAllCases)) { - List apiFailureCases = new ArrayList<>(); - List apiErrorReportCases = new ArrayList<>(); - List apiUnExecuteCases = new ArrayList<>(); - for (TestPlanFailureApiDTO apiDTO : apiAllCases) { + List apiFailureCases = new ArrayList<>(); + List apiErrorReportCases = new ArrayList<>(); + List apiUnExecuteCases = new ArrayList<>(); + for (TestPlanApiDTO apiDTO : apiAllCases) { if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.ERROR.name())) { apiFailureCases.add(apiDTO); } else if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.FAKE_ERROR.name())) { @@ -865,13 +893,13 @@ public class TestPlanScenarioCaseService { return ServiceUtils.checkConfigEnable(config, key, subKey); } - private void screenScenariosByStatusAndReportConfig(ApiPlanReportDTO report, List scenarios, Map reportConfig) { + private void screenScenariosByStatusAndReportConfig(ApiPlanReportDTO report, List scenarios, Map reportConfig) { if (!CollectionUtils.isEmpty(scenarios)) { - List failureScenarios = new ArrayList<>(); - List errorReportScenarios = new ArrayList<>(); - List unExecuteScenarios = new ArrayList<>(); - for (TestPlanFailureScenarioDTO scenario : scenarios) { + List failureScenarios = new ArrayList<>(); + List errorReportScenarios = new ArrayList<>(); + List unExecuteScenarios = new ArrayList<>(); + for (TestPlanScenarioDTO scenario : scenarios) { if (StringUtils.equalsAnyIgnoreCase(scenario.getLastResult(), ApiReportStatus.ERROR.name())) { failureScenarios.add(scenario); } else if (StringUtils.equalsIgnoreCase(scenario.getLastResult(), ApiReportStatus.FAKE_ERROR.name())) { @@ -893,80 +921,26 @@ public class TestPlanScenarioCaseService { } } - public ApiPlanReportDTO buildExecuteApiReport(ApiPlanReportRequest request) { - ApiPlanReportDTO report = new ApiPlanReportDTO(); - TestPlanExecuteReportDTO testPlanExecuteReportDTO = request.getTestPlanExecuteReportDTO(); - Map config = request.getConfig(); - if (MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap()) - && MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap())) { - return new ApiPlanReportDTO(); + public ApiReportResultDTO buildExecuteApiReport(ApiPlanReportRequest request) { + ApiReportResultDTO resultDTO = new ApiReportResultDTO(); + if (ObjectUtils.isNotEmpty(request)) { + Map apiReportResultMap = apiDefinitionExecResultService.selectResultByIdList(request.getApiReportIdList()); + Map scenarioReportResultMap = apiScenarioReportService.selectResultByIdList(request.getScenarioReportIdList()); + resultDTO.setApiReportResultMap(apiReportResultMap); + resultDTO.setScenarioReportResultMap(scenarioReportResultMap); } - if (ServiceUtils.checkConfigEnable(config, "api")) { - List apiAllCases = null; - List scenarioAllCases = null; - if (checkReportConfig(config, "api", "all")) { - // 接口 - apiAllCases = getByApiExecReportIds(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap(), testPlanExecuteReportDTO.getApiCaseInfoDTOMap()); - //场景 - scenarioAllCases = getTestPlanScenario(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap(), testPlanExecuteReportDTO.getScenarioInfoDTOMap()); - this.checkApiCaseCreatorName(apiAllCases, scenarioAllCases); - report.setApiAllCases(apiAllCases); - report.setScenarioAllCases(scenarioAllCases); - } - - //筛选符合配置需要的执行结果的用例和场景 - this.screenApiCaseByStatusAndReportConfig(report, apiAllCases, config); - this.screenScenariosByStatusAndReportConfig(report, scenarioAllCases, config); - } - return report; + return resultDTO; } - private void checkApiCaseCreatorName(List apiCases, List scenarioCases) { - List userIdList = new ArrayList<>(); - if (CollectionUtils.isNotEmpty(apiCases)) { - apiCases.forEach(item -> { - if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUserId())) { - userIdList.add(item.getCreateUserId()); - } - }); + public List getTestPlanScenario(Map idMap, Map scenarioInfoDTOMap) { + if (MapUtils.isEmpty(idMap) || MapUtils.isEmpty(scenarioInfoDTOMap)) { + return new ArrayList<>(); } - if (CollectionUtils.isNotEmpty(scenarioCases)) { - scenarioCases.forEach(item -> { - if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUser())) { - userIdList.add(item.getCreateUser()); - } - }); - } - Map usersMap = baseUserService.queryNameByIds(userIdList); - if (CollectionUtils.isNotEmpty(apiCases)) { - for (TestPlanFailureApiDTO dto : apiCases) { - if (StringUtils.isEmpty(dto.getCreatorName())) { - User user = usersMap.get(dto.getCreateUserId()); - if (user != null) { - dto.setCreatorName(user.getName()); - } - } - } - } - if (CollectionUtils.isNotEmpty(scenarioCases)) { - for (TestPlanFailureScenarioDTO dto : scenarioCases) { - if (StringUtils.isEmpty(dto.getCreatorName())) { - User user = usersMap.get(dto.getCreateUser()); - if (user != null) { - dto.setCreatorName(user.getName()); - } - } - } - } - - } - - public List getTestPlanScenario(Map idMap, Map scenarioInfoDTOMap) { Map reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values()); Map savedReportMap = new HashMap<>(idMap); - List apiTestCases = new ArrayList<>(); - for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) { + List apiTestCases = new ArrayList<>(); + for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) { String reportId = savedReportMap.get(dto.getId()); savedReportMap.remove(dto.getId()); dto.setReportId(reportId); @@ -984,15 +958,15 @@ public class TestPlanScenarioCaseService { } - public List getByApiExecReportIds(Map testPlanApiCaseReportMap, Map apiCaseInfoDTOMap) { - if (testPlanApiCaseReportMap.isEmpty()) { + public List getByApiExecReportIds(Map testPlanApiCaseReportMap, Map apiCaseInfoDTOMap) { + if (MapUtils.isEmpty(testPlanApiCaseReportMap) || MapUtils.isEmpty(apiCaseInfoDTOMap)) { return new ArrayList<>(); } String defaultStatus = ApiReportStatus.ERROR.name(); Map reportResult = apiDefinitionExecResultService.selectReportResultByReportIds(testPlanApiCaseReportMap.values()); Map savedReportMap = new HashMap<>(testPlanApiCaseReportMap); - List apiTestCases = new ArrayList<>(); - for (TestPlanFailureApiDTO dto : apiCaseInfoDTOMap.values()) { + List apiTestCases = new ArrayList<>(); + for (TestPlanApiDTO dto : apiCaseInfoDTOMap.values()) { String testPlanApiCaseId = dto.getId(); String reportId = savedReportMap.get(testPlanApiCaseId); savedReportMap.remove(testPlanApiCaseId); @@ -1019,7 +993,7 @@ public class TestPlanScenarioCaseService { .isEmpty(); } - public List getFailureListByIds(Set ids) { + public List getListByIds(Set ids) { return extTestPlanScenarioCaseMapper.getFailureListByIds(ids, null); } diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java index 19dbad1977..f3f3bde571 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportService.java @@ -899,4 +899,15 @@ public class ApiScenarioReportService { public List selectForPlanReport(List reportIds) { return extApiScenarioReportMapper.selectForPlanReport(reportIds); } + + public Map selectResultByIdList(List reportIdList) { + Map returnMap = new HashMap<>(); + if (CollectionUtils.isNotEmpty(reportIdList)) { + List apiDefinitionExecResultList = extApiScenarioReportMapper.selectStatusByIds(reportIdList); + if (CollectionUtils.isNotEmpty(apiDefinitionExecResultList)) { + returnMap = apiDefinitionExecResultList.stream().collect(Collectors.toMap(ApiScenarioReport::getId, ApiScenarioReport::getStatus, (k1, k2) -> k1)); + } + } + return returnMap; + } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java index de9bb34665..52449e24dc 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java @@ -614,7 +614,7 @@ public class ApiScenarioReportStructureService { return reportDTO; } - private List filterProcessResult(List reportResults) { + public List filterProcessResult(List reportResults) { List withOutProcessList = new ArrayList<>(); for (ApiScenarioReportResultWithBLOBs item : reportResults) { if (item.getBaseInfo() != null) { diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/commons/constants/TestPlanReportStatus.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/commons/constants/TestPlanReportStatus.java index ee327fbfdf..af8efb9520 100644 --- a/framework/sdk-parent/sdk/src/main/java/io/metersphere/commons/constants/TestPlanReportStatus.java +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/commons/constants/TestPlanReportStatus.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum TestPlanReportStatus { - RUNNING, COMPLETED, SUCCESS, FAILED + RUNNING, COMPLETED, SUCCESS, FAILED, UNDERWAY } diff --git a/performance-test/backend/src/main/java/io/metersphere/plan/service/PerfQueueService.java b/performance-test/backend/src/main/java/io/metersphere/plan/service/PerfQueueService.java index 6c9e38a4ba..8e2fb113d8 100644 --- a/performance-test/backend/src/main/java/io/metersphere/plan/service/PerfQueueService.java +++ b/performance-test/backend/src/main/java/io/metersphere/plan/service/PerfQueueService.java @@ -14,6 +14,7 @@ import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.plan.exec.queue.DBTestQueue; import io.metersphere.request.RunTestPlanRequest; import io.metersphere.utils.LoggerUtil; +import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -22,7 +23,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import jakarta.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @@ -66,15 +66,22 @@ public class PerfQueueService { List testPlanReportIds = queues.stream().map(ApiExecutionQueue::getReportId).collect(Collectors.toList()); for (String testPlanReportId : testPlanReportIds) { LoggerUtil.info("处理测试计划报告状态", loadTestReport.getId()); - testPlanReportTestEnded(testPlanReportId); + checkTestPlanLoadCaseExecOver(null, testPlanReportId); } for (ApiExecutionQueueDetail detail : details) { // 更新测试计划关联数据状态 - TestPlanLoadCaseWithBLOBs loadCase = new TestPlanLoadCaseWithBLOBs(); - loadCase.setId(loadTestReport.getTestId()); - loadCase.setStatus(TestPlanLoadCaseStatus.success.name()); - testPlanLoadCaseMapper.updateByPrimaryKeySelective(loadCase); + TestPlanLoadCaseExample example = new TestPlanLoadCaseExample(); + example.createCriteria().andIdEqualTo(loadTestReport.getTestId()); + if (testPlanLoadCaseMapper.countByExample(example) > 0) { + TestPlanLoadCaseWithBLOBs loadCase = new TestPlanLoadCaseWithBLOBs(); + loadCase.setId(loadTestReport.getTestId()); + loadCase.setStatus(TestPlanLoadCaseStatus.success.name()); + testPlanLoadCaseMapper.updateByPrimaryKeySelective(loadCase); + if (CollectionUtils.isNotEmpty(testPlanReportIds)) { + checkTestPlanLoadCaseExecOver(loadCase.getId(), null); + } + } // 检查队列是否已空 ApiExecutionQueueDetailExample queueDetailExample = new ApiExecutionQueueDetailExample(); @@ -116,9 +123,15 @@ public class PerfQueueService { } } - public void testPlanReportTestEnded(String testPlanReportId) { - // 检查测试计划中其他队列是否结束 - kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId); + public void checkTestPlanLoadCaseExecOver(String testId, String testPlanReportId) { + if (StringUtils.isNotBlank(testPlanReportId)) { + // 整体执行测试计划报告时触发的 + kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId); + } else { + // 测试计划内调试时触发的 + kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testId, UUID.randomUUID().toString()); + } + } public DBTestQueue handleQueue(String id, String testId) { diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.java index 519f5c301e..b6e61502e4 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.java +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.java @@ -1,10 +1,19 @@ package io.metersphere.base.mapper.ext; +import io.metersphere.base.domain.TestPlanApiCase; +import io.metersphere.plan.dto.CaseExecResult; import io.metersphere.plan.dto.TestPlanApiCaseInfoDTO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; public interface ExtTestPlanApiCaseMapper { List selectLegalDataByTestPlanId(String planId); + + List selectExecResult(@Param("testPlanId") String testPlanId, @Param("apiCaseIds") List apiCaseIdList); + + @Select("SELECT id,test_plan_id,api_case_id,status FROM test_plan_api_case WHERE id = #{0} ") + TestPlanApiCase selectBaseInfoById(String testId); } diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml index 41cd507124..4a1489a86d 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanApiCaseMapper.xml @@ -9,4 +9,14 @@ AND (a.status IS NULL OR a.status != 'Trash') ORDER BY t.`order` DESC + + diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.java new file mode 100644 index 0000000000..9ca2ee71bf --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.java @@ -0,0 +1,15 @@ +package io.metersphere.base.mapper.ext; + +import io.metersphere.base.domain.TestPlanLoadCase; +import io.metersphere.plan.dto.CaseExecResult; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface ExtTestPlanLoadCaseMapper { + @Select("SELECT id,test_plan_id,load_case_id,status FROM test_plan_load_case WHERE id = #{0} ") + TestPlanLoadCase selectBaseInfoById(String testId); + + List selectExecResult(@Param("testPlanId") String testPlanId, @Param("ids") List relevanceApiCaseList); +} diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml new file mode 100644 index 0000000000..edce1bfcdd --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanLoadCaseMapper.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java index 7eaee9338d..713358e9d8 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java @@ -53,4 +53,6 @@ public interface ExtTestPlanMapper { Map testPlanUiScenarioCount(@Param("planIds") Set planIds); List planListAll(@Param("request") QueryTestPlanRequest params); + + Boolean checkSyncTestCaseExecResultByTestPlanId(String testPlanId); } diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml index be6eb8fe26..9088a9cdd7 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml @@ -422,4 +422,8 @@ set actual_end_time = null where id = #{0} + + diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.java index d296c5b5f2..d39737e22a 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.java +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.java @@ -1,6 +1,10 @@ package io.metersphere.base.mapper.ext; +import io.metersphere.base.domain.TestPlanApiScenario; +import io.metersphere.plan.dto.CaseExecResult; import io.metersphere.plan.dto.TestPlanApiScenarioInfoDTO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -8,4 +12,9 @@ public interface ExtTestPlanScenarioCaseMapper { List selectLegalDataByTestPlanId(String planId); List selectLegalUiDataByTestPlanId(String planId); - } + + List selectExecResult(@Param("testPlanId") String testPlanId, @Param("scenarioCaseIds") List loadCaseIdList); + + @Select("SELECT id,test_plan_id,api_scenario_id,last_result FROM test_plan_api_scenario WHERE id = #{0} ") + TestPlanApiScenario selectBaseInfoById(String testId); +} diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.xml index 6396f0f460..3d2b96337c 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.xml +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanScenarioCaseMapper.xml @@ -28,4 +28,14 @@ AND tpas.test_plan_id = #{0} ORDER BY tpas.`order` DESC; + + diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java index 7973bec55b..216e2a489e 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java @@ -1,11 +1,11 @@ package io.metersphere.base.mapper.ext; -import io.metersphere.dto.PlanReportCaseDTO; +import io.metersphere.base.domain.TestPlanTestCase; +import io.metersphere.dto.*; import io.metersphere.plan.dto.TestCaseReportStatusResultDTO; import io.metersphere.plan.request.function.QueryTestPlanCaseRequest; -import io.metersphere.request.BaseQueryRequest; -import io.metersphere.dto.*; import io.metersphere.plan.request.function.TestPlanFuncCaseConditions; +import io.metersphere.request.BaseQueryRequest; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -70,4 +70,10 @@ public interface ExtTestPlanTestCaseMapper { String selectCaseId(String id); List getCaseIdsByIds(@Param("ids") List ids); + + void updateExecResultByTestPlanCaseIdList(@Param("ids") List testPlanCaseIdList, @Param("execResult") String execResult); + + void updateExecResultByTestCaseIdAndTestPlanId(@Param("testCaseId") String testCaseId, @Param("testPlanId") String testPlanId, @Param("execResult") String execResult); + + List selectByAutomationCaseIdAndTestPlanId(@Param("automationCaseId") String automationCaseId, @Param("test_plan_id") String testPlanId); } diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml index ebc58e1b41..2e6d35741c 100644 --- a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml @@ -644,4 +644,27 @@ and ${versionTable}.ref_id = #{request.refId} + + + + + + UPDATE test_plan_test_case SET status = #{execResult} + WHERE id IN + + #{value} + + + + + UPDATE test_plan_test_case SET status = #{execResult} + WHERE case_id = #{testCaseId} AND plan_id = #{testPlanId} + + diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.java b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.java new file mode 100644 index 0000000000..5baba3d352 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.java @@ -0,0 +1,15 @@ +package io.metersphere.base.mapper.ext; + +import io.metersphere.base.domain.TestPlanUiScenario; +import io.metersphere.plan.dto.CaseExecResult; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface ExtTestPlanUiCaseMapper { + @Select("SELECT id,test_plan_id,ui_scenario_id,last_result FROM test_plan_ui_scenario WHERE id = #{0} ") + TestPlanUiScenario selectBaseInfoById(String testId); + + List selectExecResult(@Param("testPlanId") String testPlanId, @Param("ids") List relevanceApiCaseList); +} diff --git a/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.xml b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.xml new file mode 100644 index 0000000000..aa005f538b --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanUiCaseMapper.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/test-track/backend/src/main/java/io/metersphere/config/DatabaseConfig.java b/test-track/backend/src/main/java/io/metersphere/config/DatabaseConfig.java new file mode 100644 index 0000000000..e7291e9d04 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/config/DatabaseConfig.java @@ -0,0 +1,34 @@ +package io.metersphere.config; + +import io.metersphere.base.domain.AuthSource; +import io.metersphere.base.domain.FileContent; +import io.metersphere.base.domain.TestPlanReportContentWithBLOBs; +import io.metersphere.base.domain.TestResource; +import io.metersphere.commons.utils.CompressUtils; +import io.metersphere.interceptor.MybatisInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class DatabaseConfig { + @Bean + public MybatisInterceptor dbInterceptor() { + MybatisInterceptor interceptor = new MybatisInterceptor(); + List configList = new ArrayList<>(); + //这三行不能删除,否则会覆盖sdk中的设置 + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(FileContent.class, "file", CompressUtils.class, "zip", "unzip")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestResource.class, "configuration")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(AuthSource.class, "configuration")); + //测试计划报告 api-base-count字段进行解压缩处理 + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestPlanReportContentWithBLOBs.class, "apiBaseCount", CompressUtils.class, "zipString", "unzipString")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestPlanReportContentWithBLOBs.class, "planApiCaseReportStruct", CompressUtils.class, "zipString", "unzipString")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestPlanReportContentWithBLOBs.class, "planScenarioReportStruct", CompressUtils.class, "zipString", "unzipString")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestPlanReportContentWithBLOBs.class, "planLoadCaseReportStruct", CompressUtils.class, "zipString", "unzipString")); + configList.add(new io.metersphere.commons.utils.MybatisInterceptorConfig(TestPlanReportContentWithBLOBs.class, "planUiScenarioReportStruct", CompressUtils.class, "zipString", "unzipString")); + interceptor.setInterceptorConfigList(configList); + return interceptor; + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/controller/ShareController.java b/test-track/backend/src/main/java/io/metersphere/controller/ShareController.java index e5b0438366..dedd45f820 100644 --- a/test-track/backend/src/main/java/io/metersphere/controller/ShareController.java +++ b/test-track/backend/src/main/java/io/metersphere/controller/ShareController.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.metersphere.commons.utils.HttpHeaderUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.dto.TestPlanCaseDTO; -import io.metersphere.plan.dto.TestPlanExtReportDTO; +import io.metersphere.plan.dto.ExecutionModeDTO; import io.metersphere.plan.dto.TestPlanSimpleReportDTO; import io.metersphere.plan.service.TestPlanReportService; import io.metersphere.plan.service.TestPlanService; @@ -12,10 +12,10 @@ import io.metersphere.plan.service.TestPlanTestCaseService; import io.metersphere.service.IssuesService; import io.metersphere.service.ShareInfoService; import io.metersphere.xpack.track.dto.IssuesDao; -import org.springframework.web.bind.annotation.*; - import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.*; + import java.io.UnsupportedEncodingException; import java.util.List; @@ -67,24 +67,27 @@ public class ShareController { } @GetMapping("test/plan/ext/report/{shareId}/{reportId}") - public TestPlanExtReportDTO getExtReport(@PathVariable String shareId, @PathVariable String reportId) throws JsonProcessingException { + public ExecutionModeDTO getExtReport(@PathVariable String shareId, @PathVariable String reportId) throws JsonProcessingException { shareInfoService.validate(shareId, reportId); if (SessionUtils.getUser() == null) { HttpHeaderUtils.runAsUser("admin"); } - TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByReportId(reportId); + // testPlanService.getExtInfoByPlanId 这个方法逻辑有问题。分不清楚干嘛用的。方法删了,调用地方先注释了。 + // TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByReportId(reportId); + ExecutionModeDTO reportExtInfo = new ExecutionModeDTO(); HttpHeaderUtils.clearUser(); return reportExtInfo; } @GetMapping("test/plan/ext/plan/{shareId}/{planId}") - public TestPlanExtReportDTO getExtPlan(@PathVariable String shareId, @PathVariable String planId) throws JsonProcessingException { + public ExecutionModeDTO getExtPlan(@PathVariable String shareId, @PathVariable String planId) throws JsonProcessingException { shareInfoService.validate(shareId, planId); if (SessionUtils.getUser() == null) { HttpHeaderUtils.runAsUser("admin"); } - TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByPlanId(planId); + // testPlanService.getExtInfoByPlanId 这个方法逻辑有问题。分不清楚干嘛用的。方法删了,调用地方先注释了。 + // TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByPlanId(planId); HttpHeaderUtils.clearUser(); - return reportExtInfo; + return new ExecutionModeDTO(); } } diff --git a/test-track/backend/src/main/java/io/metersphere/controller/TestPlanController.java b/test-track/backend/src/main/java/io/metersphere/controller/TestPlanController.java index c9a3f654ab..995eb976e0 100644 --- a/test-track/backend/src/main/java/io/metersphere/controller/TestPlanController.java +++ b/test-track/backend/src/main/java/io/metersphere/controller/TestPlanController.java @@ -14,9 +14,9 @@ import io.metersphere.dto.TestPlanRerunParametersDTO; import io.metersphere.i18n.Translator; import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.notice.annotation.SendNotice; +import io.metersphere.plan.dto.ExecutionModeDTO; import io.metersphere.plan.dto.TestCaseReportStatusResultDTO; import io.metersphere.plan.dto.TestPlanDTO; -import io.metersphere.plan.dto.TestPlanExtReportDTO; import io.metersphere.plan.dto.TestPlanSimpleReportDTO; import io.metersphere.plan.request.AddTestPlanRequest; import io.metersphere.plan.request.BatchOperateRequest; @@ -61,7 +61,7 @@ public class TestPlanController { @GetMapping("/auto-check/{testPlanId}") public void autoCheck(@PathVariable String testPlanId) { - testPlanService.checkStatus(testPlanId); + testPlanService.checkTestPlanStatus(testPlanId); } @PostMapping("/list/{goPage}/{pageSize}") @@ -148,7 +148,7 @@ public class TestPlanController { @MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#planId)", content = "#msClass.getLogDetails(#planId)", msClass = TestPlanService.class) public void editTestPlanStatus(@PathVariable String planId) { checkPermissionService.checkTestPlanOwner(planId); - testPlanService.checkStatus(planId); + testPlanService.checkTestPlanStatus(planId); } @PostMapping("/edit/report/config") @@ -387,12 +387,12 @@ public class TestPlanController { } @GetMapping("/ext/report/{reportId}") - public TestPlanExtReportDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException { - return testPlanService.getExtInfoByReportId(reportId); + public ExecutionModeDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException { + return new ExecutionModeDTO(); } @GetMapping("/ext/plan/{planId}") - public TestPlanExtReportDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException { - return testPlanService.getExtInfoByPlanId(planId); + public ExecutionModeDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException { + return new ExecutionModeDTO(); } } diff --git a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureApiDTO.java b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanApiDTO.java similarity index 79% rename from test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureApiDTO.java rename to test-track/backend/src/main/java/io/metersphere/dto/TestPlanApiDTO.java index de58c18252..24e79970d4 100644 --- a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureApiDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanApiDTO.java @@ -7,7 +7,7 @@ import lombok.Setter; @Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) -public class TestPlanFailureApiDTO extends TestPlanApiCaseDTO { +public class TestPlanApiDTO extends TestPlanApiCaseDTO { private String response; private String reportId; } diff --git a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanCaseReportResultDTO.java b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanCaseReportResultDTO.java new file mode 100644 index 0000000000..58c707442d --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanCaseReportResultDTO.java @@ -0,0 +1,25 @@ +package io.metersphere.dto; + +import io.metersphere.plan.dto.ApiPlanReportDTO; +import io.metersphere.plan.dto.UiPlanReportDTO; +import io.metersphere.plan.request.performance.LoadPlanReportDTO; +import io.metersphere.xpack.track.dto.IssuesDao; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +public class TestPlanCaseReportResultDTO { + private Map testPlanApiCaseIdAndReportIdMap; + private Map testPlanScenarioIdAndReportIdMap; + private Map testPlanUiScenarioIdAndReportIdMap; + private Map testPlanLoadCaseIdAndReportIdMap; + private ApiPlanReportDTO apiPlanReportDTO; + private LoadPlanReportDTO loadPlanReportDTO; + private UiPlanReportDTO uiPlanReportDTO; + private List functionCaseList; + private List issueList; +} diff --git a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanExecuteReportDTO.java b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanExecuteReportDTO.java deleted file mode 100644 index 6ef81af7de..0000000000 --- a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanExecuteReportDTO.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.metersphere.dto; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.Map; - -@Getter -@Setter -@AllArgsConstructor -@NoArgsConstructor -public class TestPlanExecuteReportDTO { - private Map testPlanApiCaseIdAndReportIdMap; - private Map testPlanScenarioIdAndReportIdMap; - private Map testPlanUiScenarioIdAndReportIdMap; - private Map testPlanLoadCaseIdAndReportIdMap; - private Map apiCaseInfoDTOMap; - private Map scenarioInfoDTOMap; - private Map uiScenarioInfoDTOMap; -} diff --git a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanReportBuildResultDTO.java b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanReportBuildResultDTO.java index e6cd898c1d..701524e10e 100644 --- a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanReportBuildResultDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanReportBuildResultDTO.java @@ -8,9 +8,4 @@ import lombok.Setter; @Setter public class TestPlanReportBuildResultDTO { private TestPlanSimpleReportDTO testPlanSimpleReportDTO; - /** - * 判断testPlanReportContent中,APIBaseInfo字段是否改变。 - * 如果改变过,则需要更新testPlanReportContent数据 - */ - private boolean apiBaseInfoChanged = false; } diff --git a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureScenarioDTO.java b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanScenarioDTO.java similarity index 83% rename from test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureScenarioDTO.java rename to test-track/backend/src/main/java/io/metersphere/dto/TestPlanScenarioDTO.java index 1e301d34bf..e5c5d4a99b 100644 --- a/test-track/backend/src/main/java/io/metersphere/dto/TestPlanFailureScenarioDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/dto/TestPlanScenarioDTO.java @@ -9,6 +9,6 @@ import lombok.Setter; @Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) -public class TestPlanFailureScenarioDTO extends ApiScenarioDTO { +public class TestPlanScenarioDTO extends ApiScenarioDTO { private APIScenarioReportResult response; } diff --git a/test-track/backend/src/main/java/io/metersphere/listener/ExecReportListener.java b/test-track/backend/src/main/java/io/metersphere/listener/ExecReportListener.java index 3280ec6ad2..fc303ba75a 100644 --- a/test-track/backend/src/main/java/io/metersphere/listener/ExecReportListener.java +++ b/test-track/backend/src/main/java/io/metersphere/listener/ExecReportListener.java @@ -7,14 +7,16 @@ import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper; import io.metersphere.base.mapper.ApiExecutionQueueMapper; import io.metersphere.commons.constants.KafkaTopicConstants; import io.metersphere.commons.constants.TestPlanReportStatus; +import io.metersphere.plan.service.TestCaseSyncStatusService; import io.metersphere.plan.service.TestPlanReportService; import io.metersphere.utils.LoggerUtil; +import jakarta.annotation.Resource; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; -import jakarta.annotation.Resource; import java.util.List; import java.util.stream.Collectors; @@ -27,11 +29,29 @@ public class ExecReportListener { private ApiExecutionQueueDetailMapper executionQueueDetailMapper; @Resource private TestPlanReportService testPlanReportService; + @Resource + private TestCaseSyncStatusService testCaseSyncStatusService; @KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, groupId = "${spring.application.name}") public void consume(ConsumerRecord record) { LoggerUtil.info("Execute message received:", record.value()); - this.testPlanReportTestEnded(record.value()); + Object testIdObj = record.key(); + if (ObjectUtils.isEmpty(testIdObj)) { + this.testPlanReportTestEnded(record.value()); + } else { + this.automationCaseTestEnd(testIdObj.toString()); + } + + } + + /** + * 测试计划相关的自动化用例结束后,会根据测试计划的配置判断是否要同步功能用例的状态 + * 目前暂时只有这一个需求。后续如果有了更多操作,建议将该方法内的逻辑处理放入一个共有方法中。 + * + * @param testId + */ + public void automationCaseTestEnd(String testId) { + testCaseSyncStatusService.checkAndUpdateFunctionCaseStatus(testId); } public void testPlanReportTestEnded(String testPlanReportId) { @@ -41,7 +61,7 @@ public class ExecReportListener { List queues = queueMapper.selectByExample(executionQueueExample); if (CollectionUtils.isEmpty(queues)) { LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId); - testPlanReportService.finishedTestPlanReport(testPlanReportId, TestPlanReportStatus.COMPLETED.name()); + testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name()); } else { List ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList()); ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample(); @@ -49,7 +69,7 @@ public class ExecReportListener { long count = executionQueueDetailMapper.countByExample(detailExample); if (count == 0) { LoggerUtil.info("Normal execution completes, update test plan report status:" + testPlanReportId); - testPlanReportService.finishedTestPlanReport(testPlanReportId, TestPlanReportStatus.COMPLETED.name()); + testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name()); LoggerUtil.info("Clear Queue:" + ids); ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample(); queueExample.createCriteria().andIdIn(ids); diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiPlanReportDTO.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiPlanReportDTO.java index 775e57d78e..e53f84a817 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiPlanReportDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiPlanReportDTO.java @@ -1,8 +1,8 @@ package io.metersphere.plan.dto; -import io.metersphere.dto.TestPlanFailureApiDTO; -import io.metersphere.dto.TestPlanFailureScenarioDTO; +import io.metersphere.dto.TestPlanApiDTO; +import io.metersphere.dto.TestPlanScenarioDTO; import lombok.Getter; import lombok.Setter; @@ -11,13 +11,13 @@ import java.util.List; @Setter @Getter public class ApiPlanReportDTO { - private List apiAllCases; - private List apiFailureCases; - private List errorReportCases; - private List unExecuteCases; + private List apiAllCases; + private List apiFailureCases; + private List errorReportCases; + private List unExecuteCases; - private List scenarioAllCases; - private List scenarioFailureCases; - private List errorReportScenarios; - private List unExecuteScenarios; + private List scenarioAllCases; + private List scenarioFailureCases; + private List errorReportScenarios; + private List unExecuteScenarios; } diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiReportResultDTO.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiReportResultDTO.java new file mode 100644 index 0000000000..ffba19718f --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/ApiReportResultDTO.java @@ -0,0 +1,17 @@ +package io.metersphere.plan.dto; + + +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Setter +@Getter +public class ApiReportResultDTO { + // 接口报告结果 + Map apiReportResultMap; + + // 场景报告结果 + Map scenarioReportResultMap; +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/CaseExecResult.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/CaseExecResult.java new file mode 100644 index 0000000000..13e466aec2 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/CaseExecResult.java @@ -0,0 +1,17 @@ +package io.metersphere.plan.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CaseExecResult { + private String id; + private String execResult; + + //用例类型、对应执行的reportId + private String caseType; + private String reportId; + private String caseName; + private String testCaseId; +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanExtReportDTO.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/ExecutionModeDTO.java similarity index 84% rename from test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanExtReportDTO.java rename to test-track/backend/src/main/java/io/metersphere/plan/dto/ExecutionModeDTO.java index ca7f510c7b..f1f18d9619 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanExtReportDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/ExecutionModeDTO.java @@ -3,7 +3,7 @@ package io.metersphere.plan.dto; import lombok.Data; @Data -public class TestPlanExtReportDTO { +public class ExecutionModeDTO { /** * 运行模式 diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceCasesRequest.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceCasesRequest.java new file mode 100644 index 0000000000..8404da38d6 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceCasesRequest.java @@ -0,0 +1,24 @@ +package io.metersphere.plan.dto; + +import io.metersphere.base.domain.TestCaseTest; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.Map; + +@Getter +@Setter +public class TestCaseRelevanceCasesRequest { + private String testCaseId; + private String testPlanId; + + List testCaseTestList; + + //以下四个自动化用例执行结果map,key-> testCaseId + Map apiAllCaseMap; + Map scenarioAllCaseMap; + Map loadAllCaseMap; + Map uiAllCaseMap; + +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceVo.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceVo.java new file mode 100644 index 0000000000..15ec7e6eec --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestCaseRelevanceVo.java @@ -0,0 +1,13 @@ +package io.metersphere.plan.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class TestCaseRelevanceVo { + private String testCaseId; + private String relevanceCaseId; + + private String relevanceType; +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanSimpleReportDTO.java b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanSimpleReportDTO.java index d0ba8a349f..bd5587e21f 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanSimpleReportDTO.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/dto/TestPlanSimpleReportDTO.java @@ -48,15 +48,15 @@ public class TestPlanSimpleReportDTO extends TestPlanReportContent { List loadAllCases; List loadFailureCases; - List apiAllCases; - List errorReportCases; - List apiFailureCases; - List unExecuteCases; + List apiAllCases; + List errorReportCases; + List apiFailureCases; + List unExecuteCases; - List scenarioAllCases; - List errorReportScenarios; - List scenarioFailureCases; - List unExecuteScenarios; + List scenarioAllCases; + List errorReportScenarios; + List scenarioFailureCases; + List unExecuteScenarios; List uiAllCases; List uiFailureCases; diff --git a/test-track/backend/src/main/java/io/metersphere/plan/enums/FunctionCaseExecResult.java b/test-track/backend/src/main/java/io/metersphere/plan/enums/FunctionCaseExecResult.java new file mode 100644 index 0000000000..c201bbd5e9 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/enums/FunctionCaseExecResult.java @@ -0,0 +1,23 @@ +package io.metersphere.plan.enums; + +public enum FunctionCaseExecResult { + PREPARE("Prepare"), + SUCCESS("Pass"), + ERROR("Failure"), + BLOCKING("Blocking"), + SKIP("Skip"); + String value; + + FunctionCaseExecResult(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + public String getValue() { + return this.value; + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/enums/TestCaseReleevanceType.java b/test-track/backend/src/main/java/io/metersphere/plan/enums/TestCaseReleevanceType.java new file mode 100644 index 0000000000..01dac83bea --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/enums/TestCaseReleevanceType.java @@ -0,0 +1,19 @@ +package io.metersphere.plan.enums; + +public enum TestCaseReleevanceType { + API_CASE("testcase"), SCENARIO("automation"), LOAD_CASE("performance"), UI_AUTOMATION("uiAutomation"); + String value; + + TestCaseReleevanceType(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + public String getValue() { + return this.value; + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/request/api/ApiPlanReportRequest.java b/test-track/backend/src/main/java/io/metersphere/plan/request/api/ApiPlanReportRequest.java index 5203b5bb5b..3d2bc24675 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/request/api/ApiPlanReportRequest.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/request/api/ApiPlanReportRequest.java @@ -1,13 +1,17 @@ package io.metersphere.plan.request.api; -import io.metersphere.dto.TestPlanExecuteReportDTO; +import io.metersphere.dto.TestPlanCaseReportResultDTO; import io.metersphere.request.PlanSubReportRequest; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Setter @Getter public class ApiPlanReportRequest extends PlanSubReportRequest { - private TestPlanExecuteReportDTO testPlanExecuteReportDTO; + List apiReportIdList; + List scenarioReportIdList; + private TestPlanCaseReportResultDTO testPlanExecuteReportDTO; } diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestCaseSyncStatusService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestCaseSyncStatusService.java new file mode 100644 index 0000000000..186b249369 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestCaseSyncStatusService.java @@ -0,0 +1,269 @@ +package io.metersphere.plan.service; + +import io.metersphere.base.domain.*; +import io.metersphere.base.mapper.TestCaseCommentMapper; +import io.metersphere.base.mapper.TestCaseTestMapper; +import io.metersphere.base.mapper.TestPlanMapper; +import io.metersphere.base.mapper.ext.*; +import io.metersphere.commons.utils.HttpHeaderUtils; +import io.metersphere.constants.TestCaseCommentType; +import io.metersphere.dto.*; +import io.metersphere.i18n.Translator; +import io.metersphere.plan.constant.ApiReportStatus; +import io.metersphere.plan.dto.CaseExecResult; +import io.metersphere.plan.dto.TestCaseRelevanceCasesRequest; +import io.metersphere.plan.enums.FunctionCaseExecResult; +import io.metersphere.plan.enums.TestCaseReleevanceType; +import io.metersphere.plan.utils.TestCaseSyncStatusUtil; +import io.metersphere.service.BaseUserService; +import io.metersphere.utils.BatchProcessingUtil; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Transactional(rollbackFor = Exception.class) +public class TestCaseSyncStatusService { + + @Resource + private ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper; + @Resource + private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper; + @Resource + private ExtTestPlanScenarioCaseMapper extTestPlanScenarioCaseMapper; + @Resource + private ExtTestPlanLoadCaseMapper extTestPlanLoadCaseMapper; + @Resource + private ExtTestPlanUiCaseMapper extTestPlanUiCaseMapper; + @Resource + private TestCaseTestMapper testCaseTestMapper; + @Resource + private TestPlanMapper testPlanMapper; + @Resource + private BaseUserService baseUserService; + @Resource + private TestCaseCommentMapper testCaseCommentMapper; + + //通过自动化用例的状态,获取最新的功能用例状态。 + public void getTestCaseStatusByTestPlanExecuteOver(List testPlanCaseList, List apiAllCases, List scenarioAllCases, List loadAllCases, List uiAllCases) { + List testCaseTestList = this.selectTestPlanTestCaseByPlanReportCase(testPlanCaseList); + Map testCaseStatusByAutomationCase = TestCaseSyncStatusUtil.getTestCaseStatusByAutomationCaseRunResult( + testPlanCaseList, testCaseTestList, apiAllCases, scenarioAllCases, loadAllCases, uiAllCases); + TestCaseSyncStatusUtil.updateFunctionCaseStatusByAutomationExecResult(testPlanCaseList, testCaseStatusByAutomationCase); + } + + private List selectTestPlanTestCaseByPlanReportCase(List testPlanCaseList) { + if (CollectionUtils.isNotEmpty(testPlanCaseList)) { + List testCaseIdList = new ArrayList<>(); + testPlanCaseList.forEach(item -> { + if (!testCaseIdList.contains(item.getCaseId())) { + testCaseIdList.add(item.getCaseId()); + } + }); + return BatchProcessingUtil.selectTestCaseTestByPrimaryKey(testCaseIdList, testCaseTestMapper::selectByExample); + } else { + return new ArrayList<>(); + } + + } + + //测试计划执行完成后,通过自动化用例的状态,同步更改功能用例状态。 + public void syncStatusByTestPlanExecuteOver(String operator, String testPlanName, List testPlanCaseList, List apiAllCaseList, List scenarioAllCaseList, List loadAllCaseList, List uiAllCaseList) { + if (CollectionUtils.isNotEmpty(testPlanCaseList)) { + List testCaseTestList = this.selectTestPlanTestCaseByPlanReportCase(testPlanCaseList); + Map testCaseStatusByAutomationCase = TestCaseSyncStatusUtil.getTestCaseStatusByAutomationCaseRunResult( + testPlanCaseList, testCaseTestList, apiAllCaseList, scenarioAllCaseList, loadAllCaseList, uiAllCaseList); + + Map successCaseMap = new HashMap<>(); + Map errorCaseMap = new HashMap<>(); + Map blockingCaseMap = new HashMap<>(); + for (PlanReportCaseDTO testPlanCase : testPlanCaseList) { + String testCaseId = testPlanCase.getCaseId(); + if (testCaseStatusByAutomationCase.containsKey(testCaseId)) { + CaseExecResult execResult = testCaseStatusByAutomationCase.get(testCaseId); + testPlanCase.setStatus(execResult.getExecResult()); + execResult.setTestCaseId(testCaseId); + if (StringUtils.equalsIgnoreCase(FunctionCaseExecResult.ERROR.toString(), execResult.getExecResult())) { + errorCaseMap.put(testPlanCase.getId(), execResult); + } else if (StringUtils.equalsIgnoreCase(FunctionCaseExecResult.BLOCKING.toString(), execResult.getExecResult())) { + blockingCaseMap.put(testPlanCase.getId(), execResult); + } else if (StringUtils.equalsIgnoreCase(FunctionCaseExecResult.SUCCESS.toString(), execResult.getExecResult())) { + successCaseMap.put(testPlanCase.getId(), execResult); + } + } + } + if (MapUtils.isNotEmpty(successCaseMap)) { + extTestPlanTestCaseMapper.updateExecResultByTestPlanCaseIdList(new ArrayList<>(successCaseMap.keySet()), FunctionCaseExecResult.SUCCESS.toString()); + } + if (MapUtils.isNotEmpty(errorCaseMap)) { + extTestPlanTestCaseMapper.updateExecResultByTestPlanCaseIdList(new ArrayList<>(errorCaseMap.keySet()), FunctionCaseExecResult.ERROR.toString()); + } + if (MapUtils.isNotEmpty(blockingCaseMap)) { + extTestPlanTestCaseMapper.updateExecResultByTestPlanCaseIdList(new ArrayList<>(blockingCaseMap.keySet()), FunctionCaseExecResult.BLOCKING.toString()); + this.addTestCaseComment(operator, testPlanName, blockingCaseMap, FunctionCaseExecResult.BLOCKING.toString()); + } + } + } + + public void checkAndUpdateFunctionCaseStatus(String testId) { + TestPlanApiCase testPlanApiCase = null; + TestPlanApiScenario testPlanApiScenario = null; + TestPlanLoadCase testPlanLoadCase = null; + TestPlanUiScenario testPlanUiScenario = null; + + testPlanApiCase = extTestPlanApiCaseMapper.selectBaseInfoById(testId); + if (testPlanApiCase == null) { + testPlanApiScenario = extTestPlanScenarioCaseMapper.selectBaseInfoById(testId); + } + if (ObjectUtils.allNull(testPlanApiCase, testPlanApiScenario)) { + testPlanLoadCase = extTestPlanLoadCaseMapper.selectBaseInfoById(testId); + } + if (ObjectUtils.allNull(testPlanApiCase, testPlanApiScenario, testPlanLoadCase)) { + testPlanUiScenario = extTestPlanUiCaseMapper.selectBaseInfoById(testId); + } + + String automationCaseId = null, planId = null; + String triggerCaseExecResult = null; + if (testPlanApiCase != null) { + automationCaseId = testPlanApiCase.getApiCaseId(); + planId = testPlanApiCase.getTestPlanId(); + triggerCaseExecResult = testPlanApiCase.getStatus(); + } else if (testPlanApiScenario != null) { + automationCaseId = testPlanApiScenario.getApiScenarioId(); + planId = testPlanApiScenario.getTestPlanId(); + triggerCaseExecResult = testPlanApiScenario.getLastResult(); + } else if (testPlanLoadCase != null) { + automationCaseId = testPlanLoadCase.getLoadCaseId(); + planId = testPlanLoadCase.getTestPlanId(); + triggerCaseExecResult = testPlanLoadCase.getStatus(); + } else if (testPlanUiScenario != null) { + automationCaseId = testPlanUiScenario.getUiScenarioId(); + planId = testPlanUiScenario.getTestPlanId(); + triggerCaseExecResult = testPlanUiScenario.getLastResult(); + } + + if (StringUtils.isNoneEmpty(automationCaseId, planId, triggerCaseExecResult)) { + this.updateFunctionCaseStatusByAutomationCaseId(automationCaseId, planId, triggerCaseExecResult); + } + } + + private void updateFunctionCaseStatusByAutomationCaseId(String automationCaseId, String testPlanId, String triggerCaseRunResult) { + TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanId); + if (testPlan != null && testPlan.getAutomaticStatusUpdate()) { + HttpHeaderUtils.runAsUser(baseUserService.getUserDTO(testPlan.getCreator())); + + Set testCaseIdSet = new HashSet<>(); + List testPlanTestCaseList = extTestPlanTestCaseMapper.selectByAutomationCaseIdAndTestPlanId(automationCaseId, testPlanId); + testPlanTestCaseList.forEach(item -> testCaseIdSet.add(item.getCaseId())); + + if (CollectionUtils.isNotEmpty(testCaseIdSet)) { + TestCaseTestExample testCaseTestExample = new TestCaseTestExample(); + testCaseTestExample.createCriteria().andTestCaseIdIn(new ArrayList<>(testCaseIdSet)); + List testCaseTestList = testCaseTestMapper.selectByExample(testCaseTestExample); + Map> testCaseTestMap = testCaseTestList.stream().collect(Collectors.groupingBy(TestCaseTest::getTestCaseId)); + + for (Map.Entry> entry : testCaseTestMap.entrySet()) { + TestCaseRelevanceCasesRequest request = this.generateRelevanceCasesRequest(testPlanId, entry.getKey(), entry.getValue()); + CaseExecResult priorityResult = TestCaseSyncStatusUtil.getTestCaseExecResultByRelevance(request.getTestCaseTestList(), + request.getApiAllCaseMap(), request.getScenarioAllCaseMap(), request.getLoadAllCaseMap(), request.getUiAllCaseMap()); + if (priorityResult == null) { + continue; + } + + String automationCaseResult = null; + if (priorityResult != null && StringUtils.isNotEmpty(priorityResult.getExecResult())) { + if (StringUtils.equalsIgnoreCase(ApiReportStatus.ERROR.name(), priorityResult.getExecResult())) { + automationCaseResult = ApiReportStatus.ERROR.name(); + priorityResult.setExecResult(FunctionCaseExecResult.ERROR.toString()); + } else if (StringUtils.equalsIgnoreCase(ApiReportStatus.FAKE_ERROR.name(), priorityResult.getExecResult())) { + automationCaseResult = ApiReportStatus.FAKE_ERROR.name(); + priorityResult.setExecResult(FunctionCaseExecResult.BLOCKING.toString()); + } else if (StringUtils.equalsIgnoreCase(ApiReportStatus.SUCCESS.name(), priorityResult.getExecResult())) { + priorityResult.setExecResult(FunctionCaseExecResult.SUCCESS.toString()); + } + } + + //通过 triggerCaseRunResult(触发操作的用例的执行结果) 进行判断,会不会直接影响最终结果。如果是,在改变功能用例状态时也要增加一条评论。 + extTestPlanTestCaseMapper.updateExecResultByTestCaseIdAndTestPlanId(entry.getKey(), testPlanId, priorityResult.getExecResult()); + if (StringUtils.equalsIgnoreCase(triggerCaseRunResult, automationCaseResult) && !StringUtils.equalsIgnoreCase(triggerCaseRunResult, ApiReportStatus.SUCCESS.name())) { + this.addTestCaseComment(testPlan.getCreator(), testPlan.getName(), entry.getKey(), priorityResult.getCaseName(), FunctionCaseExecResult.BLOCKING.toString()); + } + } + } + + HttpHeaderUtils.clearUser(); + } + } + + private TestCaseRelevanceCasesRequest generateRelevanceCasesRequest(String testPlanId, String testCaseId, List testCaseTestList) { + TestCaseRelevanceCasesRequest request = new TestCaseRelevanceCasesRequest(); + request.setTestCaseId(testCaseId); + request.setTestPlanId(testPlanId); + request.setTestCaseTestList(testCaseTestList); + + List relevanceApiCaseList = new ArrayList<>(); + List relevanceScenarioList = new ArrayList<>(); + List relevanceLoadCaseList = new ArrayList<>(); + List relevanceUiList = new ArrayList<>(); + testCaseTestList.forEach(testCaseTest -> { + if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.API_CASE.toString(), testCaseTest.getTestType())) { + relevanceApiCaseList.add(testCaseTest.getTestId()); + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.SCENARIO.toString(), testCaseTest.getTestType())) { + relevanceScenarioList.add(testCaseTest.getTestId()); + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.LOAD_CASE.toString(), testCaseTest.getTestType())) { + relevanceLoadCaseList.add(testCaseTest.getTestId()); + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.UI_AUTOMATION.toString(), testCaseTest.getTestType())) { + relevanceUiList.add(testCaseTest.getTestId()); + } + }); + if (CollectionUtils.isNotEmpty(relevanceApiCaseList)) { + List apiAllCaseList = extTestPlanApiCaseMapper.selectExecResult(testPlanId, relevanceApiCaseList); + request.setApiAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(apiAllCaseList)); + } + if (CollectionUtils.isNotEmpty(relevanceScenarioList)) { + List scenarioAllCaseList = extTestPlanScenarioCaseMapper.selectExecResult(testPlanId, relevanceScenarioList); + request.setScenarioAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(scenarioAllCaseList)); + } + if (CollectionUtils.isNotEmpty(relevanceLoadCaseList)) { + List loadAllCaseList = extTestPlanLoadCaseMapper.selectExecResult(testPlanId, relevanceLoadCaseList); + request.setLoadAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(loadAllCaseList)); + } + if (CollectionUtils.isNotEmpty(relevanceUiList)) { + List uiAllCaseList = extTestPlanUiCaseMapper.selectExecResult(testPlanId, relevanceUiList); + request.setUiAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(uiAllCaseList)); + } + return request; + } + + private void addTestCaseComment(String commentCreateUser, String testPlanName, Map caseExecResultMap, String commentStatus) { + if (MapUtils.isNotEmpty(caseExecResultMap)) { + for (Map.Entry itemEntry : caseExecResultMap.entrySet()) { + this.addTestCaseComment(commentCreateUser, testPlanName, itemEntry.getValue().getTestCaseId(), itemEntry.getValue().getCaseName(), commentStatus); + } + } + } + + private void addTestCaseComment(String commentCreateUser, String testPlanName, String testCaseId, String caseName, String commentStatus) { + if (StringUtils.isNoneBlank(testPlanName, testCaseId, commentStatus, caseName)) { + String commentDesc = TestCaseSyncStatusUtil.generateCommentDesc(testPlanName, caseName, Translator.get("api_status_fake_error")); + long systemTime = System.currentTimeMillis(); + TestCaseComment testCaseComment = new TestCaseComment(); + testCaseComment.setCaseId(testCaseId); + testCaseComment.setId(UUID.randomUUID().toString()); + testCaseComment.setCreateTime(systemTime); + testCaseComment.setUpdateTime(systemTime); + testCaseComment.setStatus(commentStatus); + testCaseComment.setType(TestCaseCommentType.PLAN.name()); + testCaseComment.setDescription(commentDesc); + testCaseComment.setAuthor(commentCreateUser); + testCaseCommentMapper.insert(testCaseComment); + } + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanMessageService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanMessageService.java index a4e8b88a46..8f8c01997f 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanMessageService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanMessageService.java @@ -15,6 +15,7 @@ import io.metersphere.service.BaseProjectService; import io.metersphere.service.BaseShareInfoService; import io.metersphere.service.BaseUserService; import io.metersphere.service.SystemParameterService; +import jakarta.annotation.Resource; import org.apache.commons.beanutils.BeanMap; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -23,7 +24,6 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import jakarta.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @@ -102,11 +102,11 @@ public class TestPlanMessageService { // 已结束:超过了计划结束时间(如有) 或 测试进度=100% 且 通过率非100% Long plannedEndTime = testPlan.getPlannedEndTime(); long currentTime = System.currentTimeMillis(); - if(Objects.nonNull(plannedEndTime) && currentTime >= plannedEndTime){ + if (Objects.nonNull(plannedEndTime) && currentTime >= plannedEndTime) { return TestPlanStatus.Finished.name(); } - if(testRate >= FULL_MARKS && passRate < FULL_MARKS){ + if (testRate >= FULL_MARKS && passRate < FULL_MARKS) { return TestPlanStatus.Finished.name(); } @@ -281,7 +281,7 @@ public class TestPlanMessageService { result.put("functionAllCount", (long) functionAllCases.size()); } - List apiAllCases = report.getApiAllCases(); + List apiAllCases = report.getApiAllCases(); if (CollectionUtils.isNotEmpty(apiAllCases)) { Map apiCountMap = apiAllCases.stream() .collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getExecResult()) ? "default" : plan.getExecResult().toLowerCase(), Collectors.counting())); @@ -312,7 +312,7 @@ public class TestPlanMessageService { result.put("apiCaseAllCount", (long) apiAllCases.size()); } - List scenarioAllCases = report.getScenarioAllCases(); + List scenarioAllCases = report.getScenarioAllCases(); if (CollectionUtils.isNotEmpty(scenarioAllCases)) { Map scenarioCountMap = scenarioAllCases.stream() .collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getLastResult()) ? "unexecute" : plan.getLastResult().toLowerCase(), Collectors.counting())); diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanReportService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanReportService.java index 4c290f0e6c..0ec3cddd18 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanReportService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanReportService.java @@ -1,7 +1,6 @@ package io.metersphere.plan.service; -import com.fasterxml.jackson.core.JsonProcessingException; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.*; @@ -18,16 +17,19 @@ import io.metersphere.plan.constant.ApiReportStatus; import io.metersphere.plan.dto.*; import io.metersphere.plan.request.QueryTestPlanRequest; import io.metersphere.plan.request.TestPlanReportSaveRequest; +import io.metersphere.plan.request.api.ApiPlanReportRequest; import io.metersphere.plan.request.api.TestPlanRunRequest; +import io.metersphere.plan.request.performance.LoadPlanReportDTO; import io.metersphere.plan.service.remote.api.*; import io.metersphere.plan.service.remote.performance.PlanLoadTestReportService; import io.metersphere.plan.service.remote.performance.PlanTestPlanLoadCaseService; import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService; +import io.metersphere.plan.utils.TestPlanReportUtil; import io.metersphere.plan.utils.TestPlanRequestUtil; -import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.request.report.QueryTestPlanReportRequest; import io.metersphere.service.BaseProjectService; import io.metersphere.service.BaseUserService; +import io.metersphere.service.IssuesService; import io.metersphere.service.ServiceUtils; import io.metersphere.utils.DiscoveryUtil; import io.metersphere.utils.LoggerUtil; @@ -36,6 +38,7 @@ import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; @@ -112,40 +115,56 @@ public class TestPlanReportService { private BaseEnvironmentService apiTestEnvironmentService; @Resource private BaseProjectService baseProjectService; + @Lazy + @Resource + private TestPlanTestCaseService testPlanTestCaseService; + @Lazy + @Resource + private IssuesService issuesService; private final String GROUP = "GROUP"; public List list(QueryTestPlanReportRequest request) { - List list = new ArrayList<>(); - request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); if (StringUtils.isBlank(request.getProjectId())) { - return list; + return new ArrayList<>(); + } else { + request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); + try { + this.formatSelectRequest(request); + } catch (Exception e) { + LogUtil.error("格式化查询请求参数出错!", e); + } + return extTestPlanReportMapper.list(request); + + /* + 2.8之前的逻辑中,会检查有没有查到成功率,没查到的话重新计算。 + 现在想来,如果没查到就没查到。 报告结束的时候会统计成功率。 报告没结束,也没必要查询成功率。 + 在2.10之前这么处理没有问题时,2.10将去掉这段注释。 + */ } - if (request.getCombine() != null && !request.getCombine().isEmpty()) { + } + + private void formatSelectRequest(QueryTestPlanReportRequest request) { + if (MapUtils.isNotEmpty(request.getCombine()) && request.getCombine().containsKey("status")) { if (request.getCombine().get("status") != null) { HashMap map = (HashMap) request.getCombine().get("status"); - List valueList = (List) map.get("value"); - List newVal = new ArrayList<>(); - valueList.forEach(item -> { - if ("Completed".equals(item)) { - newVal.add("success"); - newVal.add("failed"); - newVal.add("completed"); + List statusFilterList = new ArrayList<>(); + ((List) map.get("value")).forEach(item -> { + if (StringUtils.equalsAnyIgnoreCase(item, TestPlanReportStatus.COMPLETED.name())) { + CollectionUtils.addAll(statusFilterList, new String[]{ + TestPlanReportStatus.COMPLETED.name(), + TestPlanReportStatus.FAILED.name(), + TestPlanReportStatus.SUCCESS.name() + }); } else if ("Underway".equals(item)) { - newVal.add("Running"); + statusFilterList.add("Running"); } else { - newVal.add("Starting"); + statusFilterList.add("Starting"); } }); - valueList.clear(); - valueList.addAll(newVal); + map.put("status", statusFilterList); } } - list = extTestPlanReportMapper.list(request); - - // 设置测试计划报告成功率 - setTestPlanReportPassRate(list); - return list; } public boolean hasRunningReport(String planId) { @@ -156,93 +175,6 @@ public class TestPlanReportService { return extTestPlanReportContentMapper.hasRunningReportByPlanIds(planIds); } - public void setTestPlanReportPassRate(List list) { - for (TestPlanReportDTO testPlanReportDTO : list) { - // 如果数据库查询成功率字段为空或 0 则重新计算一次 - if (testPlanReportDTO.getPassRate() == null || testPlanReportDTO.getPassRate() == 0) { - if (this.isDynamicallyGenerateReports(testPlanReportDTO.getId())) { - TestPlanReportContentWithBLOBs testPlanReportContent = extTestPlanReportContentMapper.selectForPassRate(testPlanReportDTO.getId()); - String planId = testPlanReportDTO.getTestPlanId(); - TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO(); - Map statusResultMap = new HashMap<>(); - - TestPlanExecuteReportDTO testPlanExecuteReportDTO = genTestPlanExecuteReportDTOByTestPlanReportContent(testPlanReportContent); - // 功能用例 - TestPlanStatusCalculator.buildStatusResultMap(extTestPlanTestCaseMapper.selectForPlanReport(planId), statusResultMap, report, TestPlanTestCaseStatus.Pass.name()); - - // 测试计划报告各用例集合 - List planReportCaseDTOS; - - Set serviceIdSet = DiscoveryUtil.getServiceIdSet(); - - if (testPlanExecuteReportDTO == null) { - - if (serviceIdSet.contains(MicroServiceName.API_TEST)) { - // 接口用例 - planReportCaseDTOS = planTestPlanApiCaseService.selectStatusForPlanReport(planId); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - // 场景用例 - planReportCaseDTOS = planTestPlanScenarioCaseService.selectStatusForPlanReport(planId); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - - - if (serviceIdSet.contains(MicroServiceName.PERFORMANCE_TEST)) { - // 性能用例 - planReportCaseDTOS = planTestPlanLoadCaseService.selectStatusForPlanReport(planId); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - } else { - // 报告 ID 集合 - List reportIds = null; - // 接口用例 - if (serviceIdSet.contains(MicroServiceName.API_TEST)) { - if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap())) { - reportIds = new ArrayList<>(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap().values()); - planReportCaseDTOS = planApiDefinitionExecResultService.selectForPlanReport(reportIds); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap())) { - // 场景用例 - reportIds = new ArrayList<>(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap().values()); - planReportCaseDTOS = planApiScenarioReportService.selectForPlanReport(reportIds); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - } - - if (serviceIdSet.contains(MicroServiceName.UI_TEST)) { - if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanUiScenarioIdAndReportIdMap())) { - // 场景用例 - reportIds = new ArrayList<>(testPlanExecuteReportDTO.getTestPlanUiScenarioIdAndReportIdMap().values()); - planReportCaseDTOS = planUiScenarioReportService.selectForPlanReport(reportIds); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - } - - if (serviceIdSet.contains(MicroServiceName.PERFORMANCE_TEST)) { - if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap())) { - // 性能用例 - reportIds = new ArrayList<>(testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap().values()); - planReportCaseDTOS = planLoadTestReportService.getPlanReportCaseDTO(reportIds); - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, ApiReportStatus.SUCCESS.name()); - } - } - - } - report.setExecuteRate(0.0); - report.setPassRate(0.0); - - // 设置成功率 - if (report.getCaseCount() != null && report.getCaseCount() != 0) { - report.setExecuteRate(report.getExecuteCount() * 1.0 / report.getCaseCount()); - report.setPassRate(report.getPassCount() * 1.0 / report.getCaseCount()); - } - testPlanReportDTO.setPassRate(report.getPassRate()); - } - } - } - } - public TestPlanApiReportInfoDTO genApiReportInfoForSchedule(String planId, RunModeConfigDTO runModeConfigDTO) { TestPlanApiReportInfoDTO testPlanApiReportInfo = new TestPlanApiReportInfoDTO(); Map planApiCaseIdMap = new LinkedHashMap<>(); @@ -495,28 +427,7 @@ public class TestPlanReportService { testPlanReport.setRunInfo(JSON.toJSONString(runInfoDTO)); } - Set serviceIdSet = DiscoveryUtil.getServiceIdSet(); - - if (saveRequest.isCountResources()) { - String planId = saveRequest.getPlanId(); - - if (serviceIdSet.contains(MicroServiceName.API_TEST)) { - - testPlanReport.setIsApiCaseExecuting(planTestPlanApiCaseService.isCaseExecuting(planId)); - testPlanReport.setIsScenarioExecuting(planTestPlanScenarioCaseService.isCaseExecuting(planId)); - } - - - if (serviceIdSet.contains(MicroServiceName.UI_TEST)) { - testPlanReport.setIsUiScenarioExecuting(planTestPlanUiScenarioCaseService.isCaseExecuting(planId)); - } - - - if (serviceIdSet.contains(MicroServiceName.PERFORMANCE_TEST)) { - testPlanReport.setIsPerformanceExecuting(planTestPlanLoadCaseService.isCaseExecuting(planId, testPlan.getProjectId())); - } - - } else { + if (!saveRequest.isCountResources()) { testPlanReport.setIsApiCaseExecuting(saveRequest.isApiCaseIsExecuting()); testPlanReport.setIsScenarioExecuting(saveRequest.isScenarioIsExecuting()); testPlanReport.setIsPerformanceExecuting(saveRequest.isPerformanceIsExecuting()); @@ -616,39 +527,22 @@ public class TestPlanReportService { return principalName; } - public TestPlanReportContentWithBLOBs updateReport(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs reportContent) { - if (testPlanReport == null || reportContent == null) { - return null; - } - TestPlanService testPlanService = CommonBeanFactory.getBean(TestPlanService.class); - TestPlanReportBuildResultDTO reportBuildResult = testPlanService.buildPlanReport(testPlanReport, reportContent); - TestPlanSimpleReportDTO reportDTO = reportBuildResult.getTestPlanSimpleReportDTO(); - reportDTO.setStartTime(testPlanReport.getStartTime()); - reportContent = parseReportDaoToReportContent(reportDTO, reportContent); - this.updatePassRateAndApiBaseInfoFromReportContent(testPlanReport.getStatus(), reportDTO, reportContent, reportBuildResult.isApiBaseInfoChanged()); - return reportContent; + //更新测试计划报告的数据结构 + private void updateReportStructInfo(TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs, TestPlanSimpleReportDTO reportStruct) { + //更新BaseCount统计字段和通过率 + testPlanReportContentWithBLOBs.setPassRate(reportStruct.getPassRate()); + testPlanReportContentWithBLOBs.setApiBaseCount(JSON.toJSONString(reportStruct)); + testPlanReportContentMapper.updateByPrimaryKeySelective(testPlanReportContentWithBLOBs); } - private void updatePassRateAndApiBaseInfoFromReportContent(String status, TestPlanSimpleReportDTO reportDTO, TestPlanReportContentWithBLOBs reportContent, boolean apiBaseInfoChanged) { - // 如果报告已结束,则更新测试计划报告通过率字段 passRate - if (!StringUtils.equalsIgnoreCase(status, APITestStatus.Running.name()) - && (Double.compare(reportContent.getPassRate(), reportDTO.getPassRate()) != 0 || apiBaseInfoChanged)) { - TestPlanReportContentExample contentExample = new TestPlanReportContentExample(); - contentExample.createCriteria().andTestPlanReportIdEqualTo(reportContent.getTestPlanReportId()); - TestPlanReportContentWithBLOBs content = new TestPlanReportContentWithBLOBs(); - content.setPassRate(reportDTO.getPassRate()); - if (apiBaseInfoChanged) { - content.setApiBaseCount(reportContent.getApiBaseCount()); - } - testPlanReportContentMapper.updateByExampleSelective(content, contentExample); - } - - } - - public TestPlanReport finishedTestPlanReport(String testPlanReportId, String status) { + public void testPlanExecuteOver(String testPlanReportId, String finishStatus) { TestPlanReport testPlanReport = this.getTestPlanReport(testPlanReportId); - if (testPlanReport != null && StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), "stopped")) { - return testPlanReport; + if (testPlanReport != null && StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), + "stopped", + TestPlanReportStatus.COMPLETED.name(), + TestPlanReportStatus.SUCCESS.name(), + TestPlanReportStatus.FAILED.name())) { + return; } boolean isSendMessage = false; if (testPlanReport != null) { @@ -663,9 +557,12 @@ public class TestPlanReportService { try { HttpHeaderUtils.runAsUser(testPlanReport.getCreator()); boolean isRerunningTestPlan = BooleanUtils.isTrue(StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), APITestStatus.Rerunning.name())); - content = this.initTestPlanContent(testPlanReport, status, isRerunningTestPlan); + //测试计划报告结果数据初始化 + testPlanReport.setStatus(finishStatus); + content = this.initTestPlanReportInfo(testPlanReport, isRerunningTestPlan); + this.setReportExecuteResult(testPlanReport, finishStatus); } catch (Exception e) { - testPlanReport.setStatus(status); + testPlanReport.setStatus(finishStatus); LogUtil.error("统计测试计划状态失败!", e); } finally { HttpHeaderUtils.clearUser(); @@ -674,43 +571,43 @@ public class TestPlanReportService { this.executeTestPlanByQueue(testPlanReportId); } } - return testPlanReport; } - private TestPlanReportContentWithBLOBs initTestPlanContent(TestPlanReport testPlanReport, String status, boolean isRerunningTestPlan) throws Exception { - testPlanReport.setStatus(status); - TestPlanReportContentWithBLOBs content = null; - //初始化测试计划包含组件信息 - int[] componentIndexArr = new int[]{1, 3, 4}; - testPlanReport.setComponents(JSON.toJSONString(componentIndexArr)); + /** + * 测试计划报告设置最终执行状态 + */ + private void setReportExecuteResult(TestPlanReport testPlanReport, String finishStatus) { + //计算测试计划状态 + testPlanReport.setStatus(StringUtils.equalsIgnoreCase(finishStatus, TestPlanReportStatus.COMPLETED.name()) ? + TestPlanReportStatus.SUCCESS.name() : finishStatus); + //检查更新测试计划状态 + testPlanService.checkTestPlanStatusWhenExecuteOver(testPlanReport.getTestPlanId()); + } + + /** + * 统计测试计划报告信息 + */ + public TestPlanReportContentWithBLOBs initTestPlanReportInfo(TestPlanReport testPlanReport, boolean isRerunningTestPlan) throws Exception { long endTime = System.currentTimeMillis(); //原逻辑中要判断包含测试计划功能用例时才会赋予结束时间。执行测试计划产生的测试报告,它的结束时间感觉没有这种判断必要。 testPlanReport.setEndTime(endTime); testPlanReport.setUpdateTime(endTime); - - TestPlanReportContentExample contentExample = new TestPlanReportContentExample(); - contentExample.createCriteria().andTestPlanReportIdEqualTo(testPlanReport.getId()); - List contents = testPlanReportContentMapper.selectByExampleWithBLOBs(contentExample); - if (CollectionUtils.isNotEmpty(contents)) { - content = contents.get(0); - content.setApiBaseCount(null); - content.setPassRate(null); - extTestPlanReportMapper.setApiBaseCountAndPassRateIsNullById(content.getId()); - } - - //计算测试计划状态 - if (StringUtils.equalsIgnoreCase(status, TestPlanReportStatus.COMPLETED.name())) { - testPlanReport.setStatus(TestPlanReportStatus.SUCCESS.name()); - testPlanService.checkStatus(testPlanReport.getTestPlanId()); - } + TestPlanReportContentWithBLOBs content = this.selectTestPlanReportContentByReportId(testPlanReport.getId()); if (content != null) { //更新content表对结束日期 重跑的测试计划报告不用更新 if (!isRerunningTestPlan) { content.setStartTime(testPlanReport.getStartTime()); content.setEndTime(endTime); } - this.initTestPlanReportBaseCount(testPlanReport, content); - testPlanReportContentMapper.updateByExampleSelective(content, contentExample); + TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId()); + TestPlanSimpleReportDTO apiBaseCountStruct = this.initTestPlanReportStruct(testPlan, testPlanReport, content); + if (apiBaseCountStruct.getPassRate() == 1) { + testPlanReport.setStatus(TestPlanReportStatus.SUCCESS.name()); + } else if (apiBaseCountStruct.getPassRate() < 1) { + testPlanReport.setStatus(TestPlanReportStatus.FAILED.name()); + } + //更新数据结构 + this.updateReportStructInfo(content, apiBaseCountStruct); } return content; } @@ -749,7 +646,7 @@ public class TestPlanReportService { testPlanService.runPlan(runRequest); } catch (Exception e) { LogUtil.error("执行队列中的下一个测试计划失败! ", e); - this.finishedTestPlanReport(runRequest.getReportId(), TestPlanReportStatus.FAILED.name()); + this.testPlanExecuteOver(runRequest.getReportId(), TestPlanReportStatus.FAILED.name()); } finally { HttpHeaderUtils.clearUser(); } @@ -757,16 +654,18 @@ public class TestPlanReportService { } } - private void initTestPlanReportBaseCount(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs reportContent) { + //构建测试计划报告的数据结构 + private TestPlanSimpleReportDTO initTestPlanReportStruct(TestPlanWithBLOBs testPlan, TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs reportContent) { + TestPlanSimpleReportDTO returnDTO = null; if (testPlanReport != null && reportContent != null) { try { - TestPlanReportBuildResultDTO reportBuildResultDTO = testPlanService.buildPlanReport(testPlanReport, reportContent); - reportContent.setApiBaseCount(JSON.toJSONString(reportBuildResultDTO.getTestPlanSimpleReportDTO())); + TestPlanReportBuildResultDTO reportBuildResultDTO = testPlanService.buildTestPlanReport(testPlan, testPlanReport, reportContent); + returnDTO = reportBuildResultDTO.getTestPlanSimpleReportDTO(); } catch (Exception e) { LogUtil.error("计算测试计划报告信息出错!", e); } - } + return returnDTO; } /** @@ -824,7 +723,6 @@ public class TestPlanReportService { String testPlanStatus = this.getTestPlanReportStatus(testPlanReport, reportDTO); testPlanReport.setStatus(testPlanStatus); testPlanReportMapper.updateByPrimaryKey(testPlanReport); - testPlanMessageService.checkTestPlanStatusAndSendMessage(testPlanReport, null, false); } public TestPlanReportContentWithBLOBs parseReportDaoToReportContent(TestPlanSimpleReportDTO reportDTO, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { @@ -959,20 +857,9 @@ public class TestPlanReportService { contentExample.createCriteria().andTestPlanReportIdIn(testPlanReportIdList); testPlanReportContentMapper.deleteByExample(contentExample); - // //删除关联资源对应的报告ID - // apiDefinitionExecResultService.deleteByRelevanceTestPlanReportIds(testPlanReportIdList); - // apiScenarioReportService.deleteByRelevanceTestPlanReportIds(testPlanReportIdList); - // performanceTestService.deleteByRelevanceTestPlanReportIds(testPlanReportIdList); - } } - public List getReports(List ids) { - TestPlanReportExample example = new TestPlanReportExample(); - example.createCriteria().andIdIn(ids); - return testPlanReportMapper.selectByExample(example); - } - public void delete(QueryTestPlanReportRequest request) { List deleteReportIds = request.getDataIds(); if (request.isSelectAllDate()) { @@ -1137,157 +1024,49 @@ public class TestPlanReportService { } } - public TestPlanSimpleReportDTO getReport(String reportId) { + public TestPlanReportContentWithBLOBs selectTestPlanReportContentByReportId(String reportId) { TestPlanReportContentExample example = new TestPlanReportContentExample(); example.createCriteria().andTestPlanReportIdEqualTo(reportId); List testPlanReportContents = testPlanReportContentMapper.selectByExampleWithBLOBs(example); if (CollectionUtils.isEmpty(testPlanReportContents)) { return null; + } else { + return testPlanReportContents.get(0); } - TestPlanReportContentWithBLOBs testPlanReportContent = testPlanReportContents.get(0); - if (testPlanReportContent == null) { - return null; + } + + public TestPlanSimpleReportDTO getReport(String reportId) { + TestPlanSimpleReportDTO testPlanReportDTO = new TestPlanSimpleReportDTO(); + TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId); + TestPlanReportContentWithBLOBs testPlanReportContent = this.selectTestPlanReportContentByReportId(reportId); + if (ObjectUtils.anyNull(testPlanReport, testPlanReportContent)) { + return testPlanReportDTO; } if (this.isDynamicallyGenerateReports(testPlanReportContent)) { - testPlanReportContent = this.dynamicallyGenerateReports(testPlanReportContent); + TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId()); + testPlanReportDTO = this.initTestPlanReportStruct(testPlan, testPlanReport, testPlanReportContent); } - TestPlanSimpleReportDTO testPlanReportDTO = new TestPlanSimpleReportDTO(); - BeanUtils.copyBean(testPlanReportDTO, testPlanReportContent); - TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId); - this.initTestPlanReportEnv(testPlanReportDTO, testPlanReport); - - testPlanReportDTO.setFunctionResult( - getReportContentResultObject(testPlanReportContent.getFunctionResult(), TestPlanFunctionResultReportDTO.class) - ); - - testPlanReportDTO.setApiResult( - getReportContentResultObject(testPlanReportContent.getApiResult(), TestPlanApiResultReportDTO.class) - ); - - testPlanReportDTO.setLoadResult( - getReportContentResultObject(testPlanReportContent.getLoadResult(), TestPlanLoadResultReportDTO.class) - ); - - testPlanReportDTO.setFunctionAllCases( - getReportContentResultArray(testPlanReportContent.getFunctionAllCases(), TestPlanCaseDTO.class) - ); - - testPlanReportDTO.setIssueList( - getReportContentResultArray(testPlanReportContent.getIssueList(), IssuesDao.class) - ); - - testPlanReportDTO.setApiAllCases( - getReportContentResultArray(testPlanReportContent.getApiAllCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setApiFailureCases( - getReportContentResultArray(testPlanReportContent.getApiFailureCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setScenarioAllCases( - getReportContentResultArray(testPlanReportContent.getScenarioAllCases(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setScenarioFailureCases( - getReportContentResultArray(testPlanReportContent.getScenarioFailureCases(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setLoadAllCases( - getReportContentResultArray(testPlanReportContent.getLoadAllCases(), TestPlanLoadCaseDTO.class) - ); - - testPlanReportDTO.setLoadFailureCases( - getReportContentResultArray(testPlanReportContent.getLoadFailureCases(), TestPlanLoadCaseDTO.class) - ); - - testPlanReportDTO.setErrorReportCases( - getReportContentResultArray(testPlanReportContent.getErrorReportCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setErrorReportScenarios( - getReportContentResultArray(testPlanReportContent.getErrorReportScenarios(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setUnExecuteCases( - getReportContentResultArray(testPlanReportContent.getUnExecuteCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setUnExecuteScenarios( - getReportContentResultArray(testPlanReportContent.getUnExecuteScenarios(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setUiResult( - getReportContentResultObject(testPlanReportContent.getUiResult(), TestPlanUiResultReportDTO.class) - ); - - testPlanReportDTO.setUiAllCases( - getReportContentResultArray(testPlanReportContent.getUiAllCases(), TestPlanUiScenarioDTO.class) - ); - - testPlanReportDTO.setUiFailureCases( - getReportContentResultArray(testPlanReportContent.getUiFailureCases(), TestPlanUiScenarioDTO.class) - ); - testPlanReportDTO.setId(reportId); testPlanReportDTO.setName(testPlanReport.getName()); - TestPlanService testPlanService = CommonBeanFactory.getBean(TestPlanService.class); - TestPlanExtReportDTO extReport = null; - try { - extReport = testPlanService.getExtInfoByReportId(reportId); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - if (extReport != null) { - BeanUtils.copyBean(testPlanReportDTO, extReport); - } + //查找运行环境 + this.selectEnvironmentByTestPlanReport(testPlanReportDTO, testPlanReport); return testPlanReportDTO; } - private T getReportContentResultObject(String contentStr, Class clazz) { - if (StringUtils.isNotBlank(contentStr)) { - return JSON.parseObject(contentStr, clazz); - } - return null; - - } - - private List getReportContentResultArray(String contentStr, Class clazz) { - if (StringUtils.isNotBlank(contentStr)) { - return JSON.parseArray(contentStr, clazz); - } - return null; - } - - - private void generateEnvironmentInfo(TestPlanSimpleReportDTO testPlanReportDTO, String reportId) { - TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId); - try { - if (DiscoveryUtil.hasService(MicroServiceName.API_TEST)) { - TestPlanEnvInfoDTO testPlanEnvInfo = planTestPlanScenarioCaseService.generateEnvironmentInfo(testPlanReport); - BeanUtils.copyBean(testPlanReportDTO, testPlanEnvInfo); - } - if (DiscoveryUtil.hasService(MicroServiceName.UI_TEST)) { - TestPlanEnvInfoDTO testPlanEnvInfo = planTestPlanUiScenarioCaseService.generateEnvironmentInfo(testPlanReport); - Map> projectMap = testPlanReportDTO.getProjectEnvMap(); - BeanUtils.copyBean(testPlanReportDTO, testPlanEnvInfo); - testPlanReportDTO.setProjectEnvMap(planTestPlanUiScenarioCaseService.mergeProjectEnvMap(testPlanEnvInfo.getProjectEnvMap(), projectMap)); - } - } catch (Exception e) { - LogUtil.error(e); - } - } - - public void initTestPlanReportEnv(TestPlanSimpleReportDTO testPlanReportDTO, TestPlanReport testPlanReport) { - TestPlanReportRunInfoDTO runInfoDTO = null; + public void selectEnvironmentByTestPlanReport(TestPlanSimpleReportDTO testPlanReportDTO, TestPlanReport testPlanReport) { if (StringUtils.isNotEmpty(testPlanReport.getRunInfo())) { try { - runInfoDTO = JSON.parseObject(testPlanReport.getRunInfo(), TestPlanReportRunInfoDTO.class); + TestPlanReportRunInfoDTO runInfoDTO = JSON.parseObject(testPlanReport.getRunInfo(), TestPlanReportRunInfoDTO.class); + this.setEnvironmentToDTO(testPlanReportDTO, runInfoDTO); } catch (Exception e) { LogUtil.error("解析测试计划报告记录的运行环境信息[" + testPlanReport.getRunInfo() + "]时出错!", e); } - } - if (runInfoDTO != null) { + } + + public void setEnvironmentToDTO(TestPlanSimpleReportDTO testPlanReportDTO, TestPlanReportRunInfoDTO runInfoDTO) { + if (ObjectUtils.allNotNull(testPlanReportDTO, runInfoDTO)) { + // 环境组/运行环境 if (StringUtils.isNotEmpty(runInfoDTO.getEnvGroupId())) { EnvironmentGroup environmentGroup = apiTestEnvironmentService.selectById(runInfoDTO.getEnvGroupId()); if (StringUtils.isNotEmpty(environmentGroup.getName())) { @@ -1315,6 +1094,7 @@ public class TestPlanReportService { } } } + //运行模式 testPlanReportDTO.setRunMode(StringUtils.equalsIgnoreCase(runInfoDTO.getRunMode(), "serial") ? Translator.get("serial") : Translator.get("parallel")); } } @@ -1328,122 +1108,205 @@ public class TestPlanReportService { return extTestPlanReportContentMapper.isDynamicallyGenerateReport(reportId); } - private TestPlanReportContentWithBLOBs dynamicallyGenerateReports(TestPlanReportContentWithBLOBs testPlanReportContent) { - TestPlanReport report = testPlanReportMapper.selectByPrimaryKey(testPlanReportContent.getTestPlanReportId()); - testPlanReportContent = this.updateReport(report, testPlanReportContent); - return testPlanReportContent; - } - - public void createTestPlanReportContentReportIds(String testPlanReportID, Map apiCaseReportMap, Map scenarioReportIdMap, Map loadCaseReportIdMap, Map uiScenarioReportMap) { + public void createTestPlanReportContentReportIds(String testPlanReportID, + List apiTestCases, + List scenarioCases, + List uiScenarios, + Map loadCaseReportIdMap) { TestPlanReportContentWithBLOBs content = new TestPlanReportContentWithBLOBs(); content.setId(UUID.randomUUID().toString()); content.setTestPlanReportId(testPlanReportID); - - if (MapUtils.isNotEmpty(apiCaseReportMap)) { - List apiTestCases = planTestPlanApiCaseService.getFailureListByIds(apiCaseReportMap.keySet()); - for (TestPlanFailureApiDTO dto : apiTestCases) { - dto.setReportId(apiCaseReportMap.get(dto.getId())); - } - content.setPlanApiCaseReportStruct(JSON.toJSONString(apiTestCases)); - } - if (MapUtils.isNotEmpty(scenarioReportIdMap)) { - List apiTestCases = - planTestPlanScenarioCaseService.getFailureListByIds(scenarioReportIdMap.keySet()); - for (TestPlanFailureScenarioDTO dto : apiTestCases) { - dto.setReportId(scenarioReportIdMap.get(dto.getId())); - } - content.setPlanScenarioReportStruct(JSON.toJSONString(apiTestCases)); - } if (MapUtils.isNotEmpty(loadCaseReportIdMap)) { content.setPlanLoadCaseReportStruct(JSON.toJSONString(loadCaseReportIdMap)); } - if (MapUtils.isNotEmpty(uiScenarioReportMap)) { - List uiScenarios = - planTestPlanUiScenarioCaseService.getFailureListByIds(uiScenarioReportMap.keySet()); - for (TestPlanUiScenarioDTO dto : uiScenarios) { - dto.setReportId(uiScenarioReportMap.get(dto.getId())); - } + + if (CollectionUtils.isNotEmpty(apiTestCases)) { + content.setPlanApiCaseReportStruct(JSON.toJSONString(apiTestCases)); + } + if (CollectionUtils.isNotEmpty(scenarioCases)) { + content.setPlanScenarioReportStruct(JSON.toJSONString(scenarioCases)); + } + if (CollectionUtils.isNotEmpty(uiScenarios)) { content.setPlanUiScenarioReportStruct(JSON.toJSONString(uiScenarios)); } + testPlanReportContentMapper.insert(content); } - public TestPlanExecuteReportDTO genTestPlanExecuteReportDTOByTestPlanReportContent(TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { - Map testPlanApiCaseIdAndReportIdMap = new LinkedHashMap<>(); - Map testPlanScenarioIdAndReportIdMap = new LinkedHashMap<>(); - Map testPlanUiScenarioIdAndReportIdMap = new LinkedHashMap<>(); - Map testPlanLoadCaseIdAndReportIdMap = new LinkedHashMap<>(); - Map apiCaseInfoDTOMap = new LinkedHashMap<>(); - Map scenarioInfoDTOMap = new LinkedHashMap<>(); - Map uiScenarioInfoDTOMap = new LinkedHashMap<>(); - - if (testPlanReportContentWithBLOBs != null) { - if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct())) { - List apiCaseInfoDTOList = null; + private Map parseCaseReportMap(String reportStructStr) { + Map returnMap = new HashMap<>(); + if (StringUtils.isNotEmpty(reportStructStr)) { + List caseReportList = null; + try { + caseReportList = JSON.parseArray(reportStructStr, Map.class); + } catch (Exception ignored) { + } + if (CollectionUtils.isEmpty(caseReportList)) { try { - apiCaseInfoDTOList = JSON.parseArray(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct(), TestPlanFailureApiDTO.class); + returnMap = JSON.parseObject(reportStructStr, Map.class); } catch (Exception ignored) { } - if (apiCaseInfoDTOList == null) { - try { - testPlanApiCaseIdAndReportIdMap = JSON.parseObject(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct(), Map.class); - } catch (Exception ignored) { + } else { + for (Map itemMap : caseReportList) { + if (itemMap.containsKey("id") && itemMap.containsKey("reportId")) { + String id = itemMap.get("id").toString(); + String reportId = itemMap.get("reportId").toString(); + if (StringUtils.isNoneEmpty(id, reportId)) { + returnMap.put(id, reportId); + } } - } else { - for (TestPlanFailureApiDTO item : apiCaseInfoDTOList) { - testPlanApiCaseIdAndReportIdMap.put(item.getId(), item.getReportId()); - apiCaseInfoDTOMap.put(item.getId(), item); - } - } - } - if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanScenarioReportStruct())) { - List scenarioInfoDTOList = null; - try { - scenarioInfoDTOList = JSON.parseArray(testPlanReportContentWithBLOBs.getPlanScenarioReportStruct(), TestPlanFailureScenarioDTO.class); - } catch (Exception ignored) { - } - if (scenarioInfoDTOList == null) { - try { - testPlanScenarioIdAndReportIdMap = JSON.parseObject(testPlanReportContentWithBLOBs.getPlanScenarioReportStruct(), Map.class); - } catch (Exception ignored) { - } - } else { - for (TestPlanFailureScenarioDTO item : scenarioInfoDTOList) { - testPlanScenarioIdAndReportIdMap.put(item.getId(), item.getReportId()); - scenarioInfoDTOMap.put(item.getId(), item); - } - } - } - if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct())) { - List scenarioInfoDTOList = null; - try { - scenarioInfoDTOList = JSON.parseArray(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), TestPlanUiScenarioDTO.class); - } catch (Exception ignored) { - } - if (scenarioInfoDTOList == null) { - try { - testPlanUiScenarioIdAndReportIdMap = JSON.parseObject(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), Map.class); - } catch (Exception ignored) { - } - } else { - for (TestPlanUiScenarioDTO item : scenarioInfoDTOList) { - testPlanUiScenarioIdAndReportIdMap.put(item.getId(), item.getReportId()); - uiScenarioInfoDTOMap.put(item.getId(), item); - - } - } - } - if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct())) { - try { - testPlanLoadCaseIdAndReportIdMap = JSON.parseObject(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct(), Map.class); - } catch (Exception ignore) { } } } - TestPlanExecuteReportDTO returnDTO = new TestPlanExecuteReportDTO(testPlanApiCaseIdAndReportIdMap, testPlanScenarioIdAndReportIdMap, testPlanUiScenarioIdAndReportIdMap, testPlanLoadCaseIdAndReportIdMap, apiCaseInfoDTOMap, scenarioInfoDTOMap, uiScenarioInfoDTOMap); - return returnDTO; + return returnMap; } + public TestPlanCaseReportResultDTO selectCaseDetailByTestPlanReport(Map reportConfig, String testPlanId, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】开始处理用例执行结果"); + TestPlanCaseReportResultDTO reportDetailDTO = new TestPlanCaseReportResultDTO(); + //查找api测试报告结果 + if (DiscoveryUtil.hasService(MicroServiceName.API_TEST)) { + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】开始查找接口测试报告结果"); + try { + Map apiCaseReportMap = this.parseCaseReportMap(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct()); + Map scenarioReportMap = this.parseCaseReportMap(testPlanReportContentWithBLOBs.getPlanScenarioReportStruct()); + ApiPlanReportRequest request = new ApiPlanReportRequest(); + request.setConfig(reportConfig); + request.setSaveResponse(false); + if (MapUtils.isNotEmpty(apiCaseReportMap)) { + request.setApiReportIdList(new ArrayList<>(apiCaseReportMap.values())); + } + if (MapUtils.isNotEmpty(scenarioReportMap)) { + request.setScenarioReportIdList(new ArrayList<>(scenarioReportMap.values())); + } + ApiReportResultDTO apiReportResult = planTestPlanScenarioCaseService.getApiExecuteReport(request); + reportDetailDTO.setApiPlanReportDTO(this.getApiPlanReport(reportConfig, testPlanReportContentWithBLOBs, apiReportResult)); + } catch (Exception e) { + LogUtil.error("连接Api-test查找报告结果信息失败!", e); + } + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】接口测试报告结构查找结束"); + } + //查找性能测试报告结果 + if (DiscoveryUtil.hasService(MicroServiceName.PERFORMANCE_TEST)) { + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】开始查找性能测试报告结果"); + Map testPlanLoadCaseIdAndReportIdMap = this.parseCaseReportMap(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct()); + if (MapUtils.isNotEmpty(testPlanLoadCaseIdAndReportIdMap)) { + ApiPlanReportRequest request = new ApiPlanReportRequest(); + request.setConfig(reportConfig); + request.setSaveResponse(false); + request.setReportIdMap(testPlanLoadCaseIdAndReportIdMap); + try { + LoadPlanReportDTO loadPlanReport = planTestPlanLoadCaseService.getLoadExecuteReport(request); + reportDetailDTO.setLoadPlanReportDTO(loadPlanReport); + } catch (Exception e) { + LogUtil.error("连接Load-test查找报告结果信息失败!", e); + } + } + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】性能测试报告结果查找结束"); + } + //查找UI测试报告结果 + if (DiscoveryUtil.hasService(MicroServiceName.UI_TEST)) { + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】开始查找UI测试报告结果"); + Map testPlanLoadCaseIdAndReportIdMap = this.parseCaseReportMap(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct()); + if (MapUtils.isNotEmpty(testPlanLoadCaseIdAndReportIdMap)) { + ApiPlanReportRequest request = new ApiPlanReportRequest(); + request.setConfig(reportConfig); + request.setPlanId(testPlanId); + request.setSaveResponse(null); + request.setTestPlanExecuteReportDTO(reportDetailDTO); + try { + UiPlanReportDTO uiReport = planTestPlanUiScenarioCaseService.getUiReport(request); + reportDetailDTO.setUiPlanReportDTO(uiReport); + } catch (Exception e) { + LogUtil.error("连接Ui-test查找报告结果信息失败!", e); + } + } + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】UI测试报告结果查找结束"); + } + + //统计功能用例 + if (testPlanService.checkReportConfig(reportConfig, "functional")) { + List statusList = testPlanService.getFunctionalReportStatusList(reportConfig); + if (statusList != null) { + // 不等于null,说明配置了用例,根据配置的状态查询用例 + List allCases = testPlanTestCaseService.getAllCasesByStatusList(testPlanId, statusList); + reportDetailDTO.setFunctionCaseList(allCases); + } + + if (TestPlanReportUtil.checkReportConfig(reportConfig, "functional", "issue")) { + List issueList = issuesService.getIssuesByPlanId(testPlanId); + reportDetailDTO.setIssueList(issueList); + } + } + LogUtil.info("测试计划报告【" + testPlanReportContentWithBLOBs.getTestPlanReportId() + "】用例执行结果处理结束"); + return reportDetailDTO; + } + + private List getByScenarioExecReportIds(String planScenarioReportStruct, Map scenarioReportResultMap) { + if (MapUtils.isEmpty(scenarioReportResultMap) || StringUtils.isEmpty(planScenarioReportStruct)) { + return new ArrayList<>(); + } + List testPlanScenarioDTOList = null; + try { + testPlanScenarioDTOList = JSON.parseArray(planScenarioReportStruct, TestPlanScenarioDTO.class); + if (CollectionUtils.isNotEmpty(testPlanScenarioDTOList)) { + String defaultStatus = ApiReportStatus.ERROR.name(); + for (TestPlanScenarioDTO dto : testPlanScenarioDTOList) { + String reportId = dto.getReportId(); + dto.setReportId(reportId); + dto.setLastResult(scenarioReportResultMap.getOrDefault(reportId, defaultStatus)); + } + } + } catch (Exception e) { + LogUtil.error("解析接口报告数据结构失败!", e); + } + return testPlanScenarioDTOList; + } + + public List getByApiExecReportIds(String apiCaseReportStructStr, Map reportResultMap) { + if (MapUtils.isEmpty(reportResultMap) || StringUtils.isEmpty(apiCaseReportStructStr)) { + return new ArrayList<>(); + } + List testPlanApiDTOList = null; + try { + testPlanApiDTOList = JSON.parseArray(apiCaseReportStructStr, TestPlanApiDTO.class); + if (CollectionUtils.isNotEmpty(testPlanApiDTOList)) { + String defaultStatus = ApiReportStatus.ERROR.name(); + for (TestPlanApiDTO dto : testPlanApiDTOList) { + String reportId = dto.getReportId(); + dto.setExecResult(reportResultMap.getOrDefault(reportId, defaultStatus)); + } + } + } catch (Exception e) { + LogUtil.error("解析接口报告数据结构失败!", e); + } + return testPlanApiDTOList; + } + + private ApiPlanReportDTO getApiPlanReport(Map config, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs, ApiReportResultDTO apiReportResult) { + ApiPlanReportDTO report = new ApiPlanReportDTO(); + + if (ServiceUtils.checkConfigEnable(config, "api")) { + List apiAllCases = null; + List scenarioAllCases = null; + if (TestPlanReportUtil.checkReportConfig(config, "api", "all")) { + // 接口 + apiAllCases = getByApiExecReportIds(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct(), apiReportResult.getApiReportResultMap()); + //场景 + scenarioAllCases = getByScenarioExecReportIds(testPlanReportContentWithBLOBs.getPlanScenarioReportStruct(), apiReportResult.getScenarioReportResultMap()); + // this.checkApiCaseCreatorName(apiAllCases, scenarioAllCases); + report.setApiAllCases(apiAllCases); + report.setScenarioAllCases(scenarioAllCases); + } + + //筛选符合配置需要的执行结果的用例和场景 + TestPlanReportUtil.screenApiCaseByStatusAndReportConfig(report, apiAllCases, config); + TestPlanReportUtil.screenScenariosByStatusAndReportConfig(report, scenarioAllCases, config); + } + return report; + } + + public void cleanUpReport(long time, String projectId) { TestPlanExample testPlanExample = new TestPlanExample(); testPlanExample.createCriteria().andProjectIdEqualTo(projectId); @@ -1491,7 +1354,7 @@ public class TestPlanReportService { //更新接口用例、场景用例的最终执行状态 if (!hasErrorCase && StringUtils.isNotEmpty(content.getPlanApiCaseReportStruct())) { try { - List apiTestCases = JSON.parseArray(content.getPlanApiCaseReportStruct(), TestPlanFailureApiDTO.class); + List apiTestCases = JSON.parseArray(content.getPlanApiCaseReportStruct(), TestPlanApiDTO.class); List reportIdList = new ArrayList<>(); apiTestCases.forEach(item -> { if (StringUtils.isNotEmpty(item.getReportId())) { @@ -1500,7 +1363,7 @@ public class TestPlanReportService { }); Map reportResult = planApiDefinitionExecResultService.selectReportResultByReportIds(reportIdList); String defaultStatus = ApiReportStatus.ERROR.name(); - for (TestPlanFailureApiDTO dto : apiTestCases) { + for (TestPlanApiDTO dto : apiTestCases) { String reportId = dto.getReportId(); if (StringUtils.isEmpty(reportId)) { dto.setExecResult(defaultStatus); @@ -1522,7 +1385,7 @@ public class TestPlanReportService { if (!hasErrorCase && StringUtils.isNotEmpty(content.getPlanScenarioReportStruct())) { try { - List scenarioCases = JSON.parseArray(content.getPlanScenarioReportStruct(), TestPlanFailureScenarioDTO.class); + List scenarioCases = JSON.parseArray(content.getPlanScenarioReportStruct(), TestPlanScenarioDTO.class); List reportIdList = new ArrayList<>(); scenarioCases.forEach(item -> { if (StringUtils.isNotEmpty(item.getReportId())) { @@ -1532,7 +1395,7 @@ public class TestPlanReportService { String defaultStatus = ApiReportStatus.ERROR.name(); Map reportStatus = planApiScenarioReportService.getReportStatusByReportIds(reportIdList); - for (TestPlanFailureScenarioDTO dto : scenarioCases) { + for (TestPlanScenarioDTO dto : scenarioCases) { String reportId = dto.getReportId(); if (StringUtils.isNotEmpty(reportId)) { String execStatus = reportStatus.get(reportId); @@ -1613,102 +1476,6 @@ public class TestPlanReportService { return null; } - public TestPlanSimpleReportDTO getReportOpt(String reportId) { - TestPlanReportContentExample example = new TestPlanReportContentExample(); - example.createCriteria().andTestPlanReportIdEqualTo(reportId); - List testPlanReportContents = testPlanReportContentMapper.selectByExampleWithBLOBs(example); - if (CollectionUtils.isEmpty(testPlanReportContents)) { - return null; - } - TestPlanReportContentWithBLOBs testPlanReportContent = testPlanReportContents.get(0); - if (testPlanReportContent == null) { - return null; - } - if (this.isDynamicallyGenerateReports(testPlanReportContent)) { - testPlanReportContent = this.dynamicallyGenerateReports(testPlanReportContent); - } - TestPlanSimpleReportDTO testPlanReportDTO = new TestPlanSimpleReportDTO(); - BeanUtils.copyBean(testPlanReportDTO, testPlanReportContent); - this.generateEnvironmentInfo(testPlanReportDTO, reportId); - - testPlanReportDTO.setFunctionResult( - getReportContentResultObject(testPlanReportContent.getFunctionResult(), TestPlanFunctionResultReportDTO.class) - ); - - testPlanReportDTO.setApiResult( - getReportContentResultObject(testPlanReportContent.getApiResult(), TestPlanApiResultReportDTO.class) - ); - - testPlanReportDTO.setLoadResult( - getReportContentResultObject(testPlanReportContent.getLoadResult(), TestPlanLoadResultReportDTO.class) - ); - - testPlanReportDTO.setFunctionAllCases( - getReportContentResultArray(testPlanReportContent.getFunctionAllCases(), TestPlanCaseDTO.class) - ); - - testPlanReportDTO.setIssueList( - getReportContentResultArray(testPlanReportContent.getIssueList(), IssuesDao.class) - ); - - testPlanReportDTO.setApiAllCases( - getReportContentResultArray(testPlanReportContent.getApiAllCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setApiFailureCases( - getReportContentResultArray(testPlanReportContent.getApiFailureCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setScenarioAllCases( - getReportContentResultArray(testPlanReportContent.getScenarioAllCases(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setScenarioFailureCases( - getReportContentResultArray(testPlanReportContent.getScenarioFailureCases(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setLoadAllCases( - getReportContentResultArray(testPlanReportContent.getLoadAllCases(), TestPlanLoadCaseDTO.class) - ); - - testPlanReportDTO.setLoadFailureCases( - getReportContentResultArray(testPlanReportContent.getLoadFailureCases(), TestPlanLoadCaseDTO.class) - ); - - testPlanReportDTO.setErrorReportCases( - getReportContentResultArray(testPlanReportContent.getErrorReportCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setErrorReportScenarios( - getReportContentResultArray(testPlanReportContent.getErrorReportScenarios(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setUnExecuteCases( - getReportContentResultArray(testPlanReportContent.getUnExecuteCases(), TestPlanFailureApiDTO.class) - ); - - testPlanReportDTO.setUnExecuteScenarios( - getReportContentResultArray(testPlanReportContent.getUnExecuteScenarios(), TestPlanFailureScenarioDTO.class) - ); - - testPlanReportDTO.setUiResult( - getReportContentResultObject(testPlanReportContent.getUiResult(), TestPlanUiResultReportDTO.class) - ); - - testPlanReportDTO.setUiAllCases( - getReportContentResultArray(testPlanReportContent.getUiAllCases(), TestPlanUiScenarioDTO.class) - ); - - testPlanReportDTO.setUiFailureCases( - getReportContentResultArray(testPlanReportContent.getUiFailureCases(), TestPlanUiScenarioDTO.class) - ); - - testPlanReportDTO.setId(reportId); - TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(testPlanReportContent.getTestPlanReportId()); - testPlanReportDTO.setName(testPlanReport.getName()); - return testPlanReportDTO; - } - public void editReport(TestPlanReportContentWithBLOBs reportContentWithBLOBs) { if (StringUtils.isNotBlank(reportContentWithBLOBs.getTestPlanReportId())) { TestPlanReportContentExample example = new TestPlanReportContentExample(); diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java index 301a88e8e3..7ec9e43e4f 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java @@ -22,7 +22,6 @@ import io.metersphere.log.utils.ReflexObjectUtil; import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.track.TestPlanReference; -import io.metersphere.plan.constant.RunMode; import io.metersphere.plan.dto.*; import io.metersphere.plan.job.TestPlanTestJob; import io.metersphere.plan.request.AddTestPlanRequest; @@ -44,6 +43,7 @@ import io.metersphere.plan.service.remote.performance.PerfExecService; import io.metersphere.plan.service.remote.performance.PlanTestPlanLoadCaseService; import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService; import io.metersphere.plan.service.remote.ui.PlanUiAutomationService; +import io.metersphere.plan.utils.TestPlanReportUtil; import io.metersphere.plan.utils.TestPlanRequestUtil; import io.metersphere.request.ScheduleRequest; import io.metersphere.service.*; @@ -485,7 +485,14 @@ public class TestPlanService { return testPlans; } - public void checkStatus(String testPlanId) { // 检查执行结果,自动更新计划状态 + public void checkTestPlanStatusWhenExecuteOver(String testPlanId) { + TestPlan testPlan = this.testPlanMapper.selectByPrimaryKey(testPlanId); + if (testPlan != null && !StringUtils.equalsIgnoreCase(testPlan.getStatus(), "Completed")) { + this.checkTestPlanStatus(testPlanId); + } + } + + public void checkTestPlanStatus(String testPlanId) { // 检查执行结果,自动更新计划状态 List statusList = new ArrayList<>(); statusList.addAll(extTestPlanTestCaseMapper.getExecResultByPlanId(testPlanId)); @@ -883,25 +890,56 @@ public class TestPlanService { LoggerUtil.info("预生成测试计划报告【" + reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY + "】计划报告ID[" + planReportId + "]"); - Map apiCaseReportMap = null; - Map scenarioReportMap = null; + + List apiTestCases = null; + List scenarioCases = null; + List uiScenarios = null; Map loadCaseReportMap = null; - Map uiScenarioReportMap = null; if (MapUtils.isNotEmpty(reportInfoDTO.getApiTestCaseDataMap())) { - //执行接口案例任务 - LoggerUtil.info("开始执行测试计划接口用例 " + planReportId); try { - apiCaseReportMap = this.executeApiTestCase(triggerMode, planReportId, userId, testPlanId, runModeConfig); + apiTestCases = planTestPlanApiCaseService.getFailureListByIds(reportInfoDTO.getApiTestCaseDataMap().keySet()); } catch (Exception e) { - LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划接口用例失败! ", e); + LogUtil.error("测试计划执行查询接口用例失败!", e); } } if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) { + try { + scenarioCases = planTestPlanScenarioCaseService.getFailureListByIds(reportInfoDTO.getPlanScenarioIdMap().keySet()); + } catch (Exception e) { + LogUtil.error("测试计划执行查询场景用例失败!", e); + } + } + if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) { + try { + uiScenarios = planTestPlanUiScenarioCaseService.getFailureListByIds(reportInfoDTO.getPlanScenarioIdMap().keySet()); + } catch (Exception e) { + LogUtil.error("测试计划执行查询UI用例失败!", e); + } + } + + if (CollectionUtils.isNotEmpty(apiTestCases)) { + //执行接口案例任务 + LoggerUtil.info("开始执行测试计划接口用例 " + planReportId); + try { + Map apiCaseReportMap = this.executeApiTestCase(triggerMode, planReportId, userId, testPlanId, runModeConfig); + for (TestPlanApiDTO dto : apiTestCases) { + dto.setReportId(apiCaseReportMap.get(dto.getId())); + } + } catch (Exception e) { + apiTestCases = null; + LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划接口用例失败! ", e); + } + } + if (CollectionUtils.isNotEmpty(scenarioCases)) { //执行场景执行任务 LoggerUtil.info("开始执行测试计划场景用例 " + planReportId); try { - scenarioReportMap = this.executeScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getPlanScenarioIdMap()); + Map scenarioReportMap = this.executeScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getPlanScenarioIdMap()); + for (TestPlanScenarioDTO dto : scenarioCases) { + dto.setReportId(scenarioReportMap.get(dto.getId())); + } } catch (Exception e) { + scenarioCases = null; LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划场景用例失败! ", e); } } @@ -916,19 +954,22 @@ public class TestPlanService { } } - if (reportInfoDTO.getUiScenarioIdMap() != null) { + if (CollectionUtils.isNotEmpty(uiScenarios)) { //执行UI场景执行任务 LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId); try { - uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap()); + Map uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap()); + for (TestPlanUiScenarioDTO dto : uiScenarios) { + dto.setReportId(uiScenarioReportMap.get(dto.getId())); + } } catch (Exception e) { + uiScenarios = null; LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划 UI 用例失败! ", e); } } LoggerUtil.info("开始生成测试计划报告内容 " + planReportId); - testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiCaseReportMap, scenarioReportMap, loadCaseReportMap, uiScenarioReportMap); - + testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiTestCases, scenarioCases, uiScenarios, loadCaseReportMap); return planReportId; } @@ -1245,14 +1286,14 @@ public class TestPlanService { report.setFunctionAllCases(allCases); } - if (checkReportConfig(config, "functional", "issue")) { + if (TestPlanReportUtil.checkReportConfig(config, "functional", "issue")) { List issueList = issuesService.getIssuesByPlanId(planId); report.setIssueList(issueList); } } } - public void buildUiReport(TestPlanSimpleReportDTO report, Map config, String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO, boolean saveResponse) { + public void buildUiReport(TestPlanSimpleReportDTO report, Map config, String planId, TestPlanCaseReportResultDTO testPlanExecuteReportDTO, boolean saveResponse) { ApiPlanReportRequest request = new ApiPlanReportRequest(); request.setConfig(config); request.setPlanId(planId); @@ -1274,16 +1315,16 @@ public class TestPlanService { */ public List getFunctionalReportStatusList(Map config) { List statusList = new ArrayList<>(); - if (checkReportConfig(config, "functional", "all")) { + if (TestPlanReportUtil.checkReportConfig(config, "functional", "all")) { return statusList; } - if (checkReportConfig(config, "functional", "failure")) { + if (TestPlanReportUtil.checkReportConfig(config, "functional", "failure")) { statusList.add(TestPlanTestCaseStatus.Failure.name()); } - if (checkReportConfig(config, "functional", "blocking")) { + if (TestPlanReportUtil.checkReportConfig(config, "functional", "blocking")) { statusList.add(TestPlanTestCaseStatus.Blocking.name()); } - if (checkReportConfig(config, "functional", "skip")) { + if (TestPlanReportUtil.checkReportConfig(config, "functional", "skip")) { statusList.add(TestPlanTestCaseStatus.Skip.name()); } return statusList.size() > 0 ? statusList : null; @@ -1311,89 +1352,50 @@ public class TestPlanService { } } - public void buildApiReport(TestPlanSimpleReportDTO report, Map config, TestPlanExecuteReportDTO testPlanExecuteReportDTO) { - ApiPlanReportRequest request = new ApiPlanReportRequest(); - request.setConfig(config); - request.setTestPlanExecuteReportDTO(testPlanExecuteReportDTO); - if (DiscoveryUtil.hasService(MicroServiceName.API_TEST)) { - ApiPlanReportDTO apiPlanReport = planTestPlanScenarioCaseService.getApiExecuteReport(request); - BeanUtils.copyBean(report, apiPlanReport); - } - } - - private boolean checkReportConfig(Map config, String key, String subKey) { - return ServiceUtils.checkConfigEnable(config, key, subKey); - } - - public void buildLoadReport(TestPlanSimpleReportDTO report, Map config, Map loadCaseReportMap, boolean saveResponse) { - ApiPlanReportRequest request = new ApiPlanReportRequest(); - request.setConfig(config); - request.setSaveResponse(saveResponse); - request.setReportIdMap(loadCaseReportMap); - if (DiscoveryUtil.hasService(MicroServiceName.PERFORMANCE_TEST)) { - LoadPlanReportDTO loadPlanReport = planTestPlanLoadCaseService.getLoadExecuteReport(request); - BeanUtils.copyBean(report, loadPlanReport); - } - } - /** * @param testPlanReport 测试计划报告 * @param testPlanReportContentWithBLOBs 测试计划报告内容 * @return */ - public TestPlanReportBuildResultDTO buildPlanReport(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { + public TestPlanReportBuildResultDTO buildTestPlanReport(TestPlanWithBLOBs testPlan, TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { TestPlanReportBuildResultDTO returnDTO = new TestPlanReportBuildResultDTO(); - TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId()); - if (testPlan != null) { - String reportConfig = testPlan.getReportConfig(); + if (ObjectUtils.allNotNull(testPlanReport, testPlanReportContentWithBLOBs)) { Map config = null; - if (StringUtils.isNotBlank(reportConfig)) { - config = JSON.parseMap(reportConfig); + if (StringUtils.isNotBlank(testPlan.getReportConfig())) { + config = JSON.parseMap(testPlan.getReportConfig()); } - TestPlanExecuteReportDTO testPlanExecuteReportDTO = testPlanReportService.genTestPlanExecuteReportDTOByTestPlanReportContent(testPlanReportContentWithBLOBs); - - TestPlanSimpleReportDTO report = null; - boolean apiBaseInfoChanged = false; - if (StringUtils.isEmpty(testPlanReportContentWithBLOBs.getApiBaseCount())) { - report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO); - apiBaseInfoChanged = true; - } else { - try { - report = JSON.parseObject(testPlanReportContentWithBLOBs.getApiBaseCount(), TestPlanSimpleReportDTO.class); - } catch (Exception e) { - LogUtil.info("解析接口统计数据出错!数据:" + testPlanReportContentWithBLOBs.getApiBaseCount(), e); - } - if (report == null) { - report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO); - apiBaseInfoChanged = true; - } + TestPlanSimpleReportDTO report = this.getTestPlanReportStructByCreated(testPlanReportContentWithBLOBs); + //检查是否有已经生成过的测试计划报告内容。如若没有则进行动态计算 + if (report == null) { + //查询测试计划内的用例信息,然后进行测试计划报告的结果统计 + TestPlanCaseReportResultDTO testPlanExecuteReportDTO = testPlanReportService.selectCaseDetailByTestPlanReport(config, testPlan.getId(), testPlanReportContentWithBLOBs); + report = generateTestPlanReport( + config, + testPlanReport.getCreator(), + StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name(), TestPlanReportStatus.SUCCESS.name(), TestPlanReportStatus.FAILED.name()), + testPlan, testPlanExecuteReportDTO); } - if (report.getFunctionAllCases() == null || report.getIssueList() == null) { - buildFunctionalReport(report, config, testPlanReport.getTestPlanId()); - apiBaseInfoChanged = true; - } - if (report.getApiAllCases() == null && report.getScenarioAllCases() == null) { - buildApiReport(report, config, testPlanExecuteReportDTO); - apiBaseInfoChanged = true; - } - if (report.getLoadAllCases() == null) { - buildLoadReport(report, config, testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap(), false); - apiBaseInfoChanged = true; - } - buildUiReport(report, config, testPlanReport.getTestPlanId(), testPlanExecuteReportDTO, false); returnDTO.setTestPlanSimpleReportDTO(report); - - if (apiBaseInfoChanged) { - testPlanReportContentWithBLOBs.setApiBaseCount(JSON.toJSONString(report)); - returnDTO.setApiBaseInfoChanged(true); - } - return returnDTO; } else { returnDTO.setTestPlanSimpleReportDTO(new TestPlanSimpleReportDTO()); - return returnDTO; } + return returnDTO; } + //获取已生成过的测试计划报告内容 + private TestPlanSimpleReportDTO getTestPlanReportStructByCreated(TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { + TestPlanSimpleReportDTO reportStruct = null; + try { + if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getApiBaseCount())) { + reportStruct = JSON.parseObject(testPlanReportContentWithBLOBs.getApiBaseCount(), TestPlanSimpleReportDTO.class); + } + } catch (Exception e) { + LogUtil.info("解析接口统计数据出错!数据:" + testPlanReportContentWithBLOBs.getApiBaseCount(), e); + } + return reportStruct; + } + + public TestPlanSimpleReportDTO buildPlanReport(String planId, boolean saveResponse) { TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId); @@ -1413,19 +1415,11 @@ public class TestPlanService { public void exportPlanReport(String planId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException { TestPlanSimpleReportDTO report = buildPlanReport(planId, true); report.setLang(lang); - TestPlanExtReportDTO extReport = getExtInfoByPlanId(planId); - if (extReport != null) { - BeanUtils.copyBean(report, extReport); - } render(report, response); } public void exportPlanDbReport(String reportId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException { TestPlanSimpleReportDTO report = testPlanReportService.getReport(reportId); - TestPlanExtReportDTO extReport = getExtInfoByReportId(reportId); - if (extReport != null) { - BeanUtils.copyBean(report, extReport); - } Set serviceIdSet = DiscoveryUtil.getServiceIdSet(); if (serviceIdSet.contains(MicroServiceName.API_TEST)) { report.setApiAllCases(planTestPlanApiCaseService.buildResponse(report.getApiAllCases())); @@ -1494,6 +1488,65 @@ public class TestPlanService { } } + //根据用例运行结果生成测试计划报告 + public TestPlanSimpleReportDTO generateTestPlanReport(Map reportConfig, String operator, boolean isTestPlanReportExecuteOver, TestPlanWithBLOBs testPlan, TestPlanCaseReportResultDTO testPlanCaseReportResultDTO) { + TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO(); + if (ObjectUtils.anyNotNull(testPlan, testPlanCaseReportResultDTO)) { + TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO(); + TestPlanApiResultReportDTO apiResult = new TestPlanApiResultReportDTO(); + TestPlanUiResultReportDTO uiResult = new TestPlanUiResultReportDTO(); + report.setFunctionResult(functionResult); + report.setApiResult(apiResult); + report.setUiResult(uiResult); + report.setStartTime(testPlan.getActualStartTime()); + report.setEndTime(testPlan.getActualEndTime()); + report.setSummary(testPlan.getReportSummary()); + report.setConfig(testPlan.getReportConfig()); + + if (testPlanCaseReportResultDTO.getApiPlanReportDTO() != null) { + BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getApiPlanReportDTO()); + planTestPlanApiCaseService.calculateReportByApiCase(testPlanCaseReportResultDTO.getApiPlanReportDTO().getApiAllCases(), report); + planTestPlanScenarioCaseService.calculateReportByScenario(testPlanCaseReportResultDTO.getApiPlanReportDTO().getScenarioAllCases(), report); + } + if (testPlanCaseReportResultDTO.getLoadPlanReportDTO() != null) { + BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getLoadPlanReportDTO()); + planTestPlanLoadCaseService.calculateReportByLoadCaseList(testPlanCaseReportResultDTO.getLoadPlanReportDTO().getLoadAllCases(), report); + } + if (testPlanCaseReportResultDTO.getUiPlanReportDTO() != null) { + BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getUiPlanReportDTO()); + planTestPlanUiScenarioCaseService.calculateReportByUiScenarios(testPlanCaseReportResultDTO.getUiPlanReportDTO().getUiAllCases(), report); + } + + //功能用例的状态更新以及统计 + testPlanTestCaseService.calculateReportByTestCaseList(operator, testPlan, isTestPlanReportExecuteOver, testPlanCaseReportResultDTO.getFunctionCaseList(), report); + if (report.getFunctionAllCases() == null || report.getIssueList() == null) { + //构建功能用例和issue + this.buildFunctionalReport(report, reportConfig, testPlan.getId()); + } + issuesService.calculateReportByIssueList(testPlanCaseReportResultDTO.getIssueList(), report); + + if (report.getExecuteCount() != 0 && report.getCaseCount() != null) { + report.setExecuteRate(report.getExecuteCount() * 0.1 * 10 / report.getCaseCount()); + } else { + report.setExecuteRate(0.0); + } + if (report.getPassCount() != 0 && report.getCaseCount() != null) { + report.setPassRate(report.getPassCount() * 0.1 * 10 / report.getCaseCount()); + } else { + report.setPassRate(0.0); + } + + report.setName(testPlan.getName()); + Project project = baseProjectService.getProjectById(testPlan.getProjectId()); + if (project.getPlatform() != null && project.getPlatform().equals(IssuesManagePlatform.Local.name())) { + report.setIsThirdPartIssue(false); + } else { + report.setIsThirdPartIssue(true); + } + } + return report; + } + /** * 生成测试计划报告并进行统计 * @@ -1501,7 +1554,7 @@ public class TestPlanService { * @param testPlanExecuteReportDTO 测试计划各个资源的报告。 (如果为空,则取当前测试计划资源的最新报告) * @return */ - public TestPlanSimpleReportDTO getReport(String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO) { + public TestPlanSimpleReportDTO getReport(String planId, TestPlanCaseReportResultDTO testPlanExecuteReportDTO) { TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId); TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO(); TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO(); @@ -2033,132 +2086,6 @@ public class TestPlanService { this.deleteTestPlans(ids); } - public TestPlanExtReportDTO getExtInfoByReportId(String reportId) throws JsonProcessingException { - TestPlanExtReportDTO testPlanExtReportDTO = new TestPlanExtReportDTO(); - Set serviceIdSet = DiscoveryUtil.getServiceIdSet(); - if (serviceIdSet.contains(MicroServiceName.API_TEST)) { - List apiDefinitionLists = planTestPlanApiCaseService.selectExtForPlanReport(reportId); - if (CollectionUtils.isNotEmpty(apiDefinitionLists)) { - ApiDefinitionExecResultWithBLOBs apiDefinition = apiDefinitionLists.get(0); - convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - List apiScenarioLists = planTestPlanApiCaseService.selectExtForPlanScenarioReport(reportId); - if (CollectionUtils.isNotEmpty(apiScenarioLists)) { - ApiScenarioReportWithBLOBs apiScenario = apiScenarioLists.get(0); - convertEnvConfig(apiScenario.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiScenario.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - } - if (serviceIdSet.contains(MicroServiceName.UI_TEST)) { - List apiDefinitionLists = planTestPlanUiScenarioCaseService.selectExtForPlanReport(reportId); - if (CollectionUtils.isNotEmpty(apiDefinitionLists)) { - UiScenarioReportWithBLOBs apiDefinition = apiDefinitionLists.get(0); - convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - } - if (serviceIdSet.contains(MicroServiceName.PERFORMANCE_TEST)) { - TestPlanSimpleReportDTO testPlanSimpleReportDTO = testPlanReportService.getReportOpt(reportId); - if (testPlanSimpleReportDTO != null) { - List loadList = testPlanSimpleReportDTO.getLoadAllCases(); - if (CollectionUtils.isNotEmpty(loadList)) { - String loadReportId = loadList.get(0).getLoadReportId(); - if (StringUtils.isNotEmpty(loadReportId)) { - // 资源池 - String planLoadCaseResourcePoolId = planTestPlanLoadCaseService.getPlanLoadCaseResourcePoolId(loadReportId); - // 运行模式 - TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId); - if (testPlanReport != null && StringUtils.isNotEmpty(testPlanReport.getRunInfo())) { - convertPlanEnvConfig(testPlanReport.getRunInfo(), testPlanExtReportDTO); - } - getResourcePool(planLoadCaseResourcePoolId, testPlanExtReportDTO); - } - } - } - } - return testPlanExtReportDTO; - } - - private void convertEnvConfig(String envConfig, TestPlanExtReportDTO testPlanExtReportDTO) throws JsonProcessingException { - if (StringUtils.isEmpty(envConfig)) { - return; - } - EnvConfig env = objectMapper.readValue(envConfig, EnvConfig.class); - if (StringUtils.isNotEmpty(env.getMode())) { - if (RunMode.RUN_MODE_SERIAL.getCode().equals(env.getMode())) { - testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_SERIAL.getDesc()); - } else if (RunMode.RUN_MODE_PARALLEL.getCode().equals(env.getMode())) { - testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_PARALLEL.getDesc()); - } - } - } - - private void getResourcePool(String actuator, TestPlanExtReportDTO testPlanExtReportDTO) { - if (StringUtils.isEmpty(actuator)) { - return; - } - TestResourcePool testResourcePool = testResourcePoolMapper.selectByPrimaryKey(actuator); - testPlanExtReportDTO.setResourcePool(testResourcePool == null ? null : testResourcePool.getName()); - } - - public TestPlanExtReportDTO getExtInfoByPlanId(String planId) throws JsonProcessingException { - String reportId = testPlanReportService.getLastReportByPlanId(planId); - if (StringUtils.isEmpty(reportId)) { - return null; - } - TestPlanExtReportDTO testPlanExtReportDTO = new TestPlanExtReportDTO(); - Set serviceIdSet = DiscoveryUtil.getServiceIdSet(); - if (serviceIdSet.contains(MicroServiceName.API_TEST)) { - List apiDefinitionLists = planTestPlanApiCaseService.selectExtForPlanReport(reportId); - if (CollectionUtils.isNotEmpty(apiDefinitionLists)) { - ApiDefinitionExecResultWithBLOBs apiDefinition = apiDefinitionLists.get(0); - convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - List apiScenarioLists = planTestPlanApiCaseService.selectExtForPlanScenarioReport(reportId); - if (CollectionUtils.isNotEmpty(apiScenarioLists)) { - ApiScenarioReportWithBLOBs apiScenario = apiScenarioLists.get(0); - convertEnvConfig(apiScenario.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiScenario.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - } - if (serviceIdSet.contains(MicroServiceName.UI_TEST)) { - List apiDefinitionLists = planTestPlanUiScenarioCaseService.selectExtForPlanReport(reportId); - if (CollectionUtils.isNotEmpty(apiDefinitionLists)) { - UiScenarioReportWithBLOBs apiDefinition = apiDefinitionLists.get(0); - convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO); - getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO); - return testPlanExtReportDTO; - } - } - if (serviceIdSet.contains(MicroServiceName.PERFORMANCE_TEST)) { - TestPlanSimpleReportDTO testPlanSimpleReportDTO = testPlanReportService.getReportOpt(reportId); - if (testPlanSimpleReportDTO != null) { - List loadList = testPlanSimpleReportDTO.getLoadAllCases(); - if (CollectionUtils.isNotEmpty(loadList)) { - String loadReportId = loadList.get(0).getLoadReportId(); - if (StringUtils.isNotEmpty(loadReportId)) { - // 资源池 - String planLoadCaseResourcePoolId = planTestPlanLoadCaseService.getPlanLoadCaseResourcePoolId(loadReportId); - // 运行模式 - TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId); - if (testPlanReport != null && StringUtils.isNotEmpty(testPlanReport.getRunInfo())) { - convertPlanEnvConfig(testPlanReport.getRunInfo(), testPlanExtReportDTO); - } - getResourcePool(planLoadCaseResourcePoolId, testPlanExtReportDTO); - } - } - } - } - return testPlanExtReportDTO; - } - public List getRelevanceProjectIds(String planId) { List projectIds = new ArrayList<>(); List apiCaseProjectIds = planTestPlanApiCaseService.getApiCaseProjectIds(planId); @@ -2172,17 +2099,4 @@ public class TestPlanService { return projectIds.stream().distinct().collect(Collectors.toList()); } - private void convertPlanEnvConfig(String envConfig, TestPlanExtReportDTO testPlanExtReportDTO) throws JsonProcessingException { - if (StringUtils.isEmpty(envConfig)) { - return; - } - PlanEnvConfig env = objectMapper.readValue(envConfig, PlanEnvConfig.class); - if (StringUtils.isNotEmpty(env.getRunMode())) { - if (RunMode.RUN_MODE_SERIAL.getCode().equals(env.getRunMode())) { - testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_SERIAL.getDesc()); - } else if (RunMode.RUN_MODE_PARALLEL.getCode().equals(env.getRunMode())) { - testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_PARALLEL.getDesc()); - } - } - } } diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanTestCaseService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanTestCaseService.java index 42a30c7f16..474192a092 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanTestCaseService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanTestCaseService.java @@ -10,18 +10,16 @@ import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.commons.constants.IssueRefType; import io.metersphere.commons.constants.MicroServiceName; import io.metersphere.commons.constants.ProjectApplicationType; - import io.metersphere.commons.exception.MSException; import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.*; import io.metersphere.constants.TestCaseCommentType; -import io.metersphere.dto.ProjectConfig; -import io.metersphere.dto.PlanReportCaseDTO; +import io.metersphere.dto.*; import io.metersphere.excel.constants.TestPlanTestCaseStatus; -import io.metersphere.plan.dto.TestCaseReportStatusResultDTO; -import io.metersphere.plan.dto.TestPlanSimpleReportDTO; import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.OperatingLogDetails; +import io.metersphere.plan.dto.TestCaseReportStatusResultDTO; +import io.metersphere.plan.dto.TestPlanSimpleReportDTO; import io.metersphere.plan.request.function.*; import io.metersphere.plan.service.remote.api.PlanApiAutomationService; import io.metersphere.plan.service.remote.api.PlanApiTestCaseService; @@ -33,20 +31,20 @@ import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.request.OrderRequest; import io.metersphere.request.ResetOrderRequest; import io.metersphere.request.member.QueryMemberRequest; -import io.metersphere.service.*; -import io.metersphere.dto.*; import io.metersphere.request.testcase.TrackCount; import io.metersphere.request.testreview.SaveCommentRequest; +import io.metersphere.service.*; import io.metersphere.utils.DiscoveryUtil; import io.metersphere.xpack.track.dto.IssuesDao; import io.metersphere.xpack.version.service.ProjectVersionService; +import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import jakarta.annotation.Resource; import java.util.*; import java.util.stream.Collectors; @@ -90,6 +88,8 @@ public class TestPlanTestCaseService { private FunctionCaseExecutionInfoService functionCaseExecutionInfoService; @Resource private CustomFieldTestCaseService customFieldTestCaseService; + @Resource + private TestCaseSyncStatusService testCaseSyncStatusService; private static final String CUSTOM_NUM = "custom_num"; private static final String NUM = "num"; @@ -139,10 +139,10 @@ public class TestPlanTestCaseService { public QueryTestPlanCaseRequest setCustomNumOrderParam(QueryTestPlanCaseRequest request) { List orders = ServiceUtils.getDefaultSortOrder(request.getOrders()); // CUSTOM_NUM ORDER - boolean customOrderFlag = orders.stream().anyMatch(order -> StringUtils.equals(order.getName(), CUSTOM_NUM)); + boolean customOrderFlag = orders.stream().anyMatch(order -> StringUtils.equals(order.getName(), CUSTOM_NUM)); if (customOrderFlag) { // 判断当前项目时候开启自定义字段的配置 - boolean customNumEnable = baseProjectApplicationService.checkCustomNumByProjectId(request.getProjectId()); + boolean customNumEnable = baseProjectApplicationService.checkCustomNumByProjectId(request.getProjectId()); orders.forEach(order -> { if (StringUtils.equals(order.getName(), CUSTOM_NUM)) { if (customNumEnable) { @@ -520,24 +520,56 @@ public class TestPlanTestCaseService { return null; } + public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) { try { List planReportCaseDTOS = extTestPlanTestCaseMapper.selectForPlanReport(planId); - TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult(); - List statusResult = new ArrayList<>(); - Map statusResultMap = new HashMap<>(); - - TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, TestPlanTestCaseStatus.Pass.name()); - TestPlanStatusCalculator.addToReportCommonStatusResultList(statusResultMap, statusResult); - - TestPlanStatusCalculator.addToReportStatusResultList(statusResultMap, statusResult, TestPlanTestCaseStatus.Blocking.name()); - TestPlanStatusCalculator.addToReportStatusResultList(statusResultMap, statusResult, TestPlanTestCaseStatus.Skip.name()); - functionResult.setCaseData(statusResult); + this.calculatePlanReport(planReportCaseDTOS, report); } catch (MSException e) { LogUtil.error(e); } } + public void calculateReportByTestCaseList(String operator, TestPlan testPlan, boolean isTestPlanExecuteOver, List testPlanCaseList, TestPlanSimpleReportDTO report) { + try { + if (ObjectUtils.anyNotNull(testPlan, report) && CollectionUtils.isNotEmpty(testPlanCaseList)) { + List planReportCaseDTOList = new ArrayList<>(); + testPlanCaseList.forEach(testPlanCaseDTO -> { + PlanReportCaseDTO planReportCaseDTO = new PlanReportCaseDTO(); + planReportCaseDTO.setId(testPlanCaseDTO.getId()); + planReportCaseDTO.setStatus(testPlanCaseDTO.getStatus()); + planReportCaseDTO.setCaseId(testPlanCaseDTO.getCaseId()); + planReportCaseDTOList.add(planReportCaseDTO); + }); + + if (testPlan.getAutomaticStatusUpdate()) { + if (isTestPlanExecuteOver) { + testCaseSyncStatusService.syncStatusByTestPlanExecuteOver(operator, testPlan.getName(), planReportCaseDTOList, report.getApiAllCases(), report.getScenarioAllCases(), report.getLoadAllCases(), report.getUiAllCases()); + } else { + testCaseSyncStatusService.getTestCaseStatusByTestPlanExecuteOver(planReportCaseDTOList, report.getApiAllCases(), report.getScenarioAllCases(), report.getLoadAllCases(), report.getUiAllCases()); + } + + } + this.calculatePlanReport(planReportCaseDTOList, report); + } + } catch (MSException e) { + LogUtil.error(e); + } + } + + private void calculatePlanReport(List planReportCaseDTOList, TestPlanSimpleReportDTO report) { + TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult(); + List statusResult = new ArrayList<>(); + Map statusResultMap = new HashMap<>(); + + TestPlanStatusCalculator.buildStatusResultMap(planReportCaseDTOList, statusResultMap, report, TestPlanTestCaseStatus.Pass.name()); + TestPlanStatusCalculator.addToReportCommonStatusResultList(statusResultMap, statusResult); + + TestPlanStatusCalculator.addToReportStatusResultList(statusResultMap, statusResult, TestPlanTestCaseStatus.Blocking.name()); + TestPlanStatusCalculator.addToReportStatusResultList(statusResultMap, statusResult, TestPlanTestCaseStatus.Skip.name()); + functionResult.setCaseData(statusResult); + } + public List getAllCasesByStatusList(String planId, List statusList) { return buildCaseInfo(extTestPlanTestCaseMapper.getCasesByStatusList(planId, statusList)); } diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanApiCaseService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanApiCaseService.java index 520b6441a3..23518af72c 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanApiCaseService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanApiCaseService.java @@ -62,6 +62,26 @@ public class PlanTestPlanApiCaseService extends ApiTestService { } } + + public void calculateReportByApiCase(List testPlanApiDTOList, TestPlanSimpleReportDTO report) { + try { + if (CollectionUtils.isNotEmpty(testPlanApiDTOList)) { + List planReportCaseDTOList = new ArrayList<>(); + testPlanApiDTOList.forEach(item -> { + PlanReportCaseDTO dto = new PlanReportCaseDTO(); + dto.setId(item.getId()); + dto.setStatus(item.getExecResult()); + dto.setReportId(item.getReportId()); + dto.setCaseId(item.getCaseId()); + planReportCaseDTOList.add(dto); + }); + calculatePlanReport(report, planReportCaseDTOList); + } + } catch (MSException e) { + LogUtil.error(e); + } + } + public void calculatePlanReport(List apiReportIds, TestPlanSimpleReportDTO report) { try { List planReportCaseDTOS = planApiDefinitionExecResultService.selectForPlanReport(apiReportIds); @@ -153,8 +173,8 @@ public class PlanTestPlanApiCaseService extends ApiTestService { return (Boolean) microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId); } - public List getFailureListByIds(Set ids) { - return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanFailureApiDTO.class); + public List getFailureListByIds(Set ids) { + return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanApiDTO.class); } public Boolean hasFailCase(String planId, List apiCaseIds) { @@ -165,11 +185,11 @@ public class PlanTestPlanApiCaseService extends ApiTestService { return microService.postForDataArray(serviceName, BASE_UEL + "/list/module/" + planId + "/" + protocol, projectIds, ApiModuleDTO.class); } - public List buildResponse(List apiAllCases) { + public List buildResponse(List apiAllCases) { if (CollectionUtils.isEmpty(apiAllCases)) { return null; } - return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", apiAllCases, TestPlanFailureApiDTO.class); + return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", apiAllCases, TestPlanApiDTO.class); } public Object relevanceList(int pageNum, int pageSize, ApiTestCaseRequest request) { diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanScenarioCaseService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanScenarioCaseService.java index 6cc47e4039..f09a7d814c 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanScenarioCaseService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/api/PlanTestPlanScenarioCaseService.java @@ -52,6 +52,23 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService { } } + public void calculateReportByScenario(List testPlanScenarioDTOList, TestPlanSimpleReportDTO report) { + try { + List planReportCaseDTOList = new ArrayList<>(); + testPlanScenarioDTOList.forEach(item -> { + PlanReportCaseDTO dto = new PlanReportCaseDTO(); + dto.setId(item.getId()); + dto.setStatus(item.getLastResult()); + dto.setReportId(item.getReportId()); + dto.setCaseId(item.getCaseId()); + planReportCaseDTOList.add(dto); + }); + calculatePlanReport(report, planReportCaseDTOList); + } catch (MSException e) { + LogUtil.error(e); + } + } + public void calculatePlanReport(List reportIds, TestPlanSimpleReportDTO report) { try { List planReportCaseDTOS = planApiScenarioReportService.selectForPlanReport(reportIds); @@ -69,10 +86,8 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService { TestPlanStatusCalculator.addToReportCommonStatusResultList(statusResultMap, statusResult); TestPlanScenarioStepCountSimpleDTO stepCountResult = getStepCount(planReportCaseDTOS); - TestPlanScenarioStepCountDTO stepCount = stepCountResult.getStepCount(); int underwayStepsCounts = stepCountResult.getUnderwayStepsCounts(); - List stepResult = getStepResult(stepCount, underwayStepsCounts); apiResult.setApiScenarioData(statusResult); apiResult.setApiScenarioStepData(stepResult); @@ -156,16 +171,16 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService { return microService.postForData(serviceName, BASE_UEL + "/plan/report", request, ApiPlanReportDTO.class); } - public ApiPlanReportDTO getApiExecuteReport(ApiPlanReportRequest request) { - return microService.postForData(serviceName, BASE_UEL + "/plan/execute/report", request, ApiPlanReportDTO.class); + public ApiReportResultDTO getApiExecuteReport(ApiPlanReportRequest request) { + return microService.postForData(serviceName, BASE_UEL + "/select/result/by/reportId", request, ApiReportResultDTO.class); } public Boolean isCaseExecuting(String planId) { return microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId, Boolean.class); } - public List getFailureListByIds(Set ids) { - return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanFailureScenarioDTO.class); + public List getFailureListByIds(Set ids) { + return microService.postForDataArray(serviceName, BASE_UEL + "/all/list", ids, TestPlanScenarioDTO.class); } public TestPlanEnvInfoDTO generateEnvironmentInfo(TestPlanReport testPlanReport) { @@ -180,11 +195,11 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService { return microService.postForDataArray(serviceName, BASE_UEL + "/list/module/" + planId, projectIds, ApiScenarioModuleDTO.class); } - public List buildResponse(List scenarioCases) { + public List buildResponse(List scenarioCases) { if (CollectionUtils.isEmpty(scenarioCases)) { return null; } - return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", scenarioCases, TestPlanFailureScenarioDTO.class); + return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", scenarioCases, TestPlanScenarioDTO.class); } public Object relevanceList(ApiScenarioRequest request, int pageNum, int pageSize) { diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/performance/PlanTestPlanLoadCaseService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/performance/PlanTestPlanLoadCaseService.java index 073e8958ad..d540593b61 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/performance/PlanTestPlanLoadCaseService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/performance/PlanTestPlanLoadCaseService.java @@ -15,11 +15,11 @@ import io.metersphere.plan.request.performance.LoadPlanReportDTO; import io.metersphere.plan.service.TestPlanService; import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.utils.DiscoveryUtil; +import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -43,6 +43,23 @@ public class PlanTestPlanLoadCaseService extends LoadTestService { } } + public void calculateReportByLoadCaseList(List testPlanLoadCaseDTOList, TestPlanSimpleReportDTO report) { + try { + List planReportCaseDTOList = new ArrayList<>(); + testPlanLoadCaseDTOList.forEach(item -> { + PlanReportCaseDTO dto = new PlanReportCaseDTO(); + dto.setId(item.getId()); + dto.setStatus(item.getStatus()); + dto.setReportId(item.getReportId()); + dto.setCaseId(item.getId()); + planReportCaseDTOList.add(dto); + }); + calculatePlanReport(report, planReportCaseDTOList); + } catch (MSException e) { + LogUtil.error(e); + } + } + public void calculatePlanReport(List reportIds, TestPlanSimpleReportDTO report) { try { List planReportCaseDTOs = planLoadTestReportService.getPlanReportCaseDTO(reportIds); diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/ui/PlanTestPlanUiScenarioCaseService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/ui/PlanTestPlanUiScenarioCaseService.java index 15656eaefd..d5f08f806f 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/remote/ui/PlanTestPlanUiScenarioCaseService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/remote/ui/PlanTestPlanUiScenarioCaseService.java @@ -17,14 +17,13 @@ import io.metersphere.plan.service.remote.api.PlanUiScenarioReportService; import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.request.ResetOrderRequest; import io.metersphere.utils.DiscoveryUtil; +import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import jakarta.annotation.Resource; - import java.util.*; import java.util.stream.Collectors; @@ -50,6 +49,23 @@ public class PlanTestPlanUiScenarioCaseService extends UiTestService { return microService.postForData(serviceName, BASE_URL + "/plan/report", request, UiPlanReportDTO.class); } + public void calculateReportByUiScenarios(List uiScenarioDTOList, TestPlanSimpleReportDTO report) { + try { + List planReportCaseDTOList = new ArrayList<>(); + uiScenarioDTOList.forEach(item -> { + PlanReportCaseDTO dto = new PlanReportCaseDTO(); + dto.setId(item.getId()); + dto.setStatus(item.getStatus()); + dto.setReportId(item.getReportId()); + dto.setCaseId(item.getId()); + planReportCaseDTOList.add(dto); + }); + calculatePlanReport(report, planReportCaseDTOList); + } catch (MSException e) { + LogUtil.error(e); + } + } + public void calculatePlanReport(List reportIds, TestPlanSimpleReportDTO report) { try { List planReportCaseDTOS = planUiScenarioReportService.selectForPlanReport(reportIds); diff --git a/test-track/backend/src/main/java/io/metersphere/plan/utils/TestCaseSyncStatusUtil.java b/test-track/backend/src/main/java/io/metersphere/plan/utils/TestCaseSyncStatusUtil.java new file mode 100644 index 0000000000..26a111db43 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/utils/TestCaseSyncStatusUtil.java @@ -0,0 +1,264 @@ +package io.metersphere.plan.utils; + +import io.metersphere.base.domain.TestCaseTest; +import io.metersphere.commons.constants.TestPlanStatus; +import io.metersphere.dto.*; +import io.metersphere.i18n.Translator; +import io.metersphere.plan.constant.ApiReportStatus; +import io.metersphere.plan.dto.CaseExecResult; +import io.metersphere.plan.enums.FunctionCaseExecResult; +import io.metersphere.plan.enums.TestCaseReleevanceType; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class TestCaseSyncStatusUtil { + + public static Map getTestCaseStatusByAutomationCaseRunResult( + List testPlanCaseList, + List testCaseTestList, + List apiAllCaseList, + List scenarioAllCaseList, + List loadAllCaseList, + List uiAllCaseList) { + Map testCaseResultMap = new HashMap<>(); + if (CollectionUtils.isNotEmpty(testPlanCaseList) && CollectionUtils.isNotEmpty(testCaseTestList)) { + + + Map> testCaseTestMap = testCaseTestList.stream().collect(Collectors.groupingBy(TestCaseTest::getTestCaseId)); + Map apiExecResultMap = TestCaseSyncStatusUtil.getApiExecResultMap(apiAllCaseList); + Map scenarioExecResultMap = TestCaseSyncStatusUtil.getScenarioExecResultMap(scenarioAllCaseList); + Map loadCaseExecResultMap = TestCaseSyncStatusUtil.getLoadExecResultMap(loadAllCaseList); + Map uiExecResultMap = TestCaseSyncStatusUtil.getUiExecResultMap(uiAllCaseList); + + for (PlanReportCaseDTO testPlanCase : testPlanCaseList) { + if (testCaseTestMap.containsKey(testPlanCase.getCaseId())) { + List relevanceList = testCaseTestMap.get(testPlanCase.getCaseId()); + CaseExecResult priorityResult = getTestCaseExecResultByRelevance(relevanceList, apiExecResultMap, scenarioExecResultMap, loadCaseExecResultMap, uiExecResultMap); + if (priorityResult != null && StringUtils.isNotEmpty(priorityResult.getExecResult())) { + if (StringUtils.equalsIgnoreCase(ApiReportStatus.ERROR.name(), priorityResult.getExecResult())) { + priorityResult.setExecResult(FunctionCaseExecResult.ERROR.toString()); + } else if (StringUtils.equalsIgnoreCase(ApiReportStatus.FAKE_ERROR.name(), priorityResult.getExecResult())) { + priorityResult.setExecResult(FunctionCaseExecResult.BLOCKING.toString()); + } else if (StringUtils.equalsIgnoreCase(ApiReportStatus.SUCCESS.name(), priorityResult.getExecResult())) { + priorityResult.setExecResult(FunctionCaseExecResult.SUCCESS.toString()); + } + testCaseResultMap.put(testPlanCase.getCaseId(), priorityResult); + } + } + } + + } + + return testCaseResultMap; + } + + public static CaseExecResult getTestCaseExecResultByRelevance(List testCaseTestList, + Map apiCaseExecResultMap, + Map scenarioExecResultMap, + Map loadCaseExecResultMap, + Map uiExecResultMap) { + CaseExecResult testCaseExecResult = null; + if (apiCaseExecResultMap == null) { + apiCaseExecResultMap = new HashMap<>(); + } + if (scenarioExecResultMap == null) { + scenarioExecResultMap = new HashMap<>(); + } + if (loadCaseExecResultMap == null) { + loadCaseExecResultMap = new HashMap<>(); + } + if (uiExecResultMap == null) { + uiExecResultMap = new HashMap<>(); + } + + ArrayList statusList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(testCaseTestList)) { + for (TestCaseTest item : testCaseTestList) { + String relevanceId = item.getTestId(); + String relevanceType = item.getTestType(); + if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.API_CASE.toString(), relevanceType)) { + CaseExecResult execResult = apiCaseExecResultMap.get(relevanceId); + if (execResult != null) { + statusList.add(execResult); + } + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.SCENARIO.toString(), relevanceType)) { + CaseExecResult execResult = scenarioExecResultMap.get(relevanceId); + if (execResult != null) { + statusList.add(execResult); + } + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.LOAD_CASE.toString(), relevanceType)) { + CaseExecResult execResult = loadCaseExecResultMap.get(relevanceId); + if (execResult != null) { + statusList.add(execResult); + } + } else if (StringUtils.equalsIgnoreCase(TestCaseReleevanceType.UI_AUTOMATION.toString(), relevanceType)) { + CaseExecResult execResult = uiExecResultMap.get(relevanceId); + if (execResult != null) { + statusList.add(execResult); + } + } + } + } + if (CollectionUtils.isNotEmpty(statusList)) { + testCaseExecResult = getPriorityStatusFromCaseExecResult(statusList.toArray(new CaseExecResult[statusList.size()])); + } + return testCaseExecResult; + } + + public static void updateFunctionCaseStatusByAutomationExecResult(List testPlanCaseList, Map testCaseStatusByAutomationCase) { + if (CollectionUtils.isNotEmpty(testPlanCaseList) && MapUtils.isNotEmpty(testCaseStatusByAutomationCase)) { + for (PlanReportCaseDTO dto : testPlanCaseList) { + if (testCaseStatusByAutomationCase.containsKey(dto.getCaseId())) { + String status = testCaseStatusByAutomationCase.get(dto.getCaseId()).getExecResult(); + dto.setStatus(status); + } + } + } + } + + public static Map getExecResultMap(List caseExecResultList) { + if (CollectionUtils.isEmpty(caseExecResultList)) { + return new HashMap<>(); + } else { + Map returnMap = new HashMap<>(); + caseExecResultList.forEach(item -> { + String id = item.getId(); + if (returnMap.containsKey(id)) { + returnMap.put(id, getPriorityStatusFromCaseExecResult(item, returnMap.get(id))); + } else { + returnMap.put(id, item); + } + }); + return returnMap; + } + } + + public static Map getApiExecResultMap(List apiAllCaseList) { + if (CollectionUtils.isEmpty(apiAllCaseList)) { + return new HashMap<>(); + } else { + Map returnMap = new HashMap<>(); + apiAllCaseList.forEach(item -> { + String id = item.getCaseId(); + CaseExecResult execResult = new CaseExecResult(); + execResult.setId(item.getId()); + execResult.setReportId(item.getReportId()); + execResult.setExecResult(item.getExecResult()); + execResult.setCaseName(item.getName()); + if (returnMap.containsKey(id)) { + returnMap.put(id, getPriorityStatusFromCaseExecResult(execResult, returnMap.get(id))); + } else { + returnMap.put(id, execResult); + } + }); + return returnMap; + } + } + + public static Map getScenarioExecResultMap(List scenarioAllCaseList) { + if (CollectionUtils.isEmpty(scenarioAllCaseList)) { + return new HashMap<>(); + } else { + Map returnMap = new HashMap<>(); + scenarioAllCaseList.forEach(item -> { + String id = item.getCaseId(); + CaseExecResult execResult = new CaseExecResult(); + execResult.setId(item.getId()); + execResult.setReportId(item.getReportId()); + execResult.setExecResult(item.getLastResult()); + execResult.setCaseName(item.getName()); + if (returnMap.containsKey(id)) { + returnMap.put(id, getPriorityStatusFromCaseExecResult(execResult, returnMap.get(id))); + } else { + returnMap.put(id, execResult); + } + }); + return returnMap; + } + } + + public static Map getLoadExecResultMap(List loadAllCaseList) { + if (CollectionUtils.isEmpty(loadAllCaseList)) { + return new HashMap<>(); + } else { + Map returnMap = new HashMap<>(); + loadAllCaseList.forEach(item -> { + String id = item.getLoadCaseId(); + CaseExecResult execResult = new CaseExecResult(); + execResult.setId(item.getId()); + execResult.setReportId(item.getReportId()); + execResult.setExecResult(item.getStatus()); + execResult.setCaseName(item.getName()); + if (returnMap.containsKey(id)) { + returnMap.put(id, getPriorityStatusFromCaseExecResult(execResult, returnMap.get(id))); + } else { + returnMap.put(id, execResult); + } + }); + return returnMap; + } + } + + public static Map getUiExecResultMap(List uiAllCaseList) { + if (CollectionUtils.isEmpty(uiAllCaseList)) { + return new HashMap<>(); + } else { + Map returnMap = new HashMap<>(); + uiAllCaseList.forEach(item -> { + String id = item.getCaseId(); + CaseExecResult execResult = new CaseExecResult(); + execResult.setId(item.getId()); + execResult.setReportId(item.getReportId()); + execResult.setExecResult(item.getLastResult()); + execResult.setCaseName(item.getName()); + if (returnMap.containsKey(id)) { + returnMap.put(id, getPriorityStatusFromCaseExecResult(execResult, returnMap.get(id))); + } else { + returnMap.put(id, execResult); + } + }); + return returnMap; + } + } + + //获取更高优先级的状态 error优先级最高,其次是fake_error。 + public static CaseExecResult getPriorityStatusFromCaseExecResult(CaseExecResult... execResults) { + CaseExecResult errorStatus = null; + CaseExecResult fakeErrorStatus = null; + CaseExecResult successStatus = null; + CaseExecResult lastNotNullStatus = null; + boolean hasNoneStatus = false; + for (CaseExecResult execResult : execResults) { + if (StringUtils.equalsIgnoreCase(ApiReportStatus.ERROR.name(), execResult.getExecResult())) { + errorStatus = execResult; + } else if (StringUtils.equalsIgnoreCase(ApiReportStatus.FAKE_ERROR.name(), execResult.getExecResult())) { + fakeErrorStatus = execResult; + } else if (StringUtils.equalsAnyIgnoreCase(execResult.getExecResult(), ApiReportStatus.FAKE_ERROR.name(), TestPlanStatus.Completed.name())) { + successStatus = execResult; + } else if (StringUtils.isEmpty(execResult.getExecResult())) { + hasNoneStatus = true; + } else { + lastNotNullStatus = execResult; + } + } + if (hasNoneStatus) { + //存在未执行的状态,优先返回空 + return null; + } else { + return errorStatus != null ? errorStatus : + fakeErrorStatus != null ? fakeErrorStatus : + successStatus != null ? successStatus : lastNotNullStatus; + } + } + + public static String generateCommentDesc(String testPlanName, String caseName, String status) { + return String.format(Translator.get("test_case_sync_status_comment"), caseName, testPlanName, status); + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/plan/utils/TestPlanReportUtil.java b/test-track/backend/src/main/java/io/metersphere/plan/utils/TestPlanReportUtil.java new file mode 100644 index 0000000000..d25bb822e0 --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/plan/utils/TestPlanReportUtil.java @@ -0,0 +1,154 @@ +package io.metersphere.plan.utils; + +import io.metersphere.base.domain.TestPlanReportContentWithBLOBs; +import io.metersphere.commons.utils.JSON; +import io.metersphere.dto.*; +import io.metersphere.plan.constant.ApiReportStatus; +import io.metersphere.plan.dto.ApiPlanReportDTO; +import io.metersphere.plan.dto.TestPlanSimpleReportDTO; +import io.metersphere.service.ServiceUtils; +import io.metersphere.xpack.track.dto.IssuesDao; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class TestPlanReportUtil { + public static void initCaseExecuteInfoToDTO(TestPlanSimpleReportDTO testPlanReportDTO, TestPlanReportContentWithBLOBs testPlanReportContent) { + testPlanReportDTO.setFunctionAllCases( + getReportContentResultArray(testPlanReportContent.getFunctionAllCases(), TestPlanCaseDTO.class) + ); + testPlanReportDTO.setIssueList( + getReportContentResultArray(testPlanReportContent.getIssueList(), IssuesDao.class) + ); + testPlanReportDTO.setFunctionResult( + getReportContentResultObject(testPlanReportContent.getFunctionResult(), TestPlanFunctionResultReportDTO.class) + ); + testPlanReportDTO.setApiResult( + getReportContentResultObject(testPlanReportContent.getApiResult(), TestPlanApiResultReportDTO.class) + ); + testPlanReportDTO.setLoadResult( + getReportContentResultObject(testPlanReportContent.getLoadResult(), TestPlanLoadResultReportDTO.class) + ); + testPlanReportDTO.setFunctionAllCases( + getReportContentResultArray(testPlanReportContent.getFunctionAllCases(), TestPlanCaseDTO.class) + ); + testPlanReportDTO.setIssueList( + getReportContentResultArray(testPlanReportContent.getIssueList(), IssuesDao.class) + ); + testPlanReportDTO.setApiAllCases( + getReportContentResultArray(testPlanReportContent.getApiAllCases(), TestPlanApiDTO.class) + ); + testPlanReportDTO.setApiFailureCases( + getReportContentResultArray(testPlanReportContent.getApiFailureCases(), TestPlanApiDTO.class) + ); + testPlanReportDTO.setScenarioAllCases( + getReportContentResultArray(testPlanReportContent.getScenarioAllCases(), TestPlanScenarioDTO.class) + ); + testPlanReportDTO.setScenarioFailureCases( + getReportContentResultArray(testPlanReportContent.getScenarioFailureCases(), TestPlanScenarioDTO.class) + ); + testPlanReportDTO.setLoadAllCases( + getReportContentResultArray(testPlanReportContent.getLoadAllCases(), TestPlanLoadCaseDTO.class) + ); + testPlanReportDTO.setLoadFailureCases( + getReportContentResultArray(testPlanReportContent.getLoadFailureCases(), TestPlanLoadCaseDTO.class) + ); + testPlanReportDTO.setErrorReportCases( + getReportContentResultArray(testPlanReportContent.getErrorReportCases(), TestPlanApiDTO.class) + ); + testPlanReportDTO.setErrorReportScenarios( + getReportContentResultArray(testPlanReportContent.getErrorReportScenarios(), TestPlanScenarioDTO.class) + ); + testPlanReportDTO.setUnExecuteCases( + getReportContentResultArray(testPlanReportContent.getUnExecuteCases(), TestPlanApiDTO.class) + ); + testPlanReportDTO.setUnExecuteScenarios( + getReportContentResultArray(testPlanReportContent.getUnExecuteScenarios(), TestPlanScenarioDTO.class) + ); + testPlanReportDTO.setUiResult( + getReportContentResultObject(testPlanReportContent.getUiResult(), TestPlanUiResultReportDTO.class) + ); + testPlanReportDTO.setUiAllCases( + getReportContentResultArray(testPlanReportContent.getUiAllCases(), TestPlanUiScenarioDTO.class) + ); + testPlanReportDTO.setUiFailureCases( + getReportContentResultArray(testPlanReportContent.getUiFailureCases(), TestPlanUiScenarioDTO.class) + ); + } + + public static boolean checkReportConfig(Map config, String key, String subKey) { + return ServiceUtils.checkConfigEnable(config, key, subKey); + } + + public static void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List apiAllCases, Map reportConfig) { + if (!CollectionUtils.isEmpty(apiAllCases)) { + List apiFailureCases = new ArrayList<>(); + List apiErrorReportCases = new ArrayList<>(); + List apiUnExecuteCases = new ArrayList<>(); + for (TestPlanApiDTO apiDTO : apiAllCases) { + if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.ERROR.name())) { + apiFailureCases.add(apiDTO); + } else if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.FAKE_ERROR.name())) { + apiErrorReportCases.add(apiDTO); + } else if (StringUtils.equalsAnyIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.STOPPED.name(), + ApiReportStatus.PENDING.name())) { + apiUnExecuteCases.add(apiDTO); + } + } + + if (checkReportConfig(reportConfig, "api", "failure")) { + report.setApiFailureCases(apiFailureCases); + } + if (checkReportConfig(reportConfig, "api", ApiReportStatus.FAKE_ERROR.name())) { + report.setErrorReportCases(apiErrorReportCases); + } + if (checkReportConfig(reportConfig, "api", ApiReportStatus.PENDING.name())) { + report.setUnExecuteCases(apiUnExecuteCases); + } + } + } + + public static void screenScenariosByStatusAndReportConfig(ApiPlanReportDTO report, List scenarios, Map reportConfig) { + if (!CollectionUtils.isEmpty(scenarios)) { + List failureScenarios = new ArrayList<>(); + List errorReportScenarios = new ArrayList<>(); + List unExecuteScenarios = new ArrayList<>(); + for (TestPlanScenarioDTO scenario : scenarios) { + if (StringUtils.equalsAnyIgnoreCase(scenario.getLastResult(), ApiReportStatus.ERROR.name())) { + failureScenarios.add(scenario); + } else if (StringUtils.equalsIgnoreCase(scenario.getLastResult(), ApiReportStatus.FAKE_ERROR.name())) { + errorReportScenarios.add(scenario); + } else if (StringUtils.equalsAnyIgnoreCase(scenario.getLastResult(), ApiReportStatus.STOPPED.name(), + ApiReportStatus.PENDING.name())) { + unExecuteScenarios.add(scenario); + } + } + if (checkReportConfig(reportConfig, "api", "failure")) { + report.setScenarioFailureCases(failureScenarios); + } + if (checkReportConfig(reportConfig, "api", ApiReportStatus.FAKE_ERROR.name())) { + report.setErrorReportScenarios(errorReportScenarios); + } + if (checkReportConfig(reportConfig, "api", ApiReportStatus.PENDING.name())) { + report.setUnExecuteScenarios(unExecuteScenarios); + } + } + } + + private static T getReportContentResultObject(String contentStr, Class clazz) { + if (StringUtils.isNotBlank(contentStr)) { + return JSON.parseObject(contentStr, clazz); + } + return null; + } + + private static List getReportContentResultArray(String contentStr, Class clazz) { + if (StringUtils.isNotBlank(contentStr)) { + return JSON.parseArray(contentStr, clazz); + } + return null; + } +} diff --git a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java index 77942ec27e..2f23706efa 100644 --- a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java +++ b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java @@ -53,7 +53,6 @@ import io.metersphere.service.remote.project.TrackIssueTemplateService; import io.metersphere.service.wapper.TrackProjectService; import io.metersphere.service.wapper.UserService; import io.metersphere.utils.DistinctKeyUtil; -import io.metersphere.xpack.track.dto.AttachmentRequest; import io.metersphere.xpack.track.dto.PlatformStatusDTO; import io.metersphere.xpack.track.dto.PlatformUser; import io.metersphere.xpack.track.dto.*; @@ -61,6 +60,8 @@ import io.metersphere.xpack.track.dto.request.IssuesRequest; import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest; import io.metersphere.xpack.track.issue.IssuesPlatform; import io.metersphere.xpack.track.service.XpackIssueService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.BooleanUtils; @@ -75,8 +76,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.*; @@ -797,7 +796,7 @@ public class IssuesService { List testCaseIssues = testCaseIssuesMapper.selectByExample(example); List caseIds = testCaseIssues.stream().map(x -> - x.getRefType().equals(IssueRefType.PLAN_FUNCTIONAL.name()) ? x.getRefId() : x.getResourceId()) + x.getRefType().equals(IssueRefType.PLAN_FUNCTIONAL.name()) ? x.getRefId() : x.getResourceId()) .collect(Collectors.toList()); List notInTrashCase = testCaseService.getTestCaseByIds(caseIds); @@ -1083,25 +1082,25 @@ public class IssuesService { private void deleteSyncAttachment(AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper, Set platformAttachmentSet, List allMsAttachments) { - try { - // 删除Jira中不存在的附件 - if (CollectionUtils.isNotEmpty(allMsAttachments)) { - List deleteMsAttachments = allMsAttachments.stream() - .filter(msAttachment -> !platformAttachmentSet.contains(msAttachment.getName())) - .collect(Collectors.toList()); - deleteMsAttachments.forEach(fileAttachmentMetadata -> { - List ids = List.of(fileAttachmentMetadata.getId()); - AttachmentModuleRelationExample example = new AttachmentModuleRelationExample(); - example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type()); - // 删除MS附件及关联数据 - attachmentService.deleteAttachmentByIds(ids); - attachmentService.deleteFileAttachmentByIds(ids); - batchAttachmentModuleRelationMapper.deleteByExample(example); - }); - } - } catch (Exception e) { - LogUtil.error(e); - } + try { + // 删除Jira中不存在的附件 + if (CollectionUtils.isNotEmpty(allMsAttachments)) { + List deleteMsAttachments = allMsAttachments.stream() + .filter(msAttachment -> !platformAttachmentSet.contains(msAttachment.getName())) + .collect(Collectors.toList()); + deleteMsAttachments.forEach(fileAttachmentMetadata -> { + List ids = List.of(fileAttachmentMetadata.getId()); + AttachmentModuleRelationExample example = new AttachmentModuleRelationExample(); + example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type()); + // 删除MS附件及关联数据 + attachmentService.deleteAttachmentByIds(ids); + attachmentService.deleteFileAttachmentByIds(ids); + batchAttachmentModuleRelationMapper.deleteByExample(example); + }); + } + } catch (Exception e) { + LogUtil.error(e); + } } private void saveAttachmentModuleRelation(Platform platform, String issueId, @@ -1225,14 +1224,34 @@ public class IssuesService { abstractPlatform.userAuth(authUserIssueRequest); } + + public void calculateReportByIssueList(List issueList, TestPlanSimpleReportDTO report) { + if (CollectionUtils.isNotEmpty(issueList)) { + List planReportIssueDTOList = new ArrayList<>(); + issueList.forEach(issue -> { + PlanReportIssueDTO issueDTO = new PlanReportIssueDTO(); + issueDTO.setId(issue.getId()); + issueDTO.setStatus(issue.getStatus()); + issueDTO.setPlatform(issue.getPlatform()); + issueDTO.setPlatformStatus(issue.getPlatformStatus()); + planReportIssueDTOList.add(issueDTO); + }); + this.calculatePlanReport(planReportIssueDTOList, report); + } + } + public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) { - List planReportIssueDTOS = extIssuesMapper.selectForPlanReport(planId); - planReportIssueDTOS = DistinctKeyUtil.distinctByKey(planReportIssueDTOS, PlanReportIssueDTO::getId); + List planReportIssueDTOList = extIssuesMapper.selectForPlanReport(planId); + this.calculatePlanReport(planReportIssueDTOList, report); + } + + public void calculatePlanReport(List planReportIssueDTOList, TestPlanSimpleReportDTO report) { + planReportIssueDTOList = DistinctKeyUtil.distinctByKey(planReportIssueDTOList, PlanReportIssueDTO::getId); TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult(); List statusResult = new ArrayList<>(); Map statusResultMap = new HashMap<>(); - planReportIssueDTOS.forEach(item -> { + planReportIssueDTOList.forEach(item -> { String status; // 本地缺陷 if (StringUtils.equalsIgnoreCase(item.getPlatform(), IssuesManagePlatform.Local.name()) diff --git a/test-track/backend/src/main/java/io/metersphere/utils/BatchProcessingUtil.java b/test-track/backend/src/main/java/io/metersphere/utils/BatchProcessingUtil.java new file mode 100644 index 0000000000..836c2a898b --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/utils/BatchProcessingUtil.java @@ -0,0 +1,50 @@ +package io.metersphere.utils; + +import io.metersphere.base.domain.TestCaseTest; +import io.metersphere.base.domain.TestCaseTestExample; +import org.apache.commons.collections.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * 批量处理工具 + */ +public class BatchProcessingUtil { + + private static final int BATCH_PROCESS_QUANTITY = 2000; + + public static List selectTestCaseTestByPrimaryKey(List primaryKeyList, Function> func) { + List returnList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(primaryKeyList)) { + TestCaseTestExample example = new TestCaseTestExample(); + int unProcessingCount = primaryKeyList.size(); + while (primaryKeyList.size() > BATCH_PROCESS_QUANTITY) { + example.clear(); + List processingList = new ArrayList<>(); + for (int i = 0; i < BATCH_PROCESS_QUANTITY; i++) { + processingList.add(primaryKeyList.get(i)); + } + //函数处理 + example.createCriteria().andTestCaseIdIn(processingList); + returnList.addAll(func.apply(example)); + + primaryKeyList.removeAll(processingList); + if (primaryKeyList.size() == unProcessingCount) { + //如果剩余数量没有发生变化,则跳出循环。防止出现死循环的情况 + break; + } else { + unProcessingCount = primaryKeyList.size(); + } + } + if (CollectionUtils.isNotEmpty(primaryKeyList)) { + example.clear(); + //剩余待处理数据进行处理 + example.createCriteria().andTestCaseIdIn(primaryKeyList); + returnList.addAll(func.apply(example)); + } + } + return returnList; + } +} diff --git a/test-track/backend/src/main/resources/i18n/messages_en_US.properties b/test-track/backend/src/main/resources/i18n/messages_en_US.properties index a952d85eec..d23938ad2d 100644 --- a/test-track/backend/src/main/resources/i18n/messages_en_US.properties +++ b/test-track/backend/src/main/resources/i18n/messages_en_US.properties @@ -211,7 +211,6 @@ custom_field_select_tip=[%s] must be %s no_legitimate_case_tip=Import fails without legitimate use cases! no_legitimate_issue_tip=Import fails without legitimate issues! zentao_test_type_error=invalid Zentao request - test_case_status_prepare=Prepare test_case_status_running=Running test_case_status_finished=Finished @@ -219,16 +218,13 @@ test_case_status_error=Error test_case_status_success=Success test_case_status_trash=Trash test_case_status_saved=Saved - execute_not_pass=Not pass execute_pass=Pass jira_auth_error=Account name or password (Token) is wrong jira_auth_url_error=The test connection failed, please check whether the Jira address is correct - platform_plugin_not_exit=Platform docking function has been plug-in, please download the corresponding version of the plug-in: plan_warning=The test plan does not have an associated executable use case test_plan_delete_exec_error=The test plan is being executed - - test_case_review_status_underway=Underway test_case_review_status_re_review=ReReview +api_status_fake_error=Fake error diff --git a/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties b/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties index 75ecda01e7..e81818b84a 100644 --- a/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/test-track/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -129,7 +129,6 @@ issue_project_not_exist=ID不存在或其它错误 tapd_project_not_exist=关联的TAPD项目ID不存在 zentao_get_project_builds_fail=获取影响版本错误 zentao_project_id_not_exist=关联的禅道ID不存在或其它错误 - import_xmind_count_error=思维导图导入用例数量不能超过 800 条 license_valid_license_error=授权认证失败 import_xmind_not_found=未找到测试用例 @@ -187,19 +186,17 @@ custom_field_member_tip=[%s]必须当前项目成员 custom_field_select_tip=[%s]必须为%s no_legitimate_case_tip=导入失败,没有合法用例! no_legitimate_issue_tip=导入失败,没有合法缺陷! - test_case_status_prepare=未开始 test_case_status_running=进行中 test_case_status_finished=已完成 - execute_not_pass=未通过 execute_pass=通过 jira_auth_error=账号名或密码(Token)错误 jira_auth_url_error=测试连接失败,请检查Jira地址是否正确 - platform_plugin_not_exit=平台对接功能已插件化,请下载对应版本的插件: plan_warning=测试计划没有关联可执行的用例 test_plan_delete_exec_error=测试计划正在执行中 - test_case_review_status_underway=评审中 test_case_review_status_re_review=重新提审 +api_status_fake_error=误报 +test_case_sync_status_comment=关联的case %s 在测试计划【%s】内的执行结果出现%s。 diff --git a/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties b/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties index 499ca39e5a..a6bbb0ff9d 100644 --- a/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/test-track/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -129,7 +129,6 @@ issue_project_not_exist=ID不存在或其它錯誤 tapd_project_not_exist=關聯的TAPD項目ID不存在 zentao_get_project_builds_fail=獲取影響版本錯誤 zentao_project_id_not_exist=關聯的禪道ID不存在或其它錯誤 - import_xmind_count_error=思維導圖導入用例數量不能超過 800 條 license_valid_license_error=授權認證失敗 import_xmind_not_found=未找到測試用例 @@ -187,21 +186,16 @@ custom_field_member_tip=[%s]必須當前項目成員 custom_field_select_tip=[%s]必須為%s no_legitimate_case_tip=導入失敗,沒有合法用例! no_legitimate_issue_tip=導入失敗,沒有合法缺陷! - - test_case_status_prepare=未開始 test_case_status_running=進行中 test_case_status_finished=已完成 - execute_not_pass=未通過 execute_pass=通過 jira_auth_error=賬號名或密碼(Token)錯誤 jira_auth_url_error=測試連接失敗,請檢查Jira地址是否正確 - platform_plugin_not_exit=平臺對接功能已插件化,請下載對應版本的插件: plan_warning=測試計劃沒有關聯可執行的用例 test_plan_delete_exec_error=測試計劃正在執行中 - - test_case_review_status_underway=評審中 test_case_review_status_re_review=重新提審 +api_status_fake_error=誤報 diff --git a/test-track/frontend/src/business/plan/view/comonents/report/detail/TestPlanReportContent.vue b/test-track/frontend/src/business/plan/view/comonents/report/detail/TestPlanReportContent.vue index be843ebbe9..7416d6c7dd 100644 --- a/test-track/frontend/src/business/plan/view/comonents/report/detail/TestPlanReportContent.vue +++ b/test-track/frontend/src/business/plan/view/comonents/report/detail/TestPlanReportContent.vue @@ -1,20 +1,72 @@