refactor(接口测试): 优化报告显示

This commit is contained in:
wxg0103 2024-03-27 17:18:52 +08:00 committed by Craftsman
parent 4f5980d46c
commit f666240c09
20 changed files with 173 additions and 41 deletions

View File

@ -73,25 +73,25 @@ public class ApiTaskCenterController {
apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId()); apiTaskCenterService.projectStop(request, SessionUtils.getCurrentProjectId(), SessionUtils.getUserId());
} }
@GetMapping("/api/project/stop/{id}") @GetMapping("/api/project/stop/{moduleType}/{id}")
@Operation(summary = "项目-任务中心-接口用例/场景-停止任务") @Operation(summary = "项目-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void stopById(@PathVariable String id) { public void stopById(@PathVariable String moduleType, @PathVariable String id) {
apiTaskCenterService.stopById(id, SessionUtils.getUserId(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, "/task/center/api/project/stop"); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER, "/task/center/api/project/stop");
} }
@GetMapping("/api/org/stop/{id}") @GetMapping("/api/org/stop/{moduleType}/{id}")
@Operation(summary = "组织-任务中心-接口用例/场景-停止任务") @Operation(summary = "组织-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP) @RequiresPermissions(PermissionConstants.ORGANIZATION_TASK_CENTER_READ_STOP)
public void stopOrgById(@PathVariable String id) { public void stopOrgById(@PathVariable String moduleType, @PathVariable String id) {
apiTaskCenterService.stopById(id, SessionUtils.getUserId(), OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, "/task/center/api/org/stop"); apiTaskCenterService.stopById(moduleType, id, SessionUtils.getUserId(), OperationLogModule.SETTING_ORGANIZATION_TASK_CENTER, "/task/center/api/org/stop");
} }
@GetMapping("/api/system/stop/{id}") @GetMapping("/api/system/stop/{moduleType}/{id}")
@Operation(summary = "系统-任务中心-接口用例/场景-停止任务") @Operation(summary = "系统-任务中心-接口用例/场景-停止任务")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ) @RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_READ)
public void stopSystemById(@PathVariable String id) { public void stopSystemById(@PathVariable String moduleType,@PathVariable String id) {
apiTaskCenterService.stopById(id, SessionUtils.getUserId(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER, "/task/center/api/system/stop"); apiTaskCenterService.stopById(moduleType ,id, SessionUtils.getUserId(), OperationLogModule.SETTING_SYSTEM_TASK_CENTER, "/task/center/api/system/stop");
} }

View File

@ -22,5 +22,14 @@ public class ApiScenarioReportDTO extends ApiScenarioReport {
private String creatUserName; private String creatUserName;
@Schema(description = "请求总数") @Schema(description = "请求总数")
private Long requestTotal; private Long requestTotal;
@Schema(description = "等待时间")
private Long waitingTime;
@Schema(description = "步骤失败数")
private Long stepErrorCount;
@Schema(description = "步骤误报数")
private Long stepFakeErrorCount;
@Schema(description = "步骤未执行数")
private Long stepPendingCount;
@Schema(description = "步骤成功数")
private Long stepSuccessCount;
} }

View File

@ -36,4 +36,6 @@ public interface ExtApiReportMapper {
void updateReportStatus(@Param("ids") List<String> ids, @Param("time") long time, @Param("userId") String userId); void updateReportStatus(@Param("ids") List<String> ids, @Param("time") long time, @Param("userId") String userId);
List<ReportDTO> selectByIds(@Param("ids") List<String> ids); List<ReportDTO> selectByIds(@Param("ids") List<String> ids);
void updateApiCaseStatus(@Param("ids") List<String> ids);
} }

View File

@ -11,6 +11,17 @@
#{id} #{id}
</foreach> </foreach>
</update> </update>
<update id="updateApiCaseStatus">
update api_test_case
set last_report_status = 'STOPPED'
where id in
(select api_test_case_id from api_test_case_record where api_report_id
in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
)
</update>
<select id="list" resultType="io.metersphere.api.domain.ApiReport"> <select id="list" resultType="io.metersphere.api.domain.ApiReport">
select select
@ -186,7 +197,7 @@
api_report.deleted = false api_report.deleted = false
and api_report.test_plan_id = 'NONE' and api_report.test_plan_id = 'NONE'
and api_report.start_time BETWEEN #{startTime} AND #{endTime} and api_report.start_time BETWEEN #{startTime} AND #{endTime}
and status in ('PENDING', 'RUNNING') and status in ('PENDING', 'RUNNING', 'RERUNNING')
<if test="ids != null and ids.size() > 0"> <if test="ids != null and ids.size() > 0">
and id in and id in
<foreach collection="ids" item="id" open="(" separator="," close=")"> <foreach collection="ids" item="id" open="(" separator="," close=")">

View File

@ -1,5 +1,6 @@
package io.metersphere.api.mapper; package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiScenarioBlob;
import io.metersphere.api.domain.ApiScenarioReport; import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.dto.definition.ApiReportBatchRequest; import io.metersphere.api.dto.definition.ApiReportBatchRequest;
import io.metersphere.api.dto.definition.ApiReportPageRequest; import io.metersphere.api.dto.definition.ApiReportPageRequest;
@ -44,4 +45,8 @@ public interface ExtApiScenarioReportMapper {
* 根据项目获取组织id * 根据项目获取组织id
*/ */
List<ReportDTO> getOrgListByProjectIds(@Param("ids") List<String> ids); List<ReportDTO> getOrgListByProjectIds(@Param("ids") List<String> ids);
ApiScenarioBlob getScenarioBlob(String id);
void updateApiScenario(List<String> subList);
} }

View File

@ -11,6 +11,16 @@
#{id} #{id}
</foreach> </foreach>
</update> </update>
<update id="updateApiScenario">
update api_scenario
set last_report_status = 'STOPPED'
where id in (
select api_scenario_id from api_scenario_record where api_scenario_report_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
)
</update>
<select id="list" resultType="io.metersphere.api.domain.ApiScenarioReport"> <select id="list" resultType="io.metersphere.api.domain.ApiScenarioReport">
select select
@ -114,7 +124,7 @@
api_scenario_report.deleted = false api_scenario_report.deleted = false
and api_scenario_report.test_plan_id = 'NONE' and api_scenario_report.test_plan_id = 'NONE'
and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime} and api_scenario_report.start_time BETWEEN #{startTime} AND #{endTime}
and status in ('PENDING', 'RUNNING') and status in ('PENDING', 'RUNNING', 'RERUNNING')
<if test="ids != null and ids.size() > 0"> <if test="ids != null and ids.size() > 0">
and id in and id in
<foreach collection="ids" item="id" open="(" separator="," close=")"> <foreach collection="ids" item="id" open="(" separator="," close=")">
@ -203,6 +213,13 @@
#{id} #{id}
</foreach> </foreach>
</select> </select>
<select id="getScenarioBlob" resultType="io.metersphere.api.domain.ApiScenarioBlob">
select
api_scenario_blob.*
from api_scenario_blob inner join api_scenario_record on api_scenario_blob.id = api_scenario_record.api_scenario_id
where api_scenario_record.api_scenario_report_id = #{id}
</select>
<sql id="filters"> <sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0"> <if test="${filter} != null and ${filter}.size() > 0">

View File

@ -263,17 +263,18 @@ public class ApiTaskCenterService {
try { try {
LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString()); LogUtils.info(String.format("开始发送停止请求到 %s 节点执行", endpoint), subList.toString());
TaskRunnerClient.stopApi(endpoint, subList); TaskRunnerClient.stopApi(endpoint, subList);
} catch (Exception e) {
LogUtils.error(e);
if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) { if (request.getModuleType().equals(TaskCenterResourceType.API_CASE.toString())) {
extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); extApiReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiReportMapper.updateApiCaseStatus(subList);
//记录日志 //记录日志
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString()); saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_CASE.toString());
} else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) { } else if (request.getModuleType().equals(TaskCenterResourceType.API_SCENARIO.toString())) {
extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId); extApiScenarioReportMapper.updateReportStatus(subList, System.currentTimeMillis(), userId);
extApiScenarioReportMapper.updateApiScenario(subList);
saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString()); saveLog(subList, userId, path, method, module, TaskCenterResourceType.API_SCENARIO.toString());
} }
} catch (Exception e) {
LogUtils.error(e);
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage()); throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
} }
}); });
@ -324,11 +325,12 @@ public class ApiTaskCenterService {
stopApiTask(request, List.of(currentProjectId), userId, PROJECT_STOP, HttpMethodConstants.POST.name(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER); stopApiTask(request, List.of(currentProjectId), userId, PROJECT_STOP, HttpMethodConstants.POST.name(), OperationLogModule.PROJECT_MANAGEMENT_TASK_CENTER);
} }
public void stopById(String id, String userId, String module, String path) { public void stopById(String moduleType, String id, String userId, String module, String path) {
List<String> reportIds = new ArrayList<>(); List<String> reportIds = new ArrayList<>();
reportIds.add(id); reportIds.add(id);
TaskCenterBatchRequest request = new TaskCenterBatchRequest(); TaskCenterBatchRequest request = new TaskCenterBatchRequest();
request.setSelectIds(reportIds); request.setSelectIds(reportIds);
request.setModuleType(moduleType);
stopApiTask(request, null, userId, path, HttpMethodConstants.GET.name(), module); stopApiTask(request, null, userId, path, HttpMethodConstants.GET.name(), module);
} }
} }

View File

@ -7,8 +7,10 @@ import io.metersphere.api.mapper.*;
import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentGroup;
import io.metersphere.sdk.dto.api.result.RequestResult; import io.metersphere.sdk.dto.api.result.RequestResult;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.SubListUtils; import io.metersphere.sdk.util.SubListUtils;
@ -59,6 +61,8 @@ public class ApiReportService {
private TestResourcePoolMapper testResourcePoolMapper; private TestResourcePoolMapper testResourcePoolMapper;
@Resource @Resource
private EnvironmentMapper environmentMapper; private EnvironmentMapper environmentMapper;
@Resource
private EnvironmentGroupMapper environmentGroupMapper;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
@ -193,6 +197,11 @@ public class ApiReportService {
if (environment != null) { if (environment != null) {
environmentName = environment.getName(); environmentName = environment.getName();
} }
EnvironmentGroup environmentGroup = environmentGroupMapper.selectByPrimaryKey(apiReportDTO.getEnvironmentId());
if (environmentGroup != null) {
environmentName = environmentGroup.getName();
}
} }
apiReportDTO.setEnvironmentName(environmentName); apiReportDTO.setEnvironmentName(environmentName);
apiReportDTO.setCreatUserName(userMapper.selectByPrimaryKey(apiReportDTO.getCreateUser()).getName()); apiReportDTO.setCreatUserName(userMapper.selectByPrimaryKey(apiReportDTO.getCreateUser()).getName());

View File

@ -8,14 +8,18 @@ import io.metersphere.api.dto.report.ApiScenarioReportListDTO;
import io.metersphere.api.dto.scenario.ApiScenarioReportDTO; import io.metersphere.api.dto.scenario.ApiScenarioReportDTO;
import io.metersphere.api.dto.scenario.ApiScenarioReportDetailDTO; import io.metersphere.api.dto.scenario.ApiScenarioReportDetailDTO;
import io.metersphere.api.dto.scenario.ApiScenarioReportStepDTO; import io.metersphere.api.dto.scenario.ApiScenarioReportStepDTO;
import io.metersphere.api.dto.scenario.ScenarioConfig;
import io.metersphere.api.mapper.*; import io.metersphere.api.mapper.*;
import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.sdk.constants.ApiReportStatus; import io.metersphere.sdk.constants.ApiReportStatus;
import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentGroup;
import io.metersphere.sdk.dto.api.result.RequestResult; import io.metersphere.sdk.dto.api.result.RequestResult;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.SubListUtils; import io.metersphere.sdk.util.SubListUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.mapper.TestResourcePoolMapper; import io.metersphere.system.mapper.TestResourcePoolMapper;
@ -23,6 +27,7 @@ import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.service.UserLoginService; import io.metersphere.system.service.UserLoginService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
@ -60,6 +65,8 @@ public class ApiScenarioReportService {
@Resource @Resource
private EnvironmentMapper environmentMapper; private EnvironmentMapper environmentMapper;
@Resource @Resource
private EnvironmentGroupMapper environmentGroupMapper;
@Resource
private UserMapper userMapper; private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
@ -182,6 +189,13 @@ public class ApiScenarioReportService {
if (CollectionUtils.isEmpty(scenarioReportSteps)) { if (CollectionUtils.isEmpty(scenarioReportSteps)) {
throw new MSException(Translator.get("api_scenario_report_not_exist")); throw new MSException(Translator.get("api_scenario_report_not_exist"));
} }
if (BooleanUtils.isFalse(scenarioReport.getIntegrated())) {
ApiScenarioBlob apiScenarioBlob = extApiScenarioReportMapper.getScenarioBlob(id);
if (apiScenarioBlob != null) {
ScenarioConfig scenarioConfig = JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class);
scenarioReportDTO.setWaitingTime(scenarioConfig.getOtherConfig().getStepWaitTime());
}
}
//将scenarioReportSteps按照parentId进行分组 值为list 然后根据sort进行排序 //将scenarioReportSteps按照parentId进行分组 值为list 然后根据sort进行排序
Map<String, List<ApiScenarioReportStepDTO>> scenarioReportStepMap = scenarioReportSteps.stream().collect(Collectors.groupingBy(ApiScenarioReportStepDTO::getParentId)); Map<String, List<ApiScenarioReportStepDTO>> scenarioReportStepMap = scenarioReportSteps.stream().collect(Collectors.groupingBy(ApiScenarioReportStepDTO::getParentId));
// TODO 查询修改 // TODO 查询修改
@ -191,6 +205,11 @@ public class ApiScenarioReportService {
scenarioReportDTO.setStepTotal(steps.size()); scenarioReportDTO.setStepTotal(steps.size());
scenarioReportDTO.setRequestTotal(scenarioReportDTO.getErrorCount() + scenarioReportDTO.getPendingCount() + scenarioReportDTO.getSuccessCount() + scenarioReportDTO.getFakeErrorCount()); scenarioReportDTO.setRequestTotal(scenarioReportDTO.getErrorCount() + scenarioReportDTO.getPendingCount() + scenarioReportDTO.getSuccessCount() + scenarioReportDTO.getFakeErrorCount());
scenarioReportDTO.setChildren(steps); scenarioReportDTO.setChildren(steps);
scenarioReportDTO.setStepErrorCount(steps.stream().filter(step -> StringUtils.equals(ApiReportStatus.ERROR.name(), step.getStatus())).count());
scenarioReportDTO.setStepSuccessCount(steps.stream().filter(step -> StringUtils.equals(ApiReportStatus.SUCCESS.name(), step.getStatus())).count());
scenarioReportDTO.setStepPendingCount(steps.stream().filter(step -> StringUtils.equals(ApiReportStatus.PENDING.name(), step.getStatus())).count());
scenarioReportDTO.setStepFakeErrorCount(steps.stream().filter(step -> StringUtils.equals(ApiReportStatus.FAKE_ERROR.name(), step.getStatus())).count());
//控制台信息 console //控制台信息 console
ApiScenarioReportLogExample example = new ApiScenarioReportLogExample(); ApiScenarioReportLogExample example = new ApiScenarioReportLogExample();
example.createCriteria().andReportIdEqualTo(id); example.createCriteria().andReportIdEqualTo(id);
@ -207,6 +226,10 @@ public class ApiScenarioReportService {
if (environment != null) { if (environment != null) {
environmentName = environment.getName(); environmentName = environment.getName();
} }
EnvironmentGroup environmentGroup = environmentGroupMapper.selectByPrimaryKey(scenarioReport.getEnvironmentId());
if (environmentGroup != null) {
environmentName = environmentGroup.getName();
}
} }
scenarioReportDTO.setEnvironmentName(environmentName); scenarioReportDTO.setEnvironmentName(environmentName);
scenarioReportDTO.setCreatUserName(userMapper.selectByPrimaryKey(scenarioReport.getCreateUser()).getName()); scenarioReportDTO.setCreatUserName(userMapper.selectByPrimaryKey(scenarioReport.getCreateUser()).getName());
@ -248,7 +271,11 @@ public class ApiScenarioReportService {
} else { } else {
step.setStatus(ApiReportStatus.PENDING.name()); step.setStatus(ApiReportStatus.PENDING.name());
} }
} else if (stepTypes.contains(step.getStepType())) {
step.setStatus(ApiReportStatus.PENDING.name());
if (StringUtils.equals(ApiScenarioStepType.CONSTANT_TIMER.name(), step.getStepType())) {
step.setStatus(ApiReportStatus.SUCCESS.name());
}
} }
} }
} }

View File

@ -403,6 +403,7 @@ public class ApiScenarioService extends MoveNodeService {
public ApiScenario add(ApiScenarioAddRequest request, String creator) { public ApiScenario add(ApiScenarioAddRequest request, String creator) {
checkAddExist(request); checkAddExist(request);
ApiScenario scenario = getAddApiScenario(request, creator); ApiScenario scenario = getAddApiScenario(request, creator);
scenario.setStepTotal(request.getSteps().size());
apiScenarioMapper.insert(scenario); apiScenarioMapper.insert(scenario);
// 更新场景配置 // 更新场景配置
@ -627,6 +628,7 @@ public class ApiScenarioService extends MoveNodeService {
ApiScenario scenario = BeanUtils.copyBean(new ApiScenario(), request); ApiScenario scenario = BeanUtils.copyBean(new ApiScenario(), request);
scenario.setUpdateUser(updater); scenario.setUpdateUser(updater);
scenario.setUpdateTime(System.currentTimeMillis()); scenario.setUpdateTime(System.currentTimeMillis());
scenario.setStepTotal(CollectionUtils.isNotEmpty(request.getSteps()) ? request.getSteps().size() : 0);
apiScenarioMapper.updateByPrimaryKeySelective(scenario); apiScenarioMapper.updateByPrimaryKeySelective(scenario);
if (request.getScenarioConfig() != null) { if (request.getScenarioConfig() != null) {

View File

@ -23,7 +23,9 @@ import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentExample; import io.metersphere.sdk.domain.EnvironmentExample;
import io.metersphere.sdk.domain.EnvironmentGroup;
import io.metersphere.sdk.domain.ShareInfo; import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.mapper.ShareInfoMapper; import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -72,6 +74,8 @@ public class ApiReportControllerTests extends BaseTest {
private TestResourcePoolMapper testResourcePoolMapper; private TestResourcePoolMapper testResourcePoolMapper;
@Resource @Resource
private EnvironmentMapper environmentMapper; private EnvironmentMapper environmentMapper;
@Resource
private EnvironmentGroupMapper environmentGroupMapper;
private static final String BASIC = "/api/report/case"; private static final String BASIC = "/api/report/case";
private static final String PAGE = BASIC + "/page"; private static final String PAGE = BASIC + "/page";
@ -307,6 +311,21 @@ public class ApiReportControllerTests extends BaseTest {
apiReportMapper.updateByPrimaryKeySelective(apiReport1); apiReportMapper.updateByPrimaryKeySelective(apiReport1);
this.requestGetWithOk(GET + "test-report-id"); this.requestGetWithOk(GET + "test-report-id");
EnvironmentGroup environmentGroup = new EnvironmentGroup();
environmentGroup.setId("env_group_id");
environmentGroup.setProjectId(DEFAULT_PROJECT_ID);
environmentGroup.setName("env_group_name");
environmentGroup.setCreateUser("admin");
environmentGroup.setUpdateUser("admin");
environmentGroup.setUpdateTime(System.currentTimeMillis());
environmentGroup.setCreateTime(System.currentTimeMillis());
environmentGroup.setPos(1L);
environmentGroupMapper.insert(environmentGroup);
apiReport1.setEnvironmentId("env_group_id");
apiReportMapper.updateByPrimaryKeySelective(apiReport1);
this.requestGetWithOk(GET + "test-report-id");
environmentGroupMapper.deleteByPrimaryKey("env_group_id");
reports = new ArrayList<>(); reports = new ArrayList<>();
apiReport = new ApiReport(); apiReport = new ApiReport();
apiReport.setId("test-report-id-no-step-true"); apiReport.setId("test-report-id-no-step-true");

View File

@ -394,6 +394,7 @@ public class ApiScenarioControllerTests extends BaseTest {
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(id); ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(id);
ApiScenario copyApiScenario = BeanUtils.copyBean(new ApiScenario(), apiScenario); ApiScenario copyApiScenario = BeanUtils.copyBean(new ApiScenario(), apiScenario);
copyApiScenario = BeanUtils.copyBean(copyApiScenario, request); copyApiScenario = BeanUtils.copyBean(copyApiScenario, request);
copyApiScenario.setStepTotal(apiScenario.getStepTotal());
Assertions.assertEquals(apiScenario, copyApiScenario); Assertions.assertEquals(apiScenario, copyApiScenario);
if (scenarioConfig != null) { if (scenarioConfig != null) {
Assertions.assertEquals(scenarioConfig, JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class)); Assertions.assertEquals(scenarioConfig, JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class));

View File

@ -23,7 +23,9 @@ import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentExample; import io.metersphere.sdk.domain.EnvironmentExample;
import io.metersphere.sdk.domain.EnvironmentGroup;
import io.metersphere.sdk.domain.ShareInfo; import io.metersphere.sdk.domain.ShareInfo;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.mapper.ShareInfoMapper; import io.metersphere.sdk.mapper.ShareInfoMapper;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -72,6 +74,8 @@ public class ApiScenarioReportControllerTests extends BaseTest {
private TestResourcePoolMapper testResourcePoolMapper; private TestResourcePoolMapper testResourcePoolMapper;
@Resource @Resource
private EnvironmentMapper environmentMapper; private EnvironmentMapper environmentMapper;
@Resource
private EnvironmentGroupMapper environmentGroupMapper;
private static final String BASIC = "/api/report/scenario"; private static final String BASIC = "/api/report/scenario";
private static final String PAGE = BASIC + "/page"; private static final String PAGE = BASIC + "/page";
@ -290,14 +294,14 @@ public class ApiScenarioReportControllerTests extends BaseTest {
List<ApiScenarioReportDetail> details = new ArrayList<>(); List<ApiScenarioReportDetail> details = new ArrayList<>();
for (int i = 1; i < 20; i++) { for (int i = 1; i < 20; i++) {
ApiScenarioReportDetail apiReportDetail = new ApiScenarioReportDetail(); ApiScenarioReportDetail apiReportDetail = new ApiScenarioReportDetail();
apiReportDetail.setId("test-report-detail-id" + i+2); apiReportDetail.setId("test-report-detail-id" + i + 2);
apiReportDetail.setReportId("test-scenario-report-id"); apiReportDetail.setReportId("test-scenario-report-id");
apiReportDetail.setStepId("test-scenario-report-step-id" + i); apiReportDetail.setStepId("test-scenario-report-step-id" + i);
if (i % 2 == 0) { if (i % 2 == 0) {
apiReportDetail.setStatus(ApiReportStatus.SUCCESS.name()); apiReportDetail.setStatus(ApiReportStatus.SUCCESS.name());
apiReportDetail.setResponseSize(1L); apiReportDetail.setResponseSize(1L);
apiReportDetail.setRequestTime(2L); apiReportDetail.setRequestTime(2L);
} else if (i % 3 == 0){ } else if (i % 3 == 0) {
apiReportDetail.setStatus(null); apiReportDetail.setStatus(null);
apiReportDetail.setResponseSize(0L); apiReportDetail.setResponseSize(0L);
apiReportDetail.setRequestTime(2L); apiReportDetail.setRequestTime(2L);
@ -336,6 +340,22 @@ public class ApiScenarioReportControllerTests extends BaseTest {
apiScenarioReportMapper.updateByPrimaryKeySelective(scenarioReport1); apiScenarioReportMapper.updateByPrimaryKeySelective(scenarioReport1);
this.requestGetWithOk(GET + "test-scenario-report-id"); this.requestGetWithOk(GET + "test-scenario-report-id");
//插入一个环境组
EnvironmentGroup environmentGroup = new EnvironmentGroup();
environmentGroup.setId("env_group_id");
environmentGroup.setProjectId(DEFAULT_PROJECT_ID);
environmentGroup.setName("env_group_name");
environmentGroup.setCreateUser("admin");
environmentGroup.setUpdateUser("admin");
environmentGroup.setUpdateTime(System.currentTimeMillis());
environmentGroup.setCreateTime(System.currentTimeMillis());
environmentGroup.setPos(1L);
environmentGroupMapper.insert(environmentGroup);
scenarioReport1.setEnvironmentId("env_group_id");
apiScenarioReportMapper.updateByPrimaryKeySelective(scenarioReport1);
this.requestGetWithOk(GET + "test-scenario-report-id");
environmentGroupMapper.deleteByPrimaryKey("env_group_id");
mockMvc.perform(getRequestBuilder(GET + "test")) mockMvc.perform(getRequestBuilder(GET + "test"))
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError()); .andExpect(status().is5xxServerError());
@ -396,7 +416,7 @@ public class ApiScenarioReportControllerTests extends BaseTest {
Assertions.assertNotNull(shareInfoDTO.getShareUrl()); Assertions.assertNotNull(shareInfoDTO.getShareUrl());
Assertions.assertNotNull(shareInfoDTO.getId()); Assertions.assertNotNull(shareInfoDTO.getId());
String shareId = shareInfoDTO.getId(); String shareId = shareInfoDTO.getId();
MvcResult mvcResult1 = this.requestGetWithOk(BASIC+ "/share/" + shareId + "/" + "test-scenario-report-id") MvcResult mvcResult1 = this.requestGetWithOk(BASIC + "/share/" + shareId + "/" + "test-scenario-report-id")
.andReturn(); .andReturn();
ApiScenarioReportDTO apiReportDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult1).get("data")), ApiScenarioReportDTO.class); ApiScenarioReportDTO apiReportDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult1).get("data")), ApiScenarioReportDTO.class);
Assertions.assertNotNull(apiReportDTO); Assertions.assertNotNull(apiReportDTO);
@ -409,7 +429,7 @@ public class ApiScenarioReportControllerTests extends BaseTest {
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError()); .andExpect(status().is5xxServerError());
mvcResult = this.requestGetWithOk(BASIC+ "/share/detail/" + shareId + "/" + "test-scenario-report-id" + "/" + "test-scenario-report-step-id1") mvcResult = this.requestGetWithOk(BASIC + "/share/detail/" + shareId + "/" + "test-scenario-report-id" + "/" + "test-scenario-report-step-id1")
.andReturn(); .andReturn();
List<ApiScenarioReportDetailDTO> data = ApiDataUtils.parseArray(JSON.toJSONString(parseResponse(mvcResult).get("data")), ApiScenarioReportDetailDTO.class); List<ApiScenarioReportDetailDTO> data = ApiDataUtils.parseArray(JSON.toJSONString(parseResponse(mvcResult).get("data")), ApiScenarioReportDetailDTO.class);
Assertions.assertNotNull(data); Assertions.assertNotNull(data);
@ -418,10 +438,10 @@ public class ApiScenarioReportControllerTests extends BaseTest {
shareInfo1.setUpdateTime(1702950953000L); shareInfo1.setUpdateTime(1702950953000L);
shareInfoMapper.updateByPrimaryKey(shareInfo1); shareInfoMapper.updateByPrimaryKey(shareInfo1);
mockMvc.perform(getRequestBuilder(BASIC+ "/share/" + shareId + "/" + "test-scenario-report-id")) mockMvc.perform(getRequestBuilder(BASIC + "/share/" + shareId + "/" + "test-scenario-report-id"))
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError()); .andExpect(status().is5xxServerError());
shareInfo = new ApiReportShareRequest(); shareInfo = new ApiReportShareRequest();
shareInfo.setReportId("test-scenario-report-id"); shareInfo.setReportId("test-scenario-report-id");
@ -445,7 +465,7 @@ public class ApiScenarioReportControllerTests extends BaseTest {
projectApplicationMapper.insert(projectApplication); projectApplicationMapper.insert(projectApplication);
} }
mvcResult1 = this.requestGetWithOk(BASIC+ "/share/" + shareId + "/" + "test-scenario-report-id") mvcResult1 = this.requestGetWithOk(BASIC + "/share/" + shareId + "/" + "test-scenario-report-id")
.andReturn(); .andReturn();
apiReportDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult1).get("data")), ApiScenarioReportDTO.class); apiReportDTO = ApiDataUtils.parseObject(JSON.toJSONString(parseResponse(mvcResult1).get("data")), ApiScenarioReportDTO.class);
Assertions.assertNotNull(apiReportDTO); Assertions.assertNotNull(apiReportDTO);
@ -456,7 +476,7 @@ public class ApiScenarioReportControllerTests extends BaseTest {
shareInfo1.setUpdateTime(1702950953000L); shareInfo1.setUpdateTime(1702950953000L);
shareInfoMapper.updateByPrimaryKey(shareInfo1); shareInfoMapper.updateByPrimaryKey(shareInfo1);
mockMvc.perform(getRequestBuilder(BASIC+ "/share/" + shareId + "/" + "test-scenario-report-id")) mockMvc.perform(getRequestBuilder(BASIC + "/share/" + shareId + "/" + "test-scenario-report-id"))
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError()); .andExpect(status().is5xxServerError());
} }

View File

@ -202,7 +202,7 @@ public class ApiTaskCenterControllerTests extends BaseTest {
@Order(12) @Order(12)
public void stopById() throws Exception { public void stopById() throws Exception {
mockPost("/api/stop", ""); mockPost("/api/stop", "");
mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/project/stop/task-report-id0") mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/project/stop/API_CASE/task-report-id0")
.header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken) .header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID) .header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID)
@ -210,14 +210,14 @@ public class ApiTaskCenterControllerTests extends BaseTest {
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
mockPost("/api/stop", ""); mockPost("/api/stop", "");
mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/org/stop/task-report-id0") mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/org/stop/API_SCENARIO/task-report-id0")
.header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken) .header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID) .header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID)
.header(SessionConstants.CURRENT_ORGANIZATION, DEFAULT_ORGANIZATION_ID)) .header(SessionConstants.CURRENT_ORGANIZATION, DEFAULT_ORGANIZATION_ID))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/system/stop/task-report-id0") mockMvc.perform(MockMvcRequestBuilders.get("/task/center/api/system/stop/API_SCENARIO/task-report-id0")
.header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken) .header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID) .header(SessionConstants.CURRENT_PROJECT, DEFAULT_PROJECT_ID)

View File

@ -43,14 +43,14 @@ export function batchStopRealProjectApi(data: TableQueryParams) {
return MSR.post<CommonList<RealTaskCenterApiCaseItem>>({ url: batchStopRealProjectApiUrl, data }); return MSR.post<CommonList<RealTaskCenterApiCaseItem>>({ url: batchStopRealProjectApiUrl, data });
} }
export function stopRealSysApi(id: string) { export function stopRealSysApi(moduleType: string, id: string) {
return MSR.get({ url: `${stopRealSysApiUrl}/${id}` }); return MSR.get({ url: `${stopRealSysApiUrl}/${moduleType}/${id}` });
} }
export function stopRealOrdApi(id: string) { export function stopRealOrdApi(moduleType: string, id: string) {
return MSR.get({ url: `${stopRealOrdApiUrl}/${id}` }); return MSR.get({ url: `${stopRealOrdApiUrl}/${moduleType}/${id}` });
} }
export function stopRealProjectApi(id: string) { export function stopRealProjectApi(moduleType: string, id: string) {
return MSR.get({ url: `${stopRealProjectApiUrl}/${id}` }); return MSR.get({ url: `${stopRealProjectApiUrl}/${moduleType}/${id}` });
} }
// 定时任务 // 定时任务

View File

@ -67,6 +67,7 @@
:label="t('case.execute.reportName')" :label="t('case.execute.reportName')"
:rules="[{ required: true, message: t('apiTestManagement.reportNameRequired') }]" :rules="[{ required: true, message: t('apiTestManagement.reportNameRequired') }]"
:validate-trigger="['blur', 'input']" :validate-trigger="['blur', 'input']"
asterisk-position="end"
> >
<a-input <a-input
v-model="batchExecuteForm.integratedReportName" v-model="batchExecuteForm.integratedReportName"
@ -77,6 +78,7 @@
<a-form-item <a-form-item
field="poolId" field="poolId"
:label="t('case.execute.pool')" :label="t('case.execute.pool')"
asterisk-position="end"
:rules="[{ required: true, message: t('apiTestManagement.poolRequired') }]" :rules="[{ required: true, message: t('apiTestManagement.poolRequired') }]"
> >
<a-select v-model="batchExecuteForm.poolId" :placeholder="t('common.pleaseSelect')"> <a-select v-model="batchExecuteForm.poolId" :placeholder="t('common.pleaseSelect')">

View File

@ -88,25 +88,25 @@
<div class="countItem"> <div class="countItem">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--success-6))]"></div> <div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--success-6))]"></div>
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.successCount') }}</div> <div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.successCount') }}</div>
{{ getIndicators(detail.successCount) }} {{ getIndicators(detail.stepSuccessCount) }}
</div> </div>
<!-- 误报 --> <!-- 误报 -->
<div class="countItem"> <div class="countItem">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--warning-6))]"></div> <div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--warning-6))]"></div>
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.fakeErrorCount') }}</div> <div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.fakeErrorCount') }}</div>
{{ getIndicators(detail.fakeErrorCount) }} {{ getIndicators(detail.stepFakeErrorCount) }}
</div> </div>
<!-- 失败 --> <!-- 失败 -->
<div class="countItem"> <div class="countItem">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--danger-6))]"></div> <div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--danger-6))]"></div>
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.errorCount') }}</div> <div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.errorCount') }}</div>
{{ getIndicators(detail.errorCount) }} {{ getIndicators(detail.stepErrorCount) }}
</div> </div>
<!-- 未执行 --> <!-- 未执行 -->
<div class="countItem"> <div class="countItem">
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[var(--color-text-input-border)]"></div> <div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[var(--color-text-input-border)]"></div>
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.pendingCount') }}</div> <div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.pendingCount') }}</div>
{{ getIndicators(detail.pendingCount) }} {{ getIndicators(detail.stepPendingCount) }}
</div> </div>
</div> </div>
<StepProgress :report-detail="detail" height="8px" radius="var(--border-radius-mini)" /> <StepProgress :report-detail="detail" height="8px" radius="var(--border-radius-mini)" />
@ -254,6 +254,10 @@
children: [], // children: [], //
stepTotal: 0, // stepTotal: 0, //
console: '', console: '',
stepSuccessCount: 0, //
stepErrorCount: 0, //
stepFakeErrorCount: 0, //
stepPendingCount: 0, //
}); });
const cascaderKeywords = ref<string>(''); const cascaderKeywords = ref<string>('');

View File

@ -293,6 +293,7 @@
await loadRealMap.value[props.group].batchStop({ await loadRealMap.value[props.group].batchStop({
selectIds: selectAll ? [] : selectIds, selectIds: selectAll ? [] : selectIds,
selectAll, selectAll,
moduleType: props.moduleType,
}); });
resetSelector(); resetSelector();
Message.success(t('project.taskCenter.stopSuccess')); Message.success(t('project.taskCenter.stopSuccess'));
@ -330,7 +331,7 @@
}, },
onBeforeOk: async () => { onBeforeOk: async () => {
try { try {
await loadRealMap.value[props.group].stop(record.id); await loadRealMap.value[props.group].stop(props.moduleType, record.id);
resetSelector(); resetSelector();
Message.success(t('project.taskCenter.stopSuccess')); Message.success(t('project.taskCenter.stopSuccess'));
initData(); initData();

View File

@ -18,7 +18,8 @@ export default {
'project.taskCenter.viewReport': 'View report', 'project.taskCenter.viewReport': 'View report',
'project.taskCenter.batchStopTask': 'Are you sure to stop {num} tasks?', 'project.taskCenter.batchStopTask': 'Are you sure to stop {num} tasks?',
'project.taskCenter.stopTask': 'Are you sure to stop {name} task?', 'project.taskCenter.stopTask': 'Are you sure to stop {name} task?',
'project.taskCenter.stopTaskContent': 'After stopping,{name} please operate with caution?', 'project.taskCenter.stopTaskContent':
'Stopping will affect report generation, and the completed report cannot be stopped.',
'project.taskCenter.confirmStop': 'Confirm stop', 'project.taskCenter.confirmStop': 'Confirm stop',
'project.taskCenter.stopSuccess': 'Stop successfully', 'project.taskCenter.stopSuccess': 'Stop successfully',
'project.taskCenter.testResource': 'Test resource', 'project.taskCenter.testResource': 'Test resource',

View File

@ -18,7 +18,7 @@ export default {
'project.taskCenter.viewReport': '查看报告', 'project.taskCenter.viewReport': '查看报告',
'project.taskCenter.batchStopTask': '确定停止 {num} 个任务吗?', 'project.taskCenter.batchStopTask': '确定停止 {num} 个任务吗?',
'project.taskCenter.stopTask': '确定停止 {name} 个任务吗?', 'project.taskCenter.stopTask': '确定停止 {name} 个任务吗?',
'project.taskCenter.stopTaskContent': '停止后,{ name }请谨慎操作?', 'project.taskCenter.stopTaskContent': '停止后会影响报告的生成,执行完成的报告不可以停止',
'project.taskCenter.confirmStop': '确认停止', 'project.taskCenter.confirmStop': '确认停止',
'project.taskCenter.stopSuccess': '停止成功', 'project.taskCenter.stopSuccess': '停止成功',
'project.taskCenter.testResource': '测试资源', 'project.taskCenter.testResource': '测试资源',