feat(接口测试): 测试报告增加展示运行环境信息

--story=1006994 --user=宋天阳 【通用功能】测试报告增加展示运行环境信息
https://www.tapd.cn/55049933/s/1198098
This commit is contained in:
song-tianyang 2022-05-23 09:00:38 +08:00 committed by TIanyang
parent 736657536f
commit e391fd2f90
42 changed files with 1903 additions and 1162 deletions

View File

@ -5,7 +5,6 @@ import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Setter
@Getter

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto;
import lombok.Data;
import java.util.LinkedHashMap;
import java.util.List;
@Data
@ -37,4 +38,7 @@ public class ApiScenarioReportDTO {
private String name;
private String envConfig;
//<项目名称<环境名称>>
private LinkedHashMap<String, List<String>> projectEnvMap;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.api.dto;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class RunModeConfigWithEnvironmentDTO extends RunModeConfigDTO {
// 接口/用例在运行时采用的环境信息 <项目ID , <环境ID>>
private Map<String, List<String>> executionEnvironmentMap;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.api.exec.api;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.RunModeConfigWithEnvironmentDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.scenario.DatabaseConfig;
@ -25,6 +26,7 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTypeConstants;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.constants.RunModeConstants;
@ -112,7 +114,18 @@ public class ApiCaseExecuteService {
if (!request.isRerun()) {
Map<String, String> planProjects = new HashMap<>();
for (TestPlanApiCase testPlanApiCase : planApiCases) {
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status, caseMap, resourcePoolId);
//处理环境配置为空时的情况
RunModeConfigDTO runModeConfigDTO = new RunModeConfigDTO();
BeanUtils.copyBean(runModeConfigDTO, request.getConfig());
if (MapUtils.isEmpty(runModeConfigDTO.getEnvMap())) {
ApiTestCase testCase = caseMap.get(testPlanApiCase.getApiCaseId());
if (testCase != null) {
runModeConfigDTO.setEnvMap(new HashMap<>() {{
this.put(testCase.getProjectId(), testPlanApiCase.getEnvironmentId());
}});
}
}
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.addResult(request, runModeConfigDTO, testPlanApiCase, status, caseMap, resourcePoolId);
if (planProjects.containsKey(testPlanApiCase.getTestPlanId())) {
report.setProjectId(planProjects.get(testPlanApiCase.getTestPlanId()));
} else {
@ -153,7 +166,8 @@ public class ApiCaseExecuteService {
return responseDTOS;
}
public void checkEnv(List<ApiTestCaseWithBLOBs> caseList) {
public Map<String, List<String>> checkEnv(List<ApiTestCaseWithBLOBs> caseList) {
Map<String, List<String>> projectEnvMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(caseList)) {
StringBuilder builderHttp = new StringBuilder();
StringBuilder builderTcp = new StringBuilder();
@ -163,6 +177,18 @@ public class ApiCaseExecuteService {
if (apiCaseNew.has("type") && "HTTPSamplerProxy".equals(apiCaseNew.getString("type"))) {
if (!apiCaseNew.has("useEnvironment") || StringUtils.isEmpty(apiCaseNew.getString("useEnvironment"))) {
builderHttp.append(apiCase.getName()).append("; ");
} else {
//记录运行环境ID
String envId = apiCaseNew.getString("useEnvironment");
if (projectEnvMap.containsKey(apiCase.getProjectId())) {
if (!projectEnvMap.get(apiCase.getProjectId()).contains(envId)) {
projectEnvMap.get(apiCase.getProjectId()).add(envId);
}
} else {
projectEnvMap.put(apiCase.getProjectId(), new ArrayList<>() {{
this.add(envId);
}});
}
}
}
if (apiCaseNew.has("type") && "JDBCSampler".equals(apiCaseNew.getString("type"))) {
@ -179,6 +205,16 @@ public class ApiCaseExecuteService {
for (DatabaseConfig item : envConfig.getDatabaseConfigs()) {
if (item.getId().equals(dataSourceId)) {
dataSource = item;
//记录运行环境ID
if (projectEnvMap.containsKey(apiCase.getProjectId())) {
if (!projectEnvMap.get(apiCase.getProjectId()).contains(environmentId)) {
projectEnvMap.get(apiCase.getProjectId()).add(environmentId);
}
} else {
projectEnvMap.put(apiCase.getProjectId(), new ArrayList<>() {{
this.add(environmentId);
}});
}
}
}
}
@ -196,6 +232,7 @@ public class ApiCaseExecuteService {
MSException.throwException("用例:" + builderTcp + "数据源为空!请检查");
}
}
return projectEnvMap;
}
/**
@ -225,16 +262,25 @@ public class ApiCaseExecuteService {
example.createCriteria().andIdIn(request.getIds()).andStatusNotEqualTo("Trash");
List<ApiTestCaseWithBLOBs> caseList = apiTestCaseMapper.selectByExampleWithBLOBs(example);
LoggerUtil.debug("查询到执行数据:" + caseList.size());
Map<String, List<String>> testCaseEnvMap = new HashMap<>();
// 环境检查
if (MapUtils.isEmpty(request.getConfig().getEnvMap())) {
this.checkEnv(caseList);
testCaseEnvMap = this.checkEnv(caseList);
}
// 集合报告设置
String serialReportId = request.isRerun() ? request.getReportId() : null;
if (!request.isRerun() && StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
&& StringUtils.isNotEmpty(request.getConfig().getReportName())) {
serialReportId = UUID.randomUUID().toString();
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.initBase(null, APITestStatus.Running.name(), serialReportId, request.getConfig());
RunModeConfigDTO config = request.getConfig();
if (MapUtils.isEmpty(config.getEnvMap())) {
RunModeConfigWithEnvironmentDTO runModeConfig = new RunModeConfigWithEnvironmentDTO();
BeanUtils.copyBean(runModeConfig, request.getConfig());
this.setExecutionEnvironmen(runModeConfig, testCaseEnvMap);
config = runModeConfig;
}
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.initBase(null, APITestStatus.Running.name(), serialReportId, config);
report.setName(request.getConfig().getReportName());
report.setProjectId(request.getProjectId());
report.setReportType(ReportTypeConstants.API_INTEGRATED.name());
@ -313,4 +359,28 @@ public class ApiCaseExecuteService {
}
return responseDTOS;
}
public void setExecutionEnvironmen(RunModeConfigWithEnvironmentDTO config, Map<String, List<String>> projectEnvMap) {
if (MapUtils.isNotEmpty(projectEnvMap) && config != null) {
config.setExecutionEnvironmentMap(projectEnvMap);
}
}
public void setRunModeConfigEnvironment(RunModeConfigWithEnvironmentDTO config, Map<String, String> projectEnvMap) {
if (MapUtils.isNotEmpty(projectEnvMap) && config != null) {
Map<String, List<String>> executionEnvMap = new HashMap<>();
for (Map.Entry<String, String> entry : projectEnvMap.entrySet()) {
String projectId = entry.getKey();
String envId = entry.getValue();
if (StringUtils.isNoneEmpty(projectId, envId)) {
executionEnvMap.put(projectId, new ArrayList<>() {{
this.add(envId);
}});
}
}
if (MapUtils.isNotEmpty(executionEnvMap)) {
config.setExecutionEnvironmentMap(executionEnvMap);
}
}
}
}

View File

@ -29,10 +29,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
@Service
@ -277,7 +274,15 @@ public class ApiScenarioEnvService {
}
}
public void checkEnv(RunScenarioRequest request, List<ApiScenarioWithBLOBs> apiScenarios) {
/**
* 检查是否存在运行环境若不存在则报错存在的话返回所存在的运行环境
*
* @param request
* @param apiScenarios
* @return <projectId,envIds>
*/
public Map<String, List<String>> checkEnv(RunScenarioRequest request, List<ApiScenarioWithBLOBs> apiScenarios) {
Map<String, List<String>> projectEnvMap = new HashMap<>();
if (StringUtils.equals(request.getRequestOriginator(), "TEST_PLAN")) {
this.checkPlanScenarioEnv(request);
} else if (StringUtils.isNotBlank(request.getRunMode()) &&
@ -306,6 +311,55 @@ public class ApiScenarioEnvService {
}
}
}
return projectEnvMap;
}
public Map<String, List<String>> selectApiScenarioEnv(List<ApiScenarioWithBLOBs> list) {
Map<String, List<String>> projectEnvMap = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
try {
Map<String, String> map = new HashMap<>();
String environmentType = list.get(i).getEnvironmentType();
String environmentGroupId = list.get(i).getEnvironmentGroupId();
String env = list.get(i).getEnvironmentJson();
if (StringUtils.equals(environmentType, EnvironmentType.JSON.name())) {
// 环境属性为空 跳过
if (StringUtils.isBlank(env)) {
continue;
}
map = JSON.parseObject(env, Map.class);
} else if (StringUtils.equals(environmentType, EnvironmentType.GROUP.name())) {
map = environmentGroupProjectService.getEnvMap(environmentGroupId);
}
Set<String> set = map.keySet();
HashMap<String, String> envMap = new HashMap<>(16);
// 项目为空 跳过
if (set.isEmpty()) {
continue;
}
for (String projectId : set) {
String envId = map.get(projectId);
envMap.put(projectId, envId);
}
for (Map.Entry<String, String> entry : envMap.entrySet()) {
String projectId = entry.getKey();
String envId = entry.getValue();
if (projectEnvMap.containsKey(projectId)) {
if (!projectEnvMap.get(projectId).contains(envId)) {
projectEnvMap.get(projectId).add(envId);
}
} else {
projectEnvMap.put(projectId, new ArrayList<>() {{
this.add(envId);
}});
}
}
} catch (Exception e) {
LogUtil.error("api scenario environment map incorrect parsing. api scenario id:" + list.get(i).getId());
}
}
return projectEnvMap;
}
public void setApiScenarioEnv(List<ApiScenarioDTO> list) {

View File

@ -2,6 +2,7 @@ package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.RunModeConfigWithEnvironmentDTO;
import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
@ -9,6 +10,7 @@ import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.exec.api.ApiCaseExecuteService;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
@ -16,7 +18,10 @@ import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiScenarioReportStructureService;
import io.metersphere.api.service.TcpApiParamService;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ApiScenarioExample;
import io.metersphere.base.domain.ApiScenarioReportWithBLOBs;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
@ -26,10 +31,7 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ReportTypeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.commons.utils.*;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
@ -86,6 +88,8 @@ public class ApiScenarioExecuteService {
@Resource
private TcpApiParamService tcpApiParamService;
@Resource
private ApiCaseExecuteService apiCaseExecuteService;
@Resource
protected JMeterService jMeterService;
public List<MsExecResponseDTO> run(RunScenarioRequest request) {
@ -154,10 +158,18 @@ public class ApiScenarioExecuteService {
LoggerUtil.info("Scenario run-执行脚本装载-初始化集成报告:" + serialReportId);
request.getConfig().setReportId(UUID.randomUUID().toString());
String reportScenarioIds = generateScenarioIds(scenarioIds);
if (request.getConfig() == null) {
request.setConfig(new RunModeConfigWithEnvironmentDTO());
}
if (MapUtils.isEmpty(request.getConfig().getEnvMap())) {
RunModeConfigWithEnvironmentDTO runModeConfig = new RunModeConfigWithEnvironmentDTO();
BeanUtils.copyBean(runModeConfig, request.getConfig());
Map<String, List<String>> projectEnvMap = apiScenarioEnvService.selectApiScenarioEnv(apiScenarios);
apiCaseExecuteService.setExecutionEnvironmen(runModeConfig, projectEnvMap);
request.setConfig(runModeConfig);
}
APIScenarioReportResult report = getApiScenarioReportResult(request, serialReportId, scenarioNames, reportScenarioIds);
report.setVersionId(apiScenarios.get(0).getVersionId());
apiScenarioReportMapper.insert(report);
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(scenarioIds), serialReportId, request.getRunMode()));
@ -303,7 +315,12 @@ public class ApiScenarioExecuteService {
executeQueue.put(report.getId(), runModeDataDTO);
scenarioNames.append(scenario.getName()).append(",");
if (request.getConfig() != null) {
report.setEnvConfig(JSON.toJSONString(request.getConfig()));
RunModeConfigWithEnvironmentDTO runModeConfig = new RunModeConfigWithEnvironmentDTO();
BeanUtils.copyBean(runModeConfig, request.getConfig());
if (MapUtils.isEmpty(runModeConfig.getEnvMap())) {
apiCaseExecuteService.setRunModeConfigEnvironment(runModeConfig, planEnvMap);
}
report.setEnvConfig(JSON.toJSONString(runModeConfig));
}
// 生成文档结构
if (!StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
@ -385,6 +402,12 @@ public class ApiScenarioExecuteService {
MSException.throwException(e.getMessage());
}
if (request.isSaved()) {
//记录环境
RunModeConfigDTO runModeCconfig = request.getConfig();
if (runModeCconfig == null) {
runModeCconfig = new RunModeConfigDTO();
runModeCconfig.setEnvMap(map);
}
APIScenarioReportResult report = apiScenarioReportService.init(request.getId(),
request.getScenarioId(),
request.getScenarioName(),
@ -392,7 +415,7 @@ public class ApiScenarioExecuteService {
request.getExecuteType(),
request.getProjectId(),
SessionUtils.getUserId(),
request.getConfig());
runModeCconfig);
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(request.getScenarioId());
String reportType = request.getConfig() != null ? request.getConfig().getReportType() : null;
if (scenario != null) {

View File

@ -43,7 +43,7 @@ public class ApiDefinitionExecResultUtil {
return apiResult;
}
public static ApiDefinitionExecResultWithBLOBs addResult(BatchRunDefinitionRequest request, TestPlanApiCase key, String status,
public static ApiDefinitionExecResultWithBLOBs addResult(BatchRunDefinitionRequest request, RunModeConfigDTO runModeConfigDTO, TestPlanApiCase key, String status,
Map<String, ApiTestCase> caseMap, String poolId) {
ApiDefinitionExecResultWithBLOBs apiResult = new ApiDefinitionExecResultWithBLOBs();
apiResult.setId(UUID.randomUUID().toString());
@ -75,7 +75,7 @@ public class ApiDefinitionExecResultUtil {
apiResult.setType(ApiRunMode.API_PLAN.name());
apiResult.setStatus(status);
apiResult.setContent(request.getPlanReportId());
apiResult.setEnvConfig(JSON.toJSONString(request.getConfig()));
apiResult.setEnvConfig(JSON.toJSONString(runModeConfigDTO));
return apiResult;
}

View File

@ -42,6 +42,7 @@ import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.ProjectConfig;
import io.metersphere.dto.RelationshipEdgeDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.SwaggerUrlImportJob;
import io.metersphere.log.utils.ReflexObjectUtil;
@ -58,6 +59,7 @@ import io.metersphere.track.service.TestCaseService;
import io.metersphere.track.service.TestPlanService;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.comparators.FixedOrderComparator;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@ -152,6 +154,8 @@ public class ApiDefinitionService {
@Lazy
@Resource
private ApiModuleService apiModuleService;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -1225,6 +1229,13 @@ public class ApiDefinitionService {
result.setName(reportName);
result.setProjectId(request.getProjectId());
result.setTriggerMode(TriggerMode.MANUAL.name());
if (StringUtils.isNotEmpty(request.getEnvironmentId())) {
RunModeConfigDTO runModeConfigDTO = new RunModeConfigDTO();
runModeConfigDTO.setEnvMap(new HashMap<>() {{
this.put(request.getProjectId(), request.getEnvironmentId());
}});
result.setEnvConfig(JSONObject.toJSONString(runModeConfigDTO));
}
apiDefinitionExecResultMapper.insert(result);
}
if (request.isEditCaseRequest() && CollectionUtils.isNotEmpty(request.getTestElement().getHashTree()) &&
@ -1278,10 +1289,31 @@ public class ApiDefinitionService {
}
APIReportResult reportResult = new APIReportResult();
reportResult.setStatus(result.getStatus());
if (StringUtils.isNotEmpty(result.getEnvConfig())) {
JSONObject content = JSONObject.parseObject(result.getContent());
content.put("envName", this.getEnvNameByEnvConfig(result.getProjectId(), result.getEnvConfig()));
reportResult.setContent(content.toJSONString());
} else {
reportResult.setContent(result.getContent());
}
return reportResult;
}
public String getEnvNameByEnvConfig(String projectId, String envConfig) {
String envName = null;
RunModeConfigDTO runModeConfigDTO = null;
try {
runModeConfigDTO = JSONObject.parseObject(envConfig, RunModeConfigDTO.class);
} catch (Exception e) {
LogUtil.error("解析" + envConfig + "为RunModeConfigDTO时失败", e);
}
if (StringUtils.isNotEmpty(projectId) && runModeConfigDTO != null && MapUtils.isNotEmpty(runModeConfigDTO.getEnvMap())) {
String envId = runModeConfigDTO.getEnvMap().get(projectId);
envName = apiTestEnvironmentService.selectNameById(envId);
}
return envName;
}
public APIReportResult getDbResult(String testId, String type) {
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(testId, type);
return buildAPIReportResult(result);

View File

@ -155,13 +155,14 @@ public class ApiScenarioReportService {
* @return
*/
public APIScenarioReportResult getApiIntegrated(String reportId) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportId);
ApiDefinitionExecResultWithBLOBs result = definitionExecResultMapper.selectByPrimaryKey(reportId);
if (result != null) {
APIScenarioReportResult reportResult = new APIScenarioReportResult();
BeanUtils.copyBean(reportResult, result);
reportResult.setReportVersion(2);
reportResult.setTestId(reportId);
ApiScenarioReportDTO dto = apiScenarioReportStructureService.apiIntegratedReport(reportId);
apiScenarioReportStructureService.initProjectEnvironmentByEnvConfig(dto, result.getEnvConfig());
reportResult.setContent(JSON.toJSONString(dto));
return reportResult;
}

View File

@ -4,10 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiScenarioReportBaseInfoDTO;
import io.metersphere.api.dto.ApiScenarioReportDTO;
import io.metersphere.api.dto.RequestResultExpandDTO;
import io.metersphere.api.dto.StepTreeDTO;
import io.metersphere.api.dto.*;
import io.metersphere.api.exec.utils.ResultParseUtil;
import io.metersphere.api.service.vo.ApiDefinitionExecResultVo;
import io.metersphere.base.domain.*;
@ -22,10 +19,14 @@ import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.service.ProjectService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -50,6 +51,11 @@ public class ApiScenarioReportStructureService {
private ApiDefinitionExecResultMapper definitionExecResultMapper;
@Resource
private ExtApiScenarioReportResultMapper extApiScenarioReportResultMapper;
@Lazy
@Resource
private ProjectService projectService;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
private static final List<String> requests = Arrays.asList("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor", "AbstractSampler");
private static final List<String> controls = Arrays.asList("Assertions", "IfController", "ConstantTimer");
@ -524,10 +530,73 @@ public class ApiScenarioReportStructureService {
dto.setActuator(report.getActuator());
dto.setName(report.getName());
dto.setEnvConfig(report.getEnvConfig());
this.initProjectEnvironmentByEnvConfig(dto, report.getEnvConfig());
return dto;
}
}
public void initProjectEnvironmentByEnvConfig(ApiScenarioReportDTO dto, String envConfig) {
if (StringUtils.isNotEmpty(envConfig)) {
//运行设置中选择的环境信息批量执行时在前台选择了执行信息
Map<String, String> envMapByRunConfig = null;
//执行时选择的环境信息 一般在集合报告中会记录
Map<String, List<String>> envMapByExecution = null;
try {
JSONObject jsonObject = JSONObject.parseObject(envConfig);
if (jsonObject.containsKey("executionEnvironmentMap")) {
RunModeConfigWithEnvironmentDTO configWithEnvironment = JSONObject.parseObject(envConfig, RunModeConfigWithEnvironmentDTO.class);
if (MapUtils.isNotEmpty(configWithEnvironment.getExecutionEnvironmentMap())) {
envMapByExecution = configWithEnvironment.getExecutionEnvironmentMap();
} else {
envMapByRunConfig = configWithEnvironment.getEnvMap();
}
} else {
RunModeConfigDTO config = JSONObject.parseObject(envConfig, RunModeConfigDTO.class);
envMapByRunConfig = config.getEnvMap();
}
} catch (Exception e) {
LogUtil.error("解析RunModeConfig失败!参数:" + envConfig, e);
}
LinkedHashMap<String, List<String>> projectEnvMap = new LinkedHashMap<>();
if (MapUtils.isNotEmpty(envMapByExecution)) {
for (Map.Entry<String, List<String>> entry : envMapByExecution.entrySet()) {
String projectId = entry.getKey();
List<String> envIdList = entry.getValue();
String projectName = projectService.selectNameById(projectId);
List<String> envNameList = apiTestEnvironmentService.selectNameByIds(envIdList);
if (CollectionUtils.isNotEmpty(envNameList) && StringUtils.isNotEmpty(projectName)) {
projectEnvMap.put(projectName, new ArrayList<>() {{
this.addAll(envNameList);
}});
}
}
if (MapUtils.isNotEmpty(projectEnvMap)) {
dto.setProjectEnvMap(projectEnvMap);
}
}
if (MapUtils.isNotEmpty(envMapByRunConfig)) {
for (Map.Entry<String, String> entry : envMapByRunConfig.entrySet()) {
String projectId = entry.getKey();
String envId = entry.getValue();
String projectName = projectService.selectNameById(projectId);
String envName = apiTestEnvironmentService.selectNameById(envId);
if (StringUtils.isNoneEmpty(projectName, envName)) {
projectEnvMap.put(projectName, new ArrayList<>() {{
this.add(envName);
}});
}
}
if (MapUtils.isNotEmpty(projectEnvMap)) {
dto.setProjectEnvMap(projectEnvMap);
}
}
}
}
private ApiScenarioReportDTO getReport(String reportId, boolean selectContent) {
List<ApiScenarioReportResultWithBLOBs> reportResults = null;
if (selectContent) {

View File

@ -10,6 +10,7 @@ import io.metersphere.base.domain.ApiTestEnvironmentExample;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.base.domain.Project;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.ext.ExtApiTestEnvironmentMapper;
import io.metersphere.commons.constants.ProjectApplicationType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
@ -47,6 +48,8 @@ public class ApiTestEnvironmentService {
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private ProjectApplicationService projectApplicationService;
@Resource
private ExtApiTestEnvironmentMapper extApiTestEnvironmentMapper;
public List<ApiTestEnvironmentWithBLOBs> list(String projectId) {
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
@ -119,6 +122,7 @@ public class ApiTestEnvironmentService {
}
request.setConfig(configObj.toJSONString());
} catch (Exception e) {
LogUtil.error("设置是否为mock环境出错!参数:" + request.getConfig(), e);
}
}
return request;
@ -130,6 +134,7 @@ public class ApiTestEnvironmentService {
apiTestEnvironment.setUpdateTime(System.currentTimeMillis());
apiTestEnvironmentMapper.updateByPrimaryKeyWithBLOBs(apiTestEnvironment);
}
private void checkEnvironmentExist(ApiTestEnvironmentWithBLOBs environment) {
if (environment.getName() != null) {
if (StringUtils.isEmpty(environment.getProjectId())) {
@ -460,4 +465,16 @@ public class ApiTestEnvironmentService {
}
return returnStr;
}
public List<String> selectNameByIds(Collection<String> envIds) {
if (CollectionUtils.isNotEmpty(envIds)) {
return extApiTestEnvironmentMapper.selectNameByIds(envIds);
} else {
return new ArrayList<>(0);
}
}
public String selectNameById(String id) {
return extApiTestEnvironmentMapper.selectNameById(id);
}
}

View File

@ -37,5 +37,7 @@ public class TestPlanReport implements Serializable {
private Boolean isNew;
private String runInfo;
private static final long serialVersionUID = 1L;
}

View File

@ -51,5 +51,7 @@ public class TestPlanReportContentWithBLOBs extends TestPlanReportContent implem
private String unExecuteScenarios;
private String apiBaseCount;
private static final long serialVersionUID = 1L;
}

View File

@ -33,6 +33,7 @@
<result column="error_report_scenarios" jdbcType="LONGVARCHAR" property="errorReportScenarios" />
<result column="un_execute_cases" jdbcType="LONGVARCHAR" property="unExecuteCases" />
<result column="un_execute_scenarios" jdbcType="LONGVARCHAR" property="unExecuteScenarios" />
<result column="api_base_count" jdbcType="LONGVARCHAR" property="apiBaseCount" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -101,7 +102,7 @@
issue_list, api_all_cases, api_failure_cases, scenario_all_cases, scenario_failure_cases,
load_all_Cases, load_failure_cases, plan_scenario_report_struct, plan_api_case_report_struct,
plan_load_case_report_struct, error_report_cases, error_report_scenarios, un_execute_cases,
un_execute_scenarios
un_execute_scenarios, api_base_count
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanReportContentExample" resultMap="ResultMapWithBLOBs">
select
@ -163,7 +164,8 @@
plan_scenario_report_struct, plan_api_case_report_struct,
plan_load_case_report_struct, error_report_cases,
error_report_scenarios, un_execute_cases,
un_execute_scenarios)
un_execute_scenarios, api_base_count
)
values (#{id,jdbcType=VARCHAR}, #{testPlanReportId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT},
#{caseCount,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT}, #{executeRate,jdbcType=DOUBLE},
#{passRate,jdbcType=DOUBLE}, #{isThirdPartIssue,jdbcType=BIT}, #{config,jdbcType=LONGVARCHAR},
@ -175,7 +177,8 @@
#{planScenarioReportStruct,jdbcType=LONGVARCHAR}, #{planApiCaseReportStruct,jdbcType=LONGVARCHAR},
#{planLoadCaseReportStruct,jdbcType=LONGVARCHAR}, #{errorReportCases,jdbcType=LONGVARCHAR},
#{errorReportScenarios,jdbcType=LONGVARCHAR}, #{unExecuteCases,jdbcType=LONGVARCHAR},
#{unExecuteScenarios,jdbcType=LONGVARCHAR})
#{unExecuteScenarios,jdbcType=LONGVARCHAR}, #{apiBaseCount,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanReportContentWithBLOBs">
insert into test_plan_report_content
@ -267,6 +270,9 @@
<if test="unExecuteScenarios != null">
un_execute_scenarios,
</if>
<if test="apiBaseCount != null">
api_base_count,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -356,6 +362,9 @@
<if test="unExecuteScenarios != null">
#{unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="apiBaseCount != null">
#{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanReportContentExample" resultType="java.lang.Long">
@ -454,6 +463,9 @@
<if test="record.unExecuteScenarios != null">
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="record.apiBaseCount != null">
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -489,7 +501,8 @@
error_report_cases = #{record.errorReportCases,jdbcType=LONGVARCHAR},
error_report_scenarios = #{record.errorReportScenarios,jdbcType=LONGVARCHAR},
un_execute_cases = #{record.unExecuteCases,jdbcType=LONGVARCHAR},
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR}
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR},
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -595,6 +608,9 @@
<if test="unExecuteScenarios != null">
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="apiBaseCount != null">
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -627,7 +643,8 @@
error_report_cases = #{errorReportCases,jdbcType=LONGVARCHAR},
error_report_scenarios = #{errorReportScenarios,jdbcType=LONGVARCHAR},
un_execute_cases = #{unExecuteCases,jdbcType=LONGVARCHAR},
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR}
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR},
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanReportContent">

View File

@ -1,13 +1,8 @@
package io.metersphere.base.mapper;
import io.metersphere.api.dto.definition.ParamsDTO;
import io.metersphere.base.domain.TestPlanReport;
import io.metersphere.base.domain.TestPlanReportExample;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
public interface TestPlanReportMapper {
@ -21,15 +16,21 @@ public interface TestPlanReportMapper {
int insertSelective(TestPlanReport record);
List<TestPlanReport> selectByExampleWithBLOBs(TestPlanReportExample example);
List<TestPlanReport> selectByExample(TestPlanReportExample example);
TestPlanReport selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestPlanReport record, @Param("example") TestPlanReportExample example);
int updateByExampleWithBLOBs(@Param("record") TestPlanReport record, @Param("example") TestPlanReportExample example);
int updateByExample(@Param("record") TestPlanReport record, @Param("example") TestPlanReportExample example);
int updateByPrimaryKeySelective(TestPlanReport record);
int updateByPrimaryKeyWithBLOBs(TestPlanReport record);
int updateByPrimaryKey(TestPlanReport record);
}

View File

@ -19,6 +19,9 @@
<result column="components" jdbcType="VARCHAR" property="components" />
<result column="is_new" jdbcType="BIT" property="isNew" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanReport">
<result column="run_info" jdbcType="LONGVARCHAR" property="runInfo" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
@ -82,6 +85,25 @@
start_time, end_time, is_api_case_executing, is_scenario_executing, is_performance_executing,
principal, components, is_new
</sql>
<sql id="Blob_Column_List">
run_info
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanReportExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_report
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanReportExample" resultMap="BaseResultMap">
select
<if test="distinct">
@ -96,9 +118,11 @@
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_report
where id = #{id,jdbcType=VARCHAR}
</select>
@ -118,13 +142,13 @@
trigger_mode, creator, start_time,
end_time, is_api_case_executing, is_scenario_executing,
is_performance_executing, principal, components,
is_new)
is_new, run_info)
values (#{id,jdbcType=VARCHAR}, #{testPlanId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{triggerMode,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{isApiCaseExecuting,jdbcType=BIT}, #{isScenarioExecuting,jdbcType=BIT},
#{isPerformanceExecuting,jdbcType=BIT}, #{principal,jdbcType=VARCHAR}, #{components,jdbcType=VARCHAR},
#{isNew,jdbcType=BIT})
#{isNew,jdbcType=BIT}, #{runInfo,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanReport">
insert into test_plan_report
@ -177,6 +201,9 @@
<if test="isNew != null">
is_new,
</if>
<if test="runInfo != null">
run_info,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -227,6 +254,9 @@
<if test="isNew != null">
#{isNew,jdbcType=BIT},
</if>
<if test="runInfo != null">
#{runInfo,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanReportExample" resultType="java.lang.Long">
@ -235,7 +265,6 @@
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_report
<set>
@ -287,11 +316,37 @@
<if test="record.isNew != null">
is_new = #{record.isNew,jdbcType=BIT},
</if>
<if test="record.runInfo != null">
run_info = #{record.runInfo,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update test_plan_report
set id = #{record.id,jdbcType=VARCHAR},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
`name` = #{record.name,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
creator = #{record.creator,jdbcType=VARCHAR},
start_time = #{record.startTime,jdbcType=BIGINT},
end_time = #{record.endTime,jdbcType=BIGINT},
is_api_case_executing = #{record.isApiCaseExecuting,jdbcType=BIT},
is_scenario_executing = #{record.isScenarioExecuting,jdbcType=BIT},
is_performance_executing = #{record.isPerformanceExecuting,jdbcType=BIT},
principal = #{record.principal,jdbcType=VARCHAR},
components = #{record.components,jdbcType=VARCHAR},
is_new = #{record.isNew,jdbcType=BIT},
run_info = #{record.runInfo,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_report
set id = #{record.id,jdbcType=VARCHAR},
@ -362,9 +417,32 @@
<if test="isNew != null">
is_new = #{isNew,jdbcType=BIT},
</if>
<if test="runInfo != null">
run_info = #{runInfo,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanReport">
update test_plan_report
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
`name` = #{name,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
creator = #{creator,jdbcType=VARCHAR},
start_time = #{startTime,jdbcType=BIGINT},
end_time = #{endTime,jdbcType=BIGINT},
is_api_case_executing = #{isApiCaseExecuting,jdbcType=BIT},
is_scenario_executing = #{isScenarioExecuting,jdbcType=BIT},
is_performance_executing = #{isPerformanceExecuting,jdbcType=BIT},
principal = #{principal,jdbcType=VARCHAR},
components = #{components,jdbcType=VARCHAR},
is_new = #{isNew,jdbcType=BIT},
run_info = #{runInfo,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanReport">
update test_plan_report
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},

View File

@ -0,0 +1,12 @@
package io.metersphere.base.mapper.ext;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtApiTestEnvironmentMapper {
List<String> selectNameByIds(@Param("ids") Collection<String> envIdSet);
String selectNameById(String id);
}

View File

@ -0,0 +1,26 @@
<?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.ExtApiTestEnvironmentMapper">
<resultMap id="BaseResultMap" type="io.metersphere.api.dto.APITestResult"
extends="io.metersphere.base.mapper.ApiTestMapper.BaseResultMap">
<result column="project_name" property="projectName"/>
<result column="user_name" property="userName"/>
</resultMap>
<select id="selectNameByIds" resultType="java.lang.String">
SELECT name
FROM api_test_environment
<where>
id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</where>
</select>
<select id="selectNameById" resultType="java.lang.String">
SELECT name
FROM api_test_environment
WHERE id = #{0}
</select>
</mapper>

View File

@ -6,6 +6,7 @@ import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.track.dto.PlanReportCaseDTO;
import io.metersphere.track.dto.testplan.TestPlanApiCaseInfoDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
@ -30,7 +31,7 @@ public interface ExtTestPlanApiCaseMapper {
String getApiTestCaseIdById(String testPlanApiCaseId);
List<TestPlanApiCase> selectLegalDataByTestPlanId(String planId);
List<TestPlanApiCaseInfoDTO> selectLegalDataByTestPlanId(String planId);
List<PlanReportCaseDTO> selectForPlanReport(String planId);

View File

@ -4,29 +4,43 @@
<insert id="insertIfNotExists" parameterType="io.metersphere.base.domain.TestPlanApiCase">
INSERT INTO test_plan_api_case(id, test_plan_id, api_case_id, environment_id, create_time, update_time, create_user, `order`)
SELECT #{request.id}, #{request.testPlanId}, #{request.apiCaseId}, #{request.environmentId}, #{request.createTime}, #{request.updateTime}, #{request.createUser}, #{request.order}
INSERT INTO test_plan_api_case(id, test_plan_id, api_case_id, environment_id, create_time, update_time,
create_user, `order`)
SELECT #{request.id},
#{request.testPlanId},
#{request.apiCaseId},
#{request.environmentId},
#{request.createTime},
#{request.updateTime},
#{request.createUser},
#{request.order}
FROM DUAL
WHERE NOT EXISTS(
SELECT id FROM
test_plan_api_case
WHERE test_plan_id = #{request.testPlanId} and api_case_id = #{request.apiCaseId}
SELECT id
FROM test_plan_api_case
WHERE test_plan_id = #{request.testPlanId}
and api_case_id = #{request.apiCaseId}
)
</insert>
<select id="getApiTestCaseById" resultType="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
SELECT t.* FROM api_test_case t
SELECT t.*
FROM api_test_case t
INNER JOIN test_plan_api_case tpac ON t.id = tpac.api_case_id
WHERE tpac.id = #{0}
</select>
<select id="getApiTestCaseIdById" resultType="java.lang.String">
SELECT api_case_id FROM test_plan_api_case t WHERE id = #{0}
SELECT api_case_id
FROM test_plan_api_case t
WHERE id = #{0}
</select>
<select id="selectLegalDataByTestPlanId" resultType="io.metersphere.base.domain.TestPlanApiCase">
SELECT t.* FROM test_plan_api_case t WHERE t.test_plan_id = #{0}
AND t.api_case_id IN (
SELECT id FROM api_test_case WHERE status IS NULL OR status != 'Trash'
)
ORDER BY `order` DESC
<select id="selectLegalDataByTestPlanId" resultType="io.metersphere.track.dto.testplan.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.test_plan_id = #{0}
AND (a.status IS NULL OR a.status != 'Trash')
ORDER BY t.`order` DESC
</select>
<select id="list" resultType="io.metersphere.api.dto.definition.TestPlanApiCaseDTO">
select
@ -251,8 +265,7 @@
</select>
<select id="getExecResultByPlanId" resultType="java.lang.String">
select status
from
test_plan_api_case
from test_plan_api_case
where test_plan_id = #{planId}
AND api_case_id in (SELECT id FROM api_test_case WHERE (`status` is null or `status` != 'Trash'))
</select>
@ -277,11 +290,20 @@
where t.test_plan_id = #{planId}
</select>
<select id="getStatusByTestPlanId" resultType="java.lang.String">
SELECT `status` FROM test_plan_api_case WHERE test_plan_id = #{0}
SELECT `status`
FROM test_plan_api_case
WHERE test_plan_id = #{0}
</select>
<select id="selectForPlanReport" resultType="io.metersphere.track.dto.PlanReportCaseDTO">
select id,status from test_plan_api_case where test_plan_id = #{planId} and api_case_id IN (
SELECT id FROM api_test_case where status is null or status != 'Trash'
select id, status
from test_plan_api_case
where test_plan_id = #{planId}
and api_case_id IN (
SELECT id
FROM api_test_case
where status is null
or status
!= 'Trash'
)
</select>
<select id="getFailureList" resultType="io.metersphere.api.dto.automation.TestPlanFailureApiDTO">
@ -329,10 +351,14 @@
<select id="selectPlanIds" resultType="java.lang.String">
select DISTINCT test_plan_id from test_plan_api_case;
select DISTINCT test_plan_id
from test_plan_api_case;
</select>
<select id="getIdsOrderByUpdateTime" resultType="java.lang.String">
select id from test_plan_api_case where test_plan_id = #{planId} order by update_time ASC;
select id
from test_plan_api_case
where test_plan_id = #{planId}
order by update_time ASC;
</select>
<select id="getLastOrder" resultType="java.lang.Long">

View File

@ -5,6 +5,7 @@ import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.track.dto.PlanReportCaseDTO;
import io.metersphere.track.dto.testplan.TestPlanApiScenarioInfoDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
@ -25,7 +26,7 @@ public interface ExtTestPlanScenarioCaseMapper {
List<TestPlanApiScenario> selectByIds(@Param("ids")String ids ,@Param("oderId")String oderId );
List<TestPlanApiScenario> selectLegalDataByTestPlanId(String planId);
List<TestPlanApiScenarioInfoDTO> selectLegalDataByTestPlanId(String planId);
List<PlanReportCaseDTO> selectForPlanReport(String planId);

View File

@ -15,12 +15,12 @@
)
</insert>
<select id="selectLegalDataByTestPlanId" resultType="io.metersphere.base.domain.TestPlanApiScenario">
SELECT t.* FROM test_plan_api_scenario t WHERE t.test_plan_id = #{0}
AND t.api_scenario_id IN (
SELECT id FROM api_scenario WHERE status IS NULL OR status != 'Trash'
)
ORDER BY `order` DESC
<select id="selectLegalDataByTestPlanId" resultType="io.metersphere.track.dto.testplan.TestPlanApiScenarioInfoDTO">
SELECT tpas.id, tpas.api_scenario_id,tpas.environment,apis.project_id FROM
test_plan_api_scenario tpas INNER JOIN api_scenario apis ON tpas.api_scenario_id = apis.id
WHERE (apis.`status` IS NULL OR apis.`status` != 'Trash')
AND tpas.test_plan_id = #{0}
ORDER BY tpas.`order` DESC;
</select>
<select id="list" resultType="io.metersphere.api.dto.automation.ApiScenarioDTO">

View File

@ -307,4 +307,8 @@ public class EnvironmentGroupService {
}
return result;
}
public EnvironmentGroup selectById(String id) {
return environmentGroupMapper.selectByPrimaryKey(id);
}
}

View File

@ -1080,4 +1080,13 @@ public class ProjectService {
}
}
}
public String selectNameById(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
if (project == null) {
return null;
} else {
return project.getName();
}
}
}

View File

@ -76,7 +76,7 @@ public class TestPlanReportController {
String userId = SessionUtils.getUser().getId();
String reportId = UUID.randomUUID().toString();
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId, planId, userId, triggerMode);
TestPlanScheduleReportInfoDTO report = testPlanReportService.genTestPlanReport(saveRequest);
TestPlanScheduleReportInfoDTO report = testPlanReportService.genTestPlanReport(saveRequest,null);
testPlanReportService.genTestPlanReportContent(report);
testPlanReportService.countReportByTestPlanReportId(report.getTestPlanReport().getId(), null, triggerMode);
return "success";

View File

@ -8,6 +8,7 @@ import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@ -20,6 +21,16 @@ public class TestPlanSimpleReportDTO extends TestPlanReportContent {
private String summary;
private String config;
/**
* 运行环境信息
* runMode:运行模式 并行/串行
* envGroupName 用户组名称
* projectEnvMap: <项目,运行环境>
*/
private String runMode;
private String envGroupName;
private Map<String, List<String>> projectEnvMap;
/**
* 导出保存国际化
*/

View File

@ -0,0 +1,13 @@
package io.metersphere.track.dto.testplan;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TestPlanApiCaseInfoDTO {
private String id;
private String apiCaseId;
private String environmentId;
private String projectId;
}

View File

@ -0,0 +1,13 @@
package io.metersphere.track.dto.testplan;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TestPlanApiScenarioInfoDTO {
private String id;
private String apiScenarioId;
private String environment;
private String projectId;
}

View File

@ -0,0 +1,37 @@
package io.metersphere.track.dto.testplan;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
@Getter
@Setter
public class TestPlanReportRunInfoDTO {
private String envGroupId;
private String runMode;
// <测试计划场景关联表ID, <项目ID环境ID>>
private Map<String, Map<String,String>> scenarioRunInfo;
// <测试计划用例关联表ID, <项目ID环境ID>>
private Map<String, Map<String,String>> apiCaseRunInfo;
public TestPlanReportRunInfoDTO(){
scenarioRunInfo = new HashMap<>();
apiCaseRunInfo = new HashMap<>();
}
public void putScenarioRunInfo(String scenarioResourceId,String projectId,String environmentId){
scenarioRunInfo.put(scenarioResourceId,new HashMap<>(){{
this.put(projectId,environmentId);
}});
}
public void putApiCaseRunInfo(String apiCaseResourceId,String projectId,String environmentId){
apiCaseRunInfo.put(apiCaseResourceId,new HashMap<>(){{
this.put(projectId,environmentId);
}});
}
}

View File

@ -7,18 +7,24 @@ import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO;
import io.metersphere.api.service.ApiDefinitionExecResultService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ShareInfoService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.*;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.dto.TestPlanExecuteReportDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.service.EnvironmentGroupService;
import io.metersphere.service.ProjectService;
import io.metersphere.service.UserService;
import io.metersphere.track.dto.*;
import io.metersphere.track.dto.testplan.TestPlanApiCaseInfoDTO;
import io.metersphere.track.dto.testplan.TestPlanApiScenarioInfoDTO;
import io.metersphere.track.dto.testplan.TestPlanReportRunInfoDTO;
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
import io.metersphere.track.request.report.TestPlanReportSaveRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
@ -70,14 +76,8 @@ public class TestPlanReportService {
@Resource
TestPlanReportContentMapper testPlanReportContentMapper;
@Resource
ShareInfoService shareInfoService;
@Resource
private TestPlanPrincipalMapper testPlanPrincipalMapper;
@Resource
private UserService userService;
@Resource
private ProjectService projectService;
@Resource
ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper;
@Resource
private ExtLoadTestReportMapper extLoadTestReportMapper;
@ -96,6 +96,14 @@ public class TestPlanReportService {
private TestPlanExecutionQueueMapper testPlanExecutionQueueMapper;
@Resource
private TestPlanMessageService testPlanMessageService;
@Resource
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private EnvironmentGroupService environmentGroupService;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
@Resource
private ProjectService projectService;
public List<TestPlanReportDTO> list(QueryTestPlanReportRequest request) {
List<TestPlanReportDTO> list = new ArrayList<>();
@ -214,7 +222,7 @@ public class TestPlanReportService {
}
}
public TestPlanScheduleReportInfoDTO genTestPlanReportBySchedule(String planReportId, String planId, String userId, String triggerMode) {
public TestPlanScheduleReportInfoDTO genTestPlanReportBySchedule(String planReportId, String planId, String userId, String triggerMode, RunModeConfigDTO runModeConfigDTO) {
TestPlanReport testPlanReport = this.getTestPlanReport(planReportId);
TestPlanScheduleReportInfoDTO returnDTO = new TestPlanScheduleReportInfoDTO();
if (testPlanReport != null) {
@ -224,14 +232,19 @@ public class TestPlanReportService {
Map<String, String> planScenarioIdMap = new LinkedHashMap<>();
Map<String, String> planTestCaseIdMap = new LinkedHashMap<>();
Map<String, String> performanceIdMap = new LinkedHashMap<>();
List<TestPlanApiScenario> testPlanApiScenarioList = extTestPlanScenarioCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanApiScenario model : testPlanApiScenarioList) {
List<TestPlanApiScenarioInfoDTO> testPlanApiScenarioList = extTestPlanScenarioCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanApiScenarioInfoDTO model : testPlanApiScenarioList) {
planScenarioIdMap.put(model.getId(), model.getApiScenarioId());
}
List<TestPlanApiCase> testPlanApiCaseList = extTestPlanApiCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanApiCase model : testPlanApiCaseList) {
List<TestPlanApiCaseInfoDTO> testPlanApiCaseList = extTestPlanApiCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanApiCaseInfoDTO model : testPlanApiCaseList) {
planTestCaseIdMap.put(model.getId(), model.getApiCaseId());
}
//解析运行环境信息
TestPlanReportRunInfoDTO runInfoDTO = this.parseTestPlanRunInfo(runModeConfigDTO, testPlanApiCaseList, testPlanApiScenarioList);
LoadCaseRequest loadCaseRequest = new LoadCaseRequest();
loadCaseRequest.setTestPlanId(planId);
List<TestPlanLoadCaseDTO> testPlanLoadCaseDTOList = extTestPlanLoadCaseMapper.selectTestPlanLoadCaseList(loadCaseRequest);
@ -257,7 +270,7 @@ public class TestPlanReportService {
apiCaseInfoMap, scenarioInfoMap, performanceInfoMap);
if (testPlanReport == null) {
returnDTO = this.genTestPlanReport(saveRequest);
returnDTO = this.genTestPlanReport(saveRequest, runInfoDTO);
}
returnDTO.setPlanScenarioIdMap(planScenarioIdMap);
returnDTO.setApiTestCaseDataMap(planTestCaseIdMap);
@ -266,6 +279,42 @@ public class TestPlanReportService {
return returnDTO;
}
public TestPlanReportRunInfoDTO parseTestPlanRunInfo(RunModeConfigDTO runModeConfigDTO, List<TestPlanApiCaseInfoDTO> testPlanApiCaseList, List<TestPlanApiScenarioInfoDTO> testPlanApiScenarioList) {
TestPlanReportRunInfoDTO runInfoDTO = new TestPlanReportRunInfoDTO();
Map<String, String> selectEnvMap = runModeConfigDTO.getEnvMap();
runInfoDTO.setRunMode(runModeConfigDTO.getMode());
if (StringUtils.equals("GROUP", runModeConfigDTO.getEnvironmentType()) && StringUtils.isNotEmpty(runModeConfigDTO.getEnvironmentGroupId())) {
selectEnvMap = environmentGroupProjectService.getEnvMap(runModeConfigDTO.getEnvironmentGroupId());
runInfoDTO.setEnvGroupId(runModeConfigDTO.getEnvironmentGroupId());
}
for (TestPlanApiScenarioInfoDTO model : testPlanApiScenarioList) {
if (MapUtils.isNotEmpty(selectEnvMap) && selectEnvMap.containsKey(model.getProjectId())) {
runInfoDTO.putScenarioRunInfo(model.getId(), model.getProjectId(), selectEnvMap.get(model.getProjectId()));
} else if (StringUtils.isNotEmpty(model.getEnvironment())) {
try {
Map<String, String> envMap = JSONObject.parseObject(model.getEnvironment(), Map.class);
if (MapUtils.isNotEmpty(envMap)) {
String envId = null;
for (String envIdStr : envMap.values()) {
envId = envIdStr;
}
runInfoDTO.putScenarioRunInfo(model.getId(), model.getProjectId(), envId);
}
} catch (Exception ignore) {
}
}
}
for (TestPlanApiCaseInfoDTO model : testPlanApiCaseList) {
if (MapUtils.isNotEmpty(selectEnvMap) && selectEnvMap.containsKey(model.getProjectId())) {
runInfoDTO.putApiCaseRunInfo(model.getId(), model.getProjectId(), selectEnvMap.get(model.getProjectId()));
} else {
runInfoDTO.putApiCaseRunInfo(model.getId(), model.getProjectId(), model.getEnvironmentId());
}
}
return runInfoDTO;
}
/**
* saveRequest.reportId 报告ID(外部传入
* saveRequest.planId 测试计划ID
@ -276,7 +325,7 @@ public class TestPlanReportService {
* saveRequest.scenarioIsExecuting 场景案例是否执行中
* saveRequest.performanceIsExecuting 性能案例是否执行中
*/
public TestPlanScheduleReportInfoDTO genTestPlanReport(TestPlanReportSaveRequest saveRequest) {
public TestPlanScheduleReportInfoDTO genTestPlanReport(TestPlanReportSaveRequest saveRequest, TestPlanReportRunInfoDTO runInfoDTO) {
TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(saveRequest.getPlanId());
String testPlanReportID = saveRequest.getReportID();
TestPlanReport testPlanReport = new TestPlanReport();
@ -297,14 +346,15 @@ public class TestPlanReportService {
testPlanReport.setStartTime(System.currentTimeMillis());
testPlanReport.setEndTime(System.currentTimeMillis());
testPlanReport.setIsNew(true);
testPlanReport.setRunInfo(JSONObject.toJSONString(runInfoDTO));
if (saveRequest.isCountResources()) {
List<TestPlanApiCase> testPlanApiCaseList = extTestPlanApiCaseMapper.selectLegalDataByTestPlanId(saveRequest.getPlanId());
List<String> apiCaseIdList = testPlanApiCaseList.stream().map(TestPlanApiCase::getApiCaseId).collect(Collectors.toList());
List<TestPlanApiCaseInfoDTO> testPlanApiCaseList = extTestPlanApiCaseMapper.selectLegalDataByTestPlanId(saveRequest.getPlanId());
List<String> apiCaseIdList = testPlanApiCaseList.stream().map(TestPlanApiCaseInfoDTO::getApiCaseId).collect(Collectors.toList());
testPlanReport.setIsApiCaseExecuting(!apiCaseIdList.isEmpty());
List<TestPlanApiScenario> testPlanApiScenarioList = extTestPlanScenarioCaseMapper.selectLegalDataByTestPlanId(saveRequest.getPlanId());
List<String> scenarioIdList = testPlanApiScenarioList.stream().map(TestPlanApiScenario::getApiScenarioId).collect(Collectors.toList());
List<TestPlanApiScenarioInfoDTO> testPlanApiScenarioList = extTestPlanScenarioCaseMapper.selectLegalDataByTestPlanId(saveRequest.getPlanId());
List<String> scenarioIdList = testPlanApiScenarioList.stream().map(TestPlanApiScenarioInfoDTO::getApiScenarioId).collect(Collectors.toList());
testPlanReport.setIsScenarioExecuting(!scenarioIdList.isEmpty());
LoadCaseRequest loadCaseRequest = new LoadCaseRequest();
@ -829,12 +879,11 @@ public class TestPlanReportService {
return null;
}
if (this.isDynamicallyGenerateReports(testPlanReportContent)) {
LogUtil.info("----> GenerateReports: " + JSONObject.toJSONString(testPlanReportContent));
testPlanReportContent = this.dynamicallyGenerateReports(testPlanReportContent);
LogUtil.info("----> GenerateReports OVER: " + JSONObject.toJSONString(testPlanReportContent));
}
TestPlanSimpleReportDTO testPlanReportDTO = new TestPlanSimpleReportDTO();
BeanUtils.copyBean(testPlanReportDTO, testPlanReportContent);
this.generateEnvironmentInfo(testPlanReportDTO, reportId);
if (StringUtils.isNotBlank(testPlanReportContent.getFunctionResult())) {
testPlanReportDTO.setFunctionResult(JSONObject.parseObject(testPlanReportContent.getFunctionResult(), TestPlanFunctionResultReportDTO.class));
}
@ -889,6 +938,70 @@ public class TestPlanReportService {
return testPlanReportDTO;
}
private void generateEnvironmentInfo(TestPlanSimpleReportDTO testPlanReportDTO, String reportId) {
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(reportId);
TestPlanReportRunInfoDTO runInfoDTO = null;
if (StringUtils.isNotEmpty(testPlanReport.getRunInfo())) {
try {
runInfoDTO = JSONObject.parseObject(testPlanReport.getRunInfo(), TestPlanReportRunInfoDTO.class);
} catch (Exception e) {
LogUtil.error("解析测试计划报告记录的运行环境信息[" + testPlanReport.getRunInfo() + "]时出错!", e);
}
}
if (runInfoDTO != null) {
if (StringUtils.isNotEmpty(runInfoDTO.getEnvGroupId())) {
EnvironmentGroup environmentGroup = environmentGroupService.selectById(runInfoDTO.getEnvGroupId());
if (StringUtils.isNotEmpty(environmentGroup.getName())) {
testPlanReportDTO.setEnvGroupName(environmentGroup.getName());
}
}
testPlanReportDTO.setRunMode(StringUtils.equalsIgnoreCase(runInfoDTO.getRunMode(), "serial") ? Translator.get("serial") : Translator.get("parallel"));
Map<String, Set<String>> projectEnvMap = new LinkedHashMap<>();
if (MapUtils.isNotEmpty(runInfoDTO.getApiCaseRunInfo())) {
this.setProjectEnvMap(projectEnvMap, runInfoDTO.getApiCaseRunInfo());
}
if (MapUtils.isNotEmpty(runInfoDTO.getScenarioRunInfo())) {
this.setProjectEnvMap(projectEnvMap, runInfoDTO.getScenarioRunInfo());
}
Map<String, List<String>> showProjectEnvMap = new LinkedHashMap<>();
for (Map.Entry<String, Set<String>> entry : projectEnvMap.entrySet()) {
String projectId = entry.getKey();
Set<String> envIdSet = entry.getValue();
String projectName = projectService.selectNameById(projectId);
List<String> envNames = apiTestEnvironmentService.selectNameByIds(envIdSet);
if (StringUtils.isNotEmpty(projectName) && CollectionUtils.isNotEmpty(envNames)) {
showProjectEnvMap.put(projectName, envNames);
}
}
if (MapUtils.isNotEmpty(showProjectEnvMap)) {
testPlanReportDTO.setProjectEnvMap(showProjectEnvMap);
}
}
}
private void setProjectEnvMap(Map<String, Set<String>> projectEnvMap, Map<String, Map<String, String>> caseEnvironmentMap) {
if (projectEnvMap == null || caseEnvironmentMap == null) {
return;
}
for (Map<String, String> map : caseEnvironmentMap.values()) {
if (MapUtils.isEmpty(map)) {
continue;
}
for (Map.Entry<String, String> entry : map.entrySet()) {
String projectId = entry.getKey();
String envId = entry.getValue();
if (projectEnvMap.containsKey(projectId)) {
projectEnvMap.get(projectId).add(envId);
} else {
projectEnvMap.put(projectId, new LinkedHashSet<>() {{
this.add(envId);
}});
}
}
}
}
private boolean isDynamicallyGenerateReports(TestPlanReportContentWithBLOBs testPlanReportContent) {
return testPlanReportContent != null &&
(StringUtils.isNotEmpty(testPlanReportContent.getPlanApiCaseReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanScenarioReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanLoadCaseReportStruct()));

View File

@ -951,8 +951,8 @@ public class TestPlanService {
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
TestPlanScheduleReportInfoDTO genTestPlanReport(String planReportId, String planId, String userId, String triggerMode) {
TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanReportService.genTestPlanReportBySchedule(planReportId, planId, userId, triggerMode);
TestPlanScheduleReportInfoDTO genTestPlanReport(String planReportId, String planId, String userId, String triggerMode, RunModeConfigDTO runModeConfigDTO) {
TestPlanScheduleReportInfoDTO reportInfoDTO = testPlanReportService.genTestPlanReportBySchedule(planReportId, planId, userId, triggerMode, runModeConfigDTO);
return reportInfoDTO;
}
@ -979,7 +979,7 @@ public class TestPlanService {
}
//创建测试报告然后返回的ID重新赋值为resourceID作为后续的参数
TestPlanScheduleReportInfoDTO reportInfoDTO = this.genTestPlanReport(planReportId, testPlanID, userId, triggerMode);
TestPlanScheduleReportInfoDTO reportInfoDTO = this.genTestPlanReport(planReportId, testPlanID, userId, triggerMode, runModeConfig);
//测试计划准备执行取消测试计划的实际结束时间
extTestPlanMapper.updateActualEndTimeIsNullById(testPlanID);
@ -1435,6 +1435,11 @@ public class TestPlanService {
cases.forEach(item -> {
if (resultMap.get(item.getReportId()) != null &&
StringUtils.isNotBlank(resultMap.get(item.getReportId()).getContent())) {
ApiDefinitionExecResultWithBLOBs execResult = resultMap.get(item.getReportId());
JSONObject responseObj = JSONObject.parseObject(execResult.getContent());
if (StringUtils.isNotEmpty(execResult.getEnvConfig())) {
responseObj.put("envName", apiDefinitionService.getEnvNameByEnvConfig(execResult.getProjectId(), execResult.getEnvConfig()));
}
item.setResponse(resultMap.get(item.getReportId()).getContent());
}
});
@ -2172,7 +2177,8 @@ public class TestPlanService {
TestPlanWithBLOBs testPlan = testPlanMap.get(id);
String planReportId = UUID.randomUUID().toString();
//创建测试报告
this.genTestPlanReport(planReportId, testPlan.getId(), request.getUserId(), request.getTriggerMode());
// TODO: 2022/5/16 genTestPlanReport的runModeConfig先赋值为null日后这里需要将前台传递的具体数据填写进来
this.genTestPlanReport(planReportId, testPlan.getId(), request.getUserId(), request.getTriggerMode(), null);
//测试计划准备执行取消测试计划的实际结束时间
extTestPlanMapper.updateActualEndTimeIsNullById(testPlan.getId());
executeQueue.put(testPlan.getId(), planReportId);

View File

@ -86,8 +86,7 @@
<!-- <ignoreColumn column="clean_load_report_expr"/>-->
<!-- <ignoreColumn column="repeatable"/>-->
<!-- </table>-->
<table tableName="api_case_execution_info"/>
<table tableName="scenario_execution_info"/>
<table tableName="test_plan_report"/>
<!--<table tableName="enterprise_test_report_send_record"/>-->
<!--<table tableName="test_case_review_api_case"/>
<table tableName="test_case_review_load"/>

View File

@ -392,3 +392,5 @@ ui_element_import_template_name=Ui_element_templates
ui_element_import_template_sheet=Template
ui_element_already_exists_excel=There are duplicate data in the import file
ui_element_already_exists_data=An element with the same name already exists
serial=Serial
parallel=Parallel

View File

@ -391,3 +391,5 @@ ui_element_import_template_name=元素库导入模板
ui_element_import_template_sheet=模板
ui_element_already_exists_excel=文件中存在多条相同数据
ui_element_already_exists_data=已经存在同名元素
serial=串行
parallel=并行

View File

@ -390,3 +390,5 @@ ui_element_import_template_name=元素庫導入模板
ui_element_import_template_sheet=模板
ui_element_already_exists_excel=文件中存在多條相同數據
ui_element_already_exists_data=已經存在同名元素
serial=串行
parallel=並行

View File

@ -11,6 +11,7 @@
:is-template="isTemplate"
:debug="debug"
:report="report"
:project-env-map="projectEnvMap"
@reportExport="handleExport"
@reportSave="handleSave"/>
@ -116,8 +117,8 @@
import MsApiReportExport from "./ApiReportExport";
import MsApiReportViewHeader from "./ApiReportViewHeader";
import {RequestFactory} from "../../definition/model/ApiTestModel";
import {windowPrint, getUUID, getCurrentProjectID, hasLicense} from "@/common/js/utils";
import {getScenarioReport, getShareScenarioReport, getScenarioReportAll} from "@/network/api";
import {getCurrentProjectID, getUUID, hasLicense, windowPrint} from "@/common/js/utils";
import {getScenarioReport, getScenarioReportAll, getShareScenarioReport} from "@/network/api";
import {STEP} from "@/business/components/api/automation/scenario/Setting";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
@ -150,6 +151,7 @@
stepFilter: new STEP,
exportReportIsOk: false,
tempResult: [],
projectEnvMap: {},
}
},
activated() {
@ -194,7 +196,7 @@
},
init() {
this.loading = true;
this.report = {};
this.projectEnvMap = {};
this.content = {};
this.fails = [];
this.report = {};
@ -400,6 +402,9 @@
getScenarioReportAll(this.reportId, (data) => {
if (data && data.content) {
let report = JSON.parse(data.content);
if (report.projectEnvMap) {
this.projectEnvMap = report.projectEnvMap;
}
this.content = report;
this.fullTreeNodes = report.steps;
this.content.console = report.console;
@ -453,6 +458,9 @@
if (data.content) {
let report = JSON.parse(data.content);
this.content = report;
if (report.projectEnvMap) {
this.projectEnvMap = report.projectEnvMap;
}
if (data.reportType === "UI_INDEPENDENT") {
this.tempResult = report.steps;
//
@ -680,7 +688,11 @@
}
this.loading = true;
let url = "/api/scenario/report/reName";
this.result = this.$post(url, {id: this.report.id,name: this.report.name,reportType: this.report.reportType }, response => {
this.result = this.$post(url, {
id: this.report.id,
name: this.report.name,
reportType: this.report.reportType
}, response => {
this.$success(this.$t('commons.save_success'));
this.loading = false;
this.$emit('refresh');

View File

@ -8,7 +8,9 @@
<el-button-group>
<el-tooltip class="item" effect="dark" content="left" :disabled="true" placement="left">
<el-button plain :class="{active: leftActive}" @click="changeTab('left')">{{$t('commons.scenario')}}</el-button>
<el-button plain :class="{active: leftActive}" @click="changeTab('left')">
{{ $t('commons.scenario') }}
</el-button>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="right" :disabled="true" placement="right">
@ -146,7 +148,7 @@
<script>
import {getCurrentProjectID} from "@/common/js/utils";
import {REPORT_CASE_CONFIGS, REPORT_CONFIGS} from "../../../common/components/search/search-components";
import {_filter, _sort, getLastTableSortField} from "@/common/js/tableUtils";
import {_filter, _sort} from "@/common/js/tableUtils";
import MsRenameReportDialog from "@/business/components/common/components/report/MsRenameReportDialog";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsRequestResultTail from "../../../api/definition/components/response/RequestResultTail";
@ -452,6 +454,7 @@ export default {
.table-content {
width: 100%;
}
.active {
border: solid 1px #6d317c !important;
background-color: var(--primary_color) !important;

View File

@ -3,15 +3,18 @@
<el-row>
<el-col>
<span v-if="!debug">
<el-input v-if="nameIsEdit" size="mini" @blur="handleSave(report.name)" @keyup.enter.native="handleSaveKeyUp" style="width: 200px" v-model="report.name" maxlength="60" show-word-limit/>
<el-input v-if="nameIsEdit" size="mini" @blur="handleSave(report.name)" @keyup.enter.native="handleSaveKeyUp"
style="width: 200px" v-model="report.name" maxlength="60" show-word-limit/>
<span v-else>
<router-link v-if="isSingleScenario" :to="{name: isUi ? 'uiAutomation' : 'ApiAutomation', params: { dataSelectRange: 'edit:' + scenarioId }}">
<router-link v-if="isSingleScenario"
:to="{name: isUi ? 'uiAutomation' : 'ApiAutomation', params: { dataSelectRange: 'edit:' + scenarioId }}">
{{ report.name }}
</router-link>
<span v-else>
{{ report.name }}
</span>
<i v-if="showCancelButton" class="el-icon-edit" style="cursor:pointer" @click="nameIsEdit = true" @click.stop/>
<i v-if="showCancelButton" class="el-icon-edit" style="cursor:pointer" @click="nameIsEdit = true"
@click.stop/>
</span>
</span>
<span v-if="report.endTime || report.createTime">
@ -21,7 +24,9 @@
<span class="time"> {{ report.endTime | timestampFormatDate }}</span>
</span>
<div style="float: right">
<el-button v-if="!isPlan && (!debug || exportFlag) && !isTemplate && !isUi" v-permission="['PROJECT_API_REPORT:READ+EXPORT']" :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
<el-button v-if="!isPlan && (!debug || exportFlag) && !isTemplate && !isUi"
v-permission="['PROJECT_API_REPORT:READ+EXPORT']" :disabled="isReadOnly" class="export-button"
plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
{{ $t('test_track.plan_view.export_report') }}
</el-button>
@ -56,6 +61,14 @@
</div>
</el-col>
</el-row>
<el-row v-if="showProjectEnv" type="flex">
<span> {{ $t('commons.environment') + ':' }} </span>
<div v-for="(values,key) in projectEnvMap" :key="key" style="margin-right: 10px">
{{ key + ":" }}
<ms-tag v-for="(item,index) in values" :key="index" type="success" :content="item"
style="margin-left: 2px"/>
</div>
</el-row>
</header>
</template>
@ -63,11 +76,14 @@
import {generateShareInfoWithExpired} from "@/network/share";
import {getCurrentProjectID} from "@/common/js/utils";
import MsTag from "@/business/components/common/components/MsTag";
export default {
name: "MsApiReportViewHeader",
components: {MsTag},
props: {
report: {},
projectEnvMap: {},
debug: Boolean,
showCancelButton: {
type: Boolean,
@ -85,6 +101,9 @@ export default {
isPlan: Boolean
},
computed: {
showProjectEnv() {
return this.projectEnvMap && JSON.stringify(this.projectEnvMap) !== '{}';
},
path() {
return "/api/test/edit?id=" + this.report.testId;
},
@ -116,7 +135,6 @@ export default {
}
},
created() {
},
methods: {
handleExport(name) {
@ -165,14 +183,11 @@ export default {
let unit = res.data.typeValue.substring(res.data.typeValue.length - 1);
if (unit === 'H') {
res.data.typeValue = quantity + this.$t('commons.date_unit.hour');
}else
if(unit==='D'){
} else if (unit === 'D') {
res.data.typeValue = quantity + this.$t('commons.date_unit.day');
}else
if(unit==='M'){
} else if (unit === 'M') {
res.data.typeValue = quantity + this.$t('commons.workspace_unit') + this.$t('commons.date_unit.month');
}else
if(unit==='Y'){
} else if (unit === 'Y') {
res.data.typeValue = quantity + this.$t('commons.date_unit.year');
}
this.application = res.data;

View File

@ -84,7 +84,10 @@ export default {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
stepArray[i].document = {type: "JSON", data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}};
stepArray[i].document = {
type: "JSON",
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
if (stepArray[i] && stepArray[i].authManager && !stepArray[i].authManager.clazzName) {
stepArray[i].authManager.clazzName = TYPE_TO_C.get(stepArray[i].authManager.type);
@ -122,7 +125,14 @@ export default {
})
this.sort(testPlan.hashTree);
this.requestResult.reportId = this.reportId;
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type, clazzName: this.clazzName ? this.clazzName : TYPE_TO_C.get(this.type), projectId: projectId, environmentMap: strMapToObj(this.envMap)};
let reqObj = {
id: this.reportId,
testElement: testPlan,
type: this.type,
clazzName: this.clazzName ? this.clazzName : TYPE_TO_C.get(this.type),
projectId: projectId,
environmentMap: strMapToObj(this.envMap)
};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
reqObj.editCaseRequest = this.editCaseRequest;
reqObj.debug = this.debug;
@ -131,6 +141,9 @@ export default {
} else {
reqObj.name = this.runData[0].path;
}
if (this.runData[0].useEnvironment) {
reqObj.environmentId = this.runData[0].useEnvironment;
}
reqObj.reportId = this.reportId;
let url = "/api/definition/run/debug";
if (!this.debug) {

View File

@ -8,7 +8,9 @@
:content="responseResult.responseCode"
placement="top">
<div v-if="response.attachInfoMap && response.attachInfoMap.errorReportResult && response.attachInfoMap.status === 'errorReportResult'" class="node-title" :class="'ms-req-error-report-result'">
<div
v-if="response.attachInfoMap && response.attachInfoMap.errorReportResult && response.attachInfoMap.status === 'errorReportResult'"
class="node-title" :class="'ms-req-error-report-result'">
{{ responseResult && responseResult.responseCode ? responseResult.responseCode : '0' }}
</div>
<div v-else class="node-title" :class="response && response.success ?'ms-req-success':'ms-req-error'">
@ -19,10 +21,12 @@
{{ responseResult && responseResult.responseCode ? responseResult.responseCode : '0' }}
</div>
<div v-if="response && response.attachInfoMap && response.attachInfoMap.errorReportResult">
<div class="node-title ms-req-error-report-result" v-if="response.attachInfoMap.status === 'errorReportResult'" style="margin-left: 0px;padding-left: 0px">
<div class="node-title ms-req-error-report-result"
v-if="response.attachInfoMap.status === 'errorReportResult'" style="margin-left: 0px;padding-left: 0px">
{{ response.attachInfoMap.errorReportResult }}
</div>
<div class="node-title ms-req-success" v-else-if="response.success" style="margin-left: 0px;padding-left: 0px">
<div class="node-title ms-req-success" v-else-if="response.success"
style="margin-left: 0px;padding-left: 0px">
{{ response.attachInfoMap.errorReportResult }}
</div>
<div class="node-title ms-req-error" v-else style="margin-left: 0px;padding-left: 0px">
@ -32,13 +36,25 @@
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{ $t('api_report.response_time') }} :</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">{{ responseResult && responseResult.responseTime ? responseResult.responseTime : 0 }} ms</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">
{{ responseResult && responseResult.responseTime ? responseResult.responseTime : 0 }} ms
</div>
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{ $t('api_report.response_size') }} :</div>
<div style="font-size: 14px;color:#61C550; margin-top:2px;margin-left:10px;float: left">{{ responseResult && responseResult.responseSize ? responseResult.responseSize : 0 }} bytes</div>
<div style="font-size: 14px;color:#61C550; margin-top:2px;margin-left:10px;float: left">
{{ responseResult && responseResult.responseSize ? responseResult.responseSize : 0 }} bytes
</div>
</el-col>
</el-row>
<el-row type="flex" v-if="response.envName">
<div style="font-size: 14px;color: #AAAAAA;float: left">
<span> {{ $t('commons.environment') + ':' }} </span>
</div>
<div style="font-size: 14px;color:#61C550; margin-left:10px;float: left">
{{ response.envName }}
</div>
</el-row>
</div>
</template>

View File

@ -4,6 +4,21 @@
<el-form-item :label="$t('test_track.report.testing_time') + ':'">
{{ showTime }}
</el-form-item>
<el-row type="flex" class="select-time"
v-if="report.envGroupName || report.projectEnvMap">
<span> {{ $t('commons.environment') + ':' }} </span>
<div v-if="report.envGroupName" style="margin-left: 12px">
<ms-tag type="danger" :content="$t('commons.group')"></ms-tag>
{{ report.envGroupName }}
</div>
<div v-else-if="report.projectEnvMap" style="margin-left: 12px">
<div v-for="(values,key) in report.projectEnvMap" :key="key" style="margin-right: 10px">
{{ key + ":" }}
<ms-tag v-for="(item,index) in values" :key="index" type="success" :content="item"
style="margin-left: 2px"/>
</div>
</div>
</el-row>
<el-row type="flex" justify="space-between" class="select-time">
<el-col :span="8">
<el-form-item :label="$t('test_track.report.total_number_tests') + ':'">
@ -33,9 +48,11 @@ import TestPlanReportContainer
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportContainer";
import {timestampFormatDate} from "@/common/js/filter";
import MsInstructionsIcon from "@/business/components/common/components/MsInstructionsIcon";
import MsTag from "@/business/components/common/components/MsTag";
export default {
name: "TestPlanOverviewReport",
components: {MsInstructionsIcon, TestPlanReportContainer, MsFormDivider},
components: {MsInstructionsIcon, TestPlanReportContainer, MsFormDivider, MsTag},
props: {
report: Object,
},

View File

@ -69,10 +69,14 @@ import TypeTableItem from "../../../../../../common/tableItems/planview/TypeTabl
import MethodTableItem from "../../../../../../common/tableItems/planview/MethodTableItem";
import StatusTableItem from "../../../../../../common/tableItems/planview/StatusTableItem";
import {
getPlanApiAllCase, getPlanApiErrorReportCase,
getPlanApiFailureCase, getPlanApiUnExecuteCase,
getSharePlanApiAllCase, getSharePlanApiErrorReportCase,
getSharePlanApiFailureCase, getSharePlanApiUnExecuteCase
getPlanApiAllCase,
getPlanApiErrorReportCase,
getPlanApiFailureCase,
getPlanApiUnExecuteCase,
getSharePlanApiAllCase,
getSharePlanApiErrorReportCase,
getSharePlanApiFailureCase,
getSharePlanApiUnExecuteCase
} from "@/network/test-plan";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";