refactor(测试跟踪): 测试计划报告性能优化

--story=1011161 --user=宋天阳 测试计划报告性能优化
https://www.tapd.cn/55049933/s/1346616
This commit is contained in:
song-tianyang 2023-02-27 16:58:19 +08:00 committed by 建国
parent e68d64924b
commit 38b7175b61
76 changed files with 2202 additions and 1266 deletions

View File

@ -8,7 +8,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureApiDTO extends TestPlanApiCaseDTO { public class TestPlanApiDTO extends TestPlanApiCaseDTO {
private String response; private String response;
private String reportId; private String reportId;
} }

View File

@ -7,6 +7,6 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureScenarioDTO extends ApiScenarioDTO { public class TestPlanScenarioDTO extends ApiScenarioDTO {
private ApiScenarioReportResult response; private ApiScenarioReportResult response;
} }

View File

@ -1,8 +1,8 @@
package io.metersphere.api.dto.plan; package io.metersphere.api.dto.plan;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; import io.metersphere.api.dto.automation.TestPlanApiDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; import io.metersphere.api.dto.automation.TestPlanScenarioDTO;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -11,13 +11,13 @@ import java.util.List;
@Setter @Setter
@Getter @Getter
public class ApiPlanReportDTO { public class ApiPlanReportDTO {
private List<TestPlanFailureApiDTO> apiAllCases; private List<TestPlanApiDTO> apiAllCases;
private List<TestPlanFailureApiDTO> apiFailureCases; private List<TestPlanApiDTO> apiFailureCases;
private List<TestPlanFailureApiDTO> errorReportCases; private List<TestPlanApiDTO> errorReportCases;
private List<TestPlanFailureApiDTO> unExecuteCases; private List<TestPlanApiDTO> unExecuteCases;
private List<TestPlanFailureScenarioDTO> scenarioAllCases; private List<TestPlanScenarioDTO> scenarioAllCases;
private List<TestPlanFailureScenarioDTO> scenarioFailureCases; private List<TestPlanScenarioDTO> scenarioFailureCases;
private List<TestPlanFailureScenarioDTO> errorReportScenarios; private List<TestPlanScenarioDTO> errorReportScenarios;
private List<TestPlanFailureScenarioDTO> unExecuteScenarios; private List<TestPlanScenarioDTO> unExecuteScenarios;
} }

View File

@ -5,8 +5,12 @@ import io.metersphere.request.PlanSubReportRequest;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Setter @Setter
@Getter @Getter
public class ApiPlanReportRequest extends PlanSubReportRequest { public class ApiPlanReportRequest extends PlanSubReportRequest {
List<String> apiReportIdList;
List<String> scenarioReportIdList;
private TestPlanExecuteReportDTO testPlanExecuteReportDTO; private TestPlanExecuteReportDTO testPlanExecuteReportDTO;
} }

View File

@ -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 {
// <reportId status>接口报告结果
Map<String, String> apiReportResultMap;
// <reportId status>场景报告结果
Map<String, String> scenarioReportResultMap;
}

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.plan; package io.metersphere.api.dto.plan;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO; import io.metersphere.api.dto.automation.TestPlanApiDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO; import io.metersphere.api.dto.automation.TestPlanScenarioDTO;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -16,6 +16,6 @@ import java.util.Map;
public class TestPlanExecuteReportDTO { public class TestPlanExecuteReportDTO {
private Map<String, String> testPlanApiCaseIdAndReportIdMap; private Map<String, String> testPlanApiCaseIdAndReportIdMap;
private Map<String, String> testPlanScenarioIdAndReportIdMap; private Map<String, String> testPlanScenarioIdAndReportIdMap;
private Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap; private Map<String, TestPlanApiDTO> apiCaseInfoDTOMap;
private Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap; private Map<String, TestPlanScenarioDTO> scenarioInfoDTOMap;
} }

View File

@ -91,10 +91,8 @@ public class KafkaListenerTask implements Runnable {
// 全局并发队列 // 全局并发队列
PoolExecBlockingQueueUtil.offer(testResult.getReportId()); PoolExecBlockingQueueUtil.offer(testResult.getReportId());
// 更新测试计划报告 // 更新测试计划报告
if (StringUtils.isNotEmpty(testResult.getTestPlanReportId())) { LoggerUtil.info("Check Processing Test Plan report status" + testResult.getQueueId() + "" + testResult.getTestId(), testResult.getReportId());
LoggerUtil.info("Check Processing Test Plan report status" + testResult.getQueueId() + "" + testResult.getTestId(), testResult.getReportId()); apiExecutionQueueService.checkTestPlanCaseTestEnd(testResult.getTestId(), testResult.getRunMode(), testResult.getTestPlanReportId());
apiExecutionQueueService.testPlanReportTestEnded(testResult.getTestPlanReportId());
}
}); });
} }
} catch (Exception e) { } catch (Exception e) {

View File

@ -115,10 +115,8 @@ public class MsApiBackendListener extends AbstractBackendListenerClient implemen
apiExecutionQueueService.queueNext(dto); apiExecutionQueueService.queueNext(dto);
} }
// 更新测试计划报告 // 更新测试计划报告
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) { LoggerUtil.info("Check Processing Test Plan report status" + dto.getQueueId() + "" + dto.getTestId());
LoggerUtil.info("Check Processing Test Plan report status" + dto.getQueueId() + "" + dto.getTestId()); apiExecutionQueueService.checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId());
apiExecutionQueueService.testPlanReportTestEnded(dto.getTestPlanReportId());
}
LoggerUtil.info("TEST-END处理结果集完成", dto.getReportId()); LoggerUtil.info("TEST-END处理结果集完成", dto.getReportId());
JvmUtil.memoryInfo(); JvmUtil.memoryInfo();

View File

@ -15,4 +15,6 @@ public interface ExtApiScenarioReportResultMapper {
List<String> selectDistinctStatusByReportId(String reportId); List<String> selectDistinctStatusByReportId(String reportId);
int deleteByProjectId(String projectId); int deleteByProjectId(String projectId);
List<ApiScenarioReportResultWithBLOBs> selectIdAndStatusByReportIdList(@Param("ids") List<String> scenarioReportIdList);
} }

View File

@ -38,4 +38,13 @@
FROM api_scenario_report_result FROM api_scenario_report_result
WHERE report_id = #{0} WHERE report_id = #{0}
</select> </select>
<select id="selectIdAndStatusByReportIdList" resultType="io.metersphere.base.domain.ApiScenarioReportResultWithBLOBs">
SELECT t.id,t.status,t.base_info FROM api_scenario_report_result t
where t.report_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper> </mapper>

View File

@ -1,8 +1,8 @@
package io.metersphere.base.mapper.plan.ext; package io.metersphere.base.mapper.plan.ext;
import io.metersphere.api.dto.QueryReferenceRequest; 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.TestPlanDTO;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest; import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO; import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO; import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO;
@ -39,9 +39,9 @@ public interface ExtTestPlanApiCaseMapper {
List<Map> selectForPlanReport(String planId); List<Map> selectForPlanReport(String planId);
List<TestPlanFailureApiDTO> getFailureList(@Param("planId") String planId, @Param("status") String status); List<TestPlanApiDTO> getFailureList(@Param("planId") String planId, @Param("status") String status);
List<TestPlanFailureApiDTO> getFailureListByIds(@Param("ids") Collection<String> caseIdList, @Param("status") String status); List<TestPlanApiDTO> getFailureListByIds(@Param("ids") Collection<String> caseIdList, @Param("status") String status);
List<String> selectPlanIds(); List<String> selectPlanIds();

View File

@ -366,7 +366,7 @@
!= 'Trash' != 'Trash'
) )
</select> </select>
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanFailureApiDTO"> <select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanApiDTO">
select select
t.id, t.id,
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_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 where t.test_plan_id = #{planId} ORDER BY t.order DESC
</select> </select>
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanFailureApiDTO"> <select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanApiDTO">
select select
t.id, t.id,
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_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} #{v}
</foreach> </foreach>
</select> </select>
<select id="selectByPlanCaseIds" resultType="io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO">
SELECT a.project_id, t.*
FROM test_plan_api_case t
INNER JOIN api_test_case a ON t.api_case_id = a.id
WHERE t.id in
<foreach collection="planCaseIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
ORDER BY t.order DESC
</select>
</mapper> </mapper>

View File

@ -1,7 +1,7 @@
package io.metersphere.base.mapper.plan.ext; package io.metersphere.base.mapper.plan.ext;
import io.metersphere.api.dto.automation.ApiScenarioDTO; 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.automation.TestPlanScenarioRequest;
import io.metersphere.api.dto.plan.TestPlanApiScenarioInfoDTO; import io.metersphere.api.dto.plan.TestPlanApiScenarioInfoDTO;
import io.metersphere.base.domain.TestPlanApiScenario; import io.metersphere.base.domain.TestPlanApiScenario;
@ -32,9 +32,9 @@ public interface ExtTestPlanScenarioCaseMapper {
List<PlanReportCaseDTO> selectForPlanReport(String planId); List<PlanReportCaseDTO> selectForPlanReport(String planId);
List<TestPlanFailureScenarioDTO> getFailureList(@Param("planId") String planId, @Param("status") String status); List<TestPlanScenarioDTO> getFailureList(@Param("planId") String planId, @Param("status") String status);
List<TestPlanFailureScenarioDTO> getFailureListByIds(@Param("ids") Collection<String> ids, @Param("status") String status); List<TestPlanScenarioDTO> getFailureListByIds(@Param("ids") Collection<String> ids, @Param("status") String status);
List<Integer> getUnderwaySteps(@Param("ids") List<String> underwayIds); List<Integer> getUnderwaySteps(@Param("ids") List<String> underwayIds);

View File

@ -299,7 +299,7 @@
!= 'Trash' != 'Trash'
) )
</select> </select>
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO"> <select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanScenarioDTO">
select 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.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.status,c.step_total, c.step_total, c.project_id,
@ -323,9 +323,9 @@
ORDER BY t.order DESC ORDER BY t.order DESC
</select> </select>
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO"> <select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanScenarioDTO">
select 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.status,c.step_total, c.step_total, c.project_id,
c.num, c.custom_num c.num, c.custom_num
from from

View File

@ -1,6 +1,6 @@
package io.metersphere.controller.plan; 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.ShareInfoService;
import io.metersphere.service.plan.TestPlanApiCaseService; import io.metersphere.service.plan.TestPlanApiCaseService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -21,25 +21,25 @@ public class ShareTestPlanApiCaseController {
TestPlanApiCaseService testPlanApiCaseService; TestPlanApiCaseService testPlanApiCaseService;
@GetMapping("/list/failure/{shareId}/{planId}") @GetMapping("/list/failure/{shareId}/{planId}")
public List<TestPlanFailureApiDTO> getApiFailureList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanApiDTO> getApiFailureList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanApiCaseService.getFailureCases(planId); return testPlanApiCaseService.getFailureCases(planId);
} }
@GetMapping("/list/errorReport/{shareId}/{planId}") @GetMapping("/list/errorReport/{shareId}/{planId}")
public List<TestPlanFailureApiDTO> getErrorReportApiCaseList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanApiDTO> getErrorReportApiCaseList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanApiCaseService.getErrorReportCases(planId); return testPlanApiCaseService.getErrorReportCases(planId);
} }
@GetMapping("/list/unExecute/{shareId}/{planId}") @GetMapping("/list/unExecute/{shareId}/{planId}")
public List<TestPlanFailureApiDTO> getUnExecuteCases(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanApiDTO> getUnExecuteCases(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanApiCaseService.getUnExecuteCases(planId); return testPlanApiCaseService.getUnExecuteCases(planId);
} }
@GetMapping("/list/all/{shareId}/{planId}") @GetMapping("/list/all/{shareId}/{planId}")
public List<TestPlanFailureApiDTO> getApiAllList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanApiDTO> getApiAllList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanApiCaseService.getAllCases(planId); return testPlanApiCaseService.getAllCases(planId);
} }

View File

@ -1,7 +1,8 @@
package io.metersphere.controller.plan; package io.metersphere.controller.plan;
import io.metersphere.api.dto.automation.ApiScenarioReportResult; 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.ShareInfoService;
import io.metersphere.service.plan.TestPlanScenarioCaseService; import io.metersphere.service.plan.TestPlanScenarioCaseService;
import io.metersphere.service.scenario.ApiScenarioReportService; import io.metersphere.service.scenario.ApiScenarioReportService;
@ -25,25 +26,25 @@ public class ShareTestPlanScenarioCaseController {
private ApiScenarioReportService apiReportService; private ApiScenarioReportService apiReportService;
@GetMapping("/list/failure/{shareId}/{planId}") @GetMapping("/list/failure/{shareId}/{planId}")
public List<TestPlanFailureScenarioDTO> getScenarioFailureList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanScenarioDTO> getScenarioFailureList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanScenarioCaseService.getFailureCases(planId); return testPlanScenarioCaseService.getFailureCases(planId);
} }
@GetMapping("/list/all/{shareId}/{planId}") @GetMapping("/list/all/{shareId}/{planId}")
public List<TestPlanFailureScenarioDTO> getScenarioAllList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanScenarioDTO> getScenarioAllList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanScenarioCaseService.getAllCases(planId); return testPlanScenarioCaseService.getAllCases(planId);
} }
@GetMapping("/list/errorReport/{shareId}/{planId}") @GetMapping("/list/errorReport/{shareId}/{planId}")
public List<TestPlanFailureScenarioDTO> getScenarioErrorReportList(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanScenarioDTO> getScenarioErrorReportList(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanScenarioCaseService.getErrorReportCases(planId); return testPlanScenarioCaseService.getErrorReportCases(planId);
} }
@GetMapping("/list/unExecute/{shareId}/{planId}") @GetMapping("/list/unExecute/{shareId}/{planId}")
public List<TestPlanFailureScenarioDTO> getUnExecuteScenarioCases(@PathVariable String shareId, @PathVariable String planId) { public List<TestPlanScenarioDTO> getUnExecuteScenarioCases(@PathVariable String shareId, @PathVariable String planId) {
shareInfoService.validate(shareId); shareInfoService.validate(shareId);
return testPlanScenarioCaseService.getUnExecuteCases(planId); return testPlanScenarioCaseService.getUnExecuteCases(planId);
} }

View File

@ -3,8 +3,8 @@ package io.metersphere.controller.plan;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.QueryReferenceRequest; 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.TestPlanDTO;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest; import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs; import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
@ -19,10 +19,10 @@ import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.request.ResetOrderRequest; import io.metersphere.request.ResetOrderRequest;
import io.metersphere.service.plan.TestPlanApiCaseService; import io.metersphere.service.plan.TestPlanApiCaseService;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -41,22 +41,22 @@ public class TestPlanApiCaseController {
} }
@GetMapping("/list/failure/{planId}") @GetMapping("/list/failure/{planId}")
public List<TestPlanFailureApiDTO> getFailureList(@PathVariable String planId) { public List<TestPlanApiDTO> getFailureList(@PathVariable String planId) {
return testPlanApiCaseService.getFailureCases(planId); return testPlanApiCaseService.getFailureCases(planId);
} }
@GetMapping("/list/errorReport/{planId}") @GetMapping("/list/errorReport/{planId}")
public List<TestPlanFailureApiDTO> getErrorReportList(@PathVariable String planId) { public List<TestPlanApiDTO> getErrorReportList(@PathVariable String planId) {
return testPlanApiCaseService.getErrorReportCases(planId); return testPlanApiCaseService.getErrorReportCases(planId);
} }
@GetMapping("/list/unExecute/{planId}") @GetMapping("/list/unExecute/{planId}")
public List<TestPlanFailureApiDTO> getUnExecuteCases(@PathVariable String planId) { public List<TestPlanApiDTO> getUnExecuteCases(@PathVariable String planId) {
return testPlanApiCaseService.getUnExecuteCases(planId); return testPlanApiCaseService.getUnExecuteCases(planId);
} }
@GetMapping("/list/all/{planId}") @GetMapping("/list/all/{planId}")
public List<TestPlanFailureApiDTO> getAllList(@PathVariable String planId) { public List<TestPlanApiDTO> getAllList(@PathVariable String planId) {
return testPlanApiCaseService.getAllCases(planId); return testPlanApiCaseService.getAllCases(planId);
} }
@ -170,7 +170,7 @@ public class TestPlanApiCaseController {
} }
@PostMapping("/failure/list") @PostMapping("/failure/list")
public List<TestPlanFailureApiDTO> getFailureListByIds(@RequestBody Set<String> planApiCaseIds) { public List<TestPlanApiDTO> getFailureListByIds(@RequestBody Set<String> planApiCaseIds) {
return testPlanApiCaseService.getFailureListByIds(planApiCaseIds); return testPlanApiCaseService.getFailureListByIds(planApiCaseIds);
} }
@ -190,7 +190,7 @@ public class TestPlanApiCaseController {
} }
@PostMapping("/build/response") @PostMapping("/build/response")
public List<TestPlanFailureApiDTO> buildResponse(@RequestBody List<TestPlanFailureApiDTO> cases) { public List<TestPlanApiDTO> buildResponse(@RequestBody List<TestPlanApiDTO> cases) {
testPlanApiCaseService.buildApiResponse(cases); testPlanApiCaseService.buildApiResponse(cases);
return cases; return cases;
} }

View File

@ -4,11 +4,8 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.ApiCaseRelevanceRequest; import io.metersphere.api.dto.ApiCaseRelevanceRequest;
import io.metersphere.api.dto.RelevanceScenarioRequest; import io.metersphere.api.dto.RelevanceScenarioRequest;
import io.metersphere.api.dto.plan.TestPlanScenarioCaseBatchRequest;
import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.plan.*; 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.base.domain.TestPlanReport;
import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
@ -21,9 +18,11 @@ import io.metersphere.dto.PlanReportCaseDTO;
import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.request.ResetOrderRequest; 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 org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,22 +42,22 @@ public class TestPlanScenarioCaseController {
} }
@GetMapping("/list/failure/{planId}") @GetMapping("/list/failure/{planId}")
public List<TestPlanFailureScenarioDTO> getFailureList(@PathVariable String planId) { public List<TestPlanScenarioDTO> getFailureList(@PathVariable String planId) {
return testPlanScenarioCaseService.getFailureCases(planId); return testPlanScenarioCaseService.getFailureCases(planId);
} }
@GetMapping("/list/error-report/{planId}") @GetMapping("/list/error-report/{planId}")
public List<TestPlanFailureScenarioDTO> getErrorReportList(@PathVariable String planId) { public List<TestPlanScenarioDTO> getErrorReportList(@PathVariable String planId) {
return testPlanScenarioCaseService.getErrorReportCases(planId); return testPlanScenarioCaseService.getErrorReportCases(planId);
} }
@GetMapping("/list/pending/{planId}") @GetMapping("/list/pending/{planId}")
public List<TestPlanFailureScenarioDTO> getUnExecuteCases(@PathVariable String planId) { public List<TestPlanScenarioDTO> getUnExecuteCases(@PathVariable String planId) {
return testPlanScenarioCaseService.getUnExecuteCases(planId); return testPlanScenarioCaseService.getUnExecuteCases(planId);
} }
@GetMapping("/list/all/{planId}") @GetMapping("/list/all/{planId}")
public List<TestPlanFailureScenarioDTO> getAllList(@PathVariable String planId) { public List<TestPlanScenarioDTO> getAllList(@PathVariable String planId) {
return testPlanScenarioCaseService.getAllCases(planId); return testPlanScenarioCaseService.getAllCases(planId);
} }
@ -185,8 +184,8 @@ public class TestPlanScenarioCaseController {
return testPlanScenarioCaseService.buildApiReport(request); return testPlanScenarioCaseService.buildApiReport(request);
} }
@PostMapping("/plan/execute/report") @PostMapping("/select/result/by/reportId")
public ApiPlanReportDTO buildExecuteApiReport(@RequestBody ApiPlanReportRequest request) { public ApiReportResultDTO selectReportResultById(@RequestBody ApiPlanReportRequest request) {
return testPlanScenarioCaseService.buildExecuteApiReport(request); return testPlanScenarioCaseService.buildExecuteApiReport(request);
} }
@ -195,9 +194,9 @@ public class TestPlanScenarioCaseController {
return testPlanScenarioCaseService.isExecuting(planId); return testPlanScenarioCaseService.isExecuting(planId);
} }
@PostMapping("/failure/list") @PostMapping("/all/list")
public List<TestPlanFailureScenarioDTO> getFailureListByIds(@RequestBody Set<String> planApiCaseIds) { public List<TestPlanScenarioDTO> getListByIds(@RequestBody Set<String> planApiCaseIds) {
return testPlanScenarioCaseService.getFailureListByIds(planApiCaseIds); return testPlanScenarioCaseService.getListByIds(planApiCaseIds);
} }
@PostMapping("/env/generate") @PostMapping("/env/generate")
@ -221,7 +220,7 @@ public class TestPlanScenarioCaseController {
} }
@PostMapping("/build/response") @PostMapping("/build/response")
public List<TestPlanFailureScenarioDTO> buildResponse(@RequestBody List<TestPlanFailureScenarioDTO> cases) { public List<TestPlanScenarioDTO> buildResponse(@RequestBody List<TestPlanScenarioDTO> cases) {
testPlanScenarioCaseService.buildScenarioResponse(cases); testPlanScenarioCaseService.buildScenarioResponse(cases);
return cases; return cases;
} }

View File

@ -1,7 +1,7 @@
package io.metersphere.listener; package io.metersphere.listener;
import io.metersphere.service.ApiExecutionQueueService;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.service.ApiExecutionQueueService;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;

View File

@ -213,10 +213,7 @@ public class ApiExecutionQueueService {
if (isError) { if (isError) {
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andQueueIdEqualTo(dto.getQueueId()); example.createCriteria().andQueueIdEqualTo(dto.getQueueId());
checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId());
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) {
testPlanReportTestEnded(dto.getTestPlanReportId());
}
// 更新未执行的报告状态 // 更新未执行的报告状态
List<ApiExecutionQueueDetail> details = executionQueueDetailMapper.selectByExample(example); List<ApiExecutionQueueDetail> details = executionQueueDetailMapper.selectByExample(example);
List<String> reportIds = details.stream().map(ApiExecutionQueueDetail::getReportId).collect(Collectors.toList()); List<String> reportIds = details.stream().map(ApiExecutionQueueDetail::getReportId).collect(Collectors.toList());
@ -272,9 +269,23 @@ public class ApiExecutionQueueService {
return queue; return queue;
} }
public void testPlanReportTestEnded(String testPlanReportId) { private void testPlanCaseTestEnd(String testId, String runMode) {
// 检查测试计划中其他队列是否结束 //不是整体测试计划执行的用例发送testID给测试跟踪模块用于做单接口执行后续操作处理
kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId); 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) { public void queueNext(ResultDTO dto) {
@ -443,7 +454,7 @@ public class ApiExecutionQueueService {
// 更新测试计划报告 // 更新测试计划报告
if (StringUtils.isNotEmpty(item.getReportId())) { if (StringUtils.isNotEmpty(item.getReportId())) {
LoggerUtil.info("Handling test plan reports that are not in the execution queue" + 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)) { if (CollectionUtils.isNotEmpty(testPlanReports)) {
testPlanReports.forEach(reportId -> { testPlanReports.forEach(reportId -> {
LoggerUtil.info("Compensation Test Plan Report" + 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()); ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(detail.getQueueId());
// 更新测试计划报告 // 更新测试计划报告
if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) { 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); ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(queueId);
// 更新测试计划报告 // 更新测试计划报告
if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) { if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) {
testPlanReportTestEnded(queue.getReportId()); checkTestPlanCaseTestEnd(null, null, queue.getReportId());
queueMapper.deleteByPrimaryKey(queueId); queueMapper.deleteByPrimaryKey(queueId);
} }
} }

View File

@ -35,13 +35,11 @@ public class RemakeReportService {
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto); CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
} }
// 更新测试计划报告 // 更新测试计划报告
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) { LoggerUtil.info("Check Processing Test Plan report status.queueId" + dto.getQueueId() + "runMode:" + dto.getRunMode() + "testId:" + dto.getTestId(), dto.getReportId());
LoggerUtil.info("Check Processing Test Plan report status" + dto.getQueueId() + "" + dto.getTestId(), dto.getReportId()); CommonBeanFactory.getBean(ApiExecutionQueueService.class).checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId());
CommonBeanFactory.getBean(ApiExecutionQueueService.class).testPlanReportTestEnded(dto.getTestPlanReportId());
}
} catch (Exception e) { } catch (Exception e) {
LoggerUtil.error("回退报告异常", request.getReportId(), e); LoggerUtil.error("回退报告异常", request.getReportId(), e);
}finally { } finally {
redisTemplateService.delete(JmxFileUtil.getExecuteScriptKey(request.getReportId(), request.getTestId())); redisTemplateService.delete(JmxFileUtil.getExecuteScriptKey(request.getReportId(), request.getTestId()));
redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId())); redisTemplateService.delete(JmxFileUtil.getExecuteFileKeyInRedis(request.getReportId()));
} }

View File

@ -22,6 +22,7 @@ import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService; import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.ServiceUtils; import io.metersphere.service.ServiceUtils;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import jakarta.annotation.Resource;
import org.apache.commons.beanutils.BeanMap; import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
@ -33,7 +34,6 @@ import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -489,4 +489,15 @@ public class ApiDefinitionExecResultService {
public ApiDefinitionExecResultWithBLOBs getLastResult(String testId) { public ApiDefinitionExecResultWithBLOBs getLastResult(String testId) {
return extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId); return extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId);
} }
public Map<String, String> selectResultByIdList(List<String> reportIdList) {
Map<String, String> returnMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(reportIdList)) {
List<ApiDefinitionExecResult> apiDefinitionExecResultList = extApiDefinitionExecResultMapper.selectStatusByIdList(reportIdList);
if (CollectionUtils.isNotEmpty(apiDefinitionExecResultList)) {
returnMap = apiDefinitionExecResultList.stream().collect(Collectors.toMap(ApiDefinitionExecResult::getId, ApiDefinitionExecResult::getStatus, (k1, k2) -> k1));
}
}
return returnMap;
}
} }

View File

@ -7,8 +7,8 @@ import io.metersphere.api.dto.ApiCaseRelevanceRequest;
import io.metersphere.api.dto.ApiReportEnvConfigDTO; import io.metersphere.api.dto.ApiReportEnvConfigDTO;
import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.QueryReferenceRequest; 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.TestPlanDTO;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest; import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest;
import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO; 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.ApiModuleService;
import io.metersphere.service.definition.ApiTestCaseService; import io.metersphere.service.definition.ApiTestCaseService;
import io.metersphere.service.plan.remote.TestPlanService; import io.metersphere.service.plan.remote.TestPlanService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
@ -49,7 +50,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -392,20 +392,20 @@ public class TestPlanApiCaseService {
} }
public List<TestPlanFailureApiDTO> getFailureCases(String planId) { public List<TestPlanApiDTO> getFailureCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name()); List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public List<TestPlanFailureApiDTO> getAllCases(String planId) { public List<TestPlanApiDTO> getAllCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null); List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null);
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public void buildApiResponse(List<TestPlanFailureApiDTO> cases) { public void buildApiResponse(List<TestPlanApiDTO> cases) {
if (!org.apache.commons.collections.CollectionUtils.isEmpty(cases)) { if (!org.apache.commons.collections.CollectionUtils.isEmpty(cases)) {
List<String> reportIds = new ArrayList<>(); List<String> reportIds = new ArrayList<>();
for (TestPlanFailureApiDTO apiCase : cases) { for (TestPlanApiDTO apiCase : cases) {
if (StringUtils.isEmpty(apiCase.getReportId())) { if (StringUtils.isEmpty(apiCase.getReportId())) {
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(apiCase.getId(), "API_PLAN"); ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(apiCase.getId(), "API_PLAN");
if (result != null && StringUtils.isNotBlank(result.getContent())) { if (result != null && StringUtils.isNotBlank(result.getContent())) {
@ -464,7 +464,7 @@ public class TestPlanApiCaseService {
} }
} }
public List<TestPlanFailureApiDTO> buildCases(List<TestPlanFailureApiDTO> apiTestCases) { public List<TestPlanApiDTO> buildCases(List<TestPlanApiDTO> apiTestCases) {
if (CollectionUtils.isEmpty(apiTestCases)) { if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases; return apiTestCases;
} }
@ -479,9 +479,9 @@ public class TestPlanApiCaseService {
* *
* @param apiTestCases * @param apiTestCases
*/ */
private void buildPrincipal(List<TestPlanFailureApiDTO> apiTestCases) { private void buildPrincipal(List<TestPlanApiDTO> apiTestCases) {
List<String> apiIds = apiTestCases.stream() List<String> apiIds = apiTestCases.stream()
.map(TestPlanFailureApiDTO::getApiDefinitionId) .map(TestPlanApiDTO::getApiDefinitionId)
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<String, String> userIdMap = apiDefinitionService.selectByIds(apiIds) Map<String, String> userIdMap = apiDefinitionService.selectByIds(apiIds)
@ -503,13 +503,13 @@ public class TestPlanApiCaseService {
ServiceUtils.updateOrderField(request, TestPlanApiCase.class, testPlanApiCaseMapper::selectByPrimaryKey, extTestPlanApiCaseMapper::getPreOrder, extTestPlanApiCaseMapper::getLastOrder, testPlanApiCaseMapper::updateByPrimaryKeySelective); ServiceUtils.updateOrderField(request, TestPlanApiCase.class, testPlanApiCaseMapper::selectByPrimaryKey, extTestPlanApiCaseMapper::getPreOrder, extTestPlanApiCaseMapper::getLastOrder, testPlanApiCaseMapper::updateByPrimaryKeySelective);
} }
public List<TestPlanFailureApiDTO> getErrorReportCases(String planId) { public List<TestPlanApiDTO> getErrorReportCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name()); List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public List<TestPlanFailureApiDTO> getUnExecuteCases(String planId) { public List<TestPlanApiDTO> getUnExecuteCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name()); List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
@ -717,7 +717,7 @@ public class TestPlanApiCaseService {
return !testPlanApiCaseList.stream().map(TestPlanApiCaseInfoDTO::getApiCaseId).collect(Collectors.toList()).isEmpty(); return !testPlanApiCaseList.stream().map(TestPlanApiCaseInfoDTO::getApiCaseId).collect(Collectors.toList()).isEmpty();
} }
public List<TestPlanFailureApiDTO> getFailureListByIds(Set<String> planApiCaseIds) { public List<TestPlanApiDTO> getFailureListByIds(Set<String> planApiCaseIds) {
return extTestPlanApiCaseMapper.getFailureListByIds(planApiCaseIds, null); return extTestPlanApiCaseMapper.getFailureListByIds(planApiCaseIds, null);
} }

View File

@ -6,15 +6,16 @@ import io.metersphere.api.dto.ApiCaseRelevanceRequest;
import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.RelevanceScenarioRequest; import io.metersphere.api.dto.RelevanceScenarioRequest;
import io.metersphere.api.dto.ScenarioEnv; import io.metersphere.api.dto.ScenarioEnv;
import io.metersphere.api.dto.automation.ApiScenarioReportResult;
import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.plan.*; import io.metersphere.api.dto.plan.*;
import io.metersphere.api.exec.scenario.ApiScenarioEnvService; import io.metersphere.api.exec.scenario.ApiScenarioEnvService;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.ApiScenarioReportResult;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper; import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioModuleMapper; 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.TestPlanApiScenarioMapper;
import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiScenarioMapper; import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiScenarioMapper;
import io.metersphere.base.mapper.plan.ext.ExtTestPlanScenarioCaseMapper; 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.plan.remote.TestPlanService;
import io.metersphere.service.scenario.ApiScenarioModuleService; import io.metersphere.service.scenario.ApiScenarioModuleService;
import io.metersphere.service.scenario.ApiScenarioReportService; import io.metersphere.service.scenario.ApiScenarioReportService;
import io.metersphere.service.scenario.ApiScenarioReportStructureService;
import io.metersphere.service.scenario.ApiScenarioService; import io.metersphere.service.scenario.ApiScenarioService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
@ -103,6 +106,11 @@ public class TestPlanScenarioCaseService {
private TestPlanService testPlanService; private TestPlanService testPlanService;
@Resource @Resource
private JMeterService jMeterService; private JMeterService jMeterService;
@Resource
private ExtApiScenarioReportResultMapper extApiScenarioReportResultMapper;
@Lazy
@Resource
private ApiScenarioReportStructureService apiScenarioReportStructureService;
public List<ApiScenarioDTO> list(TestPlanScenarioRequest request) { public List<ApiScenarioDTO> list(TestPlanScenarioRequest request) {
request.setProjectId(null); request.setProjectId(null);
@ -557,17 +565,17 @@ public class TestPlanScenarioCaseService {
return envMap; return envMap;
} }
public List<TestPlanFailureScenarioDTO> getAllCases(String planId) { public List<TestPlanScenarioDTO> getAllCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases = List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, null); extTestPlanScenarioCaseMapper.getFailureList(planId, null);
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public List<TestPlanFailureScenarioDTO> getAllCases(Map<String, String> idMap, Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap) { public List<TestPlanScenarioDTO> getAllCases(Map<String, String> idMap, Map<String, TestPlanScenarioDTO> scenarioInfoDTOMap) {
Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values()); Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values());
Map<String, String> savedReportMap = new HashMap<>(idMap); Map<String, String> savedReportMap = new HashMap<>(idMap);
List<TestPlanFailureScenarioDTO> apiTestCases = new ArrayList<>(); List<TestPlanScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) { for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) {
String reportId = savedReportMap.get(dto.getId()); String reportId = savedReportMap.get(dto.getId());
savedReportMap.remove(dto.getId()); savedReportMap.remove(dto.getId());
dto.setReportId(reportId); dto.setReportId(reportId);
@ -585,13 +593,13 @@ public class TestPlanScenarioCaseService {
} }
public List<TestPlanFailureScenarioDTO> getFailureCases(String planId) { public List<TestPlanScenarioDTO> getFailureCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases = List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name()); extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public List<TestPlanFailureScenarioDTO> buildCases(List<TestPlanFailureScenarioDTO> apiTestCases) { public List<TestPlanScenarioDTO> buildCases(List<TestPlanScenarioDTO> apiTestCases) {
if (CollectionUtils.isEmpty(apiTestCases)) { if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases; return apiTestCases;
} }
@ -633,23 +641,34 @@ public class TestPlanScenarioCaseService {
testPlanApiScenarioMapper::updateByPrimaryKeySelective); testPlanApiScenarioMapper::updateByPrimaryKeySelective);
} }
public List<TestPlanFailureScenarioDTO> getErrorReportCases(String planId) { public List<TestPlanScenarioDTO> getErrorReportCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases = List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name()); extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public List<TestPlanFailureScenarioDTO> getUnExecuteCases(String planId) { public List<TestPlanScenarioDTO> getUnExecuteCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases = List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name()); extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name());
return buildCases(apiTestCases); return buildCases(apiTestCases);
} }
public TestPlanScenarioStepCountSimpleDTO getStepCount(List<PlanReportCaseDTO> planReportCaseDTOS) { public TestPlanScenarioStepCountSimpleDTO getStepCount(List<PlanReportCaseDTO> planReportCaseDTOS) {
TestPlanScenarioStepCountDTO stepCount = new TestPlanScenarioStepCountDTO(); TestPlanScenarioStepCountDTO stepCount = new TestPlanScenarioStepCountDTO();
List<String> scenarioReportIdList = new ArrayList<>();
for (PlanReportCaseDTO item : planReportCaseDTOS) { 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()); int underwayStepsCounts = getUnderwayStepsCounts(stepCount.getUnderwayIds());
TestPlanScenarioStepCountSimpleDTO stepResult = new TestPlanScenarioStepCountSimpleDTO(); TestPlanScenarioStepCountSimpleDTO stepResult = new TestPlanScenarioStepCountSimpleDTO();
stepResult.setStepCount(stepCount); stepResult.setStepCount(stepCount);
@ -665,24 +684,33 @@ public class TestPlanScenarioCaseService {
return 0; return 0;
} }
private void calculateScenarioResultDTO(PlanReportCaseDTO item, private void calculateScenarioResultDTO(List<String> scenarioReportIdList,
TestPlanScenarioStepCountDTO stepCount) { TestPlanScenarioStepCountDTO stepCount) {
if (StringUtils.isNotBlank(item.getReportId())) { if (CollectionUtils.isNotEmpty(scenarioReportIdList)) {
ApiScenarioReportResult apiScenarioReportResult = apiScenarioReportService.get(item.getReportId(), false); List<ApiScenarioReportResultWithBLOBs> resultList = extApiScenarioReportResultMapper.selectIdAndStatusByReportIdList(scenarioReportIdList);
if (apiScenarioReportResult != null) { resultList = apiScenarioReportStructureService.filterProcessResult(resultList);
String content = apiScenarioReportResult.getContent(); stepCount.setScenarioStepTotal(resultList.size());
if (StringUtils.isNotBlank(content)) { int successStep = 0;
Map map = JSON.parseMap(content); int fakeErrorStep = 0;
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + (Integer) map.get("scenarioStepTotal")); int errorStep = 0;
stepCount.setScenarioStepSuccess(stepCount.getScenarioStepSuccess() + (Integer) map.get("scenarioStepSuccess")); int unexecuteStep = 0;
stepCount.setScenarioStepError(stepCount.getScenarioStepError() + (Integer) map.get("scenarioStepError")); for (ApiScenarioReportResult result : resultList) {
stepCount.setScenarioStepErrorReport(stepCount.getScenarioStepErrorReport() + (Integer) map.get("scenarioStepErrorReport")); if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.ERROR.name())) {
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + (map.get("pending") == null ? 0 : (Integer) map.get("pending"))); 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.setScenarioStepSuccess(successStep);
stepCount.getUnderwayIds().add(item.getCaseId()); stepCount.setScenarioStepError(errorStep);
stepCount.setScenarioStepErrorReport(fakeErrorStep);
stepCount.setScenarioStepUnExecute(unexecuteStep);
} }
} }
public void relevanceByTestIds(List<String> ids, String planId) { public void relevanceByTestIds(List<String> ids, String planId) {
@ -802,8 +830,8 @@ public class TestPlanScenarioCaseService {
String planId = request.getPlanId(); String planId = request.getPlanId();
Boolean saveResponse = request.getSaveResponse(); Boolean saveResponse = request.getSaveResponse();
if (ServiceUtils.checkConfigEnable(config, "api")) { if (ServiceUtils.checkConfigEnable(config, "api")) {
List<TestPlanFailureApiDTO> apiAllCases = null; List<TestPlanApiDTO> apiAllCases = null;
List<TestPlanFailureScenarioDTO> scenarioAllCases = null; List<TestPlanScenarioDTO> scenarioAllCases = null;
if (checkReportConfig(config, "api", "all")) { if (checkReportConfig(config, "api", "all")) {
// 接口 // 接口
apiAllCases = testPlanApiCaseService.getAllCases(planId); apiAllCases = testPlanApiCaseService.getAllCases(planId);
@ -825,7 +853,7 @@ public class TestPlanScenarioCaseService {
return report; return report;
} }
public void buildScenarioResponse(List<TestPlanFailureScenarioDTO> cases) { public void buildScenarioResponse(List<TestPlanScenarioDTO> cases) {
if (!CollectionUtils.isEmpty(cases)) { if (!CollectionUtils.isEmpty(cases)) {
cases.forEach((item) -> { cases.forEach((item) -> {
item.setResponse(apiScenarioReportService.get(item.getReportId(), true)); item.setResponse(apiScenarioReportService.get(item.getReportId(), true));
@ -833,12 +861,12 @@ public class TestPlanScenarioCaseService {
} }
} }
private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanFailureApiDTO> apiAllCases, Map reportConfig) { private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanApiDTO> apiAllCases, Map reportConfig) {
if (!CollectionUtils.isEmpty(apiAllCases)) { if (!CollectionUtils.isEmpty(apiAllCases)) {
List<TestPlanFailureApiDTO> apiFailureCases = new ArrayList<>(); List<TestPlanApiDTO> apiFailureCases = new ArrayList<>();
List<TestPlanFailureApiDTO> apiErrorReportCases = new ArrayList<>(); List<TestPlanApiDTO> apiErrorReportCases = new ArrayList<>();
List<TestPlanFailureApiDTO> apiUnExecuteCases = new ArrayList<>(); List<TestPlanApiDTO> apiUnExecuteCases = new ArrayList<>();
for (TestPlanFailureApiDTO apiDTO : apiAllCases) { for (TestPlanApiDTO apiDTO : apiAllCases) {
if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.ERROR.name())) { if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.ERROR.name())) {
apiFailureCases.add(apiDTO); apiFailureCases.add(apiDTO);
} else if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.FAKE_ERROR.name())) { } else if (StringUtils.equalsIgnoreCase(apiDTO.getExecResult(), ApiReportStatus.FAKE_ERROR.name())) {
@ -865,13 +893,13 @@ public class TestPlanScenarioCaseService {
return ServiceUtils.checkConfigEnable(config, key, subKey); return ServiceUtils.checkConfigEnable(config, key, subKey);
} }
private void screenScenariosByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanFailureScenarioDTO> scenarios, Map reportConfig) { private void screenScenariosByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanScenarioDTO> scenarios, Map reportConfig) {
if (!CollectionUtils.isEmpty(scenarios)) { if (!CollectionUtils.isEmpty(scenarios)) {
List<TestPlanFailureScenarioDTO> failureScenarios = new ArrayList<>(); List<TestPlanScenarioDTO> failureScenarios = new ArrayList<>();
List<TestPlanFailureScenarioDTO> errorReportScenarios = new ArrayList<>(); List<TestPlanScenarioDTO> errorReportScenarios = new ArrayList<>();
List<TestPlanFailureScenarioDTO> unExecuteScenarios = new ArrayList<>(); List<TestPlanScenarioDTO> unExecuteScenarios = new ArrayList<>();
for (TestPlanFailureScenarioDTO scenario : scenarios) { for (TestPlanScenarioDTO scenario : scenarios) {
if (StringUtils.equalsAnyIgnoreCase(scenario.getLastResult(), ApiReportStatus.ERROR.name())) { if (StringUtils.equalsAnyIgnoreCase(scenario.getLastResult(), ApiReportStatus.ERROR.name())) {
failureScenarios.add(scenario); failureScenarios.add(scenario);
} else if (StringUtils.equalsIgnoreCase(scenario.getLastResult(), ApiReportStatus.FAKE_ERROR.name())) { } else if (StringUtils.equalsIgnoreCase(scenario.getLastResult(), ApiReportStatus.FAKE_ERROR.name())) {
@ -893,80 +921,26 @@ public class TestPlanScenarioCaseService {
} }
} }
public ApiPlanReportDTO buildExecuteApiReport(ApiPlanReportRequest request) { public ApiReportResultDTO buildExecuteApiReport(ApiPlanReportRequest request) {
ApiPlanReportDTO report = new ApiPlanReportDTO(); ApiReportResultDTO resultDTO = new ApiReportResultDTO();
TestPlanExecuteReportDTO testPlanExecuteReportDTO = request.getTestPlanExecuteReportDTO(); if (ObjectUtils.isNotEmpty(request)) {
Map config = request.getConfig(); Map<String, String> apiReportResultMap = apiDefinitionExecResultService.selectResultByIdList(request.getApiReportIdList());
if (MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap()) Map<String, String> scenarioReportResultMap = apiScenarioReportService.selectResultByIdList(request.getScenarioReportIdList());
&& MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap())) { resultDTO.setApiReportResultMap(apiReportResultMap);
return new ApiPlanReportDTO(); resultDTO.setScenarioReportResultMap(scenarioReportResultMap);
} }
if (ServiceUtils.checkConfigEnable(config, "api")) { return resultDTO;
List<TestPlanFailureApiDTO> apiAllCases = null;
List<TestPlanFailureScenarioDTO> 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;
} }
private void checkApiCaseCreatorName(List<TestPlanFailureApiDTO> apiCases, List<TestPlanFailureScenarioDTO> scenarioCases) { public List<TestPlanScenarioDTO> getTestPlanScenario(Map<String, String> idMap, Map<String, TestPlanScenarioDTO> scenarioInfoDTOMap) {
List<String> userIdList = new ArrayList<>(); if (MapUtils.isEmpty(idMap) || MapUtils.isEmpty(scenarioInfoDTOMap)) {
if (CollectionUtils.isNotEmpty(apiCases)) { return new ArrayList<>();
apiCases.forEach(item -> {
if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUserId())) {
userIdList.add(item.getCreateUserId());
}
});
} }
if (CollectionUtils.isNotEmpty(scenarioCases)) {
scenarioCases.forEach(item -> {
if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUser())) {
userIdList.add(item.getCreateUser());
}
});
}
Map<String, User> 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<TestPlanFailureScenarioDTO> getTestPlanScenario(Map<String, String> idMap, Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap) {
Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values()); Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values());
Map<String, String> savedReportMap = new HashMap<>(idMap); Map<String, String> savedReportMap = new HashMap<>(idMap);
List<TestPlanFailureScenarioDTO> apiTestCases = new ArrayList<>(); List<TestPlanScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) { for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) {
String reportId = savedReportMap.get(dto.getId()); String reportId = savedReportMap.get(dto.getId());
savedReportMap.remove(dto.getId()); savedReportMap.remove(dto.getId());
dto.setReportId(reportId); dto.setReportId(reportId);
@ -984,15 +958,15 @@ public class TestPlanScenarioCaseService {
} }
public List<TestPlanFailureApiDTO> getByApiExecReportIds(Map<String, String> testPlanApiCaseReportMap, Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap) { public List<TestPlanApiDTO> getByApiExecReportIds(Map<String, String> testPlanApiCaseReportMap, Map<String, TestPlanApiDTO> apiCaseInfoDTOMap) {
if (testPlanApiCaseReportMap.isEmpty()) { if (MapUtils.isEmpty(testPlanApiCaseReportMap) || MapUtils.isEmpty(apiCaseInfoDTOMap)) {
return new ArrayList<>(); return new ArrayList<>();
} }
String defaultStatus = ApiReportStatus.ERROR.name(); String defaultStatus = ApiReportStatus.ERROR.name();
Map<String, String> reportResult = apiDefinitionExecResultService.selectReportResultByReportIds(testPlanApiCaseReportMap.values()); Map<String, String> reportResult = apiDefinitionExecResultService.selectReportResultByReportIds(testPlanApiCaseReportMap.values());
Map<String, String> savedReportMap = new HashMap<>(testPlanApiCaseReportMap); Map<String, String> savedReportMap = new HashMap<>(testPlanApiCaseReportMap);
List<TestPlanFailureApiDTO> apiTestCases = new ArrayList<>(); List<TestPlanApiDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureApiDTO dto : apiCaseInfoDTOMap.values()) { for (TestPlanApiDTO dto : apiCaseInfoDTOMap.values()) {
String testPlanApiCaseId = dto.getId(); String testPlanApiCaseId = dto.getId();
String reportId = savedReportMap.get(testPlanApiCaseId); String reportId = savedReportMap.get(testPlanApiCaseId);
savedReportMap.remove(testPlanApiCaseId); savedReportMap.remove(testPlanApiCaseId);
@ -1019,7 +993,7 @@ public class TestPlanScenarioCaseService {
.isEmpty(); .isEmpty();
} }
public List<TestPlanFailureScenarioDTO> getFailureListByIds(Set<String> ids) { public List<TestPlanScenarioDTO> getListByIds(Set<String> ids) {
return extTestPlanScenarioCaseMapper.getFailureListByIds(ids, null); return extTestPlanScenarioCaseMapper.getFailureListByIds(ids, null);
} }

View File

@ -899,4 +899,15 @@ public class ApiScenarioReportService {
public List<PlanReportCaseDTO> selectForPlanReport(List<String> reportIds) { public List<PlanReportCaseDTO> selectForPlanReport(List<String> reportIds) {
return extApiScenarioReportMapper.selectForPlanReport(reportIds); return extApiScenarioReportMapper.selectForPlanReport(reportIds);
} }
public Map<String, String> selectResultByIdList(List<String> reportIdList) {
Map<String, String> returnMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(reportIdList)) {
List<ApiScenarioReport> apiDefinitionExecResultList = extApiScenarioReportMapper.selectStatusByIds(reportIdList);
if (CollectionUtils.isNotEmpty(apiDefinitionExecResultList)) {
returnMap = apiDefinitionExecResultList.stream().collect(Collectors.toMap(ApiScenarioReport::getId, ApiScenarioReport::getStatus, (k1, k2) -> k1));
}
}
return returnMap;
}
} }

View File

@ -614,7 +614,7 @@ public class ApiScenarioReportStructureService {
return reportDTO; return reportDTO;
} }
private List<ApiScenarioReportResultWithBLOBs> filterProcessResult(List<ApiScenarioReportResultWithBLOBs> reportResults) { public List<ApiScenarioReportResultWithBLOBs> filterProcessResult(List<ApiScenarioReportResultWithBLOBs> reportResults) {
List<ApiScenarioReportResultWithBLOBs> withOutProcessList = new ArrayList<>(); List<ApiScenarioReportResultWithBLOBs> withOutProcessList = new ArrayList<>();
for (ApiScenarioReportResultWithBLOBs item : reportResults) { for (ApiScenarioReportResultWithBLOBs item : reportResults) {
if (item.getBaseInfo() != null) { if (item.getBaseInfo() != null) {

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants; package io.metersphere.commons.constants;
public enum TestPlanReportStatus { public enum TestPlanReportStatus {
RUNNING, COMPLETED, SUCCESS, FAILED RUNNING, COMPLETED, SUCCESS, FAILED, UNDERWAY
} }

View File

@ -14,6 +14,7 @@ import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.plan.exec.queue.DBTestQueue; import io.metersphere.plan.exec.queue.DBTestQueue;
import io.metersphere.request.RunTestPlanRequest; import io.metersphere.request.RunTestPlanRequest;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; 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.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -66,15 +66,22 @@ public class PerfQueueService {
List<String> testPlanReportIds = queues.stream().map(ApiExecutionQueue::getReportId).collect(Collectors.toList()); List<String> testPlanReportIds = queues.stream().map(ApiExecutionQueue::getReportId).collect(Collectors.toList());
for (String testPlanReportId : testPlanReportIds) { for (String testPlanReportId : testPlanReportIds) {
LoggerUtil.info("处理测试计划报告状态", loadTestReport.getId()); LoggerUtil.info("处理测试计划报告状态", loadTestReport.getId());
testPlanReportTestEnded(testPlanReportId); checkTestPlanLoadCaseExecOver(null, testPlanReportId);
} }
for (ApiExecutionQueueDetail detail : details) { for (ApiExecutionQueueDetail detail : details) {
// 更新测试计划关联数据状态 // 更新测试计划关联数据状态
TestPlanLoadCaseWithBLOBs loadCase = new TestPlanLoadCaseWithBLOBs(); TestPlanLoadCaseExample example = new TestPlanLoadCaseExample();
loadCase.setId(loadTestReport.getTestId()); example.createCriteria().andIdEqualTo(loadTestReport.getTestId());
loadCase.setStatus(TestPlanLoadCaseStatus.success.name()); if (testPlanLoadCaseMapper.countByExample(example) > 0) {
testPlanLoadCaseMapper.updateByPrimaryKeySelective(loadCase); 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(); ApiExecutionQueueDetailExample queueDetailExample = new ApiExecutionQueueDetailExample();
@ -116,9 +123,15 @@ public class PerfQueueService {
} }
} }
public void testPlanReportTestEnded(String testPlanReportId) { public void checkTestPlanLoadCaseExecOver(String testId, String testPlanReportId) {
// 检查测试计划中其他队列是否结束 if (StringUtils.isNotBlank(testPlanReportId)) {
kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, 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) { public DBTestQueue handleQueue(String id, String testId) {

View File

@ -1,10 +1,19 @@
package io.metersphere.base.mapper.ext; 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 io.metersphere.plan.dto.TestPlanApiCaseInfoDTO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List; import java.util.List;
public interface ExtTestPlanApiCaseMapper { public interface ExtTestPlanApiCaseMapper {
List<TestPlanApiCaseInfoDTO> selectLegalDataByTestPlanId(String planId); List<TestPlanApiCaseInfoDTO> selectLegalDataByTestPlanId(String planId);
List<CaseExecResult> selectExecResult(@Param("testPlanId") String testPlanId, @Param("apiCaseIds") List<String> apiCaseIdList);
@Select("SELECT id,test_plan_id,api_case_id,status FROM test_plan_api_case WHERE id = #{0} ")
TestPlanApiCase selectBaseInfoById(String testId);
} }

View File

@ -9,4 +9,14 @@
AND (a.status IS NULL OR a.status != 'Trash') AND (a.status IS NULL OR a.status != 'Trash')
ORDER BY t.`order` DESC ORDER BY t.`order` DESC
</select> </select>
<select id="selectExecResult" resultType="io.metersphere.plan.dto.CaseExecResult">
SELECT t.api_case_id AS id,a.name AS caseName,t.status AS execResult
FROM test_plan_api_case t
INNER JOIN api_test_case a ON t.api_case_id = a.id
WHERE t.test_plan_id = #{testPlanId} AND t.api_case_id in
<foreach collection="apiCaseIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper> </mapper>

View File

@ -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<CaseExecResult> selectExecResult(@Param("testPlanId") String testPlanId, @Param("ids") List<String> relevanceApiCaseList);
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanLoadCaseMapper">
<select id="selectExecResult" resultType="io.metersphere.plan.dto.CaseExecResult">
SELECT t.load_case_id AS id,l.name AS caseName,t.status AS execResult
FROM test_plan_load_case t
INNER JOIN load_test l ON t.load_case_id = l.id
WHERE t.test_plan_id = #{testPlanId} AND t.load_case_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -53,4 +53,6 @@ public interface ExtTestPlanMapper {
Map<String, ParamsDTO> testPlanUiScenarioCount(@Param("planIds") Set<String> planIds); Map<String, ParamsDTO> testPlanUiScenarioCount(@Param("planIds") Set<String> planIds);
List<TestPlanDTO> planListAll(@Param("request") QueryTestPlanRequest params); List<TestPlanDTO> planListAll(@Param("request") QueryTestPlanRequest params);
Boolean checkSyncTestCaseExecResultByTestPlanId(String testPlanId);
} }

View File

@ -422,4 +422,8 @@
set actual_end_time = null set actual_end_time = null
where id = #{0} where id = #{0}
</update> </update>
<select id="checkSyncTestCaseExecResultByTestPlanId" resultType="java.lang.Boolean">
SELECT automatic_status_update FROM test_plan WHERE id = #{0}
</select>
</mapper> </mapper>

View File

@ -1,6 +1,10 @@
package io.metersphere.base.mapper.ext; 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 io.metersphere.plan.dto.TestPlanApiScenarioInfoDTO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List; import java.util.List;
@ -8,4 +12,9 @@ public interface ExtTestPlanScenarioCaseMapper {
List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(String planId); List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(String planId);
List<TestPlanApiScenarioInfoDTO> selectLegalUiDataByTestPlanId(String planId); List<TestPlanApiScenarioInfoDTO> selectLegalUiDataByTestPlanId(String planId);
}
List<CaseExecResult> selectExecResult(@Param("testPlanId") String testPlanId, @Param("scenarioCaseIds") List<String> loadCaseIdList);
@Select("SELECT id,test_plan_id,api_scenario_id,last_result FROM test_plan_api_scenario WHERE id = #{0} ")
TestPlanApiScenario selectBaseInfoById(String testId);
}

View File

@ -28,4 +28,14 @@
AND tpas.test_plan_id = #{0} AND tpas.test_plan_id = #{0}
ORDER BY tpas.`order` DESC; ORDER BY tpas.`order` DESC;
</select> </select>
<select id="selectExecResult" resultType="io.metersphere.plan.dto.CaseExecResult">
SELECT t.api_scenario_id AS id, a.name AS caseName,t.last_result AS execResult
FROM test_plan_api_scenario t
INNER JOIN api_scenario a ON t.api_scenario_id = a.id
WHERE t.test_plan_id = #{testPlanId} AND t.api_scenario_id in
<foreach collection="scenarioCaseIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper> </mapper>

View File

@ -1,11 +1,11 @@
package io.metersphere.base.mapper.ext; 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.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.request.function.QueryTestPlanCaseRequest; 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.plan.request.function.TestPlanFuncCaseConditions;
import io.metersphere.request.BaseQueryRequest;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -70,4 +70,10 @@ public interface ExtTestPlanTestCaseMapper {
String selectCaseId(String id); String selectCaseId(String id);
List<String> getCaseIdsByIds(@Param("ids") List<String> ids); List<String> getCaseIdsByIds(@Param("ids") List<String> ids);
void updateExecResultByTestPlanCaseIdList(@Param("ids") List<String> testPlanCaseIdList, @Param("execResult") String execResult);
void updateExecResultByTestCaseIdAndTestPlanId(@Param("testCaseId") String testCaseId, @Param("testPlanId") String testPlanId, @Param("execResult") String execResult);
List<TestPlanTestCase> selectByAutomationCaseIdAndTestPlanId(@Param("automationCaseId") String automationCaseId, @Param("test_plan_id") String testPlanId);
} }

View File

@ -644,4 +644,27 @@
and ${versionTable}.ref_id = #{request.refId} and ${versionTable}.ref_id = #{request.refId}
</if> </if>
</sql> </sql>
<select id="selectByAutomationCaseIdAndTestPlanId" resultType="io.metersphere.base.domain.TestPlanTestCase">
SELECT id,case_id FROM test_plan_test_case
WHERE plan_id = #{test_plan_id}
AND case_id IN (
SELECT test_case_id FROM test_case_test WHERE test_id = #{automationCaseId}
);
</select>
<update id="updateExecResultByTestPlanCaseIdList">
UPDATE test_plan_test_case SET status = #{execResult}
WHERE id IN
<foreach collection="ids" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</update>
<update id="updateExecResultByTestCaseIdAndTestPlanId">
UPDATE test_plan_test_case SET status = #{execResult}
WHERE case_id = #{testCaseId} AND plan_id = #{testPlanId}
</update>
</mapper> </mapper>

View File

@ -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<CaseExecResult> selectExecResult(@Param("testPlanId") String testPlanId, @Param("ids") List<String> relevanceApiCaseList);
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanUiCaseMapper">
<select id="selectExecResult" resultType="io.metersphere.plan.dto.CaseExecResult">
SELECT t.ui_scenario_id AS id,u.name AS caseName,t.last_result AS execResult
FROM test_plan_ui_scenario t
INNER JOIN ui_scenario u ON t.ui_scenario_id = u.id
WHERE t.test_plan_id = #{testPlanId} AND t.ui_scenario_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -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<io.metersphere.commons.utils.MybatisInterceptorConfig> 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;
}
}

View File

@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import io.metersphere.commons.utils.HttpHeaderUtils; import io.metersphere.commons.utils.HttpHeaderUtils;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.TestPlanCaseDTO; 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.dto.TestPlanSimpleReportDTO;
import io.metersphere.plan.service.TestPlanReportService; import io.metersphere.plan.service.TestPlanReportService;
import io.metersphere.plan.service.TestPlanService; 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.IssuesService;
import io.metersphere.service.ShareInfoService; import io.metersphere.service.ShareInfoService;
import io.metersphere.xpack.track.dto.IssuesDao; import io.metersphere.xpack.track.dto.IssuesDao;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.List; import java.util.List;
@ -67,24 +67,27 @@ public class ShareController {
} }
@GetMapping("test/plan/ext/report/{shareId}/{reportId}") @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); shareInfoService.validate(shareId, reportId);
if (SessionUtils.getUser() == null) { if (SessionUtils.getUser() == null) {
HttpHeaderUtils.runAsUser("admin"); HttpHeaderUtils.runAsUser("admin");
} }
TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByReportId(reportId); // testPlanService.getExtInfoByPlanId 这个方法逻辑有问题分不清楚干嘛用的方法删了调用地方先注释了
// TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByReportId(reportId);
ExecutionModeDTO reportExtInfo = new ExecutionModeDTO();
HttpHeaderUtils.clearUser(); HttpHeaderUtils.clearUser();
return reportExtInfo; return reportExtInfo;
} }
@GetMapping("test/plan/ext/plan/{shareId}/{planId}") @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); shareInfoService.validate(shareId, planId);
if (SessionUtils.getUser() == null) { if (SessionUtils.getUser() == null) {
HttpHeaderUtils.runAsUser("admin"); HttpHeaderUtils.runAsUser("admin");
} }
TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByPlanId(planId); // testPlanService.getExtInfoByPlanId 这个方法逻辑有问题分不清楚干嘛用的方法删了调用地方先注释了
// TestPlanExtReportDTO reportExtInfo = testPlanService.getExtInfoByPlanId(planId);
HttpHeaderUtils.clearUser(); HttpHeaderUtils.clearUser();
return reportExtInfo; return new ExecutionModeDTO();
} }
} }

View File

@ -14,9 +14,9 @@ import io.metersphere.dto.TestPlanRerunParametersDTO;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.log.annotation.MsAuditLog; import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice; import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.plan.dto.ExecutionModeDTO;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO; import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.dto.TestPlanDTO; import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.dto.TestPlanExtReportDTO;
import io.metersphere.plan.dto.TestPlanSimpleReportDTO; import io.metersphere.plan.dto.TestPlanSimpleReportDTO;
import io.metersphere.plan.request.AddTestPlanRequest; import io.metersphere.plan.request.AddTestPlanRequest;
import io.metersphere.plan.request.BatchOperateRequest; import io.metersphere.plan.request.BatchOperateRequest;
@ -61,7 +61,7 @@ public class TestPlanController {
@GetMapping("/auto-check/{testPlanId}") @GetMapping("/auto-check/{testPlanId}")
public void autoCheck(@PathVariable String testPlanId) { public void autoCheck(@PathVariable String testPlanId) {
testPlanService.checkStatus(testPlanId); testPlanService.checkTestPlanStatus(testPlanId);
} }
@PostMapping("/list/{goPage}/{pageSize}") @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) @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) { public void editTestPlanStatus(@PathVariable String planId) {
checkPermissionService.checkTestPlanOwner(planId); checkPermissionService.checkTestPlanOwner(planId);
testPlanService.checkStatus(planId); testPlanService.checkTestPlanStatus(planId);
} }
@PostMapping("/edit/report/config") @PostMapping("/edit/report/config")
@ -387,12 +387,12 @@ public class TestPlanController {
} }
@GetMapping("/ext/report/{reportId}") @GetMapping("/ext/report/{reportId}")
public TestPlanExtReportDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException { public ExecutionModeDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException {
return testPlanService.getExtInfoByReportId(reportId); return new ExecutionModeDTO();
} }
@GetMapping("/ext/plan/{planId}") @GetMapping("/ext/plan/{planId}")
public TestPlanExtReportDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException { public ExecutionModeDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException {
return testPlanService.getExtInfoByPlanId(planId); return new ExecutionModeDTO();
} }
} }

View File

@ -7,7 +7,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureApiDTO extends TestPlanApiCaseDTO { public class TestPlanApiDTO extends TestPlanApiCaseDTO {
private String response; private String response;
private String reportId; private String reportId;
} }

View File

@ -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<String, String> testPlanApiCaseIdAndReportIdMap;
private Map<String, String> testPlanScenarioIdAndReportIdMap;
private Map<String, String> testPlanUiScenarioIdAndReportIdMap;
private Map<String, String> testPlanLoadCaseIdAndReportIdMap;
private ApiPlanReportDTO apiPlanReportDTO;
private LoadPlanReportDTO loadPlanReportDTO;
private UiPlanReportDTO uiPlanReportDTO;
private List<TestPlanCaseDTO> functionCaseList;
private List<IssuesDao> issueList;
}

View File

@ -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<String, String> testPlanApiCaseIdAndReportIdMap;
private Map<String, String> testPlanScenarioIdAndReportIdMap;
private Map<String, String> testPlanUiScenarioIdAndReportIdMap;
private Map<String, String> testPlanLoadCaseIdAndReportIdMap;
private Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap;
private Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap;
private Map<String, TestPlanUiScenarioDTO> uiScenarioInfoDTOMap;
}

View File

@ -8,9 +8,4 @@ import lombok.Setter;
@Setter @Setter
public class TestPlanReportBuildResultDTO { public class TestPlanReportBuildResultDTO {
private TestPlanSimpleReportDTO testPlanSimpleReportDTO; private TestPlanSimpleReportDTO testPlanSimpleReportDTO;
/**
* 判断testPlanReportContent中APIBaseInfo字段是否改变
* 如果改变过则需要更新testPlanReportContent数据
*/
private boolean apiBaseInfoChanged = false;
} }

View File

@ -9,6 +9,6 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureScenarioDTO extends ApiScenarioDTO { public class TestPlanScenarioDTO extends ApiScenarioDTO {
private APIScenarioReportResult response; private APIScenarioReportResult response;
} }

View File

@ -7,14 +7,16 @@ import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.mapper.ApiExecutionQueueMapper; import io.metersphere.base.mapper.ApiExecutionQueueMapper;
import io.metersphere.commons.constants.KafkaTopicConstants; import io.metersphere.commons.constants.KafkaTopicConstants;
import io.metersphere.commons.constants.TestPlanReportStatus; import io.metersphere.commons.constants.TestPlanReportStatus;
import io.metersphere.plan.service.TestCaseSyncStatusService;
import io.metersphere.plan.service.TestPlanReportService; import io.metersphere.plan.service.TestPlanReportService;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import jakarta.annotation.Resource;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import jakarta.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -27,11 +29,29 @@ public class ExecReportListener {
private ApiExecutionQueueDetailMapper executionQueueDetailMapper; private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource @Resource
private TestPlanReportService testPlanReportService; private TestPlanReportService testPlanReportService;
@Resource
private TestCaseSyncStatusService testCaseSyncStatusService;
@KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, groupId = "${spring.application.name}") @KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, groupId = "${spring.application.name}")
public void consume(ConsumerRecord<?, String> record) { public void consume(ConsumerRecord<?, String> record) {
LoggerUtil.info("Execute message received", record.value()); 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) { public void testPlanReportTestEnded(String testPlanReportId) {
@ -41,7 +61,7 @@ public class ExecReportListener {
List<ApiExecutionQueue> queues = queueMapper.selectByExample(executionQueueExample); List<ApiExecutionQueue> queues = queueMapper.selectByExample(executionQueueExample);
if (CollectionUtils.isEmpty(queues)) { if (CollectionUtils.isEmpty(queues)) {
LoggerUtil.info("Normal execution completes, update test plan report status" + testPlanReportId); LoggerUtil.info("Normal execution completes, update test plan report status" + testPlanReportId);
testPlanReportService.finishedTestPlanReport(testPlanReportId, TestPlanReportStatus.COMPLETED.name()); testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
} else { } else {
List<String> ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList()); List<String> ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList());
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample(); ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
@ -49,7 +69,7 @@ public class ExecReportListener {
long count = executionQueueDetailMapper.countByExample(detailExample); long count = executionQueueDetailMapper.countByExample(detailExample);
if (count == 0) { if (count == 0) {
LoggerUtil.info("Normal execution completes, update test plan report status" + testPlanReportId); 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); LoggerUtil.info("Clear Queue" + ids);
ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample(); ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample();
queueExample.createCriteria().andIdIn(ids); queueExample.createCriteria().andIdIn(ids);

View File

@ -1,8 +1,8 @@
package io.metersphere.plan.dto; package io.metersphere.plan.dto;
import io.metersphere.dto.TestPlanFailureApiDTO; import io.metersphere.dto.TestPlanApiDTO;
import io.metersphere.dto.TestPlanFailureScenarioDTO; import io.metersphere.dto.TestPlanScenarioDTO;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -11,13 +11,13 @@ import java.util.List;
@Setter @Setter
@Getter @Getter
public class ApiPlanReportDTO { public class ApiPlanReportDTO {
private List<TestPlanFailureApiDTO> apiAllCases; private List<TestPlanApiDTO> apiAllCases;
private List<TestPlanFailureApiDTO> apiFailureCases; private List<TestPlanApiDTO> apiFailureCases;
private List<TestPlanFailureApiDTO> errorReportCases; private List<TestPlanApiDTO> errorReportCases;
private List<TestPlanFailureApiDTO> unExecuteCases; private List<TestPlanApiDTO> unExecuteCases;
private List<TestPlanFailureScenarioDTO> scenarioAllCases; private List<TestPlanScenarioDTO> scenarioAllCases;
private List<TestPlanFailureScenarioDTO> scenarioFailureCases; private List<TestPlanScenarioDTO> scenarioFailureCases;
private List<TestPlanFailureScenarioDTO> errorReportScenarios; private List<TestPlanScenarioDTO> errorReportScenarios;
private List<TestPlanFailureScenarioDTO> unExecuteScenarios; private List<TestPlanScenarioDTO> unExecuteScenarios;
} }

View File

@ -0,0 +1,17 @@
package io.metersphere.plan.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Setter
@Getter
public class ApiReportResultDTO {
// <reportId status>接口报告结果
Map<String, String> apiReportResultMap;
// <reportId status>场景报告结果
Map<String, String> scenarioReportResultMap;
}

View File

@ -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;
}

View File

@ -3,7 +3,7 @@ package io.metersphere.plan.dto;
import lombok.Data; import lombok.Data;
@Data @Data
public class TestPlanExtReportDTO { public class ExecutionModeDTO {
/** /**
* 运行模式 * 运行模式

View File

@ -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<TestCaseTest> testCaseTestList;
//以下四个自动化用例执行结果mapkey-> testCaseId
Map<String, CaseExecResult> apiAllCaseMap;
Map<String, CaseExecResult> scenarioAllCaseMap;
Map<String, CaseExecResult> loadAllCaseMap;
Map<String, CaseExecResult> uiAllCaseMap;
}

View File

@ -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;
}

View File

@ -48,15 +48,15 @@ public class TestPlanSimpleReportDTO extends TestPlanReportContent {
List<TestPlanLoadCaseDTO> loadAllCases; List<TestPlanLoadCaseDTO> loadAllCases;
List<TestPlanLoadCaseDTO> loadFailureCases; List<TestPlanLoadCaseDTO> loadFailureCases;
List<TestPlanFailureApiDTO> apiAllCases; List<TestPlanApiDTO> apiAllCases;
List<TestPlanFailureApiDTO> errorReportCases; List<TestPlanApiDTO> errorReportCases;
List<TestPlanFailureApiDTO> apiFailureCases; List<TestPlanApiDTO> apiFailureCases;
List<TestPlanFailureApiDTO> unExecuteCases; List<TestPlanApiDTO> unExecuteCases;
List<TestPlanFailureScenarioDTO> scenarioAllCases; List<TestPlanScenarioDTO> scenarioAllCases;
List<TestPlanFailureScenarioDTO> errorReportScenarios; List<TestPlanScenarioDTO> errorReportScenarios;
List<TestPlanFailureScenarioDTO> scenarioFailureCases; List<TestPlanScenarioDTO> scenarioFailureCases;
List<TestPlanFailureScenarioDTO> unExecuteScenarios; List<TestPlanScenarioDTO> unExecuteScenarios;
List<TestPlanUiScenarioDTO> uiAllCases; List<TestPlanUiScenarioDTO> uiAllCases;
List<TestPlanUiScenarioDTO> uiFailureCases; List<TestPlanUiScenarioDTO> uiFailureCases;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,13 +1,17 @@
package io.metersphere.plan.request.api; package io.metersphere.plan.request.api;
import io.metersphere.dto.TestPlanExecuteReportDTO; import io.metersphere.dto.TestPlanCaseReportResultDTO;
import io.metersphere.request.PlanSubReportRequest; import io.metersphere.request.PlanSubReportRequest;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Setter @Setter
@Getter @Getter
public class ApiPlanReportRequest extends PlanSubReportRequest { public class ApiPlanReportRequest extends PlanSubReportRequest {
private TestPlanExecuteReportDTO testPlanExecuteReportDTO; List<String> apiReportIdList;
List<String> scenarioReportIdList;
private TestPlanCaseReportResultDTO testPlanExecuteReportDTO;
} }

View File

@ -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<PlanReportCaseDTO> testPlanCaseList, List<TestPlanApiDTO> apiAllCases, List<TestPlanScenarioDTO> scenarioAllCases, List<TestPlanLoadCaseDTO> loadAllCases, List<TestPlanUiScenarioDTO> uiAllCases) {
List<TestCaseTest> testCaseTestList = this.selectTestPlanTestCaseByPlanReportCase(testPlanCaseList);
Map<String, CaseExecResult> testCaseStatusByAutomationCase = TestCaseSyncStatusUtil.getTestCaseStatusByAutomationCaseRunResult(
testPlanCaseList, testCaseTestList, apiAllCases, scenarioAllCases, loadAllCases, uiAllCases);
TestCaseSyncStatusUtil.updateFunctionCaseStatusByAutomationExecResult(testPlanCaseList, testCaseStatusByAutomationCase);
}
private List<TestCaseTest> selectTestPlanTestCaseByPlanReportCase(List<PlanReportCaseDTO> testPlanCaseList) {
if (CollectionUtils.isNotEmpty(testPlanCaseList)) {
List<String> 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<PlanReportCaseDTO> testPlanCaseList, List<TestPlanApiDTO> apiAllCaseList, List<TestPlanScenarioDTO> scenarioAllCaseList, List<TestPlanLoadCaseDTO> loadAllCaseList, List<TestPlanUiScenarioDTO> uiAllCaseList) {
if (CollectionUtils.isNotEmpty(testPlanCaseList)) {
List<TestCaseTest> testCaseTestList = this.selectTestPlanTestCaseByPlanReportCase(testPlanCaseList);
Map<String, CaseExecResult> testCaseStatusByAutomationCase = TestCaseSyncStatusUtil.getTestCaseStatusByAutomationCaseRunResult(
testPlanCaseList, testCaseTestList, apiAllCaseList, scenarioAllCaseList, loadAllCaseList, uiAllCaseList);
Map<String, CaseExecResult> successCaseMap = new HashMap<>();
Map<String, CaseExecResult> errorCaseMap = new HashMap<>();
Map<String, CaseExecResult> 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<String> testCaseIdSet = new HashSet<>();
List<TestPlanTestCase> 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<TestCaseTest> testCaseTestList = testCaseTestMapper.selectByExample(testCaseTestExample);
Map<String, List<TestCaseTest>> testCaseTestMap = testCaseTestList.stream().collect(Collectors.groupingBy(TestCaseTest::getTestCaseId));
for (Map.Entry<String, List<TestCaseTest>> 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<TestCaseTest> testCaseTestList) {
TestCaseRelevanceCasesRequest request = new TestCaseRelevanceCasesRequest();
request.setTestCaseId(testCaseId);
request.setTestPlanId(testPlanId);
request.setTestCaseTestList(testCaseTestList);
List<String> relevanceApiCaseList = new ArrayList<>();
List<String> relevanceScenarioList = new ArrayList<>();
List<String> relevanceLoadCaseList = new ArrayList<>();
List<String> 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<CaseExecResult> apiAllCaseList = extTestPlanApiCaseMapper.selectExecResult(testPlanId, relevanceApiCaseList);
request.setApiAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(apiAllCaseList));
}
if (CollectionUtils.isNotEmpty(relevanceScenarioList)) {
List<CaseExecResult> scenarioAllCaseList = extTestPlanScenarioCaseMapper.selectExecResult(testPlanId, relevanceScenarioList);
request.setScenarioAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(scenarioAllCaseList));
}
if (CollectionUtils.isNotEmpty(relevanceLoadCaseList)) {
List<CaseExecResult> loadAllCaseList = extTestPlanLoadCaseMapper.selectExecResult(testPlanId, relevanceLoadCaseList);
request.setLoadAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(loadAllCaseList));
}
if (CollectionUtils.isNotEmpty(relevanceUiList)) {
List<CaseExecResult> uiAllCaseList = extTestPlanUiCaseMapper.selectExecResult(testPlanId, relevanceUiList);
request.setUiAllCaseMap(TestCaseSyncStatusUtil.getExecResultMap(uiAllCaseList));
}
return request;
}
private void addTestCaseComment(String commentCreateUser, String testPlanName, Map<String, CaseExecResult> caseExecResultMap, String commentStatus) {
if (MapUtils.isNotEmpty(caseExecResultMap)) {
for (Map.Entry<String, CaseExecResult> 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);
}
}
}

View File

@ -15,6 +15,7 @@ import io.metersphere.service.BaseProjectService;
import io.metersphere.service.BaseShareInfoService; import io.metersphere.service.BaseShareInfoService;
import io.metersphere.service.BaseUserService; import io.metersphere.service.BaseUserService;
import io.metersphere.service.SystemParameterService; import io.metersphere.service.SystemParameterService;
import jakarta.annotation.Resource;
import org.apache.commons.beanutils.BeanMap; import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -23,7 +24,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -102,11 +102,11 @@ public class TestPlanMessageService {
// 已结束超过了计划结束时间如有 测试进度=100% 通过率非100% // 已结束超过了计划结束时间如有 测试进度=100% 通过率非100%
Long plannedEndTime = testPlan.getPlannedEndTime(); Long plannedEndTime = testPlan.getPlannedEndTime();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if(Objects.nonNull(plannedEndTime) && currentTime >= plannedEndTime){ if (Objects.nonNull(plannedEndTime) && currentTime >= plannedEndTime) {
return TestPlanStatus.Finished.name(); return TestPlanStatus.Finished.name();
} }
if(testRate >= FULL_MARKS && passRate < FULL_MARKS){ if (testRate >= FULL_MARKS && passRate < FULL_MARKS) {
return TestPlanStatus.Finished.name(); return TestPlanStatus.Finished.name();
} }
@ -281,7 +281,7 @@ public class TestPlanMessageService {
result.put("functionAllCount", (long) functionAllCases.size()); result.put("functionAllCount", (long) functionAllCases.size());
} }
List<TestPlanFailureApiDTO> apiAllCases = report.getApiAllCases(); List<TestPlanApiDTO> apiAllCases = report.getApiAllCases();
if (CollectionUtils.isNotEmpty(apiAllCases)) { if (CollectionUtils.isNotEmpty(apiAllCases)) {
Map<String, Long> apiCountMap = apiAllCases.stream() Map<String, Long> apiCountMap = apiAllCases.stream()
.collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getExecResult()) ? "default" : plan.getExecResult().toLowerCase(), Collectors.counting())); .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()); result.put("apiCaseAllCount", (long) apiAllCases.size());
} }
List<TestPlanFailureScenarioDTO> scenarioAllCases = report.getScenarioAllCases(); List<TestPlanScenarioDTO> scenarioAllCases = report.getScenarioAllCases();
if (CollectionUtils.isNotEmpty(scenarioAllCases)) { if (CollectionUtils.isNotEmpty(scenarioAllCases)) {
Map<String, Long> scenarioCountMap = scenarioAllCases.stream() Map<String, Long> scenarioCountMap = scenarioAllCases.stream()
.collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getLastResult()) ? "unexecute" : plan.getLastResult().toLowerCase(), Collectors.counting())); .collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getLastResult()) ? "unexecute" : plan.getLastResult().toLowerCase(), Collectors.counting()));

View File

@ -22,7 +22,6 @@ import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference; import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.plan.constant.RunMode;
import io.metersphere.plan.dto.*; import io.metersphere.plan.dto.*;
import io.metersphere.plan.job.TestPlanTestJob; import io.metersphere.plan.job.TestPlanTestJob;
import io.metersphere.plan.request.AddTestPlanRequest; 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.performance.PlanTestPlanLoadCaseService;
import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService; import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService;
import io.metersphere.plan.service.remote.ui.PlanUiAutomationService; import io.metersphere.plan.service.remote.ui.PlanUiAutomationService;
import io.metersphere.plan.utils.TestPlanReportUtil;
import io.metersphere.plan.utils.TestPlanRequestUtil; import io.metersphere.plan.utils.TestPlanRequestUtil;
import io.metersphere.request.ScheduleRequest; import io.metersphere.request.ScheduleRequest;
import io.metersphere.service.*; import io.metersphere.service.*;
@ -485,7 +485,14 @@ public class TestPlanService {
return testPlans; 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<String> statusList = new ArrayList<>(); List<String> statusList = new ArrayList<>();
statusList.addAll(extTestPlanTestCaseMapper.getExecResultByPlanId(testPlanId)); statusList.addAll(extTestPlanTestCaseMapper.getExecResultByPlanId(testPlanId));
@ -883,25 +890,56 @@ public class TestPlanService {
LoggerUtil.info("预生成测试计划报告【" + reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY + "】计划报告ID[" + planReportId + "]"); LoggerUtil.info("预生成测试计划报告【" + reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY + "】计划报告ID[" + planReportId + "]");
Map<String, String> apiCaseReportMap = null;
Map<String, String> scenarioReportMap = null; List<TestPlanApiDTO> apiTestCases = null;
List<TestPlanScenarioDTO> scenarioCases = null;
List<TestPlanUiScenarioDTO> uiScenarios = null;
Map<String, String> loadCaseReportMap = null; Map<String, String> loadCaseReportMap = null;
Map<String, String> uiScenarioReportMap = null;
if (MapUtils.isNotEmpty(reportInfoDTO.getApiTestCaseDataMap())) { if (MapUtils.isNotEmpty(reportInfoDTO.getApiTestCaseDataMap())) {
//执行接口案例任务
LoggerUtil.info("开始执行测试计划接口用例 " + planReportId);
try { try {
apiCaseReportMap = this.executeApiTestCase(triggerMode, planReportId, userId, testPlanId, runModeConfig); apiTestCases = planTestPlanApiCaseService.getFailureListByIds(reportInfoDTO.getApiTestCaseDataMap().keySet());
} catch (Exception e) { } catch (Exception e) {
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划接口用例失败! ", e); LogUtil.error("测试计划执行查询接口用例失败!", e);
} }
} }
if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) { 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<String, String> 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); LoggerUtil.info("开始执行测试计划场景用例 " + planReportId);
try { try {
scenarioReportMap = this.executeScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getPlanScenarioIdMap()); Map<String, String> scenarioReportMap = this.executeScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getPlanScenarioIdMap());
for (TestPlanScenarioDTO dto : scenarioCases) {
dto.setReportId(scenarioReportMap.get(dto.getId()));
}
} catch (Exception e) { } catch (Exception e) {
scenarioCases = null;
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划场景用例失败! ", e); LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划场景用例失败! ", e);
} }
} }
@ -916,19 +954,22 @@ public class TestPlanService {
} }
} }
if (reportInfoDTO.getUiScenarioIdMap() != null) { if (CollectionUtils.isNotEmpty(uiScenarios)) {
//执行UI场景执行任务 //执行UI场景执行任务
LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId); LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId);
try { try {
uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap()); Map<String, String> uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap());
for (TestPlanUiScenarioDTO dto : uiScenarios) {
dto.setReportId(uiScenarioReportMap.get(dto.getId()));
}
} catch (Exception e) { } catch (Exception e) {
uiScenarios = null;
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划 UI 用例失败! ", e); LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划 UI 用例失败! ", e);
} }
} }
LoggerUtil.info("开始生成测试计划报告内容 " + planReportId); LoggerUtil.info("开始生成测试计划报告内容 " + planReportId);
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiCaseReportMap, scenarioReportMap, loadCaseReportMap, uiScenarioReportMap); testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiTestCases, scenarioCases, uiScenarios, loadCaseReportMap);
return planReportId; return planReportId;
} }
@ -1245,14 +1286,14 @@ public class TestPlanService {
report.setFunctionAllCases(allCases); report.setFunctionAllCases(allCases);
} }
if (checkReportConfig(config, "functional", "issue")) { if (TestPlanReportUtil.checkReportConfig(config, "functional", "issue")) {
List<IssuesDao> issueList = issuesService.getIssuesByPlanId(planId); List<IssuesDao> issueList = issuesService.getIssuesByPlanId(planId);
report.setIssueList(issueList); 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(); ApiPlanReportRequest request = new ApiPlanReportRequest();
request.setConfig(config); request.setConfig(config);
request.setPlanId(planId); request.setPlanId(planId);
@ -1274,16 +1315,16 @@ public class TestPlanService {
*/ */
public List<String> getFunctionalReportStatusList(Map config) { public List<String> getFunctionalReportStatusList(Map config) {
List<String> statusList = new ArrayList<>(); List<String> statusList = new ArrayList<>();
if (checkReportConfig(config, "functional", "all")) { if (TestPlanReportUtil.checkReportConfig(config, "functional", "all")) {
return statusList; return statusList;
} }
if (checkReportConfig(config, "functional", "failure")) { if (TestPlanReportUtil.checkReportConfig(config, "functional", "failure")) {
statusList.add(TestPlanTestCaseStatus.Failure.name()); statusList.add(TestPlanTestCaseStatus.Failure.name());
} }
if (checkReportConfig(config, "functional", "blocking")) { if (TestPlanReportUtil.checkReportConfig(config, "functional", "blocking")) {
statusList.add(TestPlanTestCaseStatus.Blocking.name()); statusList.add(TestPlanTestCaseStatus.Blocking.name());
} }
if (checkReportConfig(config, "functional", "skip")) { if (TestPlanReportUtil.checkReportConfig(config, "functional", "skip")) {
statusList.add(TestPlanTestCaseStatus.Skip.name()); statusList.add(TestPlanTestCaseStatus.Skip.name());
} }
return statusList.size() > 0 ? statusList : null; 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<String, String> 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 testPlanReport 测试计划报告
* @param testPlanReportContentWithBLOBs 测试计划报告内容 * @param testPlanReportContentWithBLOBs 测试计划报告内容
* @return * @return
*/ */
public TestPlanReportBuildResultDTO buildPlanReport(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { public TestPlanReportBuildResultDTO buildTestPlanReport(TestPlanWithBLOBs testPlan, TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) {
TestPlanReportBuildResultDTO returnDTO = new TestPlanReportBuildResultDTO(); TestPlanReportBuildResultDTO returnDTO = new TestPlanReportBuildResultDTO();
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId()); if (ObjectUtils.allNotNull(testPlanReport, testPlanReportContentWithBLOBs)) {
if (testPlan != null) {
String reportConfig = testPlan.getReportConfig();
Map config = null; Map config = null;
if (StringUtils.isNotBlank(reportConfig)) { if (StringUtils.isNotBlank(testPlan.getReportConfig())) {
config = JSON.parseMap(reportConfig); config = JSON.parseMap(testPlan.getReportConfig());
} }
TestPlanExecuteReportDTO testPlanExecuteReportDTO = testPlanReportService.genTestPlanExecuteReportDTOByTestPlanReportContent(testPlanReportContentWithBLOBs); TestPlanSimpleReportDTO report = this.getTestPlanReportStructByCreated(testPlanReportContentWithBLOBs);
//检查是否有已经生成过的测试计划报告内容如若没有则进行动态计算
TestPlanSimpleReportDTO report = null; if (report == null) {
boolean apiBaseInfoChanged = false; //查询测试计划内的用例信息然后进行测试计划报告的结果统计
if (StringUtils.isEmpty(testPlanReportContentWithBLOBs.getApiBaseCount())) { TestPlanCaseReportResultDTO testPlanExecuteReportDTO = testPlanReportService.selectCaseDetailByTestPlanReport(config, testPlan.getId(), testPlanReportContentWithBLOBs);
report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO); report = generateTestPlanReport(
apiBaseInfoChanged = true; config,
} else { testPlanReport.getCreator(),
try { StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name(), TestPlanReportStatus.SUCCESS.name(), TestPlanReportStatus.FAILED.name()),
report = JSON.parseObject(testPlanReportContentWithBLOBs.getApiBaseCount(), TestPlanSimpleReportDTO.class); testPlan, testPlanExecuteReportDTO);
} catch (Exception e) {
LogUtil.info("解析接口统计数据出错!数据:" + testPlanReportContentWithBLOBs.getApiBaseCount(), e);
}
if (report == null) {
report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO);
apiBaseInfoChanged = true;
}
} }
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); returnDTO.setTestPlanSimpleReportDTO(report);
if (apiBaseInfoChanged) {
testPlanReportContentWithBLOBs.setApiBaseCount(JSON.toJSONString(report));
returnDTO.setApiBaseInfoChanged(true);
}
return returnDTO;
} else { } else {
returnDTO.setTestPlanSimpleReportDTO(new TestPlanSimpleReportDTO()); 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) { public TestPlanSimpleReportDTO buildPlanReport(String planId, boolean saveResponse) {
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId); TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId);
@ -1413,19 +1415,11 @@ public class TestPlanService {
public void exportPlanReport(String planId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException { public void exportPlanReport(String planId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException {
TestPlanSimpleReportDTO report = buildPlanReport(planId, true); TestPlanSimpleReportDTO report = buildPlanReport(planId, true);
report.setLang(lang); report.setLang(lang);
TestPlanExtReportDTO extReport = getExtInfoByPlanId(planId);
if (extReport != null) {
BeanUtils.copyBean(report, extReport);
}
render(report, response); render(report, response);
} }
public void exportPlanDbReport(String reportId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException { public void exportPlanDbReport(String reportId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException {
TestPlanSimpleReportDTO report = testPlanReportService.getReport(reportId); TestPlanSimpleReportDTO report = testPlanReportService.getReport(reportId);
TestPlanExtReportDTO extReport = getExtInfoByReportId(reportId);
if (extReport != null) {
BeanUtils.copyBean(report, extReport);
}
Set<String> serviceIdSet = DiscoveryUtil.getServiceIdSet(); Set<String> serviceIdSet = DiscoveryUtil.getServiceIdSet();
if (serviceIdSet.contains(MicroServiceName.API_TEST)) { if (serviceIdSet.contains(MicroServiceName.API_TEST)) {
report.setApiAllCases(planTestPlanApiCaseService.buildResponse(report.getApiAllCases())); 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 测试计划各个资源的报告 如果为空则取当前测试计划资源的最新报告 * @param testPlanExecuteReportDTO 测试计划各个资源的报告 如果为空则取当前测试计划资源的最新报告
* @return * @return
*/ */
public TestPlanSimpleReportDTO getReport(String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO) { public TestPlanSimpleReportDTO getReport(String planId, TestPlanCaseReportResultDTO testPlanExecuteReportDTO) {
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId); TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId);
TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO(); TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO();
TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO(); TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO();
@ -2033,132 +2086,6 @@ public class TestPlanService {
this.deleteTestPlans(ids); this.deleteTestPlans(ids);
} }
public TestPlanExtReportDTO getExtInfoByReportId(String reportId) throws JsonProcessingException {
TestPlanExtReportDTO testPlanExtReportDTO = new TestPlanExtReportDTO();
Set<String> serviceIdSet = DiscoveryUtil.getServiceIdSet();
if (serviceIdSet.contains(MicroServiceName.API_TEST)) {
List<ApiDefinitionExecResultWithBLOBs> apiDefinitionLists = planTestPlanApiCaseService.selectExtForPlanReport(reportId);
if (CollectionUtils.isNotEmpty(apiDefinitionLists)) {
ApiDefinitionExecResultWithBLOBs apiDefinition = apiDefinitionLists.get(0);
convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO);
getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO);
return testPlanExtReportDTO;
}
List<ApiScenarioReportWithBLOBs> 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<UiScenarioReportWithBLOBs> 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<TestPlanLoadCaseDTO> 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<String> serviceIdSet = DiscoveryUtil.getServiceIdSet();
if (serviceIdSet.contains(MicroServiceName.API_TEST)) {
List<ApiDefinitionExecResultWithBLOBs> apiDefinitionLists = planTestPlanApiCaseService.selectExtForPlanReport(reportId);
if (CollectionUtils.isNotEmpty(apiDefinitionLists)) {
ApiDefinitionExecResultWithBLOBs apiDefinition = apiDefinitionLists.get(0);
convertEnvConfig(apiDefinition.getEnvConfig(), testPlanExtReportDTO);
getResourcePool(apiDefinition.getActuator(), testPlanExtReportDTO);
return testPlanExtReportDTO;
}
List<ApiScenarioReportWithBLOBs> 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<UiScenarioReportWithBLOBs> 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<TestPlanLoadCaseDTO> 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<String> getRelevanceProjectIds(String planId) { public List<String> getRelevanceProjectIds(String planId) {
List<String> projectIds = new ArrayList<>(); List<String> projectIds = new ArrayList<>();
List<String> apiCaseProjectIds = planTestPlanApiCaseService.getApiCaseProjectIds(planId); List<String> apiCaseProjectIds = planTestPlanApiCaseService.getApiCaseProjectIds(planId);
@ -2172,17 +2099,4 @@ public class TestPlanService {
return projectIds.stream().distinct().collect(Collectors.toList()); 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());
}
}
}
} }

View File

@ -10,18 +10,16 @@ import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.IssueRefType; import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.MicroServiceName; import io.metersphere.commons.constants.MicroServiceName;
import io.metersphere.commons.constants.ProjectApplicationType; import io.metersphere.commons.constants.ProjectApplicationType;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.constants.TestCaseCommentType; import io.metersphere.constants.TestCaseCommentType;
import io.metersphere.dto.ProjectConfig; import io.metersphere.dto.*;
import io.metersphere.dto.PlanReportCaseDTO;
import io.metersphere.excel.constants.TestPlanTestCaseStatus; 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.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails; 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.request.function.*;
import io.metersphere.plan.service.remote.api.PlanApiAutomationService; import io.metersphere.plan.service.remote.api.PlanApiAutomationService;
import io.metersphere.plan.service.remote.api.PlanApiTestCaseService; 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.OrderRequest;
import io.metersphere.request.ResetOrderRequest; import io.metersphere.request.ResetOrderRequest;
import io.metersphere.request.member.QueryMemberRequest; import io.metersphere.request.member.QueryMemberRequest;
import io.metersphere.service.*;
import io.metersphere.dto.*;
import io.metersphere.request.testcase.TrackCount; import io.metersphere.request.testcase.TrackCount;
import io.metersphere.request.testreview.SaveCommentRequest; import io.metersphere.request.testreview.SaveCommentRequest;
import io.metersphere.service.*;
import io.metersphere.utils.DiscoveryUtil; import io.metersphere.utils.DiscoveryUtil;
import io.metersphere.xpack.track.dto.IssuesDao; import io.metersphere.xpack.track.dto.IssuesDao;
import io.metersphere.xpack.version.service.ProjectVersionService; import io.metersphere.xpack.version.service.ProjectVersionService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -90,6 +88,8 @@ public class TestPlanTestCaseService {
private FunctionCaseExecutionInfoService functionCaseExecutionInfoService; private FunctionCaseExecutionInfoService functionCaseExecutionInfoService;
@Resource @Resource
private CustomFieldTestCaseService customFieldTestCaseService; private CustomFieldTestCaseService customFieldTestCaseService;
@Resource
private TestCaseSyncStatusService testCaseSyncStatusService;
private static final String CUSTOM_NUM = "custom_num"; private static final String CUSTOM_NUM = "custom_num";
private static final String NUM = "num"; private static final String NUM = "num";
@ -139,10 +139,10 @@ public class TestPlanTestCaseService {
public QueryTestPlanCaseRequest setCustomNumOrderParam(QueryTestPlanCaseRequest request) { public QueryTestPlanCaseRequest setCustomNumOrderParam(QueryTestPlanCaseRequest request) {
List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders()); List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders());
// CUSTOM_NUM ORDER // 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) { if (customOrderFlag) {
// 判断当前项目时候开启自定义字段的配置 // 判断当前项目时候开启自定义字段的配置
boolean customNumEnable = baseProjectApplicationService.checkCustomNumByProjectId(request.getProjectId()); boolean customNumEnable = baseProjectApplicationService.checkCustomNumByProjectId(request.getProjectId());
orders.forEach(order -> { orders.forEach(order -> {
if (StringUtils.equals(order.getName(), CUSTOM_NUM)) { if (StringUtils.equals(order.getName(), CUSTOM_NUM)) {
if (customNumEnable) { if (customNumEnable) {
@ -520,24 +520,56 @@ public class TestPlanTestCaseService {
return null; return null;
} }
public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) { public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) {
try { try {
List<PlanReportCaseDTO> planReportCaseDTOS = extTestPlanTestCaseMapper.selectForPlanReport(planId); List<PlanReportCaseDTO> planReportCaseDTOS = extTestPlanTestCaseMapper.selectForPlanReport(planId);
TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult(); this.calculatePlanReport(planReportCaseDTOS, report);
List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>();
Map<String, TestCaseReportStatusResultDTO> 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);
} catch (MSException e) { } catch (MSException e) {
LogUtil.error(e); LogUtil.error(e);
} }
} }
public void calculateReportByTestCaseList(String operator, TestPlan testPlan, boolean isTestPlanExecuteOver, List<TestPlanCaseDTO> testPlanCaseList, TestPlanSimpleReportDTO report) {
try {
if (ObjectUtils.anyNotNull(testPlan, report) && CollectionUtils.isNotEmpty(testPlanCaseList)) {
List<PlanReportCaseDTO> 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<PlanReportCaseDTO> planReportCaseDTOList, TestPlanSimpleReportDTO report) {
TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult();
List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>();
Map<String, TestCaseReportStatusResultDTO> 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<TestPlanCaseDTO> getAllCasesByStatusList(String planId, List<String> statusList) { public List<TestPlanCaseDTO> getAllCasesByStatusList(String planId, List<String> statusList) {
return buildCaseInfo(extTestPlanTestCaseMapper.getCasesByStatusList(planId, statusList)); return buildCaseInfo(extTestPlanTestCaseMapper.getCasesByStatusList(planId, statusList));
} }

View File

@ -62,6 +62,26 @@ public class PlanTestPlanApiCaseService extends ApiTestService {
} }
} }
public void calculateReportByApiCase(List<TestPlanApiDTO> testPlanApiDTOList, TestPlanSimpleReportDTO report) {
try {
if (CollectionUtils.isNotEmpty(testPlanApiDTOList)) {
List<PlanReportCaseDTO> 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<String> apiReportIds, TestPlanSimpleReportDTO report) { public void calculatePlanReport(List<String> apiReportIds, TestPlanSimpleReportDTO report) {
try { try {
List<PlanReportCaseDTO> planReportCaseDTOS = planApiDefinitionExecResultService.selectForPlanReport(apiReportIds); List<PlanReportCaseDTO> planReportCaseDTOS = planApiDefinitionExecResultService.selectForPlanReport(apiReportIds);
@ -153,8 +173,8 @@ public class PlanTestPlanApiCaseService extends ApiTestService {
return (Boolean) microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId); return (Boolean) microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId);
} }
public List<TestPlanFailureApiDTO> getFailureListByIds(Set<String> ids) { public List<TestPlanApiDTO> getFailureListByIds(Set<String> ids) {
return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanFailureApiDTO.class); return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanApiDTO.class);
} }
public Boolean hasFailCase(String planId, List<String> apiCaseIds) { public Boolean hasFailCase(String planId, List<String> apiCaseIds) {
@ -165,11 +185,11 @@ public class PlanTestPlanApiCaseService extends ApiTestService {
return microService.postForDataArray(serviceName, BASE_UEL + "/list/module/" + planId + "/" + protocol, projectIds, ApiModuleDTO.class); return microService.postForDataArray(serviceName, BASE_UEL + "/list/module/" + planId + "/" + protocol, projectIds, ApiModuleDTO.class);
} }
public List<TestPlanFailureApiDTO> buildResponse(List<TestPlanFailureApiDTO> apiAllCases) { public List<TestPlanApiDTO> buildResponse(List<TestPlanApiDTO> apiAllCases) {
if (CollectionUtils.isEmpty(apiAllCases)) { if (CollectionUtils.isEmpty(apiAllCases)) {
return null; 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) { public Object relevanceList(int pageNum, int pageSize, ApiTestCaseRequest request) {

View File

@ -52,6 +52,23 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService {
} }
} }
public void calculateReportByScenario(List<TestPlanScenarioDTO> testPlanScenarioDTOList, TestPlanSimpleReportDTO report) {
try {
List<PlanReportCaseDTO> 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<String> reportIds, TestPlanSimpleReportDTO report) { public void calculatePlanReport(List<String> reportIds, TestPlanSimpleReportDTO report) {
try { try {
List<PlanReportCaseDTO> planReportCaseDTOS = planApiScenarioReportService.selectForPlanReport(reportIds); List<PlanReportCaseDTO> planReportCaseDTOS = planApiScenarioReportService.selectForPlanReport(reportIds);
@ -69,10 +86,8 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService {
TestPlanStatusCalculator.addToReportCommonStatusResultList(statusResultMap, statusResult); TestPlanStatusCalculator.addToReportCommonStatusResultList(statusResultMap, statusResult);
TestPlanScenarioStepCountSimpleDTO stepCountResult = getStepCount(planReportCaseDTOS); TestPlanScenarioStepCountSimpleDTO stepCountResult = getStepCount(planReportCaseDTOS);
TestPlanScenarioStepCountDTO stepCount = stepCountResult.getStepCount(); TestPlanScenarioStepCountDTO stepCount = stepCountResult.getStepCount();
int underwayStepsCounts = stepCountResult.getUnderwayStepsCounts(); int underwayStepsCounts = stepCountResult.getUnderwayStepsCounts();
List<TestCaseReportStatusResultDTO> stepResult = getStepResult(stepCount, underwayStepsCounts); List<TestCaseReportStatusResultDTO> stepResult = getStepResult(stepCount, underwayStepsCounts);
apiResult.setApiScenarioData(statusResult); apiResult.setApiScenarioData(statusResult);
apiResult.setApiScenarioStepData(stepResult); apiResult.setApiScenarioStepData(stepResult);
@ -156,16 +171,16 @@ public class PlanTestPlanScenarioCaseService extends ApiTestService {
return microService.postForData(serviceName, BASE_UEL + "/plan/report", request, ApiPlanReportDTO.class); return microService.postForData(serviceName, BASE_UEL + "/plan/report", request, ApiPlanReportDTO.class);
} }
public ApiPlanReportDTO getApiExecuteReport(ApiPlanReportRequest request) { public ApiReportResultDTO getApiExecuteReport(ApiPlanReportRequest request) {
return microService.postForData(serviceName, BASE_UEL + "/plan/execute/report", request, ApiPlanReportDTO.class); return microService.postForData(serviceName, BASE_UEL + "/select/result/by/reportId", request, ApiReportResultDTO.class);
} }
public Boolean isCaseExecuting(String planId) { public Boolean isCaseExecuting(String planId) {
return microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId, Boolean.class); return microService.getForData(serviceName, BASE_UEL + "/is/executing/" + planId, Boolean.class);
} }
public List<TestPlanFailureScenarioDTO> getFailureListByIds(Set<String> ids) { public List<TestPlanScenarioDTO> getFailureListByIds(Set<String> ids) {
return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanFailureScenarioDTO.class); return microService.postForDataArray(serviceName, BASE_UEL + "/all/list", ids, TestPlanScenarioDTO.class);
} }
public TestPlanEnvInfoDTO generateEnvironmentInfo(TestPlanReport testPlanReport) { 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); return microService.postForDataArray(serviceName, BASE_UEL + "/list/module/" + planId, projectIds, ApiScenarioModuleDTO.class);
} }
public List<TestPlanFailureScenarioDTO> buildResponse(List<TestPlanFailureScenarioDTO> scenarioCases) { public List<TestPlanScenarioDTO> buildResponse(List<TestPlanScenarioDTO> scenarioCases) {
if (CollectionUtils.isEmpty(scenarioCases)) { if (CollectionUtils.isEmpty(scenarioCases)) {
return null; 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) { public Object relevanceList(ApiScenarioRequest request, int pageNum, int pageSize) {

View File

@ -15,11 +15,11 @@ import io.metersphere.plan.request.performance.LoadPlanReportDTO;
import io.metersphere.plan.service.TestPlanService; import io.metersphere.plan.service.TestPlanService;
import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.plan.utils.TestPlanStatusCalculator;
import io.metersphere.utils.DiscoveryUtil; import io.metersphere.utils.DiscoveryUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -43,6 +43,23 @@ public class PlanTestPlanLoadCaseService extends LoadTestService {
} }
} }
public void calculateReportByLoadCaseList(List<TestPlanLoadCaseDTO> testPlanLoadCaseDTOList, TestPlanSimpleReportDTO report) {
try {
List<PlanReportCaseDTO> 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<String> reportIds, TestPlanSimpleReportDTO report) { public void calculatePlanReport(List<String> reportIds, TestPlanSimpleReportDTO report) {
try { try {
List<PlanReportCaseDTO> planReportCaseDTOs = planLoadTestReportService.getPlanReportCaseDTO(reportIds); List<PlanReportCaseDTO> planReportCaseDTOs = planLoadTestReportService.getPlanReportCaseDTO(reportIds);

View File

@ -17,14 +17,13 @@ import io.metersphere.plan.service.remote.api.PlanUiScenarioReportService;
import io.metersphere.plan.utils.TestPlanStatusCalculator; import io.metersphere.plan.utils.TestPlanStatusCalculator;
import io.metersphere.request.ResetOrderRequest; import io.metersphere.request.ResetOrderRequest;
import io.metersphere.utils.DiscoveryUtil; import io.metersphere.utils.DiscoveryUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; 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); return microService.postForData(serviceName, BASE_URL + "/plan/report", request, UiPlanReportDTO.class);
} }
public void calculateReportByUiScenarios(List<TestPlanUiScenarioDTO> uiScenarioDTOList, TestPlanSimpleReportDTO report) {
try {
List<PlanReportCaseDTO> 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<String> reportIds, TestPlanSimpleReportDTO report) { public void calculatePlanReport(List<String> reportIds, TestPlanSimpleReportDTO report) {
try { try {
List<PlanReportCaseDTO> planReportCaseDTOS = planUiScenarioReportService.selectForPlanReport(reportIds); List<PlanReportCaseDTO> planReportCaseDTOS = planUiScenarioReportService.selectForPlanReport(reportIds);

View File

@ -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<String, CaseExecResult> getTestCaseStatusByAutomationCaseRunResult(
List<PlanReportCaseDTO> testPlanCaseList,
List<TestCaseTest> testCaseTestList,
List<TestPlanApiDTO> apiAllCaseList,
List<TestPlanScenarioDTO> scenarioAllCaseList,
List<TestPlanLoadCaseDTO> loadAllCaseList,
List<TestPlanUiScenarioDTO> uiAllCaseList) {
Map<String, CaseExecResult> testCaseResultMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(testPlanCaseList) && CollectionUtils.isNotEmpty(testCaseTestList)) {
Map<String, List<TestCaseTest>> testCaseTestMap = testCaseTestList.stream().collect(Collectors.groupingBy(TestCaseTest::getTestCaseId));
Map<String, CaseExecResult> apiExecResultMap = TestCaseSyncStatusUtil.getApiExecResultMap(apiAllCaseList);
Map<String, CaseExecResult> scenarioExecResultMap = TestCaseSyncStatusUtil.getScenarioExecResultMap(scenarioAllCaseList);
Map<String, CaseExecResult> loadCaseExecResultMap = TestCaseSyncStatusUtil.getLoadExecResultMap(loadAllCaseList);
Map<String, CaseExecResult> uiExecResultMap = TestCaseSyncStatusUtil.getUiExecResultMap(uiAllCaseList);
for (PlanReportCaseDTO testPlanCase : testPlanCaseList) {
if (testCaseTestMap.containsKey(testPlanCase.getCaseId())) {
List<TestCaseTest> 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<TestCaseTest> testCaseTestList,
Map<String, CaseExecResult> apiCaseExecResultMap,
Map<String, CaseExecResult> scenarioExecResultMap,
Map<String, CaseExecResult> loadCaseExecResultMap,
Map<String, CaseExecResult> 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<CaseExecResult> 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<PlanReportCaseDTO> testPlanCaseList, Map<String, CaseExecResult> 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<String, CaseExecResult> getExecResultMap(List<CaseExecResult> caseExecResultList) {
if (CollectionUtils.isEmpty(caseExecResultList)) {
return new HashMap<>();
} else {
Map<String, CaseExecResult> 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<String, CaseExecResult> getApiExecResultMap(List<TestPlanApiDTO> apiAllCaseList) {
if (CollectionUtils.isEmpty(apiAllCaseList)) {
return new HashMap<>();
} else {
Map<String, CaseExecResult> 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<String, CaseExecResult> getScenarioExecResultMap(List<TestPlanScenarioDTO> scenarioAllCaseList) {
if (CollectionUtils.isEmpty(scenarioAllCaseList)) {
return new HashMap<>();
} else {
Map<String, CaseExecResult> 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<String, CaseExecResult> getLoadExecResultMap(List<TestPlanLoadCaseDTO> loadAllCaseList) {
if (CollectionUtils.isEmpty(loadAllCaseList)) {
return new HashMap<>();
} else {
Map<String, CaseExecResult> 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<String, CaseExecResult> getUiExecResultMap(List<TestPlanUiScenarioDTO> uiAllCaseList) {
if (CollectionUtils.isEmpty(uiAllCaseList)) {
return new HashMap<>();
} else {
Map<String, CaseExecResult> 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);
}
}

View File

@ -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<TestPlanApiDTO> apiAllCases, Map reportConfig) {
if (!CollectionUtils.isEmpty(apiAllCases)) {
List<TestPlanApiDTO> apiFailureCases = new ArrayList<>();
List<TestPlanApiDTO> apiErrorReportCases = new ArrayList<>();
List<TestPlanApiDTO> 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<TestPlanScenarioDTO> scenarios, Map reportConfig) {
if (!CollectionUtils.isEmpty(scenarios)) {
List<TestPlanScenarioDTO> failureScenarios = new ArrayList<>();
List<TestPlanScenarioDTO> errorReportScenarios = new ArrayList<>();
List<TestPlanScenarioDTO> 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> T getReportContentResultObject(String contentStr, Class<T> clazz) {
if (StringUtils.isNotBlank(contentStr)) {
return JSON.parseObject(contentStr, clazz);
}
return null;
}
private static <T> List<T> getReportContentResultArray(String contentStr, Class<T> clazz) {
if (StringUtils.isNotBlank(contentStr)) {
return JSON.parseArray(contentStr, clazz);
}
return null;
}
}

View File

@ -53,7 +53,6 @@ import io.metersphere.service.remote.project.TrackIssueTemplateService;
import io.metersphere.service.wapper.TrackProjectService; import io.metersphere.service.wapper.TrackProjectService;
import io.metersphere.service.wapper.UserService; import io.metersphere.service.wapper.UserService;
import io.metersphere.utils.DistinctKeyUtil; 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.PlatformStatusDTO;
import io.metersphere.xpack.track.dto.PlatformUser; import io.metersphere.xpack.track.dto.PlatformUser;
import io.metersphere.xpack.track.dto.*; 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.dto.request.IssuesUpdateRequest;
import io.metersphere.xpack.track.issue.IssuesPlatform; import io.metersphere.xpack.track.issue.IssuesPlatform;
import io.metersphere.xpack.track.service.XpackIssueService; 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.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
@ -75,8 +76,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -797,7 +796,7 @@ public class IssuesService {
List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(example); List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(example);
List<String> caseIds = testCaseIssues.stream().map(x -> List<String> 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()); .collect(Collectors.toList());
List<TestCaseDTO> notInTrashCase = testCaseService.getTestCaseByIds(caseIds); List<TestCaseDTO> notInTrashCase = testCaseService.getTestCaseByIds(caseIds);
@ -1083,25 +1082,25 @@ public class IssuesService {
private void deleteSyncAttachment(AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper, private void deleteSyncAttachment(AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper,
Set<String> platformAttachmentSet, Set<String> platformAttachmentSet,
List<FileAttachmentMetadata> allMsAttachments) { List<FileAttachmentMetadata> allMsAttachments) {
try { try {
// 删除Jira中不存在的附件 // 删除Jira中不存在的附件
if (CollectionUtils.isNotEmpty(allMsAttachments)) { if (CollectionUtils.isNotEmpty(allMsAttachments)) {
List<FileAttachmentMetadata> deleteMsAttachments = allMsAttachments.stream() List<FileAttachmentMetadata> deleteMsAttachments = allMsAttachments.stream()
.filter(msAttachment -> !platformAttachmentSet.contains(msAttachment.getName())) .filter(msAttachment -> !platformAttachmentSet.contains(msAttachment.getName()))
.collect(Collectors.toList()); .collect(Collectors.toList());
deleteMsAttachments.forEach(fileAttachmentMetadata -> { deleteMsAttachments.forEach(fileAttachmentMetadata -> {
List<String> ids = List.of(fileAttachmentMetadata.getId()); List<String> ids = List.of(fileAttachmentMetadata.getId());
AttachmentModuleRelationExample example = new AttachmentModuleRelationExample(); AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type()); example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
// 删除MS附件及关联数据 // 删除MS附件及关联数据
attachmentService.deleteAttachmentByIds(ids); attachmentService.deleteAttachmentByIds(ids);
attachmentService.deleteFileAttachmentByIds(ids); attachmentService.deleteFileAttachmentByIds(ids);
batchAttachmentModuleRelationMapper.deleteByExample(example); batchAttachmentModuleRelationMapper.deleteByExample(example);
}); });
} }
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e); LogUtil.error(e);
} }
} }
private void saveAttachmentModuleRelation(Platform platform, String issueId, private void saveAttachmentModuleRelation(Platform platform, String issueId,
@ -1225,14 +1224,34 @@ public class IssuesService {
abstractPlatform.userAuth(authUserIssueRequest); abstractPlatform.userAuth(authUserIssueRequest);
} }
public void calculateReportByIssueList(List<IssuesDao> issueList, TestPlanSimpleReportDTO report) {
if (CollectionUtils.isNotEmpty(issueList)) {
List<PlanReportIssueDTO> 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) { public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) {
List<PlanReportIssueDTO> planReportIssueDTOS = extIssuesMapper.selectForPlanReport(planId); List<PlanReportIssueDTO> planReportIssueDTOList = extIssuesMapper.selectForPlanReport(planId);
planReportIssueDTOS = DistinctKeyUtil.distinctByKey(planReportIssueDTOS, PlanReportIssueDTO::getId); this.calculatePlanReport(planReportIssueDTOList, report);
}
public void calculatePlanReport(List<PlanReportIssueDTO> planReportIssueDTOList, TestPlanSimpleReportDTO report) {
planReportIssueDTOList = DistinctKeyUtil.distinctByKey(planReportIssueDTOList, PlanReportIssueDTO::getId);
TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult(); TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult();
List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>(); List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>();
Map<String, TestCaseReportStatusResultDTO> statusResultMap = new HashMap<>(); Map<String, TestCaseReportStatusResultDTO> statusResultMap = new HashMap<>();
planReportIssueDTOS.forEach(item -> { planReportIssueDTOList.forEach(item -> {
String status; String status;
// 本地缺陷 // 本地缺陷
if (StringUtils.equalsIgnoreCase(item.getPlatform(), IssuesManagePlatform.Local.name()) if (StringUtils.equalsIgnoreCase(item.getPlatform(), IssuesManagePlatform.Local.name())

View File

@ -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<TestCaseTest> selectTestCaseTestByPrimaryKey(List<String> primaryKeyList, Function<TestCaseTestExample, List<TestCaseTest>> func) {
List<TestCaseTest> returnList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(primaryKeyList)) {
TestCaseTestExample example = new TestCaseTestExample();
int unProcessingCount = primaryKeyList.size();
while (primaryKeyList.size() > BATCH_PROCESS_QUANTITY) {
example.clear();
List<String> 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;
}
}

View File

@ -211,7 +211,6 @@ custom_field_select_tip=[%s] must be %s
no_legitimate_case_tip=Import fails without legitimate use cases! no_legitimate_case_tip=Import fails without legitimate use cases!
no_legitimate_issue_tip=Import fails without legitimate issues! no_legitimate_issue_tip=Import fails without legitimate issues!
zentao_test_type_error=invalid Zentao request zentao_test_type_error=invalid Zentao request
test_case_status_prepare=Prepare test_case_status_prepare=Prepare
test_case_status_running=Running test_case_status_running=Running
test_case_status_finished=Finished test_case_status_finished=Finished
@ -219,16 +218,13 @@ test_case_status_error=Error
test_case_status_success=Success test_case_status_success=Success
test_case_status_trash=Trash test_case_status_trash=Trash
test_case_status_saved=Saved test_case_status_saved=Saved
execute_not_pass=Not pass execute_not_pass=Not pass
execute_pass=Pass execute_pass=Pass
jira_auth_error=Account name or password (Token) is wrong 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 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: 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 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_plan_delete_exec_error=The test plan is being executed
test_case_review_status_underway=Underway test_case_review_status_underway=Underway
test_case_review_status_re_review=ReReview test_case_review_status_re_review=ReReview
api_status_fake_error=Fake error

View File

@ -129,7 +129,6 @@ issue_project_not_exist=ID不存在或其它错误
tapd_project_not_exist=关联的TAPD项目ID不存在 tapd_project_not_exist=关联的TAPD项目ID不存在
zentao_get_project_builds_fail=获取影响版本错误 zentao_get_project_builds_fail=获取影响版本错误
zentao_project_id_not_exist=关联的禅道ID不存在或其它错误 zentao_project_id_not_exist=关联的禅道ID不存在或其它错误
import_xmind_count_error=思维导图导入用例数量不能超过 800 条 import_xmind_count_error=思维导图导入用例数量不能超过 800 条
license_valid_license_error=授权认证失败 license_valid_license_error=授权认证失败
import_xmind_not_found=未找到测试用例 import_xmind_not_found=未找到测试用例
@ -187,19 +186,17 @@ custom_field_member_tip=[%s]必须当前项目成员
custom_field_select_tip=[%s]必须为%s custom_field_select_tip=[%s]必须为%s
no_legitimate_case_tip=导入失败,没有合法用例! no_legitimate_case_tip=导入失败,没有合法用例!
no_legitimate_issue_tip=导入失败,没有合法缺陷! no_legitimate_issue_tip=导入失败,没有合法缺陷!
test_case_status_prepare=未开始 test_case_status_prepare=未开始
test_case_status_running=进行中 test_case_status_running=进行中
test_case_status_finished=已完成 test_case_status_finished=已完成
execute_not_pass=未通过 execute_not_pass=未通过
execute_pass=通过 execute_pass=通过
jira_auth_error=账号名或密码(Token)错误 jira_auth_error=账号名或密码(Token)错误
jira_auth_url_error=测试连接失败请检查Jira地址是否正确 jira_auth_url_error=测试连接失败请检查Jira地址是否正确
platform_plugin_not_exit=平台对接功能已插件化,请下载对应版本的插件: platform_plugin_not_exit=平台对接功能已插件化,请下载对应版本的插件:
plan_warning=测试计划没有关联可执行的用例 plan_warning=测试计划没有关联可执行的用例
test_plan_delete_exec_error=测试计划正在执行中 test_plan_delete_exec_error=测试计划正在执行中
test_case_review_status_underway=评审中 test_case_review_status_underway=评审中
test_case_review_status_re_review=重新提审 test_case_review_status_re_review=重新提审
api_status_fake_error=误报
test_case_sync_status_comment=关联的case %s 在测试计划【%s】内的执行结果出现%s。

View File

@ -129,7 +129,6 @@ issue_project_not_exist=ID不存在或其它錯誤
tapd_project_not_exist=關聯的TAPD項目ID不存在 tapd_project_not_exist=關聯的TAPD項目ID不存在
zentao_get_project_builds_fail=獲取影響版本錯誤 zentao_get_project_builds_fail=獲取影響版本錯誤
zentao_project_id_not_exist=關聯的禪道ID不存在或其它錯誤 zentao_project_id_not_exist=關聯的禪道ID不存在或其它錯誤
import_xmind_count_error=思維導圖導入用例數量不能超過 800 條 import_xmind_count_error=思維導圖導入用例數量不能超過 800 條
license_valid_license_error=授權認證失敗 license_valid_license_error=授權認證失敗
import_xmind_not_found=未找到測試用例 import_xmind_not_found=未找到測試用例
@ -187,21 +186,16 @@ custom_field_member_tip=[%s]必須當前項目成員
custom_field_select_tip=[%s]必須為%s custom_field_select_tip=[%s]必須為%s
no_legitimate_case_tip=導入失敗,沒有合法用例! no_legitimate_case_tip=導入失敗,沒有合法用例!
no_legitimate_issue_tip=導入失敗,沒有合法缺陷! no_legitimate_issue_tip=導入失敗,沒有合法缺陷!
test_case_status_prepare=未開始 test_case_status_prepare=未開始
test_case_status_running=進行中 test_case_status_running=進行中
test_case_status_finished=已完成 test_case_status_finished=已完成
execute_not_pass=未通過 execute_not_pass=未通過
execute_pass=通過 execute_pass=通過
jira_auth_error=賬號名或密碼(Token)錯誤 jira_auth_error=賬號名或密碼(Token)錯誤
jira_auth_url_error=測試連接失敗請檢查Jira地址是否正確 jira_auth_url_error=測試連接失敗請檢查Jira地址是否正確
platform_plugin_not_exit=平臺對接功能已插件化,請下載對應版本的插件: platform_plugin_not_exit=平臺對接功能已插件化,請下載對應版本的插件:
plan_warning=測試計劃沒有關聯可執行的用例 plan_warning=測試計劃沒有關聯可執行的用例
test_plan_delete_exec_error=測試計劃正在執行中 test_plan_delete_exec_error=測試計劃正在執行中
test_case_review_status_underway=評審中 test_case_review_status_underway=評審中
test_case_review_status_re_review=重新提審 test_case_review_status_re_review=重新提審
api_status_fake_error=誤報

View File

@ -1,20 +1,72 @@
<template> <template>
<ms-container> <ms-container>
<ms-main-container class="report-content" :class="isShare || isTemplate? 'full-screen-container' : 'with-header-container'" id = "planReportContainer"> <ms-main-container
class="report-content"
:class="
isShare || isTemplate
? 'full-screen-container'
: 'with-header-container'
"
id="planReportContainer"
>
<el-card v-loading="loading"> <el-card v-loading="loading">
<test-plan-report-buttons :is-db="isDb" :plan-id="planId" :is-share="isShare" :report="report" <test-plan-report-buttons
v-if="!isTemplate && !isShare"/> :is-db="isDb"
<test-plan-overview-report v-if="overviewEnable" :report="report" :run-mode="runMode" :resource-pool="resourcePool"/> :plan-id="planId"
<test-plan-summary-report v-if="summaryEnable" :is-db="isDb" :is-template="isTemplate" :is-share="isShare" :is-share="isShare"
:report="report" :plan-id="planId"/> :report="report"
<test-plan-functional-report v-if="functionalEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare" v-if="!isTemplate && !isShare"
:is-template="isTemplate" :plan-id="planId" :report="report"/> />
<test-plan-api-report v-if="apiEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare" <test-plan-overview-report
:is-template="isTemplate" :report="report" :plan-id="planId"/> v-if="overviewEnable"
<test-plan-ui-report v-if="uiEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :report="report" :plan-id="planId"/> :run-mode="runMode"
<test-plan-load-report v-if="loadEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare" :resource-pool="resourcePool"
:is-template="isTemplate" :report="report" :plan-id="planId"/> />
<test-plan-summary-report
v-if="summaryEnable"
:is-db="isDb"
:is-template="isTemplate"
:is-share="isShare"
:report="report"
:plan-id="planId"
/>
<test-plan-functional-report
v-if="functionalEnable"
:is-db="isDb"
:share-id="shareId"
:is-share="isShare"
:is-template="isTemplate"
:plan-id="planId"
:report="report"
/>
<test-plan-api-report
v-if="apiEnable"
:is-db="isDb"
:share-id="shareId"
:is-share="isShare"
:is-template="isTemplate"
:report="report"
:plan-id="planId"
/>
<test-plan-ui-report
v-if="uiEnable"
:is-db="isDb"
:share-id="shareId"
:is-share="isShare"
:is-template="isTemplate"
:report="report"
:plan-id="planId"
/>
<test-plan-load-report
v-if="loadEnable"
:is-db="isDb"
:share-id="shareId"
:is-share="isShare"
:is-template="isTemplate"
:report="report"
:plan-id="planId"
/>
</el-card> </el-card>
</ms-main-container> </ms-main-container>
<test-plan-report-navigation-bar <test-plan-report-navigation-bar
@ -25,18 +77,19 @@
:load-enable="loadEnable" :load-enable="loadEnable"
:ui-enable="uiEnable" :ui-enable="uiEnable"
:overview-enable="overviewEnable" :overview-enable="overviewEnable"
:is-template="isTemplate"/> :is-template="isTemplate"
/>
</ms-container> </ms-container>
</template> </template>
<script> <script>
import TestPlanFunctionalReport from "@/business/plan/view/comonents/report/detail/TestPlanFunctionalReport"; import TestPlanFunctionalReport from "@/business/plan/view/comonents/report/detail/TestPlanFunctionalReport";
import { import {
getShareTestPlanExtReport,
getShareTestPlanReport, getShareTestPlanReport,
getShareTestPlanReportContent, getShareTestPlanReportContent,
getTestPlanReport, getTestPlanReport,
getTestPlanReportContent, getTestPlanReportContent,
getTestPlanExtReport, getShareTestPlanExtReport
} from "@/api/remote/plan/test-plan"; } from "@/api/remote/plan/test-plan";
import TestPlanApiReport from "@/business/plan/view/comonents/report/detail/TestPlanApiReport"; import TestPlanApiReport from "@/business/plan/view/comonents/report/detail/TestPlanApiReport";
import TestPlanUiReport from "@/business/plan/view/comonents/report/detail/TestPlanUiReport"; import TestPlanUiReport from "@/business/plan/view/comonents/report/detail/TestPlanUiReport";
@ -71,15 +124,15 @@ export default {
isDb: Boolean, isDb: Boolean,
shareId: String, shareId: String,
reportId: String, reportId: String,
needMoveBar: Boolean needMoveBar: Boolean,
}, },
data() { data() {
return { return {
report: {}, report: {},
runMode: '', runMode: "",
resourcePool: '', resourcePool: "",
loading: false, loading: false,
shareUrl: '' shareUrl: "",
}; };
}, },
watch: { watch: {
@ -100,40 +153,66 @@ export default {
}, },
computed: { computed: {
overviewEnable() { overviewEnable() {
let disable = this.report.config let disable =
&& this.report.config.overview && this.report.config.overview.enable === false; this.report.config &&
this.report.config.overview &&
this.report.config.overview.enable === false;
return !disable; return !disable;
}, },
summaryEnable() { summaryEnable() {
let disable = this.report.config && this.report.config.summary let disable =
&& this.report.config.summary.enable === false; this.report.config &&
this.report.config.summary &&
this.report.config.summary.enable === false;
return !disable; return !disable;
}, },
functionalEnable() { functionalEnable() {
let disable = this.report.config && this.report.config.functional.enable === false; let disable =
return !disable && this.report.functionResult this.report.config && this.report.config.functional.enable === false;
&& this.report.functionResult.caseData && this.report.functionResult.caseData.length > 0; return (
!disable &&
this.report.functionResult &&
this.report.functionResult.caseData &&
this.report.functionResult.caseData.length > 0
);
}, },
apiEnable() { apiEnable() {
let disable = this.report.config && this.report.config.api.enable === false; let disable =
return !disable && ((this.report.apiResult && this.report.config && this.report.config.api.enable === false;
( return (
(this.report.apiResult.apiCaseData && this.report.apiResult.apiCaseData.length > 0) !disable &&
|| (this.report.apiResult.apiScenarioData && this.report.apiResult.apiScenarioData.length > 0) ((this.report.apiResult &&
)) || (this.report.apiAllCases && this.report.apiAllCases.length > 0) || (this.report.scenarioAllCases && this.report.scenarioAllCases.length > 0)); ((this.report.apiResult.apiCaseData &&
this.report.apiResult.apiCaseData.length > 0) ||
(this.report.apiResult.apiScenarioData &&
this.report.apiResult.apiScenarioData.length > 0))) ||
(this.report.apiAllCases && this.report.apiAllCases.length > 0) ||
(this.report.scenarioAllCases &&
this.report.scenarioAllCases.length > 0))
);
}, },
loadEnable() { loadEnable() {
let disable = this.report.config && this.report.config.load.enable === false; let disable =
return !disable && this.report.loadResult && this.report.loadResult.caseData && this.report.loadResult.caseData.length > 0 this.report.config && this.report.config.load.enable === false;
|| (this.report.loadAllCases && this.report.loadAllCases.length > 0); return (
(!disable &&
this.report.loadResult &&
this.report.loadResult.caseData &&
this.report.loadResult.caseData.length > 0) ||
(this.report.loadAllCases && this.report.loadAllCases.length > 0)
);
}, },
uiEnable() { uiEnable() {
let disable = this.report.config && this.report.config.ui.enable === false; let disable =
return !disable && this.report.uiResult this.report.config && this.report.config.ui.enable === false;
&& this.report.uiResult.uiScenarioStepData && this.report.uiResult.uiScenarioStepData.length > 0 return (
|| (this.report.uiAllCases && this.report.uiAllCases.length > 0); (!disable &&
} this.report.uiResult &&
this.report.uiResult.uiScenarioStepData &&
this.report.uiResult.uiScenarioStepData.length > 0) ||
(this.report.uiAllCases && this.report.uiAllCases.length > 0)
);
},
}, },
methods: { methods: {
getReport() { getReport() {
@ -149,54 +228,49 @@ export default {
if (this.isShare) { if (this.isShare) {
// //
this.loading = true; this.loading = true;
getShareTestPlanReportContent(this.shareId, this.reportId) getShareTestPlanReportContent(this.shareId, this.reportId).then(
.then((r) => { (r) => {
this.loading = false; this.loading = false;
this.report = r.data; this.report = r.data;
this.runMode = r.data.runMode; this.runMode = r.data.runMode;
this.resourcePool = r.data.resourcePool; this.resourcePool = r.data.resourcePool;
this.report.config = this.getDefaultConfig(this.report); this.report.config = this.getDefaultConfig(this.report);
}); }
);
} else { } else {
this.loading = true; this.loading = true;
getTestPlanReportContent(this.reportId) getTestPlanReportContent(this.reportId).then((r) => {
.then((r) => { this.loading = false;
this.loading = false; this.report = r.data;
this.report = r.data; this.report.config = this.getDefaultConfig(this.report);
this.report.config = this.getDefaultConfig(this.report); });
});
} }
} else if (this.isShare) { } else if (this.isShare) {
this.loading = true; this.loading = true;
if (this.shareId && this.planId) { if (this.shareId && this.planId) {
getShareTestPlanReport(this.shareId, this.planId) getShareTestPlanReport(this.shareId, this.planId).then((r) => {
.then((r) => { this.loading = false;
this.loading = false; this.report = r.data;
this.report = r.data; this.report.config = this.getDefaultConfig(this.report);
this.report.config = this.getDefaultConfig(this.report); });
});
} }
} else { } else {
this.loading = true; this.loading = true;
if (this.planId) { if (this.planId) {
getTestPlanReport(this.planId) getTestPlanReport(this.planId).then((r) => {
.then((r) => { this.loading = false;
this.loading = false; this.report = r.data;
this.report = r.data; this.report.config = this.getDefaultConfig(this.report);
this.report.config = this.getDefaultConfig(this.report); });
});
} }
} }
if (!this.isTemplate) { if (!this.isTemplate) {
if (this.isShare) { if (this.isShare) {
getShareTestPlanExtReport(this.shareId, this.planId, this.reportId).then((response) => { getShareTestPlanExtReport(
if (response.data) { this.shareId,
this.runMode = response.data.runMode; this.planId,
this.resourcePool = response.data.resourcePool; this.reportId
} ).then((response) => {
});
} else {
getTestPlanExtReport(this.planId, this.reportId).then((response) => {
if (response.data) { if (response.data) {
this.runMode = response.data.runMode; this.runMode = response.data.runMode;
this.resourcePool = response.data.resourcePool; this.resourcePool = response.data.resourcePool;
@ -216,107 +290,110 @@ export default {
let config = { let config = {
overview: { overview: {
enable: true, enable: true,
name: this.$t('test_track.report.overview') name: this.$t("test_track.report.overview"),
}, },
summary: { summary: {
enable: true, enable: true,
name: this.$t('test_track.report.report_summary') name: this.$t("test_track.report.report_summary"),
}, },
functional: { functional: {
enable: true, enable: true,
name: this.$t('test_track.report.analysis_functional'), name: this.$t("test_track.report.analysis_functional"),
children: { children: {
result: { result: {
enable: true, enable: true,
name: this.$t('test_track.report.test_result'), name: this.$t("test_track.report.test_result"),
}, },
issue: { issue: {
enable: true, enable: true,
name: this.$t('test_track.report.issue_list'), name: this.$t("test_track.report.issue_list"),
}, },
all: { all: {
enable: true, enable: true,
name: this.$t('test_track.report.all_case'), name: this.$t("test_track.report.all_case"),
}, },
failure: { failure: {
enable: true, enable: true,
name: this.$t('test_track.report.fail_case'), name: this.$t("test_track.report.fail_case"),
}, },
blocking: { blocking: {
enable: true, enable: true,
name: this.$t('test_track.plan_view.blocking') + this.$t('commons.track'), name:
this.$t("test_track.plan_view.blocking") +
this.$t("commons.track"),
}, },
skip: { skip: {
enable: true, enable: true,
name: this.$t('test_track.plan_view.skip') + this.$t('commons.track'), name:
this.$t("test_track.plan_view.skip") + this.$t("commons.track"),
}, },
} },
}, },
api: { api: {
enable: true, enable: true,
name: this.$t('test_track.report.analysis_api'), name: this.$t("test_track.report.analysis_api"),
children: { children: {
result: { result: {
enable: true, enable: true,
name: this.$t('test_track.report.test_result'), name: this.$t("test_track.report.test_result"),
}, },
failure: { failure: {
enable: true, enable: true,
name: this.$t('test_track.report.fail_case'), name: this.$t("test_track.report.fail_case"),
}, },
errorReport: { errorReport: {
enable: true, enable: true,
name: this.$t('error_report_library.option.name'), name: this.$t("error_report_library.option.name"),
}, },
unExecute: { unExecute: {
enable: true, enable: true,
name: this.$t('api_test.home_page.detail_card.unexecute'), name: this.$t("api_test.home_page.detail_card.unexecute"),
}, },
all: { all: {
enable: true, enable: true,
name: this.$t('test_track.report.all_case'), name: this.$t("test_track.report.all_case"),
} },
} },
}, },
load: { load: {
enable: true, enable: true,
name: this.$t('test_track.report.analysis_load'), name: this.$t("test_track.report.analysis_load"),
children: { children: {
result: { result: {
enable: true, enable: true,
name: this.$t('test_track.report.test_result'), name: this.$t("test_track.report.test_result"),
}, },
failure: { failure: {
enable: true, enable: true,
name: this.$t('test_track.report.fail_case'), name: this.$t("test_track.report.fail_case"),
}, },
all: { all: {
enable: true, enable: true,
name: this.$t('test_track.report.all_case'), name: this.$t("test_track.report.all_case"),
} },
} },
}, },
ui: { ui: {
enable: true, enable: true,
name: this.$t('test_track.report.analysis_ui'), name: this.$t("test_track.report.analysis_ui"),
children: { children: {
result: { result: {
enable: true, enable: true,
name: this.$t('test_track.report.test_result'), name: this.$t("test_track.report.test_result"),
}, },
failure: { failure: {
enable: true, enable: true,
name: this.$t('test_track.report.fail_case'), name: this.$t("test_track.report.fail_case"),
}, },
unExecute: { unExecute: {
enable: true, enable: true,
name: this.$t('api_test.home_page.detail_card.unexecute'), name: this.$t("api_test.home_page.detail_card.unexecute"),
}, },
all: { all: {
enable: true, enable: true,
name: this.$t('test_track.report.all_case'), name: this.$t("test_track.report.all_case"),
} },
} },
}, },
}; };
if (dbConfig) { if (dbConfig) {
@ -333,13 +410,12 @@ export default {
} }
} }
} }
} },
} },
} };
</script> </script>
<style scoped> <style scoped>
.with-header-container { .with-header-container {
height: calc(100vh - 60px); height: calc(100vh - 60px);
} }