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
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureApiDTO extends TestPlanApiCaseDTO {
public class TestPlanApiDTO extends TestPlanApiCaseDTO {
private String response;
private String reportId;
}

View File

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

View File

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

View File

@ -5,8 +5,12 @@ import io.metersphere.request.PlanSubReportRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class ApiPlanReportRequest extends PlanSubReportRequest {
List<String> apiReportIdList;
List<String> scenarioReportIdList;
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;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO;
import io.metersphere.api.dto.automation.TestPlanApiDTO;
import io.metersphere.api.dto.automation.TestPlanScenarioDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@ -16,6 +16,6 @@ import java.util.Map;
public class TestPlanExecuteReportDTO {
private Map<String, String> testPlanApiCaseIdAndReportIdMap;
private Map<String, String> testPlanScenarioIdAndReportIdMap;
private Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap;
private Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap;
private Map<String, TestPlanApiDTO> apiCaseInfoDTOMap;
private Map<String, TestPlanScenarioDTO> scenarioInfoDTOMap;
}

View File

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

View File

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

View File

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

View File

@ -38,4 +38,13 @@
FROM api_scenario_report_result
WHERE report_id = #{0}
</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>

View File

@ -1,8 +1,8 @@
package io.metersphere.base.mapper.plan.ext;
import io.metersphere.api.dto.QueryReferenceRequest;
import io.metersphere.api.dto.automation.TestPlanApiDTO;
import io.metersphere.api.dto.automation.TestPlanDTO;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO;
@ -39,9 +39,9 @@ public interface ExtTestPlanApiCaseMapper {
List<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();

View File

@ -366,7 +366,7 @@
!= 'Trash'
)
</select>
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanFailureApiDTO">
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanApiDTO">
select
t.id,
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_id,
@ -388,7 +388,7 @@
where t.test_plan_id = #{planId} ORDER BY t.order DESC
</select>
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanFailureApiDTO">
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanApiDTO">
select
t.id,
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.create_user_id,
@ -544,15 +544,4 @@
#{v}
</foreach>
</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>

View File

@ -1,7 +1,7 @@
package io.metersphere.base.mapper.plan.ext;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO;
import io.metersphere.api.dto.automation.TestPlanScenarioDTO;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.api.dto.plan.TestPlanApiScenarioInfoDTO;
import io.metersphere.base.domain.TestPlanApiScenario;
@ -32,9 +32,9 @@ public interface ExtTestPlanScenarioCaseMapper {
List<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);

View File

@ -299,7 +299,7 @@
!= 'Trash'
)
</select>
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO">
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanScenarioDTO">
select
t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal,
c.status,c.step_total, c.step_total, c.project_id,
@ -323,9 +323,9 @@
ORDER BY t.order DESC
</select>
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO">
<select id="getFailureListByIds" resultType="io.metersphere.api.dto.automation.TestPlanScenarioDTO">
select
t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal,
t.id, t.last_result, t.report_id, c.id AS caseId,c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal,
c.status,c.step_total, c.step_total, c.project_id,
c.num, c.custom_num
from

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -213,10 +213,7 @@ public class ApiExecutionQueueService {
if (isError) {
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andQueueIdEqualTo(dto.getQueueId());
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) {
testPlanReportTestEnded(dto.getTestPlanReportId());
}
checkTestPlanCaseTestEnd(dto.getTestId(), dto.getRunMode(), dto.getTestPlanReportId());
// 更新未执行的报告状态
List<ApiExecutionQueueDetail> details = executionQueueDetailMapper.selectByExample(example);
List<String> reportIds = details.stream().map(ApiExecutionQueueDetail::getReportId).collect(Collectors.toList());
@ -272,10 +269,24 @@ public class ApiExecutionQueueService {
return queue;
}
public void testPlanReportTestEnded(String testPlanReportId) {
// 检查测试计划中其他队列是否结束
private void testPlanCaseTestEnd(String testId, String runMode) {
//不是整体测试计划执行的用例发送testID给测试跟踪模块用于做单接口执行后续操作处理
if (StringUtils.isNotEmpty(testId) && StringUtils.equalsAnyIgnoreCase(runMode,
ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(),
ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testId, UUID.randomUUID().toString());
}
}
public void checkTestPlanCaseTestEnd(String testId, String runMode, String testPlanReportId) {
if (StringUtils.isEmpty(testPlanReportId)) {
//不是整体测试计划执行的用例发送testID给测试跟踪模块用于做单接口执行后续操作处理
this.testPlanCaseTestEnd(testId, runMode);
} else {
// 由测试计划检查测试计划中其他队列是否结束
kafkaTemplate.send(KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, testPlanReportId);
}
}
public void queueNext(ResultDTO dto) {
LoggerUtil.info("开始处理队列:" + dto.getReportId() + "QID" + dto.getQueueId());
@ -443,7 +454,7 @@ public class ApiExecutionQueueService {
// 更新测试计划报告
if (StringUtils.isNotEmpty(item.getReportId())) {
LoggerUtil.info("Handling test plan reports that are not in the execution queue" + item.getReportId() + "");
testPlanReportTestEnded(item.getReportId());
checkTestPlanCaseTestEnd(null, null, item.getReportId());
}
});
}
@ -452,7 +463,7 @@ public class ApiExecutionQueueService {
if (CollectionUtils.isNotEmpty(testPlanReports)) {
testPlanReports.forEach(reportId -> {
LoggerUtil.info("Compensation Test Plan Report" + reportId + "");
testPlanReportTestEnded(reportId);
checkTestPlanCaseTestEnd(null, null, reportId);
});
}
// 清除异常队列/一般是服务突然停止产生
@ -473,7 +484,7 @@ public class ApiExecutionQueueService {
ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(detail.getQueueId());
// 更新测试计划报告
if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) {
testPlanReportTestEnded(queue.getReportId());
checkTestPlanCaseTestEnd(null, null, queue.getReportId());
}
}
});
@ -499,7 +510,7 @@ public class ApiExecutionQueueService {
ApiExecutionQueue queue = queueMapper.selectByPrimaryKey(queueId);
// 更新测试计划报告
if (queue != null && StringUtils.isNotEmpty(queue.getReportId())) {
testPlanReportTestEnded(queue.getReportId());
checkTestPlanCaseTestEnd(null, null, queue.getReportId());
queueMapper.deleteByPrimaryKey(queueId);
}
}

View File

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

View File

@ -22,6 +22,7 @@ import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.ServiceUtils;
import io.metersphere.utils.LoggerUtil;
import jakarta.annotation.Resource;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
@ -33,7 +34,6 @@ import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -489,4 +489,15 @@ public class ApiDefinitionExecResultService {
public ApiDefinitionExecResultWithBLOBs getLastResult(String testId) {
return extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId);
}
public Map<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.EnvironmentType;
import io.metersphere.api.dto.QueryReferenceRequest;
import io.metersphere.api.dto.automation.TestPlanApiDTO;
import io.metersphere.api.dto.automation.TestPlanDTO;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.plan.TestPlanApiCaseBatchRequest;
import io.metersphere.api.dto.plan.TestPlanApiCaseInfoDTO;
@ -39,6 +39,7 @@ import io.metersphere.service.definition.ApiDefinitionService;
import io.metersphere.service.definition.ApiModuleService;
import io.metersphere.service.definition.ApiTestCaseService;
import io.metersphere.service.plan.remote.TestPlanService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
@ -49,7 +50,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -392,20 +392,20 @@ public class TestPlanApiCaseService {
}
public List<TestPlanFailureApiDTO> getFailureCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name());
public List<TestPlanApiDTO> getFailureCases(String planId) {
List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name());
return buildCases(apiTestCases);
}
public List<TestPlanFailureApiDTO> getAllCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null);
public List<TestPlanApiDTO> getAllCases(String planId) {
List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, null);
return buildCases(apiTestCases);
}
public void buildApiResponse(List<TestPlanFailureApiDTO> cases) {
public void buildApiResponse(List<TestPlanApiDTO> cases) {
if (!org.apache.commons.collections.CollectionUtils.isEmpty(cases)) {
List<String> reportIds = new ArrayList<>();
for (TestPlanFailureApiDTO apiCase : cases) {
for (TestPlanApiDTO apiCase : cases) {
if (StringUtils.isEmpty(apiCase.getReportId())) {
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(apiCase.getId(), "API_PLAN");
if (result != null && StringUtils.isNotBlank(result.getContent())) {
@ -464,7 +464,7 @@ public class TestPlanApiCaseService {
}
}
public List<TestPlanFailureApiDTO> buildCases(List<TestPlanFailureApiDTO> apiTestCases) {
public List<TestPlanApiDTO> buildCases(List<TestPlanApiDTO> apiTestCases) {
if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases;
}
@ -479,9 +479,9 @@ public class TestPlanApiCaseService {
*
* @param apiTestCases
*/
private void buildPrincipal(List<TestPlanFailureApiDTO> apiTestCases) {
private void buildPrincipal(List<TestPlanApiDTO> apiTestCases) {
List<String> apiIds = apiTestCases.stream()
.map(TestPlanFailureApiDTO::getApiDefinitionId)
.map(TestPlanApiDTO::getApiDefinitionId)
.collect(Collectors.toList());
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);
}
public List<TestPlanFailureApiDTO> getErrorReportCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name());
public List<TestPlanApiDTO> getErrorReportCases(String planId) {
List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name());
return buildCases(apiTestCases);
}
public List<TestPlanFailureApiDTO> getUnExecuteCases(String planId) {
List<TestPlanFailureApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name());
public List<TestPlanApiDTO> getUnExecuteCases(String planId) {
List<TestPlanApiDTO> apiTestCases = extTestPlanApiCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name());
return buildCases(apiTestCases);
}
@ -717,7 +717,7 @@ public class TestPlanApiCaseService {
return !testPlanApiCaseList.stream().map(TestPlanApiCaseInfoDTO::getApiCaseId).collect(Collectors.toList()).isEmpty();
}
public List<TestPlanFailureApiDTO> getFailureListByIds(Set<String> planApiCaseIds) {
public List<TestPlanApiDTO> getFailureListByIds(Set<String> planApiCaseIds) {
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.RelevanceScenarioRequest;
import io.metersphere.api.dto.ScenarioEnv;
import io.metersphere.api.dto.automation.ApiScenarioReportResult;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.plan.*;
import io.metersphere.api.exec.scenario.ApiScenarioEnvService;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.ApiScenarioReportResult;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioModuleMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioReportResultMapper;
import io.metersphere.base.mapper.plan.TestPlanApiScenarioMapper;
import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiScenarioMapper;
import io.metersphere.base.mapper.plan.ext.ExtTestPlanScenarioCaseMapper;
@ -41,10 +42,12 @@ import io.metersphere.service.definition.ApiDefinitionExecResultService;
import io.metersphere.service.plan.remote.TestPlanService;
import io.metersphere.service.scenario.ApiScenarioModuleService;
import io.metersphere.service.scenario.ApiScenarioReportService;
import io.metersphere.service.scenario.ApiScenarioReportStructureService;
import io.metersphere.service.scenario.ApiScenarioService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
@ -103,6 +106,11 @@ public class TestPlanScenarioCaseService {
private TestPlanService testPlanService;
@Resource
private JMeterService jMeterService;
@Resource
private ExtApiScenarioReportResultMapper extApiScenarioReportResultMapper;
@Lazy
@Resource
private ApiScenarioReportStructureService apiScenarioReportStructureService;
public List<ApiScenarioDTO> list(TestPlanScenarioRequest request) {
request.setProjectId(null);
@ -557,17 +565,17 @@ public class TestPlanScenarioCaseService {
return envMap;
}
public List<TestPlanFailureScenarioDTO> getAllCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases =
public List<TestPlanScenarioDTO> getAllCases(String planId) {
List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, null);
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> savedReportMap = new HashMap<>(idMap);
List<TestPlanFailureScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) {
List<TestPlanScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) {
String reportId = savedReportMap.get(dto.getId());
savedReportMap.remove(dto.getId());
dto.setReportId(reportId);
@ -585,13 +593,13 @@ public class TestPlanScenarioCaseService {
}
public List<TestPlanFailureScenarioDTO> getFailureCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases =
public List<TestPlanScenarioDTO> getFailureCases(String planId) {
List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.ERROR.name());
return buildCases(apiTestCases);
}
public List<TestPlanFailureScenarioDTO> buildCases(List<TestPlanFailureScenarioDTO> apiTestCases) {
public List<TestPlanScenarioDTO> buildCases(List<TestPlanScenarioDTO> apiTestCases) {
if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases;
}
@ -633,23 +641,34 @@ public class TestPlanScenarioCaseService {
testPlanApiScenarioMapper::updateByPrimaryKeySelective);
}
public List<TestPlanFailureScenarioDTO> getErrorReportCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases =
public List<TestPlanScenarioDTO> getErrorReportCases(String planId) {
List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.FAKE_ERROR.name());
return buildCases(apiTestCases);
}
public List<TestPlanFailureScenarioDTO> getUnExecuteCases(String planId) {
List<TestPlanFailureScenarioDTO> apiTestCases =
public List<TestPlanScenarioDTO> getUnExecuteCases(String planId) {
List<TestPlanScenarioDTO> apiTestCases =
extTestPlanScenarioCaseMapper.getFailureList(planId, ApiReportStatus.PENDING.name());
return buildCases(apiTestCases);
}
public TestPlanScenarioStepCountSimpleDTO getStepCount(List<PlanReportCaseDTO> planReportCaseDTOS) {
TestPlanScenarioStepCountDTO stepCount = new TestPlanScenarioStepCountDTO();
List<String> scenarioReportIdList = new ArrayList<>();
for (PlanReportCaseDTO item : planReportCaseDTOS) {
calculateScenarioResultDTO(item, stepCount);
if (StringUtils.isBlank(item.getReportId())) {
stepCount.getUnderwayIds().add(item.getCaseId());
} else {
if (!scenarioReportIdList.contains(item.getReportId())) {
scenarioReportIdList.add(item.getReportId());
}
}
}
//统计各种状态的步骤
calculateScenarioResultDTO(scenarioReportIdList, stepCount);
int underwayStepsCounts = getUnderwayStepsCounts(stepCount.getUnderwayIds());
TestPlanScenarioStepCountSimpleDTO stepResult = new TestPlanScenarioStepCountSimpleDTO();
stepResult.setStepCount(stepCount);
@ -665,24 +684,33 @@ public class TestPlanScenarioCaseService {
return 0;
}
private void calculateScenarioResultDTO(PlanReportCaseDTO item,
private void calculateScenarioResultDTO(List<String> scenarioReportIdList,
TestPlanScenarioStepCountDTO stepCount) {
if (StringUtils.isNotBlank(item.getReportId())) {
ApiScenarioReportResult apiScenarioReportResult = apiScenarioReportService.get(item.getReportId(), false);
if (apiScenarioReportResult != null) {
String content = apiScenarioReportResult.getContent();
if (StringUtils.isNotBlank(content)) {
Map map = JSON.parseMap(content);
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + (Integer) map.get("scenarioStepTotal"));
stepCount.setScenarioStepSuccess(stepCount.getScenarioStepSuccess() + (Integer) map.get("scenarioStepSuccess"));
stepCount.setScenarioStepError(stepCount.getScenarioStepError() + (Integer) map.get("scenarioStepError"));
stepCount.setScenarioStepErrorReport(stepCount.getScenarioStepErrorReport() + (Integer) map.get("scenarioStepErrorReport"));
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + (map.get("pending") == null ? 0 : (Integer) map.get("pending")));
if (CollectionUtils.isNotEmpty(scenarioReportIdList)) {
List<ApiScenarioReportResultWithBLOBs> resultList = extApiScenarioReportResultMapper.selectIdAndStatusByReportIdList(scenarioReportIdList);
resultList = apiScenarioReportStructureService.filterProcessResult(resultList);
stepCount.setScenarioStepTotal(resultList.size());
int successStep = 0;
int fakeErrorStep = 0;
int errorStep = 0;
int unexecuteStep = 0;
for (ApiScenarioReportResult result : resultList) {
if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.ERROR.name())) {
errorStep++;
} else if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.SUCCESS.name())) {
successStep++;
} else if (StringUtils.equalsIgnoreCase(result.getStatus(), ApiReportStatus.FAKE_ERROR.name())) {
fakeErrorStep++;
} else if (!StringUtils.equalsAnyIgnoreCase(result.getStatus(), ApiReportStatus.RUNNING.name(), ApiReportStatus.RERUNNING.name())) {
unexecuteStep++;
}
}
} else {
stepCount.getUnderwayIds().add(item.getCaseId());
stepCount.setScenarioStepSuccess(successStep);
stepCount.setScenarioStepError(errorStep);
stepCount.setScenarioStepErrorReport(fakeErrorStep);
stepCount.setScenarioStepUnExecute(unexecuteStep);
}
}
public void relevanceByTestIds(List<String> ids, String planId) {
@ -802,8 +830,8 @@ public class TestPlanScenarioCaseService {
String planId = request.getPlanId();
Boolean saveResponse = request.getSaveResponse();
if (ServiceUtils.checkConfigEnable(config, "api")) {
List<TestPlanFailureApiDTO> apiAllCases = null;
List<TestPlanFailureScenarioDTO> scenarioAllCases = null;
List<TestPlanApiDTO> apiAllCases = null;
List<TestPlanScenarioDTO> scenarioAllCases = null;
if (checkReportConfig(config, "api", "all")) {
// 接口
apiAllCases = testPlanApiCaseService.getAllCases(planId);
@ -825,7 +853,7 @@ public class TestPlanScenarioCaseService {
return report;
}
public void buildScenarioResponse(List<TestPlanFailureScenarioDTO> cases) {
public void buildScenarioResponse(List<TestPlanScenarioDTO> cases) {
if (!CollectionUtils.isEmpty(cases)) {
cases.forEach((item) -> {
item.setResponse(apiScenarioReportService.get(item.getReportId(), true));
@ -833,12 +861,12 @@ public class TestPlanScenarioCaseService {
}
}
private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanFailureApiDTO> apiAllCases, Map reportConfig) {
private void screenApiCaseByStatusAndReportConfig(ApiPlanReportDTO report, List<TestPlanApiDTO> apiAllCases, Map reportConfig) {
if (!CollectionUtils.isEmpty(apiAllCases)) {
List<TestPlanFailureApiDTO> apiFailureCases = new ArrayList<>();
List<TestPlanFailureApiDTO> apiErrorReportCases = new ArrayList<>();
List<TestPlanFailureApiDTO> apiUnExecuteCases = new ArrayList<>();
for (TestPlanFailureApiDTO apiDTO : 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())) {
@ -865,13 +893,13 @@ public class TestPlanScenarioCaseService {
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)) {
List<TestPlanFailureScenarioDTO> failureScenarios = new ArrayList<>();
List<TestPlanFailureScenarioDTO> errorReportScenarios = new ArrayList<>();
List<TestPlanFailureScenarioDTO> unExecuteScenarios = new ArrayList<>();
for (TestPlanFailureScenarioDTO scenario : 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())) {
@ -893,80 +921,26 @@ public class TestPlanScenarioCaseService {
}
}
public ApiPlanReportDTO buildExecuteApiReport(ApiPlanReportRequest request) {
ApiPlanReportDTO report = new ApiPlanReportDTO();
TestPlanExecuteReportDTO testPlanExecuteReportDTO = request.getTestPlanExecuteReportDTO();
Map config = request.getConfig();
if (MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap())
&& MapUtils.isEmpty(testPlanExecuteReportDTO.getTestPlanScenarioIdAndReportIdMap())) {
return new ApiPlanReportDTO();
public ApiReportResultDTO buildExecuteApiReport(ApiPlanReportRequest request) {
ApiReportResultDTO resultDTO = new ApiReportResultDTO();
if (ObjectUtils.isNotEmpty(request)) {
Map<String, String> apiReportResultMap = apiDefinitionExecResultService.selectResultByIdList(request.getApiReportIdList());
Map<String, String> scenarioReportResultMap = apiScenarioReportService.selectResultByIdList(request.getScenarioReportIdList());
resultDTO.setApiReportResultMap(apiReportResultMap);
resultDTO.setScenarioReportResultMap(scenarioReportResultMap);
}
if (ServiceUtils.checkConfigEnable(config, "api")) {
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;
return resultDTO;
}
private void checkApiCaseCreatorName(List<TestPlanFailureApiDTO> apiCases, List<TestPlanFailureScenarioDTO> scenarioCases) {
List<String> userIdList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(apiCases)) {
apiCases.forEach(item -> {
if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUserId())) {
userIdList.add(item.getCreateUserId());
public List<TestPlanScenarioDTO> getTestPlanScenario(Map<String, String> idMap, Map<String, TestPlanScenarioDTO> scenarioInfoDTOMap) {
if (MapUtils.isEmpty(idMap) || MapUtils.isEmpty(scenarioInfoDTOMap)) {
return new ArrayList<>();
}
});
}
if (CollectionUtils.isNotEmpty(scenarioCases)) {
scenarioCases.forEach(item -> {
if (StringUtils.isEmpty(item.getCreatorName()) && StringUtils.isNotEmpty(item.getCreateUser())) {
userIdList.add(item.getCreateUser());
}
});
}
Map<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> savedReportMap = new HashMap<>(idMap);
List<TestPlanFailureScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureScenarioDTO dto : scenarioInfoDTOMap.values()) {
List<TestPlanScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanScenarioDTO dto : scenarioInfoDTOMap.values()) {
String reportId = savedReportMap.get(dto.getId());
savedReportMap.remove(dto.getId());
dto.setReportId(reportId);
@ -984,15 +958,15 @@ public class TestPlanScenarioCaseService {
}
public List<TestPlanFailureApiDTO> getByApiExecReportIds(Map<String, String> testPlanApiCaseReportMap, Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap) {
if (testPlanApiCaseReportMap.isEmpty()) {
public List<TestPlanApiDTO> getByApiExecReportIds(Map<String, String> testPlanApiCaseReportMap, Map<String, TestPlanApiDTO> apiCaseInfoDTOMap) {
if (MapUtils.isEmpty(testPlanApiCaseReportMap) || MapUtils.isEmpty(apiCaseInfoDTOMap)) {
return new ArrayList<>();
}
String defaultStatus = ApiReportStatus.ERROR.name();
Map<String, String> reportResult = apiDefinitionExecResultService.selectReportResultByReportIds(testPlanApiCaseReportMap.values());
Map<String, String> savedReportMap = new HashMap<>(testPlanApiCaseReportMap);
List<TestPlanFailureApiDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureApiDTO dto : apiCaseInfoDTOMap.values()) {
List<TestPlanApiDTO> apiTestCases = new ArrayList<>();
for (TestPlanApiDTO dto : apiCaseInfoDTOMap.values()) {
String testPlanApiCaseId = dto.getId();
String reportId = savedReportMap.get(testPlanApiCaseId);
savedReportMap.remove(testPlanApiCaseId);
@ -1019,7 +993,7 @@ public class TestPlanScenarioCaseService {
.isEmpty();
}
public List<TestPlanFailureScenarioDTO> getFailureListByIds(Set<String> ids) {
public List<TestPlanScenarioDTO> getListByIds(Set<String> ids) {
return extTestPlanScenarioCaseMapper.getFailureListByIds(ids, null);
}

View File

@ -899,4 +899,15 @@ public class ApiScenarioReportService {
public List<PlanReportCaseDTO> selectForPlanReport(List<String> 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;
}
private List<ApiScenarioReportResultWithBLOBs> filterProcessResult(List<ApiScenarioReportResultWithBLOBs> reportResults) {
public List<ApiScenarioReportResultWithBLOBs> filterProcessResult(List<ApiScenarioReportResultWithBLOBs> reportResults) {
List<ApiScenarioReportResultWithBLOBs> withOutProcessList = new ArrayList<>();
for (ApiScenarioReportResultWithBLOBs item : reportResults) {
if (item.getBaseInfo() != null) {

View File

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

View File

@ -1,10 +1,19 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.plan.dto.CaseExecResult;
import io.metersphere.plan.dto.TestPlanApiCaseInfoDTO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface ExtTestPlanApiCaseMapper {
List<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')
ORDER BY t.`order` DESC
</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>

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);
List<TestPlanDTO> planListAll(@Param("request") QueryTestPlanRequest params);
Boolean checkSyncTestCaseExecResultByTestPlanId(String testPlanId);
}

View File

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

View File

@ -1,6 +1,10 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.plan.dto.CaseExecResult;
import io.metersphere.plan.dto.TestPlanApiScenarioInfoDTO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@ -8,4 +12,9 @@ public interface ExtTestPlanScenarioCaseMapper {
List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(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}
ORDER BY tpas.`order` DESC;
</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>

View File

@ -1,11 +1,11 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.dto.PlanReportCaseDTO;
import io.metersphere.base.domain.TestPlanTestCase;
import io.metersphere.dto.*;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.request.function.QueryTestPlanCaseRequest;
import io.metersphere.request.BaseQueryRequest;
import io.metersphere.dto.*;
import io.metersphere.plan.request.function.TestPlanFuncCaseConditions;
import io.metersphere.request.BaseQueryRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -70,4 +70,10 @@ public interface ExtTestPlanTestCaseMapper {
String selectCaseId(String id);
List<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}
</if>
</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>

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

View File

@ -14,9 +14,9 @@ import io.metersphere.dto.TestPlanRerunParametersDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.plan.dto.ExecutionModeDTO;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.dto.TestPlanDTO;
import io.metersphere.plan.dto.TestPlanExtReportDTO;
import io.metersphere.plan.dto.TestPlanSimpleReportDTO;
import io.metersphere.plan.request.AddTestPlanRequest;
import io.metersphere.plan.request.BatchOperateRequest;
@ -61,7 +61,7 @@ public class TestPlanController {
@GetMapping("/auto-check/{testPlanId}")
public void autoCheck(@PathVariable String testPlanId) {
testPlanService.checkStatus(testPlanId);
testPlanService.checkTestPlanStatus(testPlanId);
}
@PostMapping("/list/{goPage}/{pageSize}")
@ -148,7 +148,7 @@ public class TestPlanController {
@MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#planId)", content = "#msClass.getLogDetails(#planId)", msClass = TestPlanService.class)
public void editTestPlanStatus(@PathVariable String planId) {
checkPermissionService.checkTestPlanOwner(planId);
testPlanService.checkStatus(planId);
testPlanService.checkTestPlanStatus(planId);
}
@PostMapping("/edit/report/config")
@ -387,12 +387,12 @@ public class TestPlanController {
}
@GetMapping("/ext/report/{reportId}")
public TestPlanExtReportDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException {
return testPlanService.getExtInfoByReportId(reportId);
public ExecutionModeDTO getExtReport(@PathVariable String reportId) throws JsonProcessingException {
return new ExecutionModeDTO();
}
@GetMapping("/ext/plan/{planId}")
public TestPlanExtReportDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException {
return testPlanService.getExtInfoByPlanId(planId);
public ExecutionModeDTO getExtPlan(@PathVariable String planId) throws JsonProcessingException {
return new ExecutionModeDTO();
}
}

View File

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

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
public class TestPlanReportBuildResultDTO {
private TestPlanSimpleReportDTO testPlanSimpleReportDTO;
/**
* 判断testPlanReportContent中APIBaseInfo字段是否改变
* 如果改变过则需要更新testPlanReportContent数据
*/
private boolean apiBaseInfoChanged = false;
}

View File

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

View File

@ -7,14 +7,16 @@ import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.mapper.ApiExecutionQueueMapper;
import io.metersphere.commons.constants.KafkaTopicConstants;
import io.metersphere.commons.constants.TestPlanReportStatus;
import io.metersphere.plan.service.TestCaseSyncStatusService;
import io.metersphere.plan.service.TestPlanReportService;
import io.metersphere.utils.LoggerUtil;
import jakarta.annotation.Resource;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
@ -27,11 +29,29 @@ public class ExecReportListener {
private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource
private TestPlanReportService testPlanReportService;
@Resource
private TestCaseSyncStatusService testCaseSyncStatusService;
@KafkaListener(id = CONSUME_ID, topics = KafkaTopicConstants.TEST_PLAN_REPORT_TOPIC, groupId = "${spring.application.name}")
public void consume(ConsumerRecord<?, String> record) {
LoggerUtil.info("Execute message received", record.value());
Object testIdObj = record.key();
if (ObjectUtils.isEmpty(testIdObj)) {
this.testPlanReportTestEnded(record.value());
} else {
this.automationCaseTestEnd(testIdObj.toString());
}
}
/**
* 测试计划相关的自动化用例结束后会根据测试计划的配置判断是否要同步功能用例的状态
* 目前暂时只有这一个需求后续如果有了更多操作建议将该方法内的逻辑处理放入一个共有方法中
*
* @param testId
*/
public void automationCaseTestEnd(String testId) {
testCaseSyncStatusService.checkAndUpdateFunctionCaseStatus(testId);
}
public void testPlanReportTestEnded(String testPlanReportId) {
@ -41,7 +61,7 @@ public class ExecReportListener {
List<ApiExecutionQueue> queues = queueMapper.selectByExample(executionQueueExample);
if (CollectionUtils.isEmpty(queues)) {
LoggerUtil.info("Normal execution completes, update test plan report status" + testPlanReportId);
testPlanReportService.finishedTestPlanReport(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
} else {
List<String> ids = queues.stream().map(ApiExecutionQueue::getId).collect(Collectors.toList());
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
@ -49,7 +69,7 @@ public class ExecReportListener {
long count = executionQueueDetailMapper.countByExample(detailExample);
if (count == 0) {
LoggerUtil.info("Normal execution completes, update test plan report status" + testPlanReportId);
testPlanReportService.finishedTestPlanReport(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
testPlanReportService.testPlanExecuteOver(testPlanReportId, TestPlanReportStatus.COMPLETED.name());
LoggerUtil.info("Clear Queue" + ids);
ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample();
queueExample.createCriteria().andIdIn(ids);

View File

@ -1,8 +1,8 @@
package io.metersphere.plan.dto;
import io.metersphere.dto.TestPlanFailureApiDTO;
import io.metersphere.dto.TestPlanFailureScenarioDTO;
import io.metersphere.dto.TestPlanApiDTO;
import io.metersphere.dto.TestPlanScenarioDTO;
import lombok.Getter;
import lombok.Setter;
@ -11,13 +11,13 @@ import java.util.List;
@Setter
@Getter
public class ApiPlanReportDTO {
private List<TestPlanFailureApiDTO> apiAllCases;
private List<TestPlanFailureApiDTO> apiFailureCases;
private List<TestPlanFailureApiDTO> errorReportCases;
private List<TestPlanFailureApiDTO> unExecuteCases;
private List<TestPlanApiDTO> apiAllCases;
private List<TestPlanApiDTO> apiFailureCases;
private List<TestPlanApiDTO> errorReportCases;
private List<TestPlanApiDTO> unExecuteCases;
private List<TestPlanFailureScenarioDTO> scenarioAllCases;
private List<TestPlanFailureScenarioDTO> scenarioFailureCases;
private List<TestPlanFailureScenarioDTO> errorReportScenarios;
private List<TestPlanFailureScenarioDTO> unExecuteScenarios;
private List<TestPlanScenarioDTO> scenarioAllCases;
private List<TestPlanScenarioDTO> scenarioFailureCases;
private List<TestPlanScenarioDTO> errorReportScenarios;
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;
@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> loadFailureCases;
List<TestPlanFailureApiDTO> apiAllCases;
List<TestPlanFailureApiDTO> errorReportCases;
List<TestPlanFailureApiDTO> apiFailureCases;
List<TestPlanFailureApiDTO> unExecuteCases;
List<TestPlanApiDTO> apiAllCases;
List<TestPlanApiDTO> errorReportCases;
List<TestPlanApiDTO> apiFailureCases;
List<TestPlanApiDTO> unExecuteCases;
List<TestPlanFailureScenarioDTO> scenarioAllCases;
List<TestPlanFailureScenarioDTO> errorReportScenarios;
List<TestPlanFailureScenarioDTO> scenarioFailureCases;
List<TestPlanFailureScenarioDTO> unExecuteScenarios;
List<TestPlanScenarioDTO> scenarioAllCases;
List<TestPlanScenarioDTO> errorReportScenarios;
List<TestPlanScenarioDTO> scenarioFailureCases;
List<TestPlanScenarioDTO> unExecuteScenarios;
List<TestPlanUiScenarioDTO> uiAllCases;
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;
import io.metersphere.dto.TestPlanExecuteReportDTO;
import io.metersphere.dto.TestPlanCaseReportResultDTO;
import io.metersphere.request.PlanSubReportRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class ApiPlanReportRequest extends PlanSubReportRequest {
private TestPlanExecuteReportDTO testPlanExecuteReportDTO;
List<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.BaseUserService;
import io.metersphere.service.SystemParameterService;
import jakarta.annotation.Resource;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -23,7 +24,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -281,7 +281,7 @@ public class TestPlanMessageService {
result.put("functionAllCount", (long) functionAllCases.size());
}
List<TestPlanFailureApiDTO> apiAllCases = report.getApiAllCases();
List<TestPlanApiDTO> apiAllCases = report.getApiAllCases();
if (CollectionUtils.isNotEmpty(apiAllCases)) {
Map<String, Long> apiCountMap = apiAllCases.stream()
.collect(Collectors.groupingBy(plan -> StringUtils.isEmpty(plan.getExecResult()) ? "default" : plan.getExecResult().toLowerCase(), Collectors.counting()));
@ -312,7 +312,7 @@ public class TestPlanMessageService {
result.put("apiCaseAllCount", (long) apiAllCases.size());
}
List<TestPlanFailureScenarioDTO> scenarioAllCases = report.getScenarioAllCases();
List<TestPlanScenarioDTO> scenarioAllCases = report.getScenarioAllCases();
if (CollectionUtils.isNotEmpty(scenarioAllCases)) {
Map<String, Long> scenarioCountMap = scenarioAllCases.stream()
.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.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.plan.constant.RunMode;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.job.TestPlanTestJob;
import io.metersphere.plan.request.AddTestPlanRequest;
@ -44,6 +43,7 @@ import io.metersphere.plan.service.remote.performance.PerfExecService;
import io.metersphere.plan.service.remote.performance.PlanTestPlanLoadCaseService;
import io.metersphere.plan.service.remote.ui.PlanTestPlanUiScenarioCaseService;
import io.metersphere.plan.service.remote.ui.PlanUiAutomationService;
import io.metersphere.plan.utils.TestPlanReportUtil;
import io.metersphere.plan.utils.TestPlanRequestUtil;
import io.metersphere.request.ScheduleRequest;
import io.metersphere.service.*;
@ -485,7 +485,14 @@ public class TestPlanService {
return testPlans;
}
public void checkStatus(String testPlanId) { // 检查执行结果自动更新计划状态
public void checkTestPlanStatusWhenExecuteOver(String testPlanId) {
TestPlan testPlan = this.testPlanMapper.selectByPrimaryKey(testPlanId);
if (testPlan != null && !StringUtils.equalsIgnoreCase(testPlan.getStatus(), "Completed")) {
this.checkTestPlanStatus(testPlanId);
}
}
public void checkTestPlanStatus(String testPlanId) { // 检查执行结果自动更新计划状态
List<String> statusList = new ArrayList<>();
statusList.addAll(extTestPlanTestCaseMapper.getExecResultByPlanId(testPlanId));
@ -883,25 +890,56 @@ public class TestPlanService {
LoggerUtil.info("预生成测试计划报告【" + reportInfoDTO.getTestPlanReport() != null ? reportInfoDTO.getTestPlanReport().getName() : StringUtils.EMPTY + "】计划报告ID[" + planReportId + "]");
Map<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> uiScenarioReportMap = null;
if (MapUtils.isNotEmpty(reportInfoDTO.getApiTestCaseDataMap())) {
//执行接口案例任务
LoggerUtil.info("开始执行测试计划接口用例 " + planReportId);
try {
apiCaseReportMap = this.executeApiTestCase(triggerMode, planReportId, userId, testPlanId, runModeConfig);
apiTestCases = planTestPlanApiCaseService.getFailureListByIds(reportInfoDTO.getApiTestCaseDataMap().keySet());
} catch (Exception e) {
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划接口用例失败! ", e);
LogUtil.error("测试计划执行查询接口用例失败!", e);
}
}
if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) {
try {
scenarioCases = planTestPlanScenarioCaseService.getFailureListByIds(reportInfoDTO.getPlanScenarioIdMap().keySet());
} catch (Exception e) {
LogUtil.error("测试计划执行查询场景用例失败!", e);
}
}
if (MapUtils.isNotEmpty(reportInfoDTO.getPlanScenarioIdMap())) {
try {
uiScenarios = planTestPlanUiScenarioCaseService.getFailureListByIds(reportInfoDTO.getPlanScenarioIdMap().keySet());
} catch (Exception e) {
LogUtil.error("测试计划执行查询UI用例失败!", e);
}
}
if (CollectionUtils.isNotEmpty(apiTestCases)) {
//执行接口案例任务
LoggerUtil.info("开始执行测试计划接口用例 " + planReportId);
try {
Map<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);
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) {
scenarioCases = null;
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划场景用例失败! ", e);
}
}
@ -916,19 +954,22 @@ public class TestPlanService {
}
}
if (reportInfoDTO.getUiScenarioIdMap() != null) {
if (CollectionUtils.isNotEmpty(uiScenarios)) {
//执行UI场景执行任务
LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId);
try {
uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanId, projectId, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap());
Map<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) {
uiScenarios = null;
LoggerUtil.info("测试报告" + planReportId + "本次执行测试计划 UI 用例失败! ", e);
}
}
LoggerUtil.info("开始生成测试计划报告内容 " + planReportId);
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiCaseReportMap, scenarioReportMap, loadCaseReportMap, uiScenarioReportMap);
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiTestCases, scenarioCases, uiScenarios, loadCaseReportMap);
return planReportId;
}
@ -1245,14 +1286,14 @@ public class TestPlanService {
report.setFunctionAllCases(allCases);
}
if (checkReportConfig(config, "functional", "issue")) {
if (TestPlanReportUtil.checkReportConfig(config, "functional", "issue")) {
List<IssuesDao> issueList = issuesService.getIssuesByPlanId(planId);
report.setIssueList(issueList);
}
}
}
public void buildUiReport(TestPlanSimpleReportDTO report, Map config, String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO, boolean saveResponse) {
public void buildUiReport(TestPlanSimpleReportDTO report, Map config, String planId, TestPlanCaseReportResultDTO testPlanExecuteReportDTO, boolean saveResponse) {
ApiPlanReportRequest request = new ApiPlanReportRequest();
request.setConfig(config);
request.setPlanId(planId);
@ -1274,16 +1315,16 @@ public class TestPlanService {
*/
public List<String> getFunctionalReportStatusList(Map config) {
List<String> statusList = new ArrayList<>();
if (checkReportConfig(config, "functional", "all")) {
if (TestPlanReportUtil.checkReportConfig(config, "functional", "all")) {
return statusList;
}
if (checkReportConfig(config, "functional", "failure")) {
if (TestPlanReportUtil.checkReportConfig(config, "functional", "failure")) {
statusList.add(TestPlanTestCaseStatus.Failure.name());
}
if (checkReportConfig(config, "functional", "blocking")) {
if (TestPlanReportUtil.checkReportConfig(config, "functional", "blocking")) {
statusList.add(TestPlanTestCaseStatus.Blocking.name());
}
if (checkReportConfig(config, "functional", "skip")) {
if (TestPlanReportUtil.checkReportConfig(config, "functional", "skip")) {
statusList.add(TestPlanTestCaseStatus.Skip.name());
}
return statusList.size() > 0 ? statusList : null;
@ -1311,88 +1352,49 @@ 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 testPlanReportContentWithBLOBs 测试计划报告内容
* @return
*/
public TestPlanReportBuildResultDTO buildPlanReport(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) {
public TestPlanReportBuildResultDTO buildTestPlanReport(TestPlanWithBLOBs testPlan, TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) {
TestPlanReportBuildResultDTO returnDTO = new TestPlanReportBuildResultDTO();
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId());
if (testPlan != null) {
String reportConfig = testPlan.getReportConfig();
if (ObjectUtils.allNotNull(testPlanReport, testPlanReportContentWithBLOBs)) {
Map config = null;
if (StringUtils.isNotBlank(reportConfig)) {
config = JSON.parseMap(reportConfig);
if (StringUtils.isNotBlank(testPlan.getReportConfig())) {
config = JSON.parseMap(testPlan.getReportConfig());
}
TestPlanExecuteReportDTO testPlanExecuteReportDTO = testPlanReportService.genTestPlanExecuteReportDTOByTestPlanReportContent(testPlanReportContentWithBLOBs);
TestPlanSimpleReportDTO report = null;
boolean apiBaseInfoChanged = false;
if (StringUtils.isEmpty(testPlanReportContentWithBLOBs.getApiBaseCount())) {
report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO);
apiBaseInfoChanged = true;
TestPlanSimpleReportDTO report = this.getTestPlanReportStructByCreated(testPlanReportContentWithBLOBs);
//检查是否有已经生成过的测试计划报告内容如若没有则进行动态计算
if (report == null) {
//查询测试计划内的用例信息然后进行测试计划报告的结果统计
TestPlanCaseReportResultDTO testPlanExecuteReportDTO = testPlanReportService.selectCaseDetailByTestPlanReport(config, testPlan.getId(), testPlanReportContentWithBLOBs);
report = generateTestPlanReport(
config,
testPlanReport.getCreator(),
StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name(), TestPlanReportStatus.SUCCESS.name(), TestPlanReportStatus.FAILED.name()),
testPlan, testPlanExecuteReportDTO);
}
returnDTO.setTestPlanSimpleReportDTO(report);
} else {
returnDTO.setTestPlanSimpleReportDTO(new TestPlanSimpleReportDTO());
}
return returnDTO;
}
//获取已生成过的测试计划报告内容
private TestPlanSimpleReportDTO getTestPlanReportStructByCreated(TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) {
TestPlanSimpleReportDTO reportStruct = null;
try {
report = JSON.parseObject(testPlanReportContentWithBLOBs.getApiBaseCount(), TestPlanSimpleReportDTO.class);
if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getApiBaseCount())) {
reportStruct = JSON.parseObject(testPlanReportContentWithBLOBs.getApiBaseCount(), TestPlanSimpleReportDTO.class);
}
} catch (Exception e) {
LogUtil.info("解析接口统计数据出错!数据:" + testPlanReportContentWithBLOBs.getApiBaseCount(), e);
}
if (report == null) {
report = getReport(testPlanReport.getTestPlanId(), testPlanExecuteReportDTO);
apiBaseInfoChanged = true;
return reportStruct;
}
}
if (report.getFunctionAllCases() == null || report.getIssueList() == null) {
buildFunctionalReport(report, config, testPlanReport.getTestPlanId());
apiBaseInfoChanged = true;
}
if (report.getApiAllCases() == null && report.getScenarioAllCases() == null) {
buildApiReport(report, config, testPlanExecuteReportDTO);
apiBaseInfoChanged = true;
}
if (report.getLoadAllCases() == null) {
buildLoadReport(report, config, testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap(), false);
apiBaseInfoChanged = true;
}
buildUiReport(report, config, testPlanReport.getTestPlanId(), testPlanExecuteReportDTO, false);
returnDTO.setTestPlanSimpleReportDTO(report);
if (apiBaseInfoChanged) {
testPlanReportContentWithBLOBs.setApiBaseCount(JSON.toJSONString(report));
returnDTO.setApiBaseInfoChanged(true);
}
return returnDTO;
} else {
returnDTO.setTestPlanSimpleReportDTO(new TestPlanSimpleReportDTO());
return returnDTO;
}
}
public TestPlanSimpleReportDTO buildPlanReport(String planId, boolean saveResponse) {
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId);
@ -1413,19 +1415,11 @@ public class TestPlanService {
public void exportPlanReport(String planId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException {
TestPlanSimpleReportDTO report = buildPlanReport(planId, true);
report.setLang(lang);
TestPlanExtReportDTO extReport = getExtInfoByPlanId(planId);
if (extReport != null) {
BeanUtils.copyBean(report, extReport);
}
render(report, response);
}
public void exportPlanDbReport(String reportId, String lang, HttpServletResponse response) throws UnsupportedEncodingException, JsonProcessingException {
TestPlanSimpleReportDTO report = testPlanReportService.getReport(reportId);
TestPlanExtReportDTO extReport = getExtInfoByReportId(reportId);
if (extReport != null) {
BeanUtils.copyBean(report, extReport);
}
Set<String> serviceIdSet = DiscoveryUtil.getServiceIdSet();
if (serviceIdSet.contains(MicroServiceName.API_TEST)) {
report.setApiAllCases(planTestPlanApiCaseService.buildResponse(report.getApiAllCases()));
@ -1494,6 +1488,65 @@ public class TestPlanService {
}
}
//根据用例运行结果生成测试计划报告
public TestPlanSimpleReportDTO generateTestPlanReport(Map reportConfig, String operator, boolean isTestPlanReportExecuteOver, TestPlanWithBLOBs testPlan, TestPlanCaseReportResultDTO testPlanCaseReportResultDTO) {
TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO();
if (ObjectUtils.anyNotNull(testPlan, testPlanCaseReportResultDTO)) {
TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO();
TestPlanApiResultReportDTO apiResult = new TestPlanApiResultReportDTO();
TestPlanUiResultReportDTO uiResult = new TestPlanUiResultReportDTO();
report.setFunctionResult(functionResult);
report.setApiResult(apiResult);
report.setUiResult(uiResult);
report.setStartTime(testPlan.getActualStartTime());
report.setEndTime(testPlan.getActualEndTime());
report.setSummary(testPlan.getReportSummary());
report.setConfig(testPlan.getReportConfig());
if (testPlanCaseReportResultDTO.getApiPlanReportDTO() != null) {
BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getApiPlanReportDTO());
planTestPlanApiCaseService.calculateReportByApiCase(testPlanCaseReportResultDTO.getApiPlanReportDTO().getApiAllCases(), report);
planTestPlanScenarioCaseService.calculateReportByScenario(testPlanCaseReportResultDTO.getApiPlanReportDTO().getScenarioAllCases(), report);
}
if (testPlanCaseReportResultDTO.getLoadPlanReportDTO() != null) {
BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getLoadPlanReportDTO());
planTestPlanLoadCaseService.calculateReportByLoadCaseList(testPlanCaseReportResultDTO.getLoadPlanReportDTO().getLoadAllCases(), report);
}
if (testPlanCaseReportResultDTO.getUiPlanReportDTO() != null) {
BeanUtils.copyBean(report, testPlanCaseReportResultDTO.getUiPlanReportDTO());
planTestPlanUiScenarioCaseService.calculateReportByUiScenarios(testPlanCaseReportResultDTO.getUiPlanReportDTO().getUiAllCases(), report);
}
//功能用例的状态更新以及统计
testPlanTestCaseService.calculateReportByTestCaseList(operator, testPlan, isTestPlanReportExecuteOver, testPlanCaseReportResultDTO.getFunctionCaseList(), report);
if (report.getFunctionAllCases() == null || report.getIssueList() == null) {
//构建功能用例和issue
this.buildFunctionalReport(report, reportConfig, testPlan.getId());
}
issuesService.calculateReportByIssueList(testPlanCaseReportResultDTO.getIssueList(), report);
if (report.getExecuteCount() != 0 && report.getCaseCount() != null) {
report.setExecuteRate(report.getExecuteCount() * 0.1 * 10 / report.getCaseCount());
} else {
report.setExecuteRate(0.0);
}
if (report.getPassCount() != 0 && report.getCaseCount() != null) {
report.setPassRate(report.getPassCount() * 0.1 * 10 / report.getCaseCount());
} else {
report.setPassRate(0.0);
}
report.setName(testPlan.getName());
Project project = baseProjectService.getProjectById(testPlan.getProjectId());
if (project.getPlatform() != null && project.getPlatform().equals(IssuesManagePlatform.Local.name())) {
report.setIsThirdPartIssue(false);
} else {
report.setIsThirdPartIssue(true);
}
}
return report;
}
/**
* 生成测试计划报告并进行统计
*
@ -1501,7 +1554,7 @@ public class TestPlanService {
* @param testPlanExecuteReportDTO 测试计划各个资源的报告 如果为空则取当前测试计划资源的最新报告
* @return
*/
public TestPlanSimpleReportDTO getReport(String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO) {
public TestPlanSimpleReportDTO getReport(String planId, TestPlanCaseReportResultDTO testPlanExecuteReportDTO) {
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(planId);
TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO();
TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO();
@ -2033,132 +2086,6 @@ public class TestPlanService {
this.deleteTestPlans(ids);
}
public TestPlanExtReportDTO getExtInfoByReportId(String reportId) throws JsonProcessingException {
TestPlanExtReportDTO testPlanExtReportDTO = new TestPlanExtReportDTO();
Set<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) {
List<String> projectIds = new ArrayList<>();
List<String> apiCaseProjectIds = planTestPlanApiCaseService.getApiCaseProjectIds(planId);
@ -2172,17 +2099,4 @@ public class TestPlanService {
return projectIds.stream().distinct().collect(Collectors.toList());
}
private void convertPlanEnvConfig(String envConfig, TestPlanExtReportDTO testPlanExtReportDTO) throws JsonProcessingException {
if (StringUtils.isEmpty(envConfig)) {
return;
}
PlanEnvConfig env = objectMapper.readValue(envConfig, PlanEnvConfig.class);
if (StringUtils.isNotEmpty(env.getRunMode())) {
if (RunMode.RUN_MODE_SERIAL.getCode().equals(env.getRunMode())) {
testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_SERIAL.getDesc());
} else if (RunMode.RUN_MODE_PARALLEL.getCode().equals(env.getRunMode())) {
testPlanExtReportDTO.setRunMode(RunMode.RUN_MODE_PARALLEL.getDesc());
}
}
}
}

View File

@ -10,18 +10,16 @@ import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.MicroServiceName;
import io.metersphere.commons.constants.ProjectApplicationType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*;
import io.metersphere.constants.TestCaseCommentType;
import io.metersphere.dto.ProjectConfig;
import io.metersphere.dto.PlanReportCaseDTO;
import io.metersphere.dto.*;
import io.metersphere.excel.constants.TestPlanTestCaseStatus;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.dto.TestPlanSimpleReportDTO;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.plan.dto.TestCaseReportStatusResultDTO;
import io.metersphere.plan.dto.TestPlanSimpleReportDTO;
import io.metersphere.plan.request.function.*;
import io.metersphere.plan.service.remote.api.PlanApiAutomationService;
import io.metersphere.plan.service.remote.api.PlanApiTestCaseService;
@ -33,20 +31,20 @@ import io.metersphere.plan.utils.TestPlanStatusCalculator;
import io.metersphere.request.OrderRequest;
import io.metersphere.request.ResetOrderRequest;
import io.metersphere.request.member.QueryMemberRequest;
import io.metersphere.service.*;
import io.metersphere.dto.*;
import io.metersphere.request.testcase.TrackCount;
import io.metersphere.request.testreview.SaveCommentRequest;
import io.metersphere.service.*;
import io.metersphere.utils.DiscoveryUtil;
import io.metersphere.xpack.track.dto.IssuesDao;
import io.metersphere.xpack.version.service.ProjectVersionService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -90,6 +88,8 @@ public class TestPlanTestCaseService {
private FunctionCaseExecutionInfoService functionCaseExecutionInfoService;
@Resource
private CustomFieldTestCaseService customFieldTestCaseService;
@Resource
private TestCaseSyncStatusService testCaseSyncStatusService;
private static final String CUSTOM_NUM = "custom_num";
private static final String NUM = "num";
@ -520,22 +520,54 @@ public class TestPlanTestCaseService {
return null;
}
public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) {
try {
List<PlanReportCaseDTO> planReportCaseDTOS = extTestPlanTestCaseMapper.selectForPlanReport(planId);
this.calculatePlanReport(planReportCaseDTOS, report);
} catch (MSException 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(planReportCaseDTOS, statusResultMap, report, TestPlanTestCaseStatus.Pass.name());
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);
} catch (MSException e) {
LogUtil.error(e);
}
}
public List<TestPlanCaseDTO> getAllCasesByStatusList(String planId, List<String> 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) {
try {
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);
}
public List<TestPlanFailureApiDTO> getFailureListByIds(Set<String> ids) {
return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanFailureApiDTO.class);
public List<TestPlanApiDTO> getFailureListByIds(Set<String> ids) {
return microService.postForDataArray(serviceName, BASE_UEL + "/failure/list", ids, TestPlanApiDTO.class);
}
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);
}
public List<TestPlanFailureApiDTO> buildResponse(List<TestPlanFailureApiDTO> apiAllCases) {
public List<TestPlanApiDTO> buildResponse(List<TestPlanApiDTO> apiAllCases) {
if (CollectionUtils.isEmpty(apiAllCases)) {
return null;
}
return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", apiAllCases, TestPlanFailureApiDTO.class);
return microService.postForDataArray(serviceName, BASE_UEL + "/build/response", apiAllCases, TestPlanApiDTO.class);
}
public Object relevanceList(int pageNum, int pageSize, ApiTestCaseRequest request) {

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

View File

@ -15,11 +15,11 @@ import io.metersphere.plan.request.performance.LoadPlanReportDTO;
import io.metersphere.plan.service.TestPlanService;
import io.metersphere.plan.utils.TestPlanStatusCalculator;
import io.metersphere.utils.DiscoveryUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -43,6 +43,23 @@ public class PlanTestPlanLoadCaseService extends LoadTestService {
}
}
public void calculateReportByLoadCaseList(List<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) {
try {
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.request.ResetOrderRequest;
import io.metersphere.utils.DiscoveryUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -50,6 +49,23 @@ public class PlanTestPlanUiScenarioCaseService extends UiTestService {
return microService.postForData(serviceName, BASE_URL + "/plan/report", request, UiPlanReportDTO.class);
}
public void calculateReportByUiScenarios(List<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) {
try {
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.UserService;
import io.metersphere.utils.DistinctKeyUtil;
import io.metersphere.xpack.track.dto.AttachmentRequest;
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
import io.metersphere.xpack.track.dto.PlatformUser;
import io.metersphere.xpack.track.dto.*;
@ -61,6 +60,8 @@ import io.metersphere.xpack.track.dto.request.IssuesRequest;
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
import io.metersphere.xpack.track.issue.IssuesPlatform;
import io.metersphere.xpack.track.service.XpackIssueService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
@ -75,8 +76,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.*;
@ -1225,14 +1224,34 @@ public class IssuesService {
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) {
List<PlanReportIssueDTO> planReportIssueDTOS = extIssuesMapper.selectForPlanReport(planId);
planReportIssueDTOS = DistinctKeyUtil.distinctByKey(planReportIssueDTOS, PlanReportIssueDTO::getId);
List<PlanReportIssueDTO> planReportIssueDTOList = extIssuesMapper.selectForPlanReport(planId);
this.calculatePlanReport(planReportIssueDTOList, report);
}
public void calculatePlanReport(List<PlanReportIssueDTO> planReportIssueDTOList, TestPlanSimpleReportDTO report) {
planReportIssueDTOList = DistinctKeyUtil.distinctByKey(planReportIssueDTOList, PlanReportIssueDTO::getId);
TestPlanFunctionResultReportDTO functionResult = report.getFunctionResult();
List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>();
Map<String, TestCaseReportStatusResultDTO> statusResultMap = new HashMap<>();
planReportIssueDTOS.forEach(item -> {
planReportIssueDTOList.forEach(item -> {
String status;
// 本地缺陷
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_issue_tip=Import fails without legitimate issues!
zentao_test_type_error=invalid Zentao request
test_case_status_prepare=Prepare
test_case_status_running=Running
test_case_status_finished=Finished
@ -219,16 +218,13 @@ test_case_status_error=Error
test_case_status_success=Success
test_case_status_trash=Trash
test_case_status_saved=Saved
execute_not_pass=Not pass
execute_pass=Pass
jira_auth_error=Account name or password (Token) is wrong
jira_auth_url_error=The test connection failed, please check whether the Jira address is correct
platform_plugin_not_exit=Platform docking function has been plug-in, please download the corresponding version of the plug-in:
plan_warning=The test plan does not have an associated executable use case
test_plan_delete_exec_error=The test plan is being executed
test_case_review_status_underway=Underway
test_case_review_status_re_review=ReReview
api_status_fake_error=Fake error

View File

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

View File

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

View File

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