Merge branch 'dev'

This commit is contained in:
BugKing 2021-09-29 11:37:55 +08:00
commit 3d39d312e5
222 changed files with 7472 additions and 2394 deletions

View File

@ -22,6 +22,7 @@ import io.metersphere.task.service.TaskService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testplan.FileOperationRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@ -96,7 +97,7 @@ public class ApiAutomationController {
@PostMapping(value = "/create")
@MsAuditLog(module = "api_automation", type = OperLogConstants.CREATE, title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class)
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_CREATE)
@RequiresPermissions(value={PermissionConstants.PROJECT_API_SCENARIO_READ_CREATE, PermissionConstants.PROJECT_API_SCENARIO_READ_COPY}, logical = Logical.OR)
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, event = NoticeConstants.Event.CREATE, mailTemplate = "api/AutomationCreate", subject = "接口自动化通知")
public ApiScenario create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
@ -105,7 +106,7 @@ public class ApiAutomationController {
@PostMapping(value = "/update")
@MsAuditLog(module = "api_automation", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", title = "#request.name", content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class)
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_EDIT)
@RequiresPermissions(value={PermissionConstants.PROJECT_API_SCENARIO_READ_EDIT, PermissionConstants.PROJECT_API_SCENARIO_READ_COPY}, logical = Logical.OR)
@SendNotice(taskType = NoticeConstants.TaskType.API_AUTOMATION_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "api/AutomationUpdate", subject = "接口自动化通知")
public ApiScenario update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "bodyFiles", required = false) List<MultipartFile> bodyFiles,
@RequestPart(value = "scenarioFiles", required = false) List<MultipartFile> scenarioFiles) {
@ -335,7 +336,7 @@ public class ApiAutomationController {
return apiAutomationService.setDomain(request.getDefinition());
}
@PostMapping(value = "/export/jmx")
@PostMapping(value = "/export/zip")
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_EXPORT_SCENARIO)
@MsAuditLog(module = "api_automation", type = OperLogConstants.EXPORT, sourceId = "#request.id", title = "#request.name", project = "#request.projectId")
public ResponseEntity<byte[]> downloadBodyFiles(@RequestBody ApiScenarioBatchRequest request) {
@ -345,5 +346,19 @@ public class ApiAutomationController {
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "场景JMX文件集.zip")
.body(bytes);
}
@PostMapping(value = "/export/jmx")
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ_EXPORT_SCENARIO)
@MsAuditLog(module = "api_automation", type = OperLogConstants.EXPORT, sourceId = "#request.id", title = "#request.name", project = "#request.projectId")
public List<ApiScenrioExportJmx> exportJmx(@RequestBody ApiScenarioBatchRequest request) {
return apiAutomationService.exportJmx(request);
}
@PostMapping(value = "/checkScenarioEnv")
public boolean checkScenarioEnv(@RequestBody ApiScenarioWithBLOBs request) {
return apiAutomationService.checkScenarioEnv(request);
}
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
@ -15,5 +16,5 @@ public class ApiCaseBatchRequest extends ApiTestCaseWithBLOBs {
private List<OrderRequest> orders;
private String projectId;
private String environmentId;
private BaseQueryRequest condition;
private ApiTestCaseRequest condition;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
@ -17,4 +18,5 @@ public class MsApiExportResult extends ApiExportResult {
private String version;
private List<ApiDefinitionWithBLOBs> data;
private List<ApiTestCaseWithBLOBs> cases;
private List<MockConfigImportDTO> mocks;
}

View File

@ -1,5 +1,7 @@
package io.metersphere.api.dto.definition;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import lombok.Getter;
import lombok.Setter;
@ -16,4 +18,8 @@ public class RunCaseRequest {
private String environmentId;
private String testPlanId;
private ApiTestCaseWithBLOBs bloBs;
private ApiDefinitionExecResult report;
}

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.EsbApiParamsWithBLOBs;
@ -21,5 +22,8 @@ public class ApiDefinitionImport {
//ESB文件导入的附属数据类
private Map<String,EsbApiParamsWithBLOBs> esbApiParamsMap;
//Mock数据相关
private List<MockConfigImportDTO> mocks;
private List<NodeTree> nodeTree;
}

View File

@ -268,18 +268,33 @@ public class ElementUtil {
}
};
private static void formatSampler(JSONObject element) {
if (element == null || StringUtils.isEmpty(element.getString("type"))) {
return;
}
if (element.get("clazzName") == null && element.getString("type").equals("TCPSampler")) {
if (element.getString("tcpPreProcessor") != null) {
JSONObject tcpPreProcessor = JSON.parseObject(element.getString("tcpPreProcessor"));
if (tcpPreProcessor != null && tcpPreProcessor.get("clazzName") == null) {
tcpPreProcessor.fluentPut("clazzName", clazzMap.get(tcpPreProcessor.getString("type")));
element.fluentPut("tcpPreProcessor", tcpPreProcessor);
}
}
} else if (element.getString("type").equals("HTTPSamplerProxy")) {
if (element.getString("authManager") != null) {
JSONObject authManager = JSON.parseObject(element.getString("authManager"));
if (authManager != null && authManager.get("clazzName") == null) {
authManager.fluentPut("clazzName", clazzMap.get(authManager.getString("type")));
element.fluentPut("authManager", authManager);
}
}
}
}
public static void dataFormatting(JSONArray hashTree) {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
if (element != null && element.get("clazzName") == null && element.getString("type").equals("TCPSampler")) {
if (element.getString("tcpPreProcessor") != null) {
JSONObject tcpPreProcessor = JSON.parseObject(element.getString("tcpPreProcessor"));
if (tcpPreProcessor != null && tcpPreProcessor.get("clazzName") == null) {
tcpPreProcessor.fluentPut("clazzName", clazzMap.get(tcpPreProcessor.getString("type")));
element.fluentPut("tcpPreProcessor", tcpPreProcessor);
}
}
}
formatSampler(element);
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
@ -294,6 +309,7 @@ public class ElementUtil {
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
formatSampler(element);
if (element != null && element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray);
@ -304,7 +320,28 @@ public class ElementUtil {
try {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
if (element != null && element.get("type").toString().equals("HTTPSamplerProxy")) {
boolean isScenarioEnv = false;
ParameterConfig config = new ParameterConfig();
if (element != null && element.get("type").toString().equals("scenario")) {
MsScenario scenario = JSONObject.toJavaObject(element, MsScenario.class);
if (scenario.isEnvironmentEnable()) {
isScenarioEnv = true;
Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
Map<String, String> environmentMap = (Map<String, String>) element.get("environmentMap");
if (environmentMap != null && !environmentMap.isEmpty()) {
environmentMap.keySet().forEach(projectId -> {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentMap.get(projectId));
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
env.setApiEnvironmentid(environment.getId());
envConfig.put(projectId, env);
}
});
config.setConfig(envConfig);
}
}
} else if (element != null && element.get("type").toString().equals("HTTPSamplerProxy")) {
MsHTTPSamplerProxy httpSamplerProxy = JSON.toJavaObject(element, MsHTTPSamplerProxy.class);
if (httpSamplerProxy != null
&& (!httpSamplerProxy.isCustomizeReq() || (httpSamplerProxy.isCustomizeReq() && httpSamplerProxy.getIsRefEnvironment()))) {
@ -320,7 +357,11 @@ public class ElementUtil {
}
if (element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataSetDomain(elementJSONArray, msParameter);
if (isScenarioEnv) {
dataSetDomain(elementJSONArray, config);
} else {
dataSetDomain(elementJSONArray, msParameter);
}
}
}
} catch (Exception e) {

View File

@ -64,9 +64,12 @@ public class MsScenario extends MsTestElement {
@JSONField(ordinal = 27)
private Map<String, String> environmentMap;
@JSONField(ordinal = 24)
@JSONField(ordinal = 28)
private Boolean onSampleError;
@JSONField(ordinal = 29)
private boolean environmentEnable;
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
public MsScenario() {
@ -152,8 +155,7 @@ public class MsScenario extends MsTestElement {
}
} else {
Map<String, EnvironmentConfig> map = config.getConfig();
for (EnvironmentConfig evnConfig :
map.values()) {
for (EnvironmentConfig evnConfig : map.values()) {
if (evnConfig.getHttpConfig() != null) {
this.setMockEnvironment(evnConfig.getHttpConfig().isMock());
}
@ -174,12 +176,32 @@ public class MsScenario extends MsTestElement {
//setHeader(tree, this.headers);
config.setHeaders(this.headers);
}
ParameterConfig newConfig = new ParameterConfig();
if (this.isEnvironmentEnable() && this.environmentMap != null && !this.environmentMap.isEmpty()) {
environmentMap.keySet().forEach(projectId -> {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(this.environmentMap.get(projectId));
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
env.setApiEnvironmentid(environment.getId());
envConfig.put(projectId, env);
if (StringUtils.equals(environment.getName(), MockConfigStaticData.MOCK_EVN_NAME)) {
this.setMockEnvironment(true);
}
}
});
newConfig.setConfig(envConfig);
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
// 给所有孩子加一个父亲标志
el.setParent(this);
el.setMockEnvironment(this.isMockEnvironment());
el.toHashTree(tree, el.getHashTree(), config);
if (this.isEnvironmentEnable()) {
el.toHashTree(tree, el.getHashTree(), newConfig);
} else {
el.toHashTree(tree, el.getHashTree(), config);
}
}
}
}

View File

@ -47,7 +47,7 @@ public class MsDNSCacheManager extends MsTestElement {
}
public static void addEnvironmentDNS(HashTree samplerHashTree, String name, EnvironmentConfig config, HttpConfig httpConfig) {
if (config.getCommonConfig().isEnableHost() && CollectionUtils.isNotEmpty(config.getCommonConfig().getHosts()) && httpConfig != null) {
if (config.getCommonConfig().isEnableHost() && CollectionUtils.isNotEmpty(config.getCommonConfig().getHosts()) && httpConfig != null && httpConfig.getDomain() != null) {
String domain = httpConfig.getDomain().trim();
List<Host> hosts = new ArrayList<>();
config.getCommonConfig().getHosts().forEach(host -> {

View File

@ -1,7 +1,6 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
@ -225,16 +224,14 @@ public class MsHTTPSamplerProxy extends MsTestElement {
setSamplerPath(config, httpConfig, sampler);
// 请求体
if (!StringUtils.equals(this.getMethod(), "GET")) {
if (this.body != null) {
List<KeyValue> bodyParams = this.body.getBodyParams(sampler, this.getId());
if (StringUtils.isNotEmpty(this.body.getType()) && "Form Data".equals(this.body.getType())) {
sampler.setDoMultipart(true);
}
if (CollectionUtils.isNotEmpty(bodyParams)) {
sampler.setArguments(httpArguments(bodyParams));
}
// 请求体处理
if (this.body != null) {
List<KeyValue> bodyParams = this.body.getBodyParams(sampler, this.getId());
if (StringUtils.isNotEmpty(this.body.getType()) && "Form Data".equals(this.body.getType())) {
sampler.setDoMultipart(true);
}
if (CollectionUtils.isNotEmpty(bodyParams)) {
sampler.setArguments(httpArguments(bodyParams));
}
}
@ -305,7 +302,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
preProcessor.toHashTree(httpSamplerTree, preProcessor.getHashTree(), config);
}
if (postProcessor != null && StringUtils.isNotEmpty(preProcessor.getScript())) {
if (postProcessor != null && StringUtils.isNotEmpty(postProcessor.getScript())) {
if (postProcessor.getEnvironmentId() == null) {
if (this.getEnvironmentId() == null) {
postProcessor.setEnvironmentId(useEnvironment);

View File

@ -0,0 +1,15 @@
package io.metersphere.api.dto.mockconfig;
import io.metersphere.base.domain.MockExpectConfigWithBLOBs;
import lombok.Getter;
import lombok.Setter;
/**
* @author song.tianyang
* @Date 2021/9/27 5:54 下午
*/
@Getter
@Setter
public class MockConfigImportDTO extends MockExpectConfigWithBLOBs {
public String apiId;
}

View File

@ -56,5 +56,8 @@ public class APIBackendListenerHandler {
if (!MessageCache.reportCache.containsKey(testId) && resultService.getProcessCache().containsKey(testId)) {
resultService.getProcessCache().remove(testId);
}
if(StringUtils.isNotEmpty(testId)) {
MessageCache.executionQueue.remove(testId);
}
}
}

View File

@ -32,12 +32,12 @@ public class FixedTask {
MessageCache.cache.remove(key);
} else {
try {
int number = 0;
if (guardTask.containsKey(key)) {
number = guardTask.get(key);
guardTask.put(key, number++);
} else {
int number = guardTask.get(key);
number +=1;
guardTask.put(key, number);
} else {
guardTask.put(key, 0);
}
if (CollectionUtils.isNotEmpty(counter.getPoolUrls()) && counter.getNumber() > 0 && guardTask.get(key) > 200) {
// 资源池中已经没有执行的请求了

View File

@ -43,6 +43,7 @@ public class JMeterVars {
for (String item : extracts) {
String nrKey = item + "_matchNr";
Object nr = vars.get(nrKey);
JMeterVariables jMeterVariables = new JMeterVariables();
if (nr != null) {
int nrv = 0;
try {
@ -55,10 +56,14 @@ public class JMeterVars {
data.add(vars.get(item + "_" + i));
}
String array = JSON.toJSONString(data);
vars.put(item, array);
jMeterVariables.put(item, array);
}
}
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
if (jMeterVariables.get(item) != null) {
vs.put(item, jMeterVariables.get(item));
} else {
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
}
}
vs.remove("TESTSTART.MS"); // 标示变量移除
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.jmeter;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import org.apache.jmeter.engine.StandardJMeterEngine;
import javax.websocket.Session;
@ -16,4 +17,10 @@ public class MessageCache {
public static ConcurrentHashMap<String, StandardJMeterEngine> runningEngine = new ConcurrentHashMap<>();
public static ConcurrentLinkedDeque<String> terminationOrderDeque = new ConcurrentLinkedDeque<>();
public static ConcurrentHashMap<String, ApiDefinitionExecResult> batchTestCases = new ConcurrentHashMap<>();
// 串行执行队列 KEY=报告ID VALUE=开始时间
public static Map<String, Long> executionQueue = new HashMap<>();
}

View File

@ -121,9 +121,9 @@ public class TestResult {
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
String array[] = item.getName().split(SEPARATOR);
item.setName(array[1] + array[0]);
item.getSubRequestResults().forEach(subItem -> {
subItem.setName(array[0]);
});
// item.getSubRequestResults().forEach(subItem -> {
// subItem.setName(array[0]);
// });
} else {
this.genScenarioInSubRequestResult(item);
}

View File

@ -51,7 +51,9 @@ import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testplan.FileOperationRequest;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.comparators.FixedOrderComparator;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
@ -714,6 +716,10 @@ public class ApiAutomationService {
}
if (StringUtils.equals(tr.getType(), "scenario")) {
MsScenario scenario = (MsScenario) tr;
if (scenario.isEnvironmentEnable()) {
continue;
}
env.getProjectIds().add(tr.getProjectId());
}
if (CollectionUtils.isNotEmpty(tr.getHashTree())) {
@ -786,6 +792,10 @@ public class ApiAutomationService {
}
}
if (StringUtils.equals(tr.getType(), "scenario")) {
MsScenario scenario = (MsScenario) tr;
if (scenario.isEnvironmentEnable()) {
continue;
}
env.getProjectIds().add(tr.getProjectId());
}
if (CollectionUtils.isNotEmpty(tr.getHashTree())) {
@ -989,11 +999,19 @@ public class ApiAutomationService {
// 生成集成报告
String serialReportId = null;
StringBuilder idStr = new StringBuilder();
ids.forEach(item -> {
idStr.append("\"").append(item).append("\"").append(",");
});
List<ApiScenarioWithBLOBs> apiScenarios = extApiScenarioMapper.selectByIds(idStr.toString().substring(0, idStr.toString().length() - 1), "\"" + StringUtils.join(ids, ",") + "\"");
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(ids);
List<ApiScenarioWithBLOBs> apiScenarios = apiScenarioMapper.selectByExampleWithBLOBs(example);
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (request.getCondition() == null || !request.getCondition().isSelectAll()) {
// 按照id指定顺序排序
FixedOrderComparator<String> fixedOrderComparator = new FixedOrderComparator<String>(ids);
fixedOrderComparator.setUnknownObjectBehavior(FixedOrderComparator.UnknownObjectBehavior.BEFORE);
BeanComparator beanComparator = new BeanComparator("id", fixedOrderComparator);
Collections.sort(apiScenarios, beanComparator);
}
}
// 只有一个场景且没有测试步骤则提示
if (apiScenarios != null && apiScenarios.size() == 1 && (apiScenarios.get(0).getStepTotal() == null || apiScenarios.get(0).getStepTotal() == 0)) {
MSException.throwException((apiScenarios.get(0).getName() + "" + Translator.get("automation_exec_info")));
@ -1154,6 +1172,7 @@ public class ApiAutomationService {
MessageCache.terminationOrderDeque.remove(key);
break;
}
MessageCache.executionQueue.put(key, System.currentTimeMillis());
reportIds.add(key);
APIScenarioReportResult report = executeQueue.get(key).getReport();
if (StringUtils.isNotEmpty(serialReportId)) {
@ -1185,6 +1204,7 @@ public class ApiAutomationService {
executeEnvParams = hashTreeUtil.mergeParamDataMap(executeEnvParams, envParamsMap);
} catch (Exception e) {
reportIds.remove(key);
MessageCache.executionQueue.remove(key);
LogUtil.error("执行终止:" + e.getMessage());
break;
}
@ -1852,6 +1872,7 @@ public class ApiAutomationService {
List<ApiMethodUrlDTO> useUrl = this.parseUrl(scenarioWithBLOBs);
scenarioWithBLOBs.setUseUrl(JSONArray.toJSONString(useUrl));
scenarioWithBLOBs.setOrder(getImportNextOrder(request.getProjectId()));
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
batchMapper.insert(scenarioWithBLOBs);
apiScenarioReferenceIdService.saveByApiScenario(scenarioWithBLOBs);
}
@ -1952,21 +1973,21 @@ public class ApiAutomationService {
hashTree.set(i, object);
}
} else {
ApiScenarioWithBLOBs bloBs = this.getDto(object.getString("id"));
ApiScenarioWithBLOBs bloBs = apiScenarioMapper.selectByPrimaryKey(object.getString("id"));
if (bloBs != null) {
object = JSON.parseObject(bloBs.getScenarioDefinition());
hashTree.set(i, object);
}
}
} else if ("scenario".equals(object.getString("type"))) {
ApiScenarioWithBLOBs bloBs = this.getDto(object.getString("id"));
ApiScenarioWithBLOBs bloBs = apiScenarioMapper.selectByPrimaryKey(object.getString("id"));
if (bloBs != null) {
object = JSON.parseObject(bloBs.getScenarioDefinition());
hashTree.set(i, object);
}
}
}
if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) {
if (object != null && CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) {
setHashTree(object.getJSONArray("hashTree"));
}
}
@ -1985,8 +2006,10 @@ public class ApiAutomationService {
if (StringUtils.isNotEmpty(item.getScenarioDefinition())) {
JSONObject scenario = JSONObject.parseObject(item.getScenarioDefinition());
JSONArray hashTree = scenario.getJSONArray("hashTree");
setHashTree(hashTree);
scenario.put("hashTree", hashTree);
if (hashTree != null) {
setHashTree(hashTree);
scenario.put("hashTree", hashTree);
}
item.setScenarioDefinition(JSON.toJSONString(scenario));
}
});
@ -2608,4 +2631,9 @@ public class ApiAutomationService {
extApiScenarioMapper::getLastOrder,
apiScenarioMapper::updateByPrimaryKeySelective);
}
public boolean checkScenarioEnv(ApiScenarioWithBLOBs request) {
return this.checkScenarioEnv(request, null);
}
}

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
@ -57,7 +58,8 @@ public class ApiDefinitionExecResultService {
TestCaseReviewApiCaseMapper testCaseReviewApiCaseMapper;
@Resource
SqlSessionFactory sqlSessionFactory;
private ApiDefinitionService apiDefinitionService;
@Resource
private NoticeSendService noticeSendService;
@ -67,13 +69,14 @@ public class ApiDefinitionExecResultService {
public void saveApiResult(TestResult result, String type, String triggerMode) {
if (CollectionUtils.isNotEmpty(result.getScenarios())) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper definitionExecResultMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
final boolean[] isFirst = {true};
result.getScenarios().forEach(scenarioResult -> {
if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) {
scenarioResult.getRequestResults().forEach(item -> {
ApiDefinitionExecResult saveResult = definitionExecResultMapper.selectByPrimaryKey(result.getTestId());
ApiDefinitionExecResult saveResult = MessageCache.batchTestCases.get(result.getTestId());
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId());
}
item.getResponseResult().setConsole(result.getConsole());
boolean saved = true;
if (saveResult == null || scenarioResult.getRequestResults().size() > 1) {
@ -88,6 +91,7 @@ public class ApiDefinitionExecResultService {
saveResult.setName(item.getName());
saveResult.setTriggerMode(triggerMode);
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (StringUtils.isNotEmpty(result.getUserId())) {
saveResult.setUserId(result.getUserId());
} else {
@ -98,7 +102,6 @@ public class ApiDefinitionExecResultService {
String status = item.isSuccess() ? "success" : "error";
saveResult.setName(getName(type, item.getName(), status, saveResult.getCreateTime(), saveResult.getId()));
saveResult.setStatus(status);
saveResult.setCreateTime(item.getStartTime());
saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime());
@ -108,23 +111,23 @@ public class ApiDefinitionExecResultService {
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) {
prevResult.setContent(null);
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
if (!saved) {
definitionExecResultMapper.insert(saveResult);
apiDefinitionExecResultMapper.insert(saveResult);
} else {
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
}
apiDefinitionService.removeCache(result.getTestId());
// 发送通知
sendNotice(saveResult);
});
}
});
sqlSession.flushStatements();
}
}
@ -205,6 +208,7 @@ public class ApiDefinitionExecResultService {
// 更新用例最后执行结果
caseWithBLOBs.setLastResultId(resourceId);
caseWithBLOBs.setStatus(status);
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
return caseWithBLOBs.getName();
}
@ -283,7 +287,7 @@ public class ApiDefinitionExecResultService {
if (StringUtils.equals(type, ApiRunMode.SCHEDULE_API_PLAN.name())) {
TestPlanApiCase apiCase = testPlanApiCaseService.getById(item.getName());
if(StringUtils.isEmpty(creator)){
if (StringUtils.isEmpty(creator)) {
creator = testPlanService.findScheduleCreateUserById(apiCase.getTestPlanId());
}
apiCase.setStatus(status);
@ -298,7 +302,7 @@ public class ApiDefinitionExecResultService {
testPlanApiCaseService.setExecResult(item.getName(), status, item.getStartTime());
testCaseReviewApiCaseService.setExecResult(item.getName(), status, item.getStartTime());
}
if(creator == null){
if (creator == null) {
creator = "";
}
saveResult.setUserId(creator);

View File

@ -14,6 +14,7 @@ import io.metersphere.api.dto.definition.parse.Swagger3Parser;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.RequestType;
@ -97,8 +98,6 @@ public class ApiDefinitionService {
@Resource
private ExtSwaggerUrlScheduleMapper extSwaggerUrlScheduleMapper;
@Resource
private ScheduleMapper scheduleMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiTestEnvironmentService environmentService;
@ -117,7 +116,7 @@ public class ApiDefinitionService {
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
private static Cache cache = Cache.newHardMemoryCache(0, 3600);
private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -212,6 +211,8 @@ public class ApiDefinitionService {
extApiDefinitionExecResultMapper.deleteByResourceId(apiId);
apiDefinitionMapper.deleteByPrimaryKey(apiId);
esbApiParamService.deleteByResourceId(apiId);
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
mockConfigService.deleteMockConfigByApiId(apiId);
FileUtils.deleteBodyFiles(apiId);
}
@ -220,6 +221,11 @@ public class ApiDefinitionService {
example.createCriteria().andIdIn(apiIds);
esbApiParamService.deleteByResourceIdIn(apiIds);
apiDefinitionMapper.deleteByExample(example);
apiTestCaseService.deleteBatchByDefinitionId(apiIds);
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
for (String apiId : apiIds) {
mockConfigService.deleteMockConfigByApiId(apiId);
}
}
public void removeToGc(List<String> apiIds) {
@ -467,7 +473,7 @@ public class ApiDefinitionService {
}
private ApiDefinition importCreate(ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionMapper batchMapper,
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases,
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases, List<MockConfigImportDTO> mocks,
Boolean repeatable) {
SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest();
BeanUtils.copyBean(saveReq, apiDefinition);
@ -494,7 +500,7 @@ public class ApiDefinitionService {
sameRequest = getSameRequestById(apiDefinition.getId(), apiTestImportRequest.getProjectId());
}
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases);
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases, mocks);
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
if (CollectionUtils.isEmpty(sameRequest)) {
//postman 可能含有前置脚本接口定义去掉脚本
@ -505,10 +511,10 @@ public class ApiDefinitionService {
String requestStr = setImportHashTree(apiDefinition);
reSetImportCasesApiId(cases, originId, apiDefinition.getId());
apiDefinition.setRequest(requestStr);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
importApiCase(apiDefinition, apiTestImportRequest);
}
} else {
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases);
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases, mocks);
}
return apiDefinition;
@ -535,17 +541,18 @@ public class ApiDefinitionService {
}
private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition,
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases) {
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases ,List<MockConfigImportDTO> mocks) {
String originId = apiDefinition.getId();
if (CollectionUtils.isEmpty(sameRequest)) {
apiDefinition.setId(UUID.randomUUID().toString());
apiDefinition.setOrder(getImportNextOrder(apiTestImportRequest.getProjectId()));
reSetImportCasesApiId(cases, originId, apiDefinition.getId());
reSetImportMocksApiId(mocks, originId, apiDefinition.getId());
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), RequestType.HTTP)) {
batchMapper.insert(apiDefinition);
String request = setImportHashTree(apiDefinition);
apiDefinition.setRequest(request);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
importApiCase(apiDefinition, apiTestImportRequest);
} else {
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
setImportTCPHashTree(apiDefinition);
@ -565,7 +572,7 @@ public class ApiDefinitionService {
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
apiDefinition.setRequest(request);
reSetImportCasesApiId(cases, originId, apiDefinition.getId());
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false);
importApiCase(apiDefinition, apiTestImportRequest);
} else {
apiDefinition.setId(sameRequest.get(0).getId());
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
@ -596,6 +603,16 @@ public class ApiDefinitionService {
}
}
private void reSetImportMocksApiId(List<MockConfigImportDTO> mocks, String originId, String newId) {
if (CollectionUtils.isNotEmpty(mocks)) {
mocks.forEach(item -> {
if (StringUtils.equals(item.getApiId(), originId)) {
item.setApiId(newId);
}
});
}
}
private String setImportHashTree(ApiDefinitionWithBLOBs apiDefinition) {
String request = apiDefinition.getRequest();
MsHTTPSamplerProxy msHTTPSamplerProxy = JSONObject.parseObject(request, MsHTTPSamplerProxy.class);
@ -614,7 +631,7 @@ public class ApiDefinitionService {
return request;
}
private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession, ApiTestCaseMapper apiTestCaseMapper,
private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession,
ApiTestImportRequest request) {
List<ApiTestCaseWithBLOBs> cases = apiImport.getCases();
if (CollectionUtils.isNotEmpty(cases)) {
@ -625,7 +642,7 @@ public class ApiDefinitionService {
if (apiDefinitionWithBLOBs == null) {
continue;
}
insertOrUpdateImportCase(item, request);
insertOrUpdateImportCase(item, request, apiDefinitionWithBLOBs);
}
if (batchCount % 300 == 0) {
sqlSession.flushStatements();
@ -637,8 +654,7 @@ public class ApiDefinitionService {
* 导入是插件或者postman时创建用例
* postman考虑是否有前置脚本
*/
private void importApiCase(ApiDefinitionWithBLOBs apiDefinition, ApiTestCaseMapper apiTestCaseMapper,
ApiTestImportRequest apiTestImportRequest, Boolean isInsert) {
private void importApiCase(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest apiTestImportRequest) {
try {
if (StringUtils.equalsAnyIgnoreCase(apiTestImportRequest.getPlatform(), ApiImportPlatform.Plugin.name(), ApiImportPlatform.Postman.name())) {
ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs();
@ -648,14 +664,14 @@ public class ApiDefinitionService {
if (apiTestCase.getName().length() > 255) {
apiTestCase.setName(apiTestCase.getName().substring(0, 255));
}
insertOrUpdateImportCase(apiTestCase, apiTestImportRequest);
insertOrUpdateImportCase(apiTestCase, apiTestImportRequest, apiDefinition);
}
} catch (Exception e) {
LogUtil.error("导入创建用例异常", e);
}
}
private void insertOrUpdateImportCase(ApiTestCaseWithBLOBs apiTestCase, ApiTestImportRequest apiTestImportRequest) {
private void insertOrUpdateImportCase(ApiTestCaseWithBLOBs apiTestCase, ApiTestImportRequest apiTestImportRequest, ApiDefinitionWithBLOBs apiDefinition) {
SaveApiTestCaseRequest checkRequest = new SaveApiTestCaseRequest();
checkRequest.setName(apiTestCase.getName());
checkRequest.setApiDefinitionId(apiTestCase.getApiDefinitionId());
@ -667,7 +683,7 @@ public class ApiDefinitionService {
apiTestCase.setUpdateUserId(SessionUtils.getUserId());
if (sameCase == null) {
apiTestCase.setId(UUID.randomUUID().toString());
apiTestCase.setNum(apiTestCaseService.getNextNum(apiTestCase.getApiDefinitionId()));
apiTestCase.setNum(apiTestCaseService.getNextNum(apiTestCase.getApiDefinitionId(), apiDefinition.getNum()));
apiTestCase.setCreateTime(System.currentTimeMillis());
apiTestCase.setUpdateTime(System.currentTimeMillis());
apiTestCase.setCreateUserId(SessionUtils.getUserId());
@ -800,6 +816,12 @@ public class ApiDefinitionService {
return null;
}
public void removeCache(String testId) {
if (StringUtils.isNotEmpty(testId)) {
cache.remove(testId);
}
}
/**
* 获取存储执行结果报告
*
@ -932,14 +954,14 @@ public class ApiDefinitionService {
if (apiImport.getEsbApiParamsMap() != null) {
String apiId = item.getId();
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), project.getRepeatable());
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), apiImport.getMocks(), project.getRepeatable());
if (model != null) {
apiImport.getEsbApiParamsMap().remove(apiId);
model.setResourceId(item.getId());
apiImport.getEsbApiParamsMap().put(item.getId(), model);
}
} else {
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), project.getRepeatable());
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), apiImport.getMocks(), project.getRepeatable());
}
if (i % 300 == 0) {
sqlSession.flushStatements();
@ -963,8 +985,13 @@ public class ApiDefinitionService {
}
}
if (!CollectionUtils.isEmpty(apiImport.getMocks())) {
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
mockConfigService.importMock(apiImport, sqlSession, request);
}
if (!CollectionUtils.isEmpty(apiImport.getCases())) {
importMsCase(apiImport, sqlSession, apiTestCaseMapper, request);
importMsCase(apiImport, sqlSession, request);
}
}
@ -1051,6 +1078,7 @@ public class ApiDefinitionService {
public void deleteByParams(ApiBatchRequest request) {
apiDefinitionMapper.deleteByExample(getBatchExample(request));
apiTestCaseService.deleteBatchByDefinitionId(request.getIds());
}
public ApiDefinitionExample getBatchExample(ApiBatchRequest request) {
@ -1248,9 +1276,11 @@ public class ApiDefinitionService {
example.createCriteria().andIdIn(request.getIds());
if (StringUtils.equals(type, "MS")) { // 导出为 Metersphere 格式
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
apiExportResult = new MsApiExportResult();
((MsApiExportResult) apiExportResult).setData(apiDefinitionMapper.selectByExampleWithBLOBs(example));
((MsApiExportResult) apiExportResult).setCases(apiTestCaseService.selectCasesBydApiIds(request.getIds()));
((MsApiExportResult) apiExportResult).setMocks(mockConfigService.selectMockExpectConfigByApiIdIn(request.getIds()));
((MsApiExportResult) apiExportResult).setProjectName(request.getProjectId());
((MsApiExportResult) apiExportResult).setProtocol(request.getProtocol());
((MsApiExportResult) apiExportResult).setProjectId(request.getProjectId());

View File

@ -342,7 +342,7 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionMapper apiDefinitionMapper = sqlSession.getMapper(ApiDefinitionMapper.class);
apiModule.forEach((value) -> {
apiDefinitionMapper.updateByPrimaryKey(value);
apiDefinitionMapper.updateByPrimaryKeySelective(value);
});
sqlSession.flushStatements();
}

View File

@ -287,7 +287,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
private void batchUpdateApiScenario(List<ApiScenarioDTO> apiScenarios) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioMapper apiScenarioMapper = sqlSession.getMapper(ApiScenarioMapper.class);
apiScenarios.forEach(apiScenarioMapper::updateByPrimaryKey);
apiScenarios.forEach(apiScenarioMapper::updateByPrimaryKeySelective);
sqlSession.flushStatements();
}

View File

@ -18,6 +18,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
@ -396,6 +397,18 @@ public class ApiTestCaseService {
}
}
public int getNextNum(String definitionId, Integer definitionNum) {
ApiTestCase apiTestCase = extApiTestCaseMapper.getNextNum(definitionId);
if (apiTestCase == null) {
if (definitionNum == null) {
return apiDefinitionMapper.selectByPrimaryKey(definitionId).getNum() * 1000 + 1;
}
return definitionNum * 1000 + 1;
} else {
return Optional.of(apiTestCase.getNum() + 1)
.orElse(apiDefinitionMapper.selectByPrimaryKey(definitionId).getNum() * 1000 + 1);
}
}
private void deleteFileByTestId(String testId) {
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
@ -433,6 +446,17 @@ public class ApiTestCaseService {
apiTestCaseMapper.deleteByExample(example);
}
public void deleteBatchByDefinitionId(List<String> definitionIds) {
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andApiDefinitionIdIn(definitionIds);
apiTestCaseMapper.deleteByExample(example);
List<ApiTestCase> apiTestCases = apiTestCaseMapper.selectByExample(example);
List<String> caseIds = apiTestCases.stream().map(ApiTestCase::getId).collect(Collectors.toList());
for (String testId : caseIds) {
extTestPlanTestCaseMapper.deleteByTestCaseID(testId);
}
}
public void relevanceByApi(ApiCaseRelevanceRequest request) {
if (CollectionUtils.isEmpty(request.getSelectIds())) {
return;
@ -471,7 +495,7 @@ public class ApiTestCaseService {
ExtTestPlanApiCaseMapper batchMapper = sqlSession.getMapper(ExtTestPlanApiCaseMapper.class);
Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanApiCaseMapper::getLastOrder);
for (ApiTestCase apiTestCase: apiTestCases) {
for (ApiTestCase apiTestCase : apiTestCases) {
TestPlanApiCase testPlanApiCase = new TestPlanApiCase();
testPlanApiCase.setId(UUID.randomUUID().toString());
testPlanApiCase.setCreateUser(SessionUtils.getUserId());
@ -678,50 +702,54 @@ public class ApiTestCaseService {
public void batchRun(ApiCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery(query));
Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>();
(query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest) query));
List<RunCaseRequest> executeQueue = new LinkedList<>();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
for (String testCaseId : request.getIds()) {
ApiDefinitionExecResult report = addResult(testCaseId, APITestStatus.Running.name());
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testCaseId);
if (caseWithBLOBs != null) {
report.setName(caseWithBLOBs.getName());
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
}
batchMapper.insert(report);
executeQueue.put(testCaseId, report);
}
sqlSession.flushStatements();
for (String caseId : executeQueue.keySet()) {
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdIn(request.getIds());
List<ApiTestCaseWithBLOBs> list = apiTestCaseMapper.selectByExampleWithBLOBs(example);
ApiTestCaseMapper sqlSessionMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
for (ApiTestCaseWithBLOBs caseWithBLOBs : list) {
ApiDefinitionExecResult report = addResult(caseWithBLOBs.getId(), APITestStatus.Running.name());
report.setName(caseWithBLOBs.getName());
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
sqlSessionMapper.updateByPrimaryKey(caseWithBLOBs);
// 执行对象
RunCaseRequest runCaseRequest = new RunCaseRequest();
runCaseRequest.setRunMode(ApiRunMode.DEFINITION.name());
runCaseRequest.setCaseId(caseId);
runCaseRequest.setReportId(executeQueue.get(caseId).getId());
runCaseRequest.setCaseId(caseWithBLOBs.getId());
runCaseRequest.setReportId(report.getId());
runCaseRequest.setEnvironmentId(request.getEnvironmentId());
runCaseRequest.setBloBs(caseWithBLOBs);
runCaseRequest.setReport(report);
batchMapper.insert(report);
executeQueue.add(runCaseRequest);
}
sqlSession.flushStatements();
for (RunCaseRequest runCaseRequest : executeQueue) {
run(runCaseRequest);
MessageCache.batchTestCases.put(runCaseRequest.getReportId(), runCaseRequest.getReport());
}
}
public String run(RunCaseRequest request) {
ApiTestCaseWithBLOBs testCaseWithBLOBs = null;
ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs();
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getReportId());
request.setCaseId(request.getReportId());
} else {
testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
//通过测试计划id查询环境
request.setReportId(request.getTestPlanId());
}
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS.name())) {
request.setReportId(request.getEnvironmentId());
}
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
//通过测试计划id查询环境
request.setReportId(request.getTestPlanId());
}
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
try {
@ -1066,6 +1094,7 @@ public class ApiTestCaseService {
/**
* 用例自定义排序
*
* @param request
*/
public void updateOrder(ResetOrderRequest request) {

View File

@ -4,9 +4,12 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.api.dto.mockconfig.MockConfigRequest;
import io.metersphere.api.dto.mockconfig.MockExpectConfigRequest;
import io.metersphere.api.dto.mockconfig.response.JsonSchemaReturnObj;
@ -23,6 +26,7 @@ import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.i18n.Translator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.json.XML;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -65,6 +69,28 @@ public class MockConfigService {
return this.assemblyMockConfingResponse(configList);
}
public List<MockExpectConfigWithBLOBs> selectMockExpectConfigByApiId(String apiId){
return extMockExpectConfigMapper.selectByApiId(apiId);
}
public List<MockConfigImportDTO> selectMockExpectConfigByApiIdIn(List<String> apiIds){
if(CollectionUtils.isNotEmpty(apiIds)){
List<MockConfigImportDTO> returnDTO = new ArrayList<>();
for (String apiId : apiIds) {
List<MockExpectConfigWithBLOBs> mockExpectConfigWithBLOBsList = extMockExpectConfigMapper.selectByApiId(apiId);
for (MockExpectConfigWithBLOBs model : mockExpectConfigWithBLOBsList) {
MockConfigImportDTO dto = new MockConfigImportDTO();
BeanUtils.copyBean(dto, model);
dto.setApiId(apiId);
returnDTO.add(dto);
}
}
return returnDTO;
}else {
return new ArrayList<>();
}
}
private MockConfigResponse assemblyMockConfingResponse(List<MockConfig> configList) {
if (!configList.isEmpty()) {
MockConfig config = configList.get(0);
@ -610,6 +636,19 @@ public class MockConfigService {
mockExpectConfigMapper.deleteByPrimaryKey(id);
}
public void deleteMockConfigByApiId(String apiId){
MockConfigExample configExample = new MockConfigExample();
configExample.createCriteria().andApiIdEqualTo(apiId);
List<MockConfig> mockConfigList = mockConfigMapper.selectByExample(configExample);
MockExpectConfigExample example = new MockExpectConfigExample();
for (MockConfig mockConfig : mockConfigList) {
example.clear();
example.createCriteria().andMockConfigIdEqualTo(mockConfig.getId());
mockExpectConfigMapper.deleteByExample(example);
}
mockConfigMapper.deleteByExample(configExample);
}
public JSONObject getGetParamMap(String urlParams, ApiDefinitionWithBLOBs api, HttpServletRequest request) {
JSONObject paramMap = this.getSendRestParamMapByIdAndUrl(api, urlParams);
Enumeration<String> paramNameItor = request.getParameterNames();
@ -1187,4 +1226,51 @@ public class MockConfigService {
}
return isJson;
}
public void importMock(ApiDefinitionImport apiImport, SqlSession sqlSession, ApiTestImportRequest request) {
if(CollectionUtils.isNotEmpty(apiImport.getMocks())){
Map<String,List<MockExpectConfigWithBLOBs>> saveMap = new HashMap<>();
for (MockConfigImportDTO dto : apiImport.getMocks()) {
String apiId = dto.getApiId();//de33108c-26e2-4d4f-826a-a5f8e017d2f4
if(saveMap.containsKey(apiId)){
saveMap.get(apiId).add(dto);
}else {
List<MockExpectConfigWithBLOBs> list = new ArrayList<>();
list.add(dto);
saveMap.put(apiId,list);
}
}
for (Map.Entry<String,List<MockExpectConfigWithBLOBs>> entry : saveMap.entrySet()) {
String apiId = entry.getKey();
this.deleteMockConfigByApiId(apiId);
List<MockExpectConfigWithBLOBs> list = entry.getValue();
String mockId = UUID.randomUUID().toString();
MockConfig config = new MockConfig();
config.setProjectId(request.getProjectId());
config.setId(mockId);
config.setCreateUserId(SessionUtils.getUserId());
config.setCreateTime(System.currentTimeMillis());
config.setUpdateTime(System.currentTimeMillis());
config.setApiId(apiId);
mockConfigMapper.insert(config);
int batchCount = 0;
for (MockExpectConfigWithBLOBs mockExpect : list) {
mockExpect.setId(UUID.randomUUID().toString());
mockExpect.setMockConfigId(mockId);
mockExpect.setCreateTime(System.currentTimeMillis());
mockExpect.setUpdateTime(System.currentTimeMillis());
mockExpect.setCreateUserId(SessionUtils.getUserId());
mockExpectConfigMapper.insert(mockExpect);
}
if (batchCount % 300 == 0) {
sqlSession.flushStatements();
}
}
}
}
}

View File

@ -150,11 +150,7 @@ public class TestResultService {
testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Failure.name());
}
}
if (reportTask != null) {
if (!StringUtils.equals(ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), runMode) && !StringUtils.equals(ApiRunMode.JENKINS_SCENARIO_PLAN.name(), runMode) && StringUtils.equals(ReportTriggerMode.API.name(), reportTask.getTriggerMode()) || StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), reportTask.getTriggerMode())) {
sendTask(reportTask, reportUrl, testResult);
}
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.error(e.getMessage(), e);
@ -193,66 +189,4 @@ public class TestResultService {
}
}
private static void sendTask(ApiTestReportVariable report, String reportUrl, TestResult testResult) {
if (report == null) {
return;
}
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
NoticeSendService noticeSendService = CommonBeanFactory.getBean(NoticeSendService.class);
assert systemParameterService != null;
assert noticeSendService != null;
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
String url = baseSystemConfigDTO.getUrl() + "/#/api/report/view/" + report.getId();
String url2 = baseSystemConfigDTO.getUrl() + "/#/api/automation/report/view/" + report.getId();
String successContext = "";
String failedContext = "";
String subject = "";
String event = "";
if (StringUtils.equals(ReportTriggerMode.API.name(), report.getTriggerMode())) {
successContext = "接口测试 API任务通知:jenkins所执行的" + report.getName() + "'执行成功" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "[接口定义暂无报告链接]" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试 API任务通知:jenkins所执行的" + report.getName() + "'执行失败" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "[接口定义暂无报告链接]" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
subject = Translator.get("task_notification_jenkins");
}
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), report.getTriggerMode())) {
successContext = "接口测试定时任务通知:定时任务所执行的" + report.getName() + "'执行成功" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "[接口定义暂无报告链接]" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试定时任务通知:定时任务所执行的" + report.getName() + "'执行失败" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "[接口定义暂无报告链接]" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
subject = Translator.get("task_notification");
}
if (StringUtils.equals("Success", report.getStatus())) {
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
}
if (StringUtils.equals("success", report.getStatus())) {
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
}
if (StringUtils.equals("Error", report.getStatus())) {
event = NoticeConstants.Event.EXECUTE_FAILED;
}
if (StringUtils.equals("error", report.getStatus())) {
event = NoticeConstants.Event.EXECUTE_FAILED;
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("testName", report.getName());
paramMap.put("id", report.getId());
paramMap.put("type", "api");
paramMap.put("url", baseSystemConfigDTO.getUrl());
paramMap.put("status", report.getStatus());
paramMap.put("executor", report.getExecutor());
paramMap.put("executionTime", report.getExecutionTime());
paramMap.put("executionEnvironment", report.getExecutionEnvironment());
paramMap.put("principal", report.getPrincipal());
NoticeModel noticeModel = NoticeModel.builder()
.operator(SessionUtils.getUserId())
.successContext(successContext)
.successMailTemplate("ApiSuccessfulNotification")
.failedContext(failedContext)
.failedMailTemplate("ApiFailedNotification")
.testId(testResult.getTestId())
.status(report.getStatus())
.event(event)
.subject(subject)
.paramMap(paramMap)
.build();
noticeSendService.send(report.getTriggerMode(), NoticeConstants.TaskType.API_DEFINITION_TASK, noticeModel);
}
}

View File

@ -34,7 +34,7 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
@Override
public T call() {
try {
if (runModeDataDTO.getReport()!=null && MessageCache.terminationOrderDeque.contains(runModeDataDTO.getReport().getId())) {
if (runModeDataDTO.getReport() != null && MessageCache.terminationOrderDeque.contains(runModeDataDTO.getReport().getId())) {
MessageCache.terminationOrderDeque.remove(runModeDataDTO.getReport().getId());
return null;
}
@ -43,25 +43,24 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
} else {
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
}
// 轮询查看报告状态最多200次防止死循环
int index = 1;
while (index < 200) {
Thread.sleep(3000);
index++;
report = apiScenarioReportMapper.selectByPrimaryKey(runModeDataDTO.getReport().getId());
if (report != null && !report.getStatus().equals(APITestStatus.Running.name())) {
while (MessageCache.executionQueue.containsKey(runModeDataDTO.getReport().getId())) {
long currentSecond = (System.currentTimeMillis() - MessageCache.executionQueue.get(runModeDataDTO.getReport().getId())) / 1000 / 60;
// 设置五分钟超时
if (currentSecond > 5) {
// 执行失败了恢复报告状态
report = apiScenarioReportMapper.selectByPrimaryKey(runModeDataDTO.getReport().getId());
if (report != null) {
report.setStatus(APITestStatus.Error.name());
apiScenarioReportMapper.updateByPrimaryKey(report);
}
break;
}
if (runModeDataDTO.getReport()!=null && MessageCache.terminationOrderDeque.contains(runModeDataDTO.getReport().getId())) {
if (runModeDataDTO.getReport() != null && MessageCache.terminationOrderDeque.contains(runModeDataDTO.getReport().getId())) {
MessageCache.terminationOrderDeque.remove(runModeDataDTO.getReport().getId());
break;
}
}
// 执行失败了恢复报告状态
if (index == 200 && report != null && report.getStatus().equals(APITestStatus.Running.name())) {
report.setStatus(APITestStatus.Error.name());
apiScenarioReportMapper.updateByPrimaryKey(report);
}
report = apiScenarioReportMapper.selectByPrimaryKey(runModeDataDTO.getReport().getId());
return (T) report;
} catch (Exception ex) {
LogUtil.error(ex);

View File

@ -34,7 +34,7 @@ public class TCPServer implements Runnable {
}
public boolean isSocketOpen(){
if (this.serverSocket != null && !this.serverSocket.isClosed() &&this.servicer != null) {
if (this.serverSocket != null && !this.serverSocket.isClosed()) {
return true;
}else {
return false;

View File

@ -23,5 +23,7 @@ public class TestCaseReviewTestCase implements Serializable {
private String createUser;
private Long order;
private static final long serialVersionUID = 1L;
}
}

View File

@ -713,6 +713,66 @@ public class TestCaseReviewTestCaseExample {
addCriterion("create_user not between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andOrderIsNull() {
addCriterion("`order` is null");
return (Criteria) this;
}
public Criteria andOrderIsNotNull() {
addCriterion("`order` is not null");
return (Criteria) this;
}
public Criteria andOrderEqualTo(Long value) {
addCriterion("`order` =", value, "order");
return (Criteria) this;
}
public Criteria andOrderNotEqualTo(Long value) {
addCriterion("`order` <>", value, "order");
return (Criteria) this;
}
public Criteria andOrderGreaterThan(Long value) {
addCriterion("`order` >", value, "order");
return (Criteria) this;
}
public Criteria andOrderGreaterThanOrEqualTo(Long value) {
addCriterion("`order` >=", value, "order");
return (Criteria) this;
}
public Criteria andOrderLessThan(Long value) {
addCriterion("`order` <", value, "order");
return (Criteria) this;
}
public Criteria andOrderLessThanOrEqualTo(Long value) {
addCriterion("`order` <=", value, "order");
return (Criteria) this;
}
public Criteria andOrderIn(List<Long> values) {
addCriterion("`order` in", values, "order");
return (Criteria) this;
}
public Criteria andOrderNotIn(List<Long> values) {
addCriterion("`order` not in", values, "order");
return (Criteria) this;
}
public Criteria andOrderBetween(Long value1, Long value2) {
addCriterion("`order` between", value1, value2, "order");
return (Criteria) this;
}
public Criteria andOrderNotBetween(Long value1, Long value2) {
addCriterion("`order` not between", value1, value2, "order");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
@ -807,4 +867,4 @@ public class TestCaseReviewTestCaseExample {
this(condition, value, secondValue, null);
}
}
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanPrincipal implements Serializable {
private String testPlanId;
private String principalId;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,340 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class TestPlanPrincipalExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestPlanPrincipalExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andTestPlanIdIsNull() {
addCriterion("test_plan_id is null");
return (Criteria) this;
}
public Criteria andTestPlanIdIsNotNull() {
addCriterion("test_plan_id is not null");
return (Criteria) this;
}
public Criteria andTestPlanIdEqualTo(String value) {
addCriterion("test_plan_id =", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotEqualTo(String value) {
addCriterion("test_plan_id <>", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThan(String value) {
addCriterion("test_plan_id >", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThanOrEqualTo(String value) {
addCriterion("test_plan_id >=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThan(String value) {
addCriterion("test_plan_id <", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThanOrEqualTo(String value) {
addCriterion("test_plan_id <=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLike(String value) {
addCriterion("test_plan_id like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotLike(String value) {
addCriterion("test_plan_id not like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdIn(List<String> values) {
addCriterion("test_plan_id in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotIn(List<String> values) {
addCriterion("test_plan_id not in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdBetween(String value1, String value2) {
addCriterion("test_plan_id between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotBetween(String value1, String value2) {
addCriterion("test_plan_id not between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andPrincipalIdIsNull() {
addCriterion("principal_id is null");
return (Criteria) this;
}
public Criteria andPrincipalIdIsNotNull() {
addCriterion("principal_id is not null");
return (Criteria) this;
}
public Criteria andPrincipalIdEqualTo(String value) {
addCriterion("principal_id =", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdNotEqualTo(String value) {
addCriterion("principal_id <>", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdGreaterThan(String value) {
addCriterion("principal_id >", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdGreaterThanOrEqualTo(String value) {
addCriterion("principal_id >=", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdLessThan(String value) {
addCriterion("principal_id <", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdLessThanOrEqualTo(String value) {
addCriterion("principal_id <=", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdLike(String value) {
addCriterion("principal_id like", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdNotLike(String value) {
addCriterion("principal_id not like", value, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdIn(List<String> values) {
addCriterion("principal_id in", values, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdNotIn(List<String> values) {
addCriterion("principal_id not in", values, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdBetween(String value1, String value2) {
addCriterion("principal_id between", value1, value2, "principalId");
return (Criteria) this;
}
public Criteria andPrincipalIdNotBetween(String value1, String value2) {
addCriterion("principal_id not between", value1, value2, "principalId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -11,6 +11,7 @@
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="order" jdbcType="BIGINT" property="order" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -71,7 +72,8 @@
</where>
</sql>
<sql id="Base_Column_List">
id, review_id, case_id, `status`, `result`, reviewer, create_time, update_time, create_user
id, review_id, case_id, `status`, `result`, reviewer, create_time, update_time, create_user,
`order`
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestCaseReviewTestCaseExample" resultMap="BaseResultMap">
select
@ -88,7 +90,7 @@
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
select
<include refid="Base_Column_List" />
from test_case_review_test_case
where id = #{id,jdbcType=VARCHAR}
@ -104,14 +106,14 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseReviewTestCase">
insert into test_case_review_test_case (id, review_id, case_id,
`status`, `result`, reviewer,
create_time, update_time, create_user
)
values (#{id,jdbcType=VARCHAR}, #{reviewId,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{result,jdbcType=VARCHAR}, #{reviewer,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR}
)
insert into test_case_review_test_case (id, review_id, case_id,
`status`, `result`, reviewer,
create_time, update_time, create_user,
`order`)
values (#{id,jdbcType=VARCHAR}, #{reviewId,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{result,jdbcType=VARCHAR}, #{reviewer,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR},
#{order,jdbcType=BIGINT})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseReviewTestCase">
insert into test_case_review_test_case
@ -143,6 +145,9 @@
<if test="createUser != null">
create_user,
</if>
<if test="order != null">
`order`,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -172,6 +177,9 @@
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="order != null">
#{order,jdbcType=BIGINT},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseReviewTestCaseExample" resultType="java.lang.Long">
@ -210,6 +218,9 @@
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.order != null">
`order` = #{record.order,jdbcType=BIGINT},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -225,7 +236,8 @@
reviewer = #{record.reviewer,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR}
create_user = #{record.createUser,jdbcType=VARCHAR},
`order` = #{record.order,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -257,6 +269,9 @@
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="order != null">
`order` = #{order,jdbcType=BIGINT},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -269,7 +284,8 @@
reviewer = #{reviewer,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR}
create_user = #{createUser,jdbcType=VARCHAR},
`order` = #{order,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>
</mapper>

View File

@ -144,7 +144,7 @@
from api_test_case atc
left join test_case_test tct on atc.id = tct.test_id
inner join api_definition ad on ad.id = atc.api_definition_id
where tct.test_id is NULL and ad.status != 'Trash'
where tct.test_id is NULL and atc.status != 'Trash'
<if test="request.protocol != null and request.protocol!=''">
and ad.protocol = #{request.protocol}
</if>

View File

@ -0,0 +1,22 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestPlanPrincipal;
import io.metersphere.base.domain.TestPlanPrincipalExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanPrincipalMapper {
long countByExample(TestPlanPrincipalExample example);
int deleteByExample(TestPlanPrincipalExample example);
int insert(TestPlanPrincipal record);
int insertSelective(TestPlanPrincipal record);
List<TestPlanPrincipal> selectByExample(TestPlanPrincipalExample example);
int updateByExampleSelective(@Param("record") TestPlanPrincipal record, @Param("example") TestPlanPrincipalExample example);
int updateByExample(@Param("record") TestPlanPrincipal record, @Param("example") TestPlanPrincipalExample example);
}

View File

@ -0,0 +1,140 @@
<?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.TestPlanPrincipalMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestPlanPrincipal">
<result column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<result column="principal_id" jdbcType="VARCHAR" property="principalId" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
test_plan_id, principal_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanPrincipalExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestPlanPrincipalExample">
delete from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanPrincipal">
insert into test_plan_principal (test_plan_id, principal_id)
values (#{testPlanId,jdbcType=VARCHAR}, #{principalId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanPrincipal">
insert into test_plan_principal
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="testPlanId != null">
test_plan_id,
</if>
<if test="principalId != null">
principal_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="testPlanId != null">
#{testPlanId,jdbcType=VARCHAR},
</if>
<if test="principalId != null">
#{principalId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanPrincipalExample" resultType="java.lang.Long">
select count(*) from test_plan_principal
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_principal
<set>
<if test="record.testPlanId != null">
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
</if>
<if test="record.principalId != null">
principal_id = #{record.principalId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_principal
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
principal_id = #{record.principalId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
</mapper>

View File

@ -48,7 +48,7 @@ public interface ExtApiTestCaseMapper {
List<String> selectNameByIdIn(@Param("ids")List<String> ids);
String selectNameById(String id);
List<String> selectIdsByQuery(BaseQueryRequest query);
List<String> selectIdsByQuery(@Param("request") ApiTestCaseRequest request);
List<String> selectProjectIds();

View File

@ -559,6 +559,9 @@
#{nodeId}
</foreach>
</if>
<if test="request.protocol != null and request.protocol !=''">
and a.protocol = #{request.protocol}
</if>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
@ -571,7 +574,7 @@
<select id="selectIdsByQuery" resultType="java.lang.String">
SELECT t1.id
FROM api_test_case t1
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
<if test="(request.moduleIds != null and request.moduleIds.size() > 0 ) or (request.protocol!=null and request.protocol!='' )">
inner join api_definition a on t1.api_definition_id = a.id
</if>
<include refid="queryWhereCondition"/>
@ -600,7 +603,7 @@
update api_test_case
set original_status=status,
status = 'Trash',delete_time = #{deleteTime},delete_user_id = #{deleteUserId}
where id IN
where status != 'Trash' AND id IN
<foreach collection="ids" item="v" separator="," open="(" close=")">
#{v}
</foreach>

View File

@ -1,10 +1,15 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.MockExpectConfigWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtMockExpectConfigMapper {
List<MockExpectConfigWithBLOBs> selectByProjectIdAndStatusIsOpen(String projectId);
List<MockExpectConfigWithBLOBs> selectByApiId(String apiId);
List<MockExpectConfigWithBLOBs> selectByApiIdIn(@Param("values") List<String> apiIds);
}

View File

@ -6,5 +6,19 @@
SELECT * FROM mock_expect_config WHERE status = 'true' AND mock_config_id IN
(SELECT id FROM mock_config WHERE api_path IS NULL AND project_id = #{0} )
</select>
<select id="selectByApiId" resultType="io.metersphere.base.domain.MockExpectConfigWithBLOBs">
SELECT * FROM mock_expect_config WHERE mock_config_id IN
(
SELECT id FROM mock_config WHERE api_id = #{0}
)
</select>
<select id="selectByApiIdIn" resultType="io.metersphere.base.domain.MockExpectConfigWithBLOBs">
SELECT * FROM mock_expect_config WHERE mock_config_id IN
(
SELECT id FROM mock_config WHERE api_id IN
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
)
</select>
</mapper>

View File

@ -0,0 +1,14 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.reportstatistics.dto.TestAnalysisChartRequest;
import io.metersphere.reportstatistics.dto.TestAnalysisChartResult;
import java.util.List;
public interface ExtTestAnalysisMapper {
List<TestAnalysisChartResult> getCraeteCaseReport(TestAnalysisChartRequest request);
List<TestAnalysisChartResult> getUpdateCaseReport(TestAnalysisChartRequest request);
}

View File

@ -0,0 +1,100 @@
<?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.ExtTestAnalysisMapper">
<select id="getCraeteCaseReport" resultType="io.metersphere.reportstatistics.dto.TestAnalysisChartResult">
select dateStr, ifnull(tt.num,0) countNum
from
(
select adddate('2019-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dateStr from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4
) v
left join
(select FROM_UNIXTIME(t.create_time/1000, '%Y-%m-%d') as create_times,t.project_id,t.node_id,t.priority,count(id) num ,t.maintainer from test_case t
WHERE project_id in
<foreach collection="projects" item="id" separator="," open="(" close=")">
#{id}
</foreach>
<if test="modules != null and modules.size() > 0">
and node_id in
<foreach collection="modules" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="prioritys != null and prioritys.size() > 0">
and priority in
<foreach collection="prioritys" item="p" separator="," open="(" close=")">
#{p}
</foreach>
</if>
<if test="users != null and users.size() > 0">
and maintainer in
<foreach collection="users" item="p" separator="," open="(" close=")">
#{p}
</foreach>
</if>
GROUP BY create_times
) tt
on dateStr = tt.create_times
where dateStr BETWEEN #{startTime} and #{endTime}
<if test="order == null or order == ''">
order by dateStr
</if>
<if test="order != null and order != ''">
order by countNum ${order}
</if>
</select>
<select id="getUpdateCaseReport" resultType="io.metersphere.reportstatistics.dto.TestAnalysisChartResult">
select dateStr, ifnull(tt.num,0) countNum
from
(
select adddate('2019-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) dateStr from
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4
) v
left join
(select FROM_UNIXTIME(t.update_time/1000, '%Y-%m-%d') as update_times,t.project_id,t.node_id,t.priority,t.create_time,t.update_time,count(id) num ,t.maintainer from test_case t
WHERE create_time!= update_time
and project_id in
<foreach collection="projects" item="id" separator="," open="(" close=")">
#{id}
</foreach>
<if test="modules != null and modules.size() > 0">
and node_id in
<foreach collection="modules" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="prioritys != null and prioritys.size() > 0">
and priority in
<foreach collection="prioritys" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
<if test="users != null and users.size() > 0">
and maintainer in
<foreach collection="users" item="p" separator="," open="(" close=")">
#{p}
</foreach>
</if>
GROUP BY update_times
) tt
on dateStr = tt.update_times
where dateStr BETWEEN #{startTime} and #{endTime}
<if test="order == null or order == ''">
order by dateStr
</if>
<if test="order != null and order != ''">
order by countNum ${order}
</if>
</select>
</mapper>

View File

@ -0,0 +1,65 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.reportstatistics.dto.TestCaseCountChartResult;
import io.metersphere.reportstatistics.dto.TestCaseCountRequest;
import java.util.List;
public interface ExtTestCaseCountMapper {
/**
* 创建人 维护人 用例类型 用例状态 用例等级
*
* create_user
* maintainer
* '功能用例'
* status
* priority
*
* @ request
* @return
*/
List<TestCaseCountChartResult> getFunctionCaseCount(TestCaseCountRequest request);
/**
* 创建人 维护人 用例类型 用例状态 用例等级
*
* create_user_id
* ----不知道
* '接口用例'
* status
* ----不知道
*
* @param request
* @return
*/
List<TestCaseCountChartResult> getApiCaseCount(TestCaseCountRequest request);
/**
* 创建人 维护人 用例类型 用例状态 用例等级
*
* create_user
* principal
* '场景用例'
* status
* level
*
* @param request
* @return
*/
List<TestCaseCountChartResult> getScenarioCaseCount(TestCaseCountRequest request);
/**
* 创建人 维护人 用例类型 用例状态 用例等级
*
* create_user
* follow_people
* '性能用例'
* status
* 不知道
*
* @param request
* @return
*/
List<TestCaseCountChartResult> getLoadCaseCount(TestCaseCountRequest request);
}

View File

@ -0,0 +1,219 @@
<?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.ExtTestCaseCountMapper">
<select id="getFunctionCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
select
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
${testCaseGroupColumn} AS groupName,
</if>
count(id) AS countNum
FROM test_case
<where>
project_id = #{projectId}
AND `status` != 'Trash'
<if test="startTime > 0">
AND create_time &gt;= #{startTime}
</if>
<if test="endTime > 0">
AND create_time &lt;= #{endTime}
</if>
<if test="filterSearchList != null and filterSearchList.size() > 0">
AND
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
<foreach collection="filterSearchList.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='caselevel'">
${filterType} priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='creator'">
${filterType} create_user in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='maintainer'">
${filterType} maintainer in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='casestatus'">
${filterType} UPPER(status) in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</trim>
</if>
</where>
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
GROUP BY ${testCaseGroupColumn}
</if>
</select>
<select id="getApiCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
select
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
${apiCaseGroupColumn} AS groupName,
</if>
count(id) AS countNum
FROM api_test_case
<where>
project_id = #{projectId}
AND `status` != 'Trash'
<if test="startTime > 0">
AND (create_time &gt;= #{startTime})
</if>
<if test="endTime > 0">
AND ( create_time &lt;= #{endTime})
</if>
<if test="apiFilterSearchList != null and apiFilterSearchList.size() > 0">
AND
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
<foreach collection="apiFilterSearchList.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='caselevel'">
${filterType} priority in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='creator'">
${filterType} create_user_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='casestatus'">
${filterType}
(UPPER(status) in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
<if test="values.contains('RUNNING')">
OR status IS NULL
</if>
)
</when>
</choose>
</if>
</foreach>
</trim>
</if>
</where>
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
GROUP BY ${apiCaseGroupColumn}
</if>
</select>
<select id="getScenarioCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
select
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
${scenarioCaseGroupColumn} AS groupName,
</if>
count(id) AS countNum
FROM api_scenario
<where>
project_id = #{projectId}
AND `status` != 'Trash'
<if test="startTime > 0">
AND (create_time &gt;= #{startTime})
</if>
<if test="endTime > 0">
AND ( create_time &lt;= #{endTime})
</if>
<if test="filterSearchList != null and filterSearchList.size() > 0">
AND
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
<foreach collection="filterSearchList.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='caselevel'">
${filterType} level in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='creator'">
${filterType} create_user in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='maintainer'">
${filterType} principal in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='casestatus'">
${filterType} UPPER(status) in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</trim>
</if>
</where>
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
GROUP BY ${scenarioCaseGroupColumn}
</if>
</select>
<select id="getLoadCaseCount" resultType="io.metersphere.reportstatistics.dto.TestCaseCountChartResult">
select
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
${loadCaseGroupColumn} AS groupName,
</if>
count(id) AS countNum
FROM load_test
<where>
project_id = #{projectId}
<if test="startTime > 0">
AND (create_time &gt;= #{startTime})
</if>
<if test="endTime > 0">
AND ( create_time &lt;= #{endTime})
</if>
<if test="loadFilterSearchList != null and loadFilterSearchList.size() > 0">
AND
<trim prefix="(" prefixOverrides="AND|OR" suffix=")">
<foreach collection="loadFilterSearchList.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='creator'">
${filterType} create_user in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key=='casestatus'">
${filterType} UPPER(status) in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</trim>
</if>
</where>
<if test="testCaseGroupColumn != null and testCaseGroupColumn != ''">
GROUP BY ${loadCaseGroupColumn}
</if>
</select>
</mapper>

View File

@ -390,39 +390,38 @@
GROUP BY test_case.priority
</select>
<!-- todo 排除删除的用例统计-->
<select id="countCreatedThisWeek" resultType="java.lang.Long">
SELECT count(id) AS countNumber FROM test_case WHERE test_case.project_id = #{projectId}
SELECT count(id) AS countNumber FROM test_case WHERE test_case.project_id = #{projectId} and test_case.status != 'Trash'
AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select>
<!-- todo 排除删除的用例统计-->
<select id="countStatus" resultType="io.metersphere.track.response.TrackCountResult">
SELECT review_status AS groupField,count(id) AS countNumber FROM test_case WHERE project_id = #{projectId} GROUP BY test_case.review_status
SELECT review_status AS groupField,count(id) AS countNumber FROM test_case WHERE project_id = #{projectId} and test_case.status != 'Trash'
GROUP BY test_case.review_status
</select>
<select id="countRelevance" resultType="io.metersphere.track.response.TrackCountResult">
SELECT test_case_test.test_type AS groupField, count(test_case_test.test_case_id) AS countNumber
FROM test_case join test_case_test on test_case.id = test_case_test.test_case_id
WHERE test_case.project_id = #{projectId} GROUP BY test_case_test.test_type
WHERE test_case.project_id = #{projectId} and test_case.status != 'Trash' GROUP BY test_case_test.test_type
</select>
<select id="countRelevanceCreatedThisWeek" resultType="java.lang.Long">
SELECT count(distinct test_case_test.test_case_id) AS countNumber FROM test_case join test_case_test on test_case.id = test_case_test.test_case_id
WHERE test_case.project_id = #{projectId}
WHERE test_case.project_id = #{projectId} and test_case.status != 'Trash'
AND test_case_test.create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select>
<select id="countCoverage" resultType="int">
select count(test_case.id) from test_case where test_case.project_id = #{projectId}
select count(test_case.id) from test_case where test_case.project_id = #{projectId} and test_case.status != 'Trash'
and test_case.id in (select distinct test_case_test.test_case_id from test_case_test)
</select>
<select id="countFuncMaintainer" resultType="io.metersphere.track.response.TrackCountResult">
select count(tc.id) as countNumber, user.name as groupField from test_case tc right join user on tc.maintainer = user.id
where tc.project_id = #{projectId}
where tc.project_id = #{projectId} and tc.status != 'Trash'
group by tc.maintainer
</select>
<select id="countRelevanceMaintainer" resultType="io.metersphere.track.response.TrackCountResult">
select count(tc.id) as countNumber, user.name as groupField from test_case tc right join user on tc.maintainer = user.id
where tc.project_id = #{projectId} and tc.id in (select distinct test_case_test.test_case_id from test_case_test)
where tc.project_id = #{projectId} and tc.status != 'Trash' and tc.id in (select distinct test_case_test.test_case_id from test_case_test)
group by tc.maintainer
</select>
<select id="getTestPlanBug" resultType="int">

View File

@ -36,4 +36,13 @@ public interface ExtTestReviewCaseMapper {
List<String> selectTestCaseIds(@Param("request") QueryCaseReviewRequest request);
List<TestReviewCaseDTO> listForMinder(@Param("request") QueryCaseReviewRequest request);
List<String> selectReviewIds();
List<String> getIdsOrderByUpdateTime(@Param("reviewId") String reviewId);
Long getPreOrder(@Param("reviewId")String reviewId, @Param("baseOrder") Long baseOrder);
Long getLastOrder(@Param("reviewId")String reviewId, @Param("baseOrder") Long baseOrder);
}

View File

@ -427,4 +427,28 @@
</where>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="selectReviewIds" resultType="java.lang.String">
select DISTINCT review_id from test_case_review_test_case;
</select>
<select id="getIdsOrderByUpdateTime" resultType="java.lang.String">
select id from test_case_review_test_case where review_id = #{reviewId} order by update_time ASC;
</select>
<select id="getLastOrder" resultType="java.lang.Long">
select `order` from test_case_review_test_case where review_id = #{reviewId}
<if test="baseOrder != null">
and `order` &gt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
<select id="getPreOrder" resultType="java.lang.Long">
select `order` from test_case_review_test_case where review_id = #{reviewId}
<if test="baseOrder != null">
and `order` &lt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
</mapper>

View File

@ -10,6 +10,7 @@ import java.util.Set;
/**
* JSON数据结构相关的工具类
*
* @author song.tianyang
* @Date 2021/8/16 3:50 下午
*/
@ -26,14 +27,18 @@ public class JsonStructUtils {
if (sourceObj == null && matchObj == null) {
return true;
} else if (sourceObj != null && matchObj != null) {
boolean isMatch = false;
boolean lastMatchResultIsTrue = false;
boolean hasNotMatchResult = false;
try {
Set<String> matchKeys = matchObj.keySet();
for (String key : matchKeys) {
if (sourceObj.containsKey(key)) {
Object sourceObjItem = sourceObj.get(key);
Object matchObjItem = matchObj.get(key);
isMatch = checkObjCompliance(sourceObjItem, matchObjItem);
lastMatchResultIsTrue = checkObjCompliance(sourceObjItem, matchObjItem);
if (!lastMatchResultIsTrue) {
hasNotMatchResult = true;
}
} else {
return false;
}
@ -41,7 +46,7 @@ public class JsonStructUtils {
} catch (Exception e) {
e.printStackTrace();
}
return isMatch;
return lastMatchResultIsTrue && !hasNotMatchResult;
} else {
return false;
}
@ -52,9 +57,9 @@ public class JsonStructUtils {
return true;
} else if (sourceArray != null && matchArray != null && sourceArray.size() > matchArray.size()) {
try {
for (int i = 0; i < matchArray.size(); i ++) {
for (int i = 0; i < matchArray.size(); i++) {
Object obj = matchArray.get(i);
if(!sourceArray.contains(obj)){
if (!sourceArray.contains(obj)) {
return false;
}
}
@ -70,13 +75,13 @@ public class JsonStructUtils {
public static boolean checkJsonArrayContainsObj(JSONArray sourceArray, JSONObject matchObj) {
if (sourceArray == null && matchObj == null) {
return true;
} else if (sourceArray != null && matchObj != null ) {
} else if (sourceArray != null && matchObj != null) {
try {
for (int i = 0; i < sourceArray.size(); i ++) {
for (int i = 0; i < sourceArray.size(); i++) {
Object obj = sourceArray.get(i);
if(obj instanceof JSONObject){
boolean isMatch = checkJsonObjCompliance((JSONObject) obj,matchObj);
if(isMatch){
if (obj instanceof JSONObject) {
boolean isMatch = checkJsonObjCompliance((JSONObject) obj, matchObj);
if (isMatch) {
return isMatch;
}
}
@ -92,6 +97,7 @@ public class JsonStructUtils {
/**
* 检查一个JSON对象的数据集合是否包含另一个对象包含
*
* @param sourceArray
* @param matchObj
* @return
@ -103,14 +109,14 @@ public class JsonStructUtils {
boolean isMatch = false;
try {
Set<String> matchKeys = matchObj.keySet();
for(int sourceIndex = 0;sourceIndex < sourceArray.size();sourceIndex ++){
for (int sourceIndex = 0; sourceIndex < sourceArray.size(); sourceIndex++) {
JSONObject sourceObj = sourceArray.getJSONObject(sourceIndex);
for (String key : matchKeys) {
if (sourceObj.containsKey(key)) {
Object sourceObjItem = sourceObj.get(key);
Object matchObjItem = matchObj.get(key);
isMatch = checkObjCompliance(sourceObjItem, matchObjItem);
if(!isMatch){
if (!isMatch) {
break;
}
} else {
@ -119,7 +125,7 @@ public class JsonStructUtils {
}
}
if(isMatch){
if (isMatch) {
break;
}
}
@ -173,12 +179,12 @@ public class JsonStructUtils {
public static void deepParseKeyByJsonObject(JSONObject jsonObject, List<String> keyList) {
for (String key : jsonObject.keySet()) {
Object obj = jsonObject.get(key);
if(obj instanceof JSONArray) {
if (obj instanceof JSONArray) {
deepParseKeyByJsonArray((JSONArray) obj, keyList);
}else if(obj instanceof JSONObject){
deepParseKeyByJsonObject((JSONObject) obj,keyList);
}else {
if(!keyList.contains(key)){
} else if (obj instanceof JSONObject) {
deepParseKeyByJsonObject((JSONObject) obj, keyList);
} else {
if (!keyList.contains(key)) {
keyList.add(key);
}
}
@ -186,10 +192,10 @@ public class JsonStructUtils {
}
public static void deepParseKeyByJsonArray(JSONArray jsonArray, List<String> keyList) {
for (int i = 0; i < jsonArray.size(); i ++) {
for (int i = 0; i < jsonArray.size(); i++) {
Object itemObj = jsonArray.get(i);
if(itemObj instanceof JSONObject){
deepParseKeyByJsonObject((JSONObject)itemObj,keyList);
if (itemObj instanceof JSONObject) {
deepParseKeyByJsonObject((JSONObject) itemObj, keyList);
}
}
}
@ -204,31 +210,31 @@ public class JsonStructUtils {
JSONValidator matchValidator = JSONValidator.from(matchJson);
String sourceType = sourceValidator.getType().name();
String matchType = matchValidator.getType().name();
if(StringUtils.equalsIgnoreCase(sourceType,"array")&&StringUtils.equalsIgnoreCase(matchType,"array")){
if (StringUtils.equalsIgnoreCase(sourceType, "array") && StringUtils.equalsIgnoreCase(matchType, "array")) {
isSourceJsonIsArray = true;
isMatchJsonIsArray = true;
}else if(StringUtils.equalsIgnoreCase(sourceType,"array")){
} else if (StringUtils.equalsIgnoreCase(sourceType, "array")) {
isSourceJsonIsArray = true;
}else if(StringUtils.equalsIgnoreCase(matchType,"array")){
} else if (StringUtils.equalsIgnoreCase(matchType, "array")) {
isMatchJsonIsArray = true;
}
if(isSourceJsonIsArray && isMatchJsonIsArray){
if (isSourceJsonIsArray && isMatchJsonIsArray) {
JSONArray sourceArr = JSONArray.parseArray(sourceJson);
JSONArray compArr = JSONArray.parseArray(matchJson);
isMatch = checkJsonArrayCompliance(sourceArr,compArr);
}else if(isSourceJsonIsArray && !isMatchJsonIsArray){
isMatch = checkJsonArrayCompliance(sourceArr, compArr);
} else if (isSourceJsonIsArray && !isMatchJsonIsArray) {
JSONArray sourceArr = JSONArray.parseArray(sourceJson);
JSONObject compObj = JSONObject.parseObject(matchJson);
isMatch = checkJsonArrayContainsObj(sourceArr,compObj);
}else if(!isSourceJsonIsArray && !isMatchJsonIsArray){
isMatch = checkJsonArrayContainsObj(sourceArr, compObj);
} else if (!isSourceJsonIsArray && !isMatchJsonIsArray) {
JSONObject sourceObj = JSONObject.parseObject(sourceJson);
JSONObject compObj = JSONObject.parseObject(matchJson);
isMatch = checkJsonObjCompliance(sourceObj,compObj);
}else {
isMatch = checkJsonObjCompliance(sourceObj, compObj);
} else {
isMatch = false;
}
}catch (Exception e){
} catch (Exception e) {
}
return isMatch;

View File

@ -35,6 +35,10 @@ public class ServiceUtils {
return getDefaultOrderByField(null, orders, "order");
}
public static List<OrderRequest> getDefaultSortOrder(String prefix, List<OrderRequest> orders) {
return getDefaultOrderByField(prefix, orders, "order");
}
public static List<OrderRequest> getDefaultOrder(String prefix, List<OrderRequest> orders) {
return getDefaultOrderByField(prefix, orders, "update_time");
}

View File

@ -6,7 +6,7 @@ import lombok.Data;
public class CustomFieldItemDTO {
private String id;
private String name;
private String value;
private Object value;
private String type;
private String customData;
}

View File

@ -416,6 +416,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
String customFieldsJson = this.getCustomFieldsJson(data);
testCase.setCustomFields(customFieldsJson);
if (StringUtils.isNotBlank(data.getMaintainer())) {
testCase.setMaintainer(data.getMaintainer());
}
if (StringUtils.isNotBlank(data.getStepModel())
&& StringUtils.equals(data.getStepModel(), TestCaseConstants.StepModel.TEXT.name())) {
@ -466,6 +469,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
String customFieldsJson = this.getCustomFieldsJson(data);
testCase.setCustomFields(customFieldsJson);
if (StringUtils.isNotBlank(data.getMaintainer())) {
testCase.setMaintainer(data.getMaintainer());
}
//将标签设置为前端可解析的格式
String modifiedTags = modifyTagPattern(data);

View File

@ -61,6 +61,8 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
private TestPlanLoadCaseService testPlanLoadCaseService;
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private TestReviewTestCaseService testReviewTestCaseService;
@Value("${jmeter.home}")
private String jmeterHome;
@ -128,6 +130,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initOnceOperate(testPlanApiCaseService::initOrderField, "init.sort.plan.api.case");
initOnceOperate(testPlanScenarioCaseService::initOrderField, "init.sort.plan.api.scenario");
initOnceOperate(testPlanLoadCaseService::initOrderField, "init.sort.plan.api.load");
initOnceOperate(testReviewTestCaseService::initOrderField, "init.sort.review.test.case");
}
/**

View File

@ -134,7 +134,7 @@ public class NoticeService {
public List<MessageDetail> searchMessageByTypeBySend(String type, String projectId) {
try {
String orgId = "";
if (null == SessionUtils.getUser()) {
if (StringUtils.isNotEmpty(projectId)) {
Organization organization = extProjectMapper.getOrganizationByProjectId(projectId);
orgId = organization.getId();
} else {

View File

@ -48,7 +48,7 @@ public class JmeterFileController {
@RequestParam("ratio") String ratio,
@RequestParam("reportId") String reportId, @RequestParam("resourceIndex") int resourceIndex) {
double[] ratios = Arrays.stream(ratio.split(",")).mapToDouble(Double::parseDouble).toArray();
byte[] bytes = jmeterFileService.downloadZip(testId, ratios, reportId, resourceIndex);
byte[] bytes = jmeterFileService.downloadZip(reportId, ratios, resourceIndex);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + testId + ".zip\"")

View File

@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.RunRequest;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.commons.constants.PerformanceTestStatus;
@ -21,15 +21,12 @@ import org.apache.commons.lang3.StringUtils;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
public abstract class AbstractEngine implements Engine {
protected String JMETER_IMAGE;
protected String HEAP;
protected String GC_ALGO;
private Long startTime;
private String reportId;
protected LoadTestWithBLOBs loadTest;
protected LoadTestReportWithBLOBs loadTestReport;
protected PerformanceTestService performanceTestService;
protected Integer threadNum;
protected List<TestResource> resourceList;
@ -43,8 +40,6 @@ public abstract class AbstractEngine implements Engine {
JMETER_IMAGE = CommonBeanFactory.getBean(JmeterProperties.class).getImage();
HEAP = CommonBeanFactory.getBean(JmeterProperties.class).getHeap();
GC_ALGO = CommonBeanFactory.getBean(JmeterProperties.class).getGcAlgo();
this.startTime = System.currentTimeMillis();
this.reportId = UUID.randomUUID().toString();
}
protected void initApiConfig(RunRequest runRequest) {
@ -81,16 +76,16 @@ public abstract class AbstractEngine implements Engine {
}
}
protected void init(LoadTestWithBLOBs loadTest) {
if (loadTest == null) {
protected void init(LoadTestReportWithBLOBs loadTestReport) {
if (loadTestReport == null) {
MSException.throwException("LoadTest is null.");
}
this.loadTest = loadTest;
this.loadTestReport = loadTestReport;
this.performanceTestService = CommonBeanFactory.getBean(PerformanceTestService.class);
threadNum = getThreadNum(loadTest);
String resourcePoolId = loadTest.getTestResourcePoolId();
threadNum = getThreadNum(loadTestReport);
String resourcePoolId = loadTestReport.getTestResourcePoolId();
if (StringUtils.isBlank(resourcePoolId)) {
MSException.throwException("Resource Pool ID is empty");
}
@ -127,16 +122,16 @@ public abstract class AbstractEngine implements Engine {
}
protected Integer getRunningThreadNum() {
List<LoadTestWithBLOBs> loadTests = performanceTestService.selectByTestResourcePoolId(loadTest.getTestResourcePoolId());
List<LoadTestReportWithBLOBs> loadTestReports = performanceTestService.selectReportsByTestResourcePoolId(loadTestReport.getTestResourcePoolId());
// 使用当前资源池正在运行的测试占用的并发数
return loadTests.stream()
return loadTestReports.stream()
.filter(t -> PerformanceTestStatus.Running.name().equals(t.getStatus()))
.map(this::getThreadNum)
.reduce(Integer::sum)
.orElse(0);
}
private Integer getThreadNum(LoadTestWithBLOBs t) {
private Integer getThreadNum(LoadTestReportWithBLOBs t) {
Integer s = 0;
String loadConfiguration = t.getLoadConfiguration();
JSONArray jsonArray = JSON.parseArray(loadConfiguration);
@ -175,14 +170,4 @@ public abstract class AbstractEngine implements Engine {
}
return s;
}
@Override
public Long getStartTime() {
return startTime;
}
@Override
public String getReportId() {
return reportId;
}
}

View File

@ -1,10 +1,6 @@
package io.metersphere.performance.engine;
public interface Engine {
Long getStartTime();
String getReportId();
void start();
void stop();

View File

@ -6,10 +6,11 @@ import io.metersphere.Application;
import io.metersphere.api.dto.RunRequest;
import io.metersphere.base.domain.FileContent;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
import io.metersphere.commons.constants.ResourceStatusEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.i18n.Translator;
@ -65,8 +66,8 @@ public class EngineFactory {
}
}
public static Engine createEngine(LoadTestWithBLOBs loadTest) {
String resourcePoolId = loadTest.getTestResourcePoolId();
public static Engine createEngine(LoadTestReportWithBLOBs loadTestReport) {
String resourcePoolId = loadTestReport.getTestResourcePoolId();
if (StringUtils.isBlank(resourcePoolId)) {
MSException.throwException(Translator.get("test_resource_pool_id_is_null"));
}
@ -75,15 +76,18 @@ public class EngineFactory {
if (resourcePool == null) {
MSException.throwException(Translator.get("test_resource_pool_id_is_null"));
}
if (ResourceStatusEnum.INVALID.name().equals(resourcePool.getStatus())) {
MSException.throwException(Translator.get("test_resource_pool_invalid"));
}
final ResourcePoolTypeEnum type = ResourcePoolTypeEnum.valueOf(resourcePool.getType());
if (type == ResourcePoolTypeEnum.NODE) {
return new DockerTestEngine(loadTest);
return new DockerTestEngine(loadTestReport);
}
if (type == ResourcePoolTypeEnum.K8S) {
try {
return (Engine) ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, loadTest);
return (Engine) ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, loadTestReport);
} catch (Exception e) {
LogUtil.error(e);
return null;
@ -102,10 +106,10 @@ public class EngineFactory {
return null;
}
public static EngineContext createContext(LoadTestWithBLOBs loadTest, double[] ratios, String reportId, int resourceIndex) {
final List<FileMetadata> fileMetadataList = performanceTestService.getFileMetadataByTestId(loadTest.getId());
public static EngineContext createContext(LoadTestReportWithBLOBs loadTestReport, double[] ratios, String reportId, int resourceIndex) {
final List<FileMetadata> fileMetadataList = performanceTestService.getFileMetadataByTestId(loadTestReport.getTestId());
if (org.springframework.util.CollectionUtils.isEmpty(fileMetadataList)) {
MSException.throwException(Translator.get("run_load_test_file_not_found") + loadTest.getId());
MSException.throwException(Translator.get("run_load_test_file_not_found") + loadTestReport.getTestId());
}
List<FileMetadata> jmxFiles = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), FileType.JMX.name())).collect(Collectors.toList());
@ -113,17 +117,17 @@ public class EngineFactory {
// 合并上传的jmx
byte[] jmxBytes = mergeJmx(jmxFiles);
final EngineContext engineContext = new EngineContext();
engineContext.setTestId(loadTest.getId());
engineContext.setTestName(loadTest.getName());
engineContext.setNamespace(loadTest.getProjectId());
engineContext.setTestId(loadTestReport.getTestId());
engineContext.setTestName(loadTestReport.getName());
engineContext.setNamespace(loadTestReport.getProjectId());
engineContext.setFileType(FileType.JMX.name());
engineContext.setResourcePoolId(loadTest.getTestResourcePoolId());
engineContext.setResourcePoolId(loadTestReport.getTestResourcePoolId());
engineContext.setReportId(reportId);
engineContext.setResourceIndex(resourceIndex);
engineContext.setRatios(ratios);
if (StringUtils.isNotEmpty(loadTest.getLoadConfiguration())) {
final JSONArray jsonArray = JSONObject.parseArray(loadTest.getLoadConfiguration());
if (StringUtils.isNotEmpty(loadTestReport.getLoadConfiguration())) {
final JSONArray jsonArray = JSONObject.parseArray(loadTestReport.getLoadConfiguration());
for (int i = 0; i < jsonArray.size(); i++) {
if (jsonArray.get(i) instanceof List) {
@ -160,8 +164,8 @@ public class EngineFactory {
{"timeout":10,"statusCode":["302","301"],"params":[{"name":"param1","enable":true,"value":"0","edit":false}],"domains":[{"domain":"baidu.com","enable":true,"ip":"127.0.0.1","edit":false}]}
*/
Map<String, byte[]> testResourceFiles = new HashMap<>();
byte[] props = getJMeterProperties(loadTest, engineContext);
byte[] hosts = getDNSConfig(loadTest, engineContext);
byte[] props = getJMeterProperties(loadTestReport, engineContext);
byte[] hosts = getDNSConfig(loadTestReport, engineContext);
// JMeter Properties
testResourceFiles.put("ms.properties", props);
// DNS
@ -195,10 +199,10 @@ public class EngineFactory {
return engineContext;
}
private static byte[] getDNSConfig(LoadTestWithBLOBs loadTest, EngineContext engineContext) {
private static byte[] getDNSConfig(LoadTestReportWithBLOBs loadTestReport, EngineContext engineContext) {
StringBuilder dns = new StringBuilder("# DNS Config\n");
if (StringUtils.isNotEmpty(loadTest.getAdvancedConfiguration())) {
JSONObject advancedConfiguration = JSONObject.parseObject(loadTest.getAdvancedConfiguration());
if (StringUtils.isNotEmpty(loadTestReport.getAdvancedConfiguration())) {
JSONObject advancedConfiguration = JSONObject.parseObject(loadTestReport.getAdvancedConfiguration());
engineContext.addProperties(advancedConfiguration);
JSONArray domains = advancedConfiguration.getJSONArray("domains");
if (domains != null) {
@ -214,10 +218,10 @@ public class EngineFactory {
return dns.toString().getBytes(StandardCharsets.UTF_8);
}
private static byte[] getJMeterProperties(LoadTestWithBLOBs loadTest, EngineContext engineContext) {
private static byte[] getJMeterProperties(LoadTestReportWithBLOBs loadTestReportWithBLOBs, EngineContext engineContext) {
StringBuilder props = new StringBuilder("# JMeter Properties\n");
if (StringUtils.isNotEmpty(loadTest.getAdvancedConfiguration())) {
JSONObject advancedConfiguration = JSONObject.parseObject(loadTest.getAdvancedConfiguration());
if (StringUtils.isNotEmpty(loadTestReportWithBLOBs.getAdvancedConfiguration())) {
JSONObject advancedConfiguration = JSONObject.parseObject(loadTestReportWithBLOBs.getAdvancedConfiguration());
engineContext.addProperties(advancedConfiguration);
JSONArray properties = advancedConfiguration.getJSONArray("properties");
if (properties != null) {

View File

@ -1,6 +1,7 @@
package io.metersphere.performance.engine.docker;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.base.domain.TestResource;
import io.metersphere.commons.constants.ResourceStatusEnum;
@ -26,13 +27,13 @@ public class DockerTestEngine extends AbstractEngine {
private RestTemplate restTemplate;
private RestTemplate restTemplateWithTimeOut;
public DockerTestEngine(LoadTestWithBLOBs loadTest) {
this.init(loadTest);
public DockerTestEngine(LoadTestReportWithBLOBs loadTestReport) {
this.init(loadTestReport);
}
@Override
protected void init(LoadTestWithBLOBs loadTest) {
super.init(loadTest);
protected void init(LoadTestReportWithBLOBs loadTestReport) {
super.init(loadTestReport);
this.restTemplate = (RestTemplate) CommonBeanFactory.getBean("restTemplate");
this.restTemplateWithTimeOut = (RestTemplate) CommonBeanFactory.getBean("restTemplateWithTimeOut");
}
@ -85,9 +86,9 @@ public class DockerTestEngine extends AbstractEngine {
env.put("RATIO", StringUtils.join(ratios, ","));
env.put("RESOURCE_INDEX", "" + resourceIndex);
env.put("METERSPHERE_URL", metersphereUrl);
env.put("START_TIME", "" + this.getStartTime());
env.put("TEST_ID", this.loadTest.getId());
env.put("REPORT_ID", this.getReportId());
env.put("START_TIME", "" + System.currentTimeMillis());
env.put("TEST_ID", this.loadTestReport.getTestId());
env.put("REPORT_ID", this.loadTestReport.getId());
env.put("BOOTSTRAP_SERVERS", kafkaProperties.getBootstrapServers());
env.put("LOG_TOPIC", kafkaProperties.getLog().getTopic());
env.put("JMETER_REPORTS_TOPIC", kafkaProperties.getReport().getTopic());
@ -95,7 +96,7 @@ public class DockerTestEngine extends AbstractEngine {
env.put("THREAD_NUM", "0");// 传入0表示不用修改线程数
env.put("HEAP", HEAP);
env.put("GC_ALGO", GC_ALGO);
env.put("GRANULARITY", performanceTestService.getGranularity(this.getReportId()).toString());
env.put("GRANULARITY", performanceTestService.getGranularity(this.loadTestReport.getId()).toString());
env.put("BACKEND_LISTENER", resourcePool.getBackendListener().toString());
@ -121,7 +122,7 @@ public class DockerTestEngine extends AbstractEngine {
@Override
public void stop() {
String testId = loadTest.getId();
String testId = loadTestReport.getTestId();
this.resourceList.forEach(r -> {
NodeDTO node = JSON.parseObject(r.getConfiguration(), NodeDTO.class);
String ip = node.getIp();

View File

@ -1,18 +1,13 @@
package io.metersphere.performance.service;
import com.alibaba.excel.util.CollectionUtils;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.base.domain.TestPlanLoadCase;
import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.performance.engine.EngineContext;
import io.metersphere.performance.engine.EngineFactory;
import org.codehaus.plexus.util.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -28,40 +23,18 @@ import java.util.zip.ZipOutputStream;
@Service
@Transactional(rollbackFor = Exception.class)
public class JmeterFileService {
@Resource
private LoadTestMapper loadTestMapper;
@Resource
private ExtLoadTestReportMapper extLoadTestReportMapper;
@Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
private LoadTestReportMapper loadTestReportMapper;
public byte[] downloadZip(String testId, double[] ratios, String reportId, int resourceIndex) {
public byte[] downloadZip(String reportId, double[] ratios, int resourceIndex) {
try {
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(testId);
TestPlanLoadCase testPlanLoadCase = null;
if (loadTest == null) {
// 通过测试计划执行性能用例时testId为测试计划性能用例表的主键ID根据ID查询用例自身的压力配置
testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(testId);
if (testPlanLoadCase != null) {
loadTest = loadTestMapper.selectByPrimaryKey(testPlanLoadCase.getLoadCaseId());
if (loadTest != null) {
// 用例自身设置了资源池ID
if (StringUtils.isNotBlank(testPlanLoadCase.getTestResourcePoolId())) {
loadTest.setTestResourcePoolId(testPlanLoadCase.getTestResourcePoolId());
}
// 用例自身设置了压力配置
if (StringUtils.isNotBlank(testPlanLoadCase.getLoadConfiguration())) {
loadTest.setLoadConfiguration(testPlanLoadCase.getLoadConfiguration());
}
}
}
}
EngineContext context = EngineFactory.createContext(loadTest, ratios, reportId, resourceIndex);
if (testPlanLoadCase != null) {
// ID
context.setTestId(testPlanLoadCase.getId());
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
if (loadTestReport == null) {
MSException.throwException("测试报告不存在或还没产生");
}
EngineContext context = EngineFactory.createContext(loadTestReport, ratios, reportId, resourceIndex);
return zipFilesToByteArray(context);
} catch (MSException e) {
LogUtil.error(e.getMessage(), e);

View File

@ -97,14 +97,14 @@ public class PerformanceReportService {
MSException.throwException("report id cannot be null");
}
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(loadTestReport.getTestId());
LogUtil.info("Delete report started, report ID: %s" + reportId);
if (loadTest != null) {
try {
final Engine engine = EngineFactory.createEngine(loadTest);
final Engine engine = EngineFactory.createEngine(loadTestReport);
if (engine == null) {
MSException.throwException(String.format("Delete report fail. create engine failreport ID%s", reportId));
}

View File

@ -313,6 +313,9 @@ public class PerformanceTestService {
if (request.getUserId() != null) {
loadTest.setUserId(request.getUserId());
}
if (StringUtils.isNotEmpty(request.getProjectId())) {
loadTest.setProjectId(request.getProjectId());
}
if (loadTest == null) {
MSException.throwException(Translator.get("run_load_test_not_found") + request.getId());
}
@ -320,40 +323,12 @@ public class PerformanceTestService {
if (StringUtils.equalsAny(loadTest.getStatus(), PerformanceTestStatus.Running.name(), PerformanceTestStatus.Starting.name())) {
MSException.throwException(Translator.get("load_test_is_running"));
}
String testResourcePoolId = loadTest.getTestResourcePoolId();
TestResourcePool testResourcePool = testResourcePoolMapper.selectByPrimaryKey(testResourcePoolId);
if (testResourcePool == null) {
MSException.throwException(Translator.get("test_resource_pool_not_exists"));
}
if (ResourceStatusEnum.INVALID.name().equals(testResourcePool.getStatus())) {
MSException.throwException(Translator.get("test_resource_pool_invalid"));
}
// check kafka
checkKafka();
LogUtil.info("Load test started " + loadTest.getName());
LoadTestWithBLOBs copyTest = new LoadTestWithBLOBs();
BeanUtils.copyBean(copyTest, loadTest);
// 如果是执行测试计划用例把EngineFactory.createEngine参数对象的id 设置为测试计划用例id
// 设置用例id目的是当 JmeterFileService 下载zip拼装 jmx 文件时如果用例自身带有压力配置使用用例自身压力配置拼装 jmx
String testPlanLoadId = request.getTestPlanLoadId();
if (StringUtils.isNotBlank(testPlanLoadId)) {
copyTest.setId(testPlanLoadId);
// 设置本次报告中的压力配置信息
TestPlanLoadCase testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(testPlanLoadId);
if (testPlanLoadCase != null && StringUtils.isNotBlank(testPlanLoadCase.getLoadConfiguration())) {
loadTest.setLoadConfiguration(testPlanLoadCase.getLoadConfiguration());
}
}
// engine type (NODE)
final Engine engine = EngineFactory.createEngine(copyTest);
if (engine == null) {
MSException.throwException(String.format("Test cannot be runtest ID%s", request.getId()));
}
startEngine(loadTest, engine, request.getTriggerMode());
return engine.getReportId();
return startEngine(loadTest, request);
}
private void checkKafka() {
@ -377,14 +352,16 @@ public class PerformanceTestService {
}
}
private void startEngine(LoadTestWithBLOBs loadTest, Engine engine, String triggerMode) {
private String startEngine(LoadTestWithBLOBs loadTest, RunTestPlanRequest request) {
LoadTestReportWithBLOBs testReport = new LoadTestReportWithBLOBs();
testReport.setId(engine.getReportId());
testReport.setCreateTime(engine.getStartTime());
testReport.setUpdateTime(engine.getStartTime());
testReport.setId(UUID.randomUUID().toString());
testReport.setCreateTime(System.currentTimeMillis());
testReport.setUpdateTime(System.currentTimeMillis());
testReport.setTestId(loadTest.getId());
testReport.setName(loadTest.getName());
testReport.setTriggerMode(triggerMode);
testReport.setTriggerMode(request.getTriggerMode());
if (SessionUtils.getUser() == null) {
testReport.setUserId(loadTest.getUserId());
} else {
@ -394,18 +371,36 @@ public class PerformanceTestService {
LoadTestWithBLOBs updateTest = new LoadTestWithBLOBs();
updateTest.setId(loadTest.getId());
// 启动测试
Engine engine = null;
try {
// 启动插入 report
// 保存测试里的配置
testReport.setTestResourcePoolId(loadTest.getTestResourcePoolId());
testReport.setLoadConfiguration(loadTest.getLoadConfiguration());
String testPlanLoadId = request.getTestPlanLoadId();
if (StringUtils.isNotBlank(testPlanLoadId)) {
// 设置本次报告中的压力配置信息
TestPlanLoadCase testPlanLoadCase = testPlanLoadCaseMapper.selectByPrimaryKey(testPlanLoadId);
if (testPlanLoadCase != null && StringUtils.isNotBlank(testPlanLoadCase.getLoadConfiguration())) {
testReport.setLoadConfiguration(testPlanLoadCase.getLoadConfiguration());
}
if (StringUtils.isNotBlank(testPlanLoadCase.getTestResourcePoolId())) {
testReport.setTestResourcePoolId(testPlanLoadCase.getTestResourcePoolId());
}
}
// 启动插入 report
testReport.setAdvancedConfiguration(loadTest.getAdvancedConfiguration());
testReport.setStatus(PerformanceTestStatus.Starting.name());
testReport.setProjectId(loadTest.getProjectId());
testReport.setTestResourcePoolId(loadTest.getTestResourcePoolId());
testReport.setTestName(loadTest.getName());
loadTestReportMapper.insertSelective(testReport);
engine.start();
// 启动正常修改状态 starting
// engine
engine = EngineFactory.createEngine(testReport);
if (engine == null) {
MSException.throwException(String.format("Test cannot be runtest ID%s", loadTest.getId()));
}
updateTest.setStatus(PerformanceTestStatus.Starting.name());
loadTestMapper.updateByPrimaryKeySelective(updateTest);
@ -423,9 +418,14 @@ public class PerformanceTestService {
reportResult.setReportKey(ReportKeys.ResultStatus.name());
reportResult.setReportValue("Ready"); // 初始化一个 result_status, 这个值用在data-streaming中
loadTestReportResultMapper.insertSelective(reportResult);
// 启动测试
engine.start();
return testReport.getId();
} catch (MSException e) {
// 启动失败之后清理任务
engine.stop();
if (engine != null) {
engine.stop();
}
LogUtil.error(e.getMessage(), e);
updateTest.setStatus(PerformanceTestStatus.Error.name());
updateTest.setDescription(e.getMessage());
@ -482,12 +482,6 @@ public class PerformanceTestService {
return results;
}
public List<LoadTestWithBLOBs> selectByTestResourcePoolId(String resourcePoolId) {
LoadTestExample example = new LoadTestExample();
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePoolId);
return loadTestMapper.selectByExampleWithBLOBs(example);
}
public List<DashboardTestDTO> dashboardTests(String workspaceId) {
Instant oneYearAgo = Instant.now().plus(-365, ChronoUnit.DAYS);
long startTimestamp = oneYearAgo.toEpochMilli();
@ -572,9 +566,9 @@ public class PerformanceTestService {
}
private void stopEngine(String reportId) {
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(loadTestReport.getTestId());
final Engine engine = EngineFactory.createEngine(loadTest);
final Engine engine = EngineFactory.createEngine(loadTestReport);
if (engine == null) {
MSException.throwException(String.format("Stop report fail. create engine failreport ID%s", reportId));
}
@ -832,13 +826,12 @@ public class PerformanceTestService {
Integer granularity = CommonBeanFactory.getBean(JmeterProperties.class).getReport().getGranularity();
try {
LoadTestReportWithBLOBs report = loadTestReportMapper.selectByPrimaryKey(reportId);
LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(report.getTestId());
JSONObject advancedConfig = JSON.parseObject(loadTest.getAdvancedConfiguration());
JSONObject advancedConfig = JSON.parseObject(report.getAdvancedConfiguration());
if (advancedConfig.getInteger("granularity") != null) {
return advancedConfig.getInteger("granularity") * 1000;// 单位是ms
}
AtomicReference<Integer> maxDuration = new AtomicReference<>(0);
List<List<JSONObject>> pressureConfigLists = JSON.parseObject(loadTest.getLoadConfiguration(), new TypeReference<List<List<JSONObject>>>() {
List<List<JSONObject>> pressureConfigLists = JSON.parseObject(report.getLoadConfiguration(), new TypeReference<List<List<JSONObject>>>() {
});
// 按照最长的执行时间来确定
pressureConfigLists.forEach(pcList -> {
@ -884,6 +877,7 @@ public class PerformanceTestService {
/**
* 用例自定义排序
*
* @param request
*/
public void updateOrder(ResetOrderRequest request) {
@ -893,4 +887,11 @@ public class PerformanceTestService {
extLoadTestMapper::getLastOrder,
loadTestMapper::updateByPrimaryKeySelective);
}
public List<LoadTestReportWithBLOBs> selectReportsByTestResourcePoolId(String resourcePoolId) {
LoadTestReportExample example = new LoadTestReportExample();
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePoolId)
.andStatusIn(Arrays.asList(PerformanceTestStatus.Running.name(), PerformanceTestStatus.Starting.name()));
return loadTestReportMapper.selectByExampleWithBLOBs(example);
}
}

View File

@ -0,0 +1,56 @@
package io.metersphere.reportstatistics.controller;
import com.alibaba.fastjson.JSONArray;
import io.metersphere.base.domain.ReportStatistics;
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.reportstatistics.dto.ReportStatisticsSaveRequest;
import io.metersphere.reportstatistics.service.ReportStatisticsService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* @author song.tianyang
* @Date 2021/9/14 2:58 下午
*/
@RestController
@RequestMapping(value = "/history/report")
public class HistoryReportController {
@Resource
private ReportStatisticsService reportStatisticsService;
@PostMapping("/selectByParams")
public List<ReportStatistics> selectByParams(@RequestBody ReportStatisticsSaveRequest request) {
List<ReportStatistics> returnList = reportStatisticsService.selectByProjectIdAndReportType(request.getProjectId(),request.getReportType());
LogUtil.info("报表查询结果:"+JSONArray.toJSONString(returnList));
return returnList;
}
@PostMapping("/saveReport")
public ReportStatisticsWithBLOBs saveReport(@RequestBody ReportStatisticsSaveRequest request){
ReportStatisticsWithBLOBs returnData = reportStatisticsService.saveByRequest(request);
return returnData;
}
@PostMapping("/updateReport")
public ReportStatisticsWithBLOBs updateReport(@RequestBody ReportStatisticsSaveRequest request){
ReportStatisticsWithBLOBs returnData = reportStatisticsService.updateByRequest(request);
return returnData;
}
@PostMapping("/deleteByParam")
public int deleteById(@RequestBody ReportStatisticsSaveRequest request) {
return reportStatisticsService.deleteById(request.getId());
}
@PostMapping("/selectById")
public ReportStatisticsWithBLOBs selectById(@RequestBody ReportStatisticsSaveRequest request) {
return reportStatisticsService.selectById(request.getId());
}
}

View File

@ -0,0 +1,24 @@
package io.metersphere.reportstatistics.controller;
import io.metersphere.reportstatistics.dto.TestAnalysisChartRequest;
import io.metersphere.reportstatistics.dto.TestAnalysisResult;
import io.metersphere.reportstatistics.service.TestAnalysisService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping(value = "/report/test/analysis")
public class TestAnalysisController {
@Resource
TestAnalysisService testAnalysisService;
@PostMapping("/getReport")
public TestAnalysisResult getReport(@RequestBody TestAnalysisChartRequest request) {
return testAnalysisService.getReport(request);
}
}

View File

@ -0,0 +1,34 @@
package io.metersphere.reportstatistics.controller;
import io.metersphere.reportstatistics.dto.TestCaseCountRequest;
import io.metersphere.reportstatistics.dto.TestCaseCountResponse;
import io.metersphere.reportstatistics.service.TestCaseCountService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping(value = "/report/test/case/count")
public class TestCaseCountController {
@Resource
TestCaseCountService testCaseCountService;
@PostMapping("/initDatas")
public Map<String, List<Map<String,String>>> initDatas(@RequestBody TestCaseCountRequest request) {
Map<String,List<Map<String, String>>> returnMap = testCaseCountService.getSelectFilterDatas(request.getProjectId());
return returnMap;
}
@PostMapping("/getReport")
public TestCaseCountResponse getReport(@RequestBody TestCaseCountRequest request) {
TestCaseCountResponse response = testCaseCountService.getReport(request);
return response;
}
}

View File

@ -0,0 +1,27 @@
package io.metersphere.reportstatistics.dto;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.reportstatistics.dto.charts.Series;
import io.metersphere.reportstatistics.dto.charts.Title;
import io.metersphere.reportstatistics.dto.charts.XAxis;
import io.metersphere.reportstatistics.dto.charts.YAxis;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class PieChartDTO {
private JSONObject dataset;
private JSONObject tooltip;
private XAxis xAxis;
private YAxis yAxis;
private List<Series> series;
private List<Title> title;
private int width;
public PieChartDTO() {
tooltip = new JSONObject();
}
}

View File

@ -0,0 +1,14 @@
package io.metersphere.reportstatistics.dto;
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
import lombok.Getter;
import lombok.Setter;
/**
* @author song.tianyang
* @Date 2021/9/14 4:51 下午
*/
@Getter
@Setter
public class ReportStatisticsSaveRequest extends ReportStatisticsWithBLOBs {
}

View File

@ -0,0 +1,5 @@
package io.metersphere.reportstatistics.dto;
public enum ReportStatisticsType {
TEST_CASE_COUNT,TEST_CASE_ANALYSIS
}

View File

@ -0,0 +1,29 @@
package io.metersphere.reportstatistics.dto;
import io.metersphere.reportstatistics.dto.charts.Legend;
import io.metersphere.reportstatistics.dto.charts.Series;
import io.metersphere.reportstatistics.dto.charts.XAxis;
import io.metersphere.reportstatistics.dto.charts.YAxis;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class TestAnalysisChartDTO {
private Legend legend;
private XAxis xAxis;
private YAxis yAxis;
private List<Series> series;
public TestAnalysisChartDTO() {
}
public TestAnalysisChartDTO(Legend legend, XAxis xAxis, YAxis yAxis, List<Series> series) {
this.legend = legend;
this.xAxis = xAxis;
this.yAxis = yAxis;
this.series = series;
}
}

View File

@ -0,0 +1,21 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class TestAnalysisChartRequest {
private boolean createCase;
private boolean updateCase;
private String order;
private List<Long> times;
private String startTime;
private String endTime;
private List<String> prioritys;
private List<String> projects;
private List<String> modules;
private List<String> users;
}

View File

@ -0,0 +1,12 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TestAnalysisChartResult {
private String dateStr;
private String countNum;
}

View File

@ -0,0 +1,22 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class TestAnalysisResult {
private TestAnalysisChartDTO chartDTO;
private List<TestAnalysisTableDTO> tableDTOs;
public TestAnalysisResult() {
}
public TestAnalysisResult(TestAnalysisChartDTO chartDTO, List<TestAnalysisTableDTO> tableDTOs) {
this.chartDTO = chartDTO;
this.tableDTOs = tableDTOs;
}
}

View File

@ -0,0 +1,29 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.UUID;
@Getter
@Setter
public class TestAnalysisTableDTO {
private String id;
private String name;
private String createCount;
private String updateCount;
private List<TestAnalysisTableDTO> children;
public TestAnalysisTableDTO() {
}
public TestAnalysisTableDTO(String name, String createCount, String updateCount, List<TestAnalysisTableDTO> children) {
this.id = UUID.randomUUID().toString();
this.name = name;
this.createCount = createCount;
this.updateCount = updateCount;
this.children = children;
}
}

View File

@ -0,0 +1,15 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TestCaseCountChartResult {
private String groupName;
private long countNum;
public String getCountNumStr(){
return String.valueOf(countNum);
}
}

View File

@ -0,0 +1,79 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class TestCaseCountRequest {
//x轴字段
private String xaxis;
//y轴字段
private List<String> yaxis;
//搜索条件
private String projectId;
private String timeType;
private TimeFilter timeFilter;
private List<Long> times;
private String order;
//起始时间
private long startTime = 0;
//结束时间
private long endTime = 0;
//其余条件
private String filterType;
private List<Map<String,Object>> filters;
/**
* 功能用例接口用例场景用例性能用例的分组字段
*/
private String testCaseGroupColumn;
private String apiCaseGroupColumn;
private String scenarioCaseGroupColumn;
private String loadCaseGroupColumn;
/**
* filter整理后的查询数据
* @return
*/
private Map<String,List<String>> filterSearchList;
private Map<String,List<String>> apiFilterSearchList;
private Map<String,List<String>> loadFilterSearchList;
public int getTimeRange(){
if(timeFilter != null){
return timeFilter.getTimeRange();
}else {
return 0;
}
}
public String getTimeRangeUnit(){
if(timeFilter != null){
return timeFilter.getTimeRangeUnit();
}else {
return null;
}
}
public void setFilterSearchList(String key,List<String> values){
if(this.filterSearchList == null){
this.filterSearchList = new HashMap<>();
}
filterSearchList.put(key,values);
}
}
@Getter
@Setter
class TimeFilter{
private int timeRange;
private String timeRangeUnit;
}

View File

@ -0,0 +1,24 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class TestCaseCountResponse {
private TestAnalysisChartDTO barChartDTO;
private PieChartDTO pieChartDTO;
private List<TestCaseCountTableDTO> tableDTOs;
public TestCaseCountResponse() {
}
public TestCaseCountResponse(TestAnalysisChartDTO chartDTO, PieChartDTO pieChartDTO, List<TestCaseCountTableDTO> tableDTOs) {
this.pieChartDTO = pieChartDTO;
this.barChartDTO = chartDTO;
this.tableDTOs = tableDTOs;
}
}

View File

@ -0,0 +1,22 @@
package io.metersphere.reportstatistics.dto;
/**
* @author song.tianyang
* @Date 2021/9/8 5:36 下午
*/
public class TestCaseCountSummary {
public String groupName;
public long testCaseCount = 0;
public long apiCaseCount = 0;
public long scenarioCaseCount = 0;
public long loadCaseCount = 0;
public TestCaseCountSummary(String groupName) {
this.groupName = groupName;
}
public long getAllCount() {
return this.testCaseCount + this.apiCaseCount + this.scenarioCaseCount + this.loadCaseCount;
}
}

View File

@ -0,0 +1,34 @@
package io.metersphere.reportstatistics.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Getter
@Setter
public class TestCaseCountTableDTO {
private String id;
private String name;
private String allCount;
private String testCaseCount;
private String apiCaseCount;
private String scenarioCaseCount;
private String loadCaseCount;
private List<TestCaseCountTableDTO> children;
public TestCaseCountTableDTO(String name, long testCaseCount, long apiCaseCount, long scenarioCaseCount, long loadCaseCount) {
this.id = UUID.randomUUID().toString();
this.name = name;
this.testCaseCount = String.valueOf(testCaseCount);
this.apiCaseCount = String.valueOf(apiCaseCount);
this.scenarioCaseCount = String.valueOf(scenarioCaseCount);
this.loadCaseCount = String.valueOf(loadCaseCount);
this.allCount = String.valueOf(testCaseCount+apiCaseCount+scenarioCaseCount+loadCaseCount);
children = new ArrayList<>();
}
}

View File

@ -0,0 +1,20 @@
package io.metersphere.reportstatistics.dto.charts;
import lombok.Getter;
import lombok.Setter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class Legend {
private final String x = "center";
private final String y = "bottom";
private final String type = "scroll";
private final List<Integer> padding = Arrays.asList(0, 40, 0, 0);
private Map<String, Boolean> selected;
private List<String> data;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.reportstatistics.dto.charts;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class PieData {
private String name;
private long value;
private JSONObject itemStyle;
public void setColor(String color){
if(itemStyle == null){
itemStyle = new JSONObject();
}
itemStyle.put("color",color);
}
}

View File

@ -0,0 +1,20 @@
package io.metersphere.reportstatistics.dto.charts;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class Series {
private String name;
private List<Object> data;
private String color = "#783887";
private String type = "line";
private String radius = "50";
private String stack;
private JSONObject encode;
private List<String> center;
}

View File

@ -0,0 +1,14 @@
package io.metersphere.reportstatistics.dto.charts;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Title {
private String name;
private String subtext;
private String left;
private String top = "75%";
private String textAlign = "center";
}

View File

@ -0,0 +1,17 @@
package io.metersphere.reportstatistics.dto.charts;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class XAxis {
private final String type = "category";
private List<String> data;
private String name;
private Map<String,Integer> axisLabel = new HashMap<String,Integer>(){ {this.put("interval",0);this.put("rotate",30);}};
}

View File

@ -0,0 +1,14 @@
package io.metersphere.reportstatistics.dto.charts;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class YAxis {
private String type;
private List<String> data;
private String name;
}

View File

@ -0,0 +1,77 @@
package io.metersphere.reportstatistics.service;
import io.metersphere.base.domain.ReportStatistics;
import io.metersphere.base.domain.ReportStatisticsExample;
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
import io.metersphere.base.mapper.ReportStatisticsMapper;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.reportstatistics.dto.ReportStatisticsSaveRequest;
import io.metersphere.reportstatistics.dto.ReportStatisticsType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
/**
* @author song.tianyang
* @Date 2021/9/14 4:50 下午
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ReportStatisticsService {
@Resource
private ReportStatisticsMapper reportStatisticsMapper;
public ReportStatisticsWithBLOBs saveByRequest(ReportStatisticsSaveRequest request) {
ReportStatisticsWithBLOBs model = new ReportStatisticsWithBLOBs();
model.setId(UUID.randomUUID().toString());
String name = "用例分析报表";
if(StringUtils.equalsIgnoreCase(ReportStatisticsType.TEST_CASE_COUNT.name(),request.getReportType())){
name = "用例统计报表";
model.setReportType(ReportStatisticsType.TEST_CASE_COUNT.name());
}else {
model.setReportType(ReportStatisticsType.TEST_CASE_ANALYSIS.name());
}
model.setName(name);
model.setDataOption(request.getDataOption());
model.setSelectOption(request.getSelectOption());
model.setCreateTime(System.currentTimeMillis());
model.setUpdateTime(System.currentTimeMillis());
model.setProjectId(request.getProjectId());
String userId = SessionUtils.getUserId();
model.setCreateUser(userId);
model.setUpdateUser(userId);
reportStatisticsMapper.insert(model);
return model;
}
public int deleteById(String id) {
return reportStatisticsMapper.deleteByPrimaryKey(id);
}
public List<ReportStatistics> selectByProjectIdAndReportType(String projectId, String reportType) {
ReportStatisticsExample example = new ReportStatisticsExample();
example.createCriteria().andProjectIdEqualTo(projectId).andReportTypeEqualTo(reportType);
example.setOrderByClause("create_time DESC");
return reportStatisticsMapper.selectByExample(example);
}
public ReportStatisticsWithBLOBs selectById(String id) {
return reportStatisticsMapper.selectByPrimaryKey(id);
}
public ReportStatisticsWithBLOBs updateByRequest(ReportStatisticsSaveRequest request) {
ReportStatisticsWithBLOBs updateModel = new ReportStatisticsWithBLOBs();
updateModel.setId(request.getId());
updateModel.setName(request.getName());
updateModel.setUpdateTime(request.getUpdateTime());
updateModel.setUpdateUser(SessionUtils.getUserId());
reportStatisticsMapper.updateByPrimaryKeySelective(updateModel);
return updateModel;
}
}

View File

@ -0,0 +1,171 @@
package io.metersphere.reportstatistics.service;
import io.metersphere.base.mapper.ext.ExtTestAnalysisMapper;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.ProjectRequest;
import io.metersphere.dto.ProjectDTO;
import io.metersphere.reportstatistics.dto.*;
import io.metersphere.reportstatistics.dto.charts.Legend;
import io.metersphere.reportstatistics.dto.charts.Series;
import io.metersphere.reportstatistics.dto.charts.XAxis;
import io.metersphere.reportstatistics.dto.charts.YAxis;
import io.metersphere.service.ProjectService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestAnalysisService {
@Resource
private ExtTestAnalysisMapper extTestAnalysisMapper;
@Resource
private ProjectService projectService;
private final String ADD = "新增用例";
private final String UPDATE = "修改用例";
public TestAnalysisResult getReport(TestAnalysisChartRequest request) {
if (CollectionUtils.isEmpty(request.getTimes())) {
// 最近七天
request.setTimes(Arrays.asList(System.currentTimeMillis() - 7 * 24 * 3600 * 1000L, System.currentTimeMillis()));
}
request.setStartTime(DateUtils.getDataStr(request.getTimes().get(0)));
request.setEndTime(DateUtils.getDataStr(request.getTimes().get(1)));
if (CollectionUtils.isEmpty(request.getProjects())) {
// 获取当前组织空间下所有项目
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
ProjectRequest projectRequest = new ProjectRequest();
projectRequest.setWorkspaceId(currentWorkspaceId);
List<ProjectDTO> projectDTOS = projectService.getProjectList(projectRequest);
if (CollectionUtils.isNotEmpty(projectDTOS)) {
request.setProjects(projectDTOS.stream().map(ProjectDTO::getId).collect(Collectors.toList()));
} else {
request.setProjects(new LinkedList<String>(){{this.add(UUID.randomUUID().toString());}});
}
}
TestAnalysisChartDTO dto = new TestAnalysisChartDTO();
List<TestAnalysisTableDTO> dtos = new LinkedList<>();
List<Series> seriesList = new LinkedList<>();
XAxis xAxis = new XAxis();
if (CollectionUtils.isEmpty(request.getUsers())) {
// 组织charts格式数据
Legend legend = new Legend();
formatLegend(legend, null, request);
dto.setLegend(legend);
List<TestAnalysisChartResult> createResults = extTestAnalysisMapper.getCraeteCaseReport(request);
// 获取修改的用例统计报表
List<TestAnalysisChartResult> updateResults = extTestAnalysisMapper.getUpdateCaseReport(request);
formatXaxisSeries(xAxis, seriesList, "", dto, createResults, updateResults);
formatTable(dtos, createResults, updateResults);
} else {
List<String> users = request.getUsers();
Legend legend = new Legend();
formatLegend(legend, users, request);
dto.setLegend(legend);
// 按用户展示
boolean isFlag = true;
for (String item : users) {
request.setUsers(Arrays.asList(item));
List<TestAnalysisChartResult> createResults = extTestAnalysisMapper.getCraeteCaseReport(request);
// 获取修改的用例统计报表
List<TestAnalysisChartResult> updateResults = extTestAnalysisMapper.getUpdateCaseReport(request);
formatXaxisSeries(xAxis, seriesList, item + "-", dto, createResults, updateResults);
// 初始化列表总量按天统计总量
if (isFlag) {
formatTable(dtos, createResults, updateResults);
isFlag = false;
}
// 增加子项
for (int j = 0; j < dtos.size(); j++) {
TestAnalysisTableDTO childItem = new TestAnalysisTableDTO(item, createResults.get(j).getCountNum(), updateResults.get(j).getCountNum(), null);
dtos.get(j).getChildren().add(childItem);
}
}
}
// 每行总计
dtos.forEach(item -> {
if (CollectionUtils.isNotEmpty(item.getChildren())) {
// table 总和计算
List<Integer> collect = item.getChildren().stream().map(childItem -> Integer.valueOf(childItem.getCreateCount())).collect(Collectors.toList());
// reduce求和
Optional<Integer> createCount = collect.stream().reduce(Integer::sum);
List<Integer> upCollect = item.getChildren().stream().map(childItem -> Integer.valueOf(childItem.getUpdateCount())).collect(Collectors.toList());
// reduce求和
Optional<Integer> updateCount = upCollect.stream().reduce(Integer::sum);
item.setCreateCount(createCount.get().toString());
item.setUpdateCount(updateCount.get().toString());
}
});
// table 总和计算
List<Integer> collect = dtos.stream().map(item -> Integer.valueOf(item.getCreateCount())).collect(Collectors.toList());
// reduce求和
Optional<Integer> createCount = collect.stream().reduce(Integer::sum);
List<Integer> upCollect = dtos.stream().map(item -> Integer.valueOf(item.getUpdateCount())).collect(Collectors.toList());
// reduce求和
Optional<Integer> updateCount = upCollect.stream().reduce(Integer::sum);
dtos.add(new TestAnalysisTableDTO("总计", createCount.get().toString(), updateCount.get().toString(), new LinkedList<>()));
TestAnalysisResult testAnalysisResult = new TestAnalysisResult();
testAnalysisResult.setChartDTO(dto);
testAnalysisResult.setTableDTOs(dtos);
return testAnalysisResult;
}
private void formatXaxisSeries(XAxis xAxis, List<Series> seriesList, String name, TestAnalysisChartDTO dto, List<TestAnalysisChartResult> createResults, List<TestAnalysisChartResult> updateResults) {
if (CollectionUtils.isNotEmpty(createResults)) {
xAxis.setData(createResults.stream().map(TestAnalysisChartResult::getDateStr).collect(Collectors.toList()));
Series series = new Series();
series.setName(name + ADD);
series.setData(createResults.stream().map(TestAnalysisChartResult::getCountNum).collect(Collectors.toList()));
seriesList.add(series);
}
if (CollectionUtils.isNotEmpty(updateResults)) {
xAxis.setData(updateResults.stream().map(TestAnalysisChartResult::getDateStr).collect(Collectors.toList()));
Series series = new Series();
series.setName(name + UPDATE);
series.setColor("#B8741A");
series.setData(updateResults.stream().map(TestAnalysisChartResult::getCountNum).collect(Collectors.toList()));
seriesList.add(series);
}
dto.setXAxis(xAxis);
dto.setYAxis(new YAxis());
dto.setSeries(seriesList);
}
private void formatLegend(Legend legend, List<String> datas, TestAnalysisChartRequest request) {
Map<String, Boolean> selected = new LinkedHashMap<>();
List<String> list = new LinkedList<>();
if (CollectionUtils.isEmpty(datas)) {
selected.put(ADD, request.isCreateCase());
selected.put(UPDATE, request.isUpdateCase());
list.add(ADD);
list.add(UPDATE);
} else {
datas.forEach(item -> {
selected.put(item + "-" + ADD, request.isCreateCase());
selected.put(item + "-" + UPDATE, request.isUpdateCase());
list.add(item + "-" + ADD);
list.add(item + "-" + UPDATE);
});
}
legend.setSelected(selected);
legend.setData(list);
}
private void formatTable(List<TestAnalysisTableDTO> dtos, List<TestAnalysisChartResult> createResults, List<TestAnalysisChartResult> updateResults) {
for (int i = 0; i < createResults.size(); i++) {
TestAnalysisTableDTO dto = new TestAnalysisTableDTO(createResults.get(i).getDateStr(), createResults.get(i).getCountNum(), updateResults.get(i).getCountNum(), new LinkedList<>());
dtos.add(dto);
}
}
}

View File

@ -0,0 +1,775 @@
package io.metersphere.reportstatistics.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.CustomField;
import io.metersphere.base.domain.User;
import io.metersphere.base.mapper.ext.ExtTestCaseCountMapper;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.controller.request.member.QueryMemberRequest;
import io.metersphere.dto.TestCaseTemplateDao;
import io.metersphere.i18n.Translator;
import io.metersphere.reportstatistics.dto.*;
import io.metersphere.reportstatistics.dto.charts.*;
import io.metersphere.service.TestCaseTemplateService;
import io.metersphere.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestCaseCountService {
@Resource
private ExtTestCaseCountMapper extTestCaseCountMapper;
@Resource
UserService userService;
public TestCaseCountResponse getReport(TestCaseCountRequest request) {
request.setFilterType(request.getFilterType().toUpperCase(Locale.ROOT));
TestAnalysisChartDTO dto = new TestAnalysisChartDTO();
PieChartDTO pieChartDTO = new PieChartDTO();
List<TestCaseCountTableDTO> dtos = new LinkedList<>();
List<Series> seriesList = new LinkedList<>();
XAxis xAxis = new XAxis();
xAxis.setAxisLabel(new HashMap<String,Integer>(){ {this.put("interval",0);this.put("rotate",0);}});
// 组织charts格式数据
Legend legend = new Legend();
formatLegend(legend, request.getYaxis(), request);
dto.setLegend(legend);
//根据X轴分组计算字段来整理不同表对应的字段 注意x轴维护人/查询条件有维护人时 不查接口和性能 x轴为用例等级/查询条件有用例等级的不查性能
boolean yAxisSelectTestCase = false;
boolean yAxisSelectApi = false;
boolean yAxisSelectScenarioCase = false;
boolean yAxisSelectLoad = false;
boolean selectApi = true;
boolean selectLoad = true;
boolean parseUser = false;
boolean parseStatus = false;
switch (request.getXaxis()) {
case "creator":
request.setTestCaseGroupColumn("create_user");
request.setApiCaseGroupColumn("create_user_id");
request.setScenarioCaseGroupColumn("create_user");
request.setLoadCaseGroupColumn("create_user");
parseUser = true;
break;
case "maintainer":
request.setTestCaseGroupColumn("maintainer");
request.setApiCaseGroupColumn("'无维护人'");
request.setScenarioCaseGroupColumn("principal");
request.setLoadCaseGroupColumn("'无维护人'");
selectApi = false;
selectLoad = false;
parseUser = true;
break;
case "casetype":
Map<String, String> caseDescMap = this.getCaseDescMap();
request.setTestCaseGroupColumn("'" + caseDescMap.get("testCaseDesc") + "'");
request.setApiCaseGroupColumn("'" + caseDescMap.get("apiCaseDesc") + "'");
request.setScenarioCaseGroupColumn("'" + caseDescMap.get("scenarioCaseDesc") + "'");
request.setLoadCaseGroupColumn("'" + caseDescMap.get("loadCaseDesc") + "'");
break;
case "casestatus":
request.setTestCaseGroupColumn("status");
request.setApiCaseGroupColumn("status");
request.setScenarioCaseGroupColumn("status");
request.setLoadCaseGroupColumn("status");
selectApi = false;
parseStatus = true;
break;
case "caselevel":
request.setTestCaseGroupColumn("priority");
request.setApiCaseGroupColumn("priority");
request.setScenarioCaseGroupColumn("level");
request.setLoadCaseGroupColumn("'无用例等级'");
selectLoad = false;
break;
default:
return new TestCaseCountResponse();
}
//计算时间
if (StringUtils.equalsIgnoreCase(request.getTimeType(), "dynamicTime")) {
int dateCountType = 0;
if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "day")) {
dateCountType = Calendar.DAY_OF_MONTH;
} else if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "month")) {
dateCountType = Calendar.MONTH;
} else if (StringUtils.equalsIgnoreCase(request.getTimeRangeUnit(), "year")) {
dateCountType = Calendar.YEAR;
}
if (dateCountType != 0 && request.getTimeRange() != 0) {
long startTime = DateUtils.dateSum(new Date(), (0 - request.getTimeRange()), dateCountType).getTime();
request.setStartTime(startTime);
}
} else if (StringUtils.equalsIgnoreCase(request.getTimeType(), "fixedTime")) {
if (CollectionUtils.isNotEmpty(request.getTimes()) && request.getTimes().size() == 2) {
request.setStartTime(request.getTimes().get(0));
request.setEndTime(request.getTimes().get(1));
}
}
//计算更多属性
if (CollectionUtils.isNotEmpty(request.getFilters())) {
for (Map<String, Object> filterMap : request.getFilters()) {
String filterType = String.valueOf(filterMap.get("type"));
if (StringUtils.equalsAnyIgnoreCase(filterType, "casetype", "caselevel", "creator", "maintainer")) {
Object valueObj = filterMap.get("values");
if (valueObj instanceof List) {
List<String> searchList = (List) valueObj;
if(!searchList.isEmpty()){
request.setFilterSearchList(filterType, searchList);
}
}
if (StringUtils.equalsIgnoreCase(filterType, "caselevel")) {
selectLoad = false;
}else if (StringUtils.equalsIgnoreCase(filterType, "maintainer")) {
selectApi = false;
selectLoad = false;
}
}else if(StringUtils.equalsAnyIgnoreCase(filterType, "casestatus")){
List<String> searchList = new ArrayList<>();
Object valueObj = filterMap.get("values");
if (valueObj instanceof List) {
for (String statusStr : (List<String>) valueObj) {
searchList.add(statusStr.toUpperCase(Locale.ROOT));
}
}
//如果包含Running
if(searchList.contains("RUNNING")){
if(!searchList.contains("Starting")){
searchList.add("STARTING");
}
if(!searchList.contains("Underway")){
searchList.add("UNDERWAY");
}
}
if(searchList.contains("FINISHED")){
if(!searchList.contains("Completed")){
searchList.add("Completed");
}
}
if(!searchList.isEmpty()){
request.setFilterSearchList(filterType, searchList);
}
selectApi = false;
}
}
}
//获取测试用例接口用例场景用例性能用例的统计
List<TestCaseCountChartResult> functionCaseCountResult = new ArrayList<>();
List<TestCaseCountChartResult> apiCaseCountResult = new ArrayList<>();
List<TestCaseCountChartResult> scenarioCaseCount = new ArrayList<>();
List<TestCaseCountChartResult> loadCaseCount = new ArrayList<>();
List<String> moreOptionsAboutCaseType = new ArrayList<>();
if (StringUtils.equalsIgnoreCase(request.getFilterType(), "And") && MapUtils.isNotEmpty(request.getFilterSearchList())) {
if (request.getFilterSearchList().containsKey("maintainer")) {
selectApi = false;
}
if (request.getFilterSearchList().containsKey("caselevel")) {
selectLoad = false;
}
if (request.getFilterSearchList().containsKey("casetype")) {
//如果""查询同时针对案例类型做过筛选那么则分开批量查询
List<String> selectCaseTypeList = request.getFilterSearchList().get("casetype");
request.getFilterSearchList().remove("casetype");
if (CollectionUtils.isNotEmpty(selectCaseTypeList)) {
moreOptionsAboutCaseType.addAll(selectCaseTypeList);
}
}
}
//没有选择的话默认搜索条件是所有类型的案例
if(moreOptionsAboutCaseType.isEmpty()){
moreOptionsAboutCaseType.add("testCase");
moreOptionsAboutCaseType.add("apiCase");
moreOptionsAboutCaseType.add("scenarioCase");
moreOptionsAboutCaseType.add("loadCase");
}
//解析Y轴判断要查询的案例类型
if(CollectionUtils.isNotEmpty(request.getYaxis())){
for (String selectType:request.getYaxis()) {
if(moreOptionsAboutCaseType.contains(selectType)){
if (StringUtils.equalsIgnoreCase(selectType, "testCase")) {
yAxisSelectTestCase = true;
} else if (StringUtils.equalsIgnoreCase(selectType, "apiCase")) {
if(selectApi){
yAxisSelectApi = true;
}
} else if (StringUtils.equalsIgnoreCase(selectType, "scenarioCase")) {
yAxisSelectScenarioCase = true;
} else if (StringUtils.equalsIgnoreCase(selectType, "loadCase")) {
if(selectLoad){
yAxisSelectLoad = true;
}
}
}
}
}
if(yAxisSelectTestCase){
functionCaseCountResult = extTestCaseCountMapper.getFunctionCaseCount(request);
}
if (yAxisSelectApi) {
Map<String,List<String>> apiCaseFilterList = new HashMap<>();
if(MapUtils.isNotEmpty(request.getFilterSearchList())){
for (Map.Entry<String,List<String>> entry : request.getFilterSearchList().entrySet()) {
String type = entry.getKey();
if(!StringUtils.equalsAnyIgnoreCase(type,"maintainer","casestatus")){
apiCaseFilterList.put(entry.getKey(),entry.getValue());
}
}
}
request.setApiFilterSearchList(apiCaseFilterList);
apiCaseCountResult = extTestCaseCountMapper.getApiCaseCount(request);
}
if(yAxisSelectScenarioCase){
scenarioCaseCount = extTestCaseCountMapper.getScenarioCaseCount(request);
}
if (yAxisSelectLoad) {
Map<String,List<String>> loadCaseFilterMap = new HashMap<>();
if(MapUtils.isNotEmpty(request.getFilterSearchList())){
for (Map.Entry<String,List<String>> entry : request.getFilterSearchList().entrySet()) {
String type = entry.getKey();
if(!StringUtils.equalsAnyIgnoreCase(type,"maintainer","caselevel")){
loadCaseFilterMap.put(entry.getKey(),entry.getValue());
}
}
}
request.setLoadFilterSearchList(loadCaseFilterMap);
loadCaseCount = extTestCaseCountMapper.getLoadCaseCount(request);
}
Map<String, TestCaseCountSummary> summaryMap = this.summaryCountResult(parseUser, parseStatus,request.getProjectId(),request.getOrder(),
functionCaseCountResult, apiCaseCountResult, scenarioCaseCount, loadCaseCount);
formatXaxisSeries(xAxis, seriesList, dto, summaryMap);
formatTable(dtos, summaryMap);
formatPieChart(pieChartDTO, request.getXaxis(), summaryMap,yAxisSelectTestCase,yAxisSelectApi,yAxisSelectScenarioCase,yAxisSelectLoad);
TestCaseCountResponse testCaseCountResult = new TestCaseCountResponse();
testCaseCountResult.setBarChartDTO(dto);
testCaseCountResult.setTableDTOs(dtos);
testCaseCountResult.setPieChartDTO(pieChartDTO);
return testCaseCountResult;
}
private void formatPieChart(PieChartDTO pieChartDTO, String groupName, Map<String, TestCaseCountSummary> summaryMap,
boolean selectTestCase, boolean selectApi, boolean selectScenarioCase, boolean selectLoad) {
JSONArray titleArray = new JSONArray();
titleArray.add("type");
titleArray.add("count");
titleArray.add(groupName);
List<Series> seriesArr = new ArrayList<>();
List<Title> titles = new ArrayList<>();
int leftPx = 200;
Map<String, String> caseDescMap = this.getCaseDescMap();
for (TestCaseCountSummary summary : summaryMap.values()) {
String leftPxStr = String.valueOf(leftPx);
List<Object> dataList = new ArrayList<>();
if(selectTestCase && summary.testCaseCount > 0){
PieData pieData = new PieData();
pieData.setName(caseDescMap.get("testCaseDesc"));
pieData.setValue(summary.testCaseCount);
pieData.setColor("#F38F1F");
dataList.add(pieData);
}
if(selectApi && summary.apiCaseCount > 0){
PieData apicasePieData = new PieData();
apicasePieData.setName(caseDescMap.get("apiCaseDesc"));
apicasePieData.setValue(summary.apiCaseCount);
apicasePieData.setColor("#6FD999");
dataList.add(apicasePieData);
}
if(selectScenarioCase && summary.scenarioCaseCount > 0){
PieData scenarioPieData = new PieData();
scenarioPieData.setName(caseDescMap.get("scenarioCaseDesc"));
scenarioPieData.setValue(summary.scenarioCaseCount);
scenarioPieData.setColor("#2884F3");
dataList.add(scenarioPieData);
}
if(selectLoad && summary.loadCaseCount > 0){
PieData loadCasePieData = new PieData();
loadCasePieData.setName(caseDescMap.get("loadCaseDesc"));
loadCasePieData.setValue(summary.loadCaseCount);
loadCasePieData.setColor("#F45E53");
dataList.add(loadCasePieData);
}
Series series = new Series();
series.setType("pie");
series.setRadius("50");
series.setEncode(new JSONObject() {{
this.put("itemName", "groupname");
this.put("value", summary.groupName);
}});
seriesArr.add(series);
series.setData(dataList);
series.setCenter(new ArrayList<String>() {{
this.add(leftPxStr);
this.add("50%");
}});
Title title = new Title();
title.setSubtext(summary.groupName);
title.setLeft(leftPxStr);
titles.add(title);
leftPx = leftPx + 350;
}
pieChartDTO.setSeries(seriesArr);
pieChartDTO.setTitle(titles);
pieChartDTO.setWidth(leftPx);
}
private Map<String, TestCaseCountSummary> summaryCountResult(boolean parseGroupNameToUserName, boolean parseGrouNameToCaseStatus, String projectId, String order,
List<TestCaseCountChartResult> functionCaseCountResult, List<TestCaseCountChartResult> apiCaseCountResult, List<TestCaseCountChartResult> scenarioCaseCount, List<TestCaseCountChartResult> loadCaseCount) {
Map<String, TestCaseCountSummary> summaryMap = new LinkedHashMap<>();
//groupName 解析对象
Map<String, String> groupNameParseMap = new HashMap<>();
if (parseGroupNameToUserName) {
groupNameParseMap.putAll(this.getUserIdMap());
}
if (parseGrouNameToCaseStatus) {
groupNameParseMap.putAll(this.getCaseStatusMap(projectId));
}
if (CollectionUtils.isNotEmpty(functionCaseCountResult)) {
for (TestCaseCountChartResult result : functionCaseCountResult) {
if(result.getGroupName() == null){
result.setGroupName(groupNameParseMap.get("running"));
}else {
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
}
}
String groupName = result.getGroupName();
if (StringUtils.isNotEmpty(groupName)) {
TestCaseCountSummary summary = summaryMap.get(groupName);
if (summary == null) {
summary = new TestCaseCountSummary(groupName);
}
summary.testCaseCount = result.getCountNum();
summaryMap.put(groupName, summary);
}
}
}
if (CollectionUtils.isNotEmpty(apiCaseCountResult)) {
for (TestCaseCountChartResult result : apiCaseCountResult) {
if(result.getGroupName() == null){
result.setGroupName(groupNameParseMap.get("running"));
}else {
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
}
}
String groupName = result.getGroupName();
if (StringUtils.isNotEmpty(groupName)) {
TestCaseCountSummary summary = summaryMap.get(groupName);
if (summary == null) {
summary = new TestCaseCountSummary(groupName);
}
summary.apiCaseCount = result.getCountNum();
summaryMap.put(groupName, summary);
}
}
}
if (CollectionUtils.isNotEmpty(scenarioCaseCount)) {
for (TestCaseCountChartResult result : scenarioCaseCount) {
if(result.getGroupName() == null){
result.setGroupName(groupNameParseMap.get("running"));
}else {
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
}
}
String groupName = result.getGroupName();
if (StringUtils.isNotEmpty(groupName)) {
TestCaseCountSummary summary = summaryMap.get(groupName);
if (summary == null) {
summary = new TestCaseCountSummary(groupName);
}
summary.scenarioCaseCount = result.getCountNum();
summaryMap.put(groupName, summary);
}
}
}
if (CollectionUtils.isNotEmpty(loadCaseCount)) {
for (TestCaseCountChartResult result : loadCaseCount) {
if(result.getGroupName() == null){
result.setGroupName(groupNameParseMap.get("running"));
}else {
if (groupNameParseMap.containsKey(result.getGroupName().toLowerCase(Locale.ROOT))) {
result.setGroupName(groupNameParseMap.get(result.getGroupName().toLowerCase(Locale.ROOT)));
}
}
String groupName = result.getGroupName();
if (StringUtils.isNotEmpty(groupName)) {
TestCaseCountSummary summary = summaryMap.get(groupName);
if (summary == null) {
summary = new TestCaseCountSummary(groupName);
}
summary.loadCaseCount = result.getCountNum();
summaryMap.put(groupName, summary);
}
}
}
Map<String, TestCaseCountSummary> returmMap = new LinkedHashMap<>();
if(StringUtils.equalsIgnoreCase(order,"desc")){
TreeMap<Long,List<TestCaseCountSummary>> treeMap = new TreeMap<>();
for (TestCaseCountSummary model : summaryMap.values()) {
if(treeMap.containsKey(model.getAllCount())){
treeMap.get(model.getAllCount()).add(model);
}else {
List<TestCaseCountSummary> list = new ArrayList<>();
list.add(model);
treeMap.put(model.getAllCount(),list);
}
}
ArrayList<TestCaseCountSummary> sortedList = new ArrayList<>();
for (List<TestCaseCountSummary> list : treeMap.values()) {
sortedList.addAll(list);
}
for (int i = sortedList.size(); i > 0; i --) {
TestCaseCountSummary model = sortedList.get(i-1);
returmMap.put(model.groupName,model);
}
}else if(StringUtils.equalsIgnoreCase(order,"asc")){
TreeMap<Long,List<TestCaseCountSummary>> treeMap = new TreeMap<>();
for (TestCaseCountSummary model : summaryMap.values()) {
if(treeMap.containsKey(model.getAllCount())){
treeMap.get(model.getAllCount()).add(model);
}else {
List<TestCaseCountSummary> list = new ArrayList<>();
list.add(model);
treeMap.put(model.getAllCount(),list);
}
}
for (List<TestCaseCountSummary> list : treeMap.values()) {
for (TestCaseCountSummary model : list ) {
returmMap.put(model.groupName,model);
}
}
}else {
returmMap = summaryMap;
}
return returmMap;
}
private Map<String, String> getUserIdMap() {
List<User> userList = userService.getUserList();
Map<String, String> userIdMap = new HashMap<>();
for (User model : userList) {
userIdMap.put(model.getId(), model.getId() + "\n(" + model.getName() + ")");
}
return userIdMap;
}
private Map<String, String> getCaseStatusMap(String projectId) {
Map<String, String> caseStatusMap = new HashMap<>();
TestCaseTemplateService testCaseTemplateService = CommonBeanFactory.getBean(TestCaseTemplateService.class);
TestCaseTemplateDao testCaseTemplate = testCaseTemplateService.getTemplate(projectId);
caseStatusMap.put("prepare", Translator.get("test_case_status_prepare"));
caseStatusMap.put("error", Translator.get("test_case_status_error"));
caseStatusMap.put("success", Translator.get("test_case_status_success"));
caseStatusMap.put("trash", Translator.get("test_case_status_trash"));
caseStatusMap.put("underway", Translator.get("test_case_status_running"));
caseStatusMap.put("starting", Translator.get("test_case_status_running"));
caseStatusMap.put("saved", Translator.get("test_case_status_saved"));
caseStatusMap.put("running", Translator.get("test_case_status_running"));
caseStatusMap.put("finished", Translator.get("test_case_status_finished"));
caseStatusMap.put("completed", Translator.get("test_case_status_finished"));
if (testCaseTemplate != null && CollectionUtils.isNotEmpty(testCaseTemplate.getCustomFields())) {
for (CustomField customField : testCaseTemplate.getCustomFields()) {
if (StringUtils.equals(customField.getName(), "用例状态")) {
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
for (int i = 0; i < optionsArr.size(); i++) {
JSONObject jsonObject = optionsArr.getJSONObject(i);
if (jsonObject.containsKey("value") && jsonObject.containsKey("text") &&
!StringUtils.equalsAnyIgnoreCase(jsonObject.getString("value"), "Prepare", "Error", "Success", "Trash", "Underway", "Starting", "Saved")) {
caseStatusMap.put(jsonObject.getString("value"), jsonObject.getString("text"));
}
}
}
}
}
return caseStatusMap;
}
private void formatXaxisSeries(XAxis xAxis, List<Series> seriesList, TestAnalysisChartDTO dto,
Map<String, TestCaseCountSummary> summaryMap) {
List<String> xAxisDataList = new ArrayList<>();
List<Object> testCaseCountList = new ArrayList<>();
List<Object> apiCaseCountList = new ArrayList<>();
List<Object> scenarioCaseCountList = new ArrayList<>();
List<Object> loadCaseCountList = new ArrayList<>();
for (TestCaseCountSummary summary : summaryMap.values()) {
xAxisDataList.add(summary.groupName);
testCaseCountList.add(String.valueOf(summary.testCaseCount));
apiCaseCountList.add(String.valueOf(summary.apiCaseCount));
scenarioCaseCountList.add(String.valueOf(summary.scenarioCaseCount));
loadCaseCountList.add(String.valueOf(summary.loadCaseCount));
}
xAxis.setData(xAxisDataList);
Map<String, String> caseDescMap = this.getCaseDescMap();
Series tetcaseSeries = new Series();
tetcaseSeries.setName(caseDescMap.get("testCaseDesc"));
tetcaseSeries.setColor("#F38F1F");
tetcaseSeries.setRadius("20%");
tetcaseSeries.setType("bar");
tetcaseSeries.setStack("total");
tetcaseSeries.setData(testCaseCountList);
seriesList.add(tetcaseSeries);
Series apiSeries = new Series();
apiSeries.setName(caseDescMap.get("apiCaseDesc"));
apiSeries.setColor("#6FD999");
apiSeries.setType("bar");
apiSeries.setStack("total");
apiSeries.setData(apiCaseCountList);
seriesList.add(apiSeries);
Series scenarioSeries = new Series();
scenarioSeries.setName(caseDescMap.get("scenarioCaseDesc"));
scenarioSeries.setColor("#2884F3");
scenarioSeries.setType("bar");
scenarioSeries.setStack("total");
scenarioSeries.setData(scenarioCaseCountList);
seriesList.add(scenarioSeries);
Series loadSeries = new Series();
loadSeries.setName(caseDescMap.get("loadCaseDesc"));
loadSeries.setColor("#F45E53");
loadSeries.setType("bar");
loadSeries.setStack("total");
loadSeries.setData(loadCaseCountList);
seriesList.add(loadSeries);
dto.setXAxis(xAxis);
dto.setYAxis(new YAxis());
dto.setSeries(seriesList);
}
private void formatLegend(Legend legend, List<String> datas, TestCaseCountRequest yrequest) {
Map<String, Boolean> selected = new LinkedHashMap<>();
List<String> list = new LinkedList<>();
legend.setSelected(selected);
legend.setData(datas);
}
private void formatTable(List<TestCaseCountTableDTO> dtos, Map<String, TestCaseCountSummary> summaryMap) {
for (TestCaseCountSummary summary : summaryMap.values()) {
TestCaseCountTableDTO dto = new TestCaseCountTableDTO(summary.groupName, summary.testCaseCount, summary.apiCaseCount, summary.scenarioCaseCount, summary.loadCaseCount);
dtos.add(dto);
}
}
private Map<String, String> getCaseDescMap() {
Map<String, String> map = new HashMap<>();
map.put("testCaseDesc", Translator.get("test_case"));
map.put("apiCaseDesc", Translator.get("api_case"));
map.put("scenarioCaseDesc", Translator.get("scenario_case"));
map.put("loadCaseDesc", Translator.get("performance_case"));
return map;
}
public Map<String, List<Map<String, String>>> getSelectFilterDatas(String projectId) {
Map<String, List<Map<String, String>>> returnMap = new HashMap<>();
//组装用户
QueryMemberRequest memberRequest = new QueryMemberRequest();
memberRequest.setProjectId(projectId);
List<User> userList = userService.getUserList();
List<Map<String, String>> returnUserList = new ArrayList<>();
for (User user : userList) {
Map<String, String> map = new HashMap<>();
map.put("id", user.getId());
map.put("label", user.getId() + "(" + user.getName() + ")");
returnUserList.add(map);
}
//组装用例等级和用例状态
TestCaseTemplateService testCaseTemplateService = CommonBeanFactory.getBean(TestCaseTemplateService.class);
TestCaseTemplateDao testCaseTemplate = testCaseTemplateService.getTemplate(projectId);
List<Map<String, String>> caseLevelList = new ArrayList<>();
List<Map<String, String>> caseStatusList = new ArrayList<>();
Map<String, String> statusMap1 = new HashMap<>();
statusMap1.put("id", "Prepare");
statusMap1.put("label", Translator.get("test_case_status_prepare"));
// Map<String, String> statusMap2 = new HashMap<>();
// statusMap2.put("id", "Error");
// statusMap2.put("label", Translator.get("test_case_status_error"));
//
// Map<String, String> statusMap3 = new HashMap<>();
// statusMap3.put("id", "Success");
// statusMap3.put("label", Translator.get("test_case_status_success"));
// Map<String, String> statusMap4 = new HashMap<>();
// statusMap4.put("id", "Trash");
// statusMap4.put("label", Translator.get("test_case_status_trash"));
// Map<String, String> statusMap5 = new HashMap<>();
// statusMap5.put("id", "Underway");
// statusMap5.put("label", Translator.get("test_case_status_running"));
// Map<String, String> statusMap6 = new HashMap<>();
// statusMap6.put("id", "Starting");
// statusMap6.put("label", Translator.get("test_case_status_running"));
Map<String, String> statusMap7 = new HashMap<>();
statusMap7.put("id", "Saved");
statusMap7.put("label", Translator.get("test_case_status_saved"));
Map<String, String> statusMap8 = new HashMap<>();
statusMap8.put("id", "Running");
statusMap8.put("label", Translator.get("test_case_status_running"));
Map<String, String> statusMap9 = new HashMap<>();
statusMap9.put("id", "Finished");
statusMap9.put("label", Translator.get("test_case_status_finished"));
caseStatusList.add(statusMap1);
// caseStatusList.add(statusMap2);
// caseStatusList.add(statusMap3);
// caseStatusList.add(statusMap4);
// caseStatusList.add(statusMap5);
// caseStatusList.add(statusMap6);
caseStatusList.add(statusMap7);
caseStatusList.add(statusMap8);
caseStatusList.add(statusMap9);
Map<String, String> levelMap1 = new HashMap<>();
levelMap1.put("id", "P0");
levelMap1.put("label", "P0");
Map<String, String> levelMap2 = new HashMap<>();
levelMap2.put("id", "P1");
levelMap2.put("label", "P1");
Map<String, String> levelMap3 = new HashMap<>();
levelMap3.put("id", "P2");
levelMap3.put("label", "P2");
Map<String, String> levelMap4 = new HashMap<>();
levelMap4.put("id", "P3");
levelMap4.put("label", "P3");
caseLevelList.add(levelMap1);
caseLevelList.add(levelMap2);
caseLevelList.add(levelMap3);
caseLevelList.add(levelMap4);
if (testCaseTemplate != null && CollectionUtils.isNotEmpty(testCaseTemplate.getCustomFields())) {
for (CustomField customField : testCaseTemplate.getCustomFields()) {
if (StringUtils.equals(customField.getName(), "用例状态")) {
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
for (int i = 0; i < optionsArr.size(); i++) {
JSONObject jsonObject = optionsArr.getJSONObject(i);
if (jsonObject.containsKey("value") && jsonObject.containsKey("text")) {
String value = jsonObject.getString("value");
if(!StringUtils.equalsAnyIgnoreCase(value, "Prepare", "Error", "Success", "Trash", "Underway", "Starting", "Saved",
"Completed","test_track.case.status_finished")){
Map<String, String> statusMap = new HashMap<>();
statusMap.put("id", jsonObject.getString("value"));
statusMap.put("label", jsonObject.getString("text"));
caseStatusList.add(statusMap);
}
}
}
} else if (StringUtils.equals(customField.getName(), "用例等级")) {
JSONArray optionsArr = JSONArray.parseArray(customField.getOptions());
for (int i = 0; i < optionsArr.size(); i++) {
JSONObject jsonObject = optionsArr.getJSONObject(i);
if (jsonObject.containsKey("value") && jsonObject.containsKey("text") &&
!StringUtils.equalsAnyIgnoreCase(jsonObject.getString("value"), "P0", "P1", "P2", "P3")) {
Map<String, String> levelMap = new HashMap<>();
levelMap.put("id", jsonObject.getString("value"));
levelMap.put("label", jsonObject.getString("text"));
caseLevelList.add(levelMap);
}
}
}
}
}
Map<String, String> caseDescMap = this.getCaseDescMap();
// 组装用例类型
List<Map<String, String>> caseTypeList = new ArrayList<>();
Map<String, String> caseTypeMap1 = new HashMap<>();
caseTypeMap1.put("id", "testCase");
caseTypeMap1.put("label", caseDescMap.get("testCaseDesc"));
Map<String, String> caseTypeMap2 = new HashMap<>();
caseTypeMap2.put("id", "apiCase");
caseTypeMap2.put("label", caseDescMap.get("apiCaseDesc"));
Map<String, String> caseTypeMap3 = new HashMap<>();
caseTypeMap3.put("id", "scenarioCase");
caseTypeMap3.put("label", caseDescMap.get("scenarioCaseDesc"));
Map<String, String> caseTypeMap4 = new HashMap<>();
caseTypeMap4.put("id", "loadCase");
caseTypeMap4.put("label", caseDescMap.get("loadCaseDesc"));
caseTypeList.add(caseTypeMap1);
caseTypeList.add(caseTypeMap2);
caseTypeList.add(caseTypeMap3);
caseTypeList.add(caseTypeMap4);
returnMap.put("casetype", caseTypeList);
returnMap.put("caselevel", caseLevelList);
returnMap.put("casestatus", caseStatusList);
returnMap.put("creator", returnUserList);
returnMap.put("maintainer", returnUserList);
return returnMap;
}
}

View File

@ -0,0 +1,33 @@
package io.metersphere.service;
import io.metersphere.base.domain.TestPlanPrincipal;
import io.metersphere.base.domain.TestPlanPrincipalExample;
import io.metersphere.base.mapper.TestPlanPrincipalMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanPrincipalService {
@Resource
private TestPlanPrincipalMapper testPlanPrincipalMapper;
public void deleteTestPlanPrincipalByPlanId(String planId) {
if (StringUtils.isBlank(planId)) {
return;
}
TestPlanPrincipalExample example = new TestPlanPrincipalExample();
example.createCriteria().andTestPlanIdEqualTo(planId);
testPlanPrincipalMapper.deleteByExample(example);
}
public TestPlanPrincipal insert(TestPlanPrincipal testPlanPrincipal) {
testPlanPrincipalMapper.insert(testPlanPrincipal);
return testPlanPrincipal;
}
}

View File

@ -5,10 +5,7 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.datacount.request.ScheduleInfoRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.TestPlan;
import io.metersphere.base.domain.TestPlanWithBLOBs;
import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
@ -107,8 +104,8 @@ public class TestPlanController {
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_EDIT)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#testPlanDTO.id)", content = "#msClass.getLogDetails(#testPlanDTO.id)", msClass = TestPlanService.class)
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, event = NoticeConstants.Event.UPDATE, mailTemplate = "track/TestPlanEnd", subject = "测试计划通知")
public TestPlan editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
return testPlanService.editTestPlan(testPlanDTO);
public TestPlan editTestPlan(@RequestBody AddTestPlanRequest testPlanDTO) {
return testPlanService.editTestPlanWithRequest(testPlanDTO);
}
@PostMapping("/edit/status/{planId}")
@ -259,4 +256,9 @@ public class TestPlanController {
public boolean haveExecCase(@PathVariable String id) {
return testPlanService.haveExecCase(id);
}
@GetMapping("/principal/{planId}")
public List<User> getPlanPrincipal(@PathVariable String planId) {
return testPlanService.getPlanPrincipal(planId);
}
}

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.TestPlanLoadCase;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
@ -66,6 +67,11 @@ public class TestPlanLoadCaseController {
@PostMapping("/run/batch")
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.EXECUTE, content = "#msClass.getRunLogDetails(#request.requests)", msClass = TestPlanLoadCaseService.class)
public void runBatch(@RequestBody RunBatchTestPlanRequest request) {
if (request.getRequests() != null) {
for (RunTestPlanRequest req : request.getRequests()) {
req.setTriggerMode(TriggerMode.BATCH.name());
}
}
testPlanLoadCaseService.runBatch(request);
}
@ -81,13 +87,13 @@ public class TestPlanLoadCaseController {
}
@PostMapping("/update")
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, content = "#msClass.getLogDetails(#testPlanLoadCase.id)", msClass = TestPlanLoadCaseService.class)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, content = "#msClass.getLogDetails(#testPlanLoadCase.id)", msClass = TestPlanLoadCaseService.class)
public void update(@RequestBody TestPlanLoadCase testPlanLoadCase) {
testPlanLoadCaseService.update(testPlanLoadCase);
}
@PostMapping("/update/api")
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, content = "#msClass.getLogDetails(#testPlanLoadCase.id)", msClass = TestPlanLoadCaseService.class)
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.UPDATE, content = "#msClass.getLogDetails(#testPlanLoadCase.id)", msClass = TestPlanLoadCaseService.class)
public void updateByApi(@RequestBody TestPlanLoadCase testPlanLoadCase) {
testPlanLoadCaseService.updateByApi(testPlanLoadCase);
}

View File

@ -6,6 +6,7 @@ import io.metersphere.base.domain.TestCaseReviewTestCase;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.track.dto.TestReviewCaseDTO;
import io.metersphere.track.request.testplancase.TestReviewCaseBatchRequest;
@ -75,4 +76,9 @@ public class TestReviewTestCaseController {
return testReviewTestCaseService.getTestCaseReviewDTOList(request);
}
@PostMapping("/edit/order")
public void orderCase(@RequestBody ResetOrderRequest request) {
testReviewTestCaseService.updateOrder(request);
}
}

View File

@ -12,7 +12,7 @@ public class TestPlanDTO extends TestPlanWithBLOBs {
private String projectName;
private String userName;
private List<String> projectIds;
private List<String> principals;
/**
* 定时任务ID
*/

View File

@ -34,6 +34,7 @@ import org.jsoup.safety.Whitelist;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
@ -348,4 +349,13 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
.andIssuesIdEqualTo(id);
testCaseIssuesMapper.deleteByExample(example);
}
protected void addCustomFields(IssuesUpdateRequest issuesRequest, MultiValueMap<String, Object> paramMap) {
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
customFields.forEach(item -> {
if (StringUtils.isNotBlank(item.getCustomData())) {
paramMap.add(item.getCustomData(), item.getValue());
}
});
}
}

View File

@ -79,7 +79,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
return issues;
}
public void parseIssue(IssuesWithBLOBs item, JiraIssue jiraIssue) {
public void parseIssue(IssuesWithBLOBs item, JiraIssue jiraIssue, String customFieldsStr) {
String lastmodify = "";
String status = "";
JSONObject fields = jiraIssue.getFields();
@ -89,9 +89,11 @@ public class JiraPlatform extends AbstractIssuePlatform {
String description = fields.getString("description");
Parser parser = Parser.builder().build();
Node document = parser.parse(description);
HtmlRenderer renderer = HtmlRenderer.builder().build();
description = renderer.render(document);
if (StringUtils.isNotBlank(description)) {
Node document = parser.parse(description);
HtmlRenderer renderer = HtmlRenderer.builder().build();
description = renderer.render(document);
}
if (assignee != null) {
lastmodify = assignee.getString("displayName");
@ -103,6 +105,43 @@ public class JiraPlatform extends AbstractIssuePlatform {
item.setDescription(description);
item.setPlatformStatus(status);
item.setPlatform(IssuesManagePlatform.Jira.toString());
item.setCustomFields(parseIssueCustomField(customFieldsStr, jiraIssue));
}
public String parseIssueCustomField(String customFieldsStr, JiraIssue jiraIssue) {
List<CustomFieldItemDTO> customFields = getCustomFields(customFieldsStr);
JSONObject fields = jiraIssue.getFields();
customFields.forEach(item -> {
String fieldName = item.getCustomData();
Object value = fields.get(fieldName);
if (value != null) {
if (value instanceof JSONObject) {
if (!fieldName.equals("assignee") && !fieldName.equals("reporter")) { // 获取不到账号名
item.setValue(((JSONObject)value).getString("id"));
}
} else {
if (StringUtils.isNotBlank(item.getType()) &&
StringUtils.equalsAny(item.getType(), "multipleSelect", "checkbox", "multipleMember")) {
List<String> values = new ArrayList<>();
if (item.getValue() != null) {
JSONArray attrs = (JSONArray) item.getValue();
attrs.forEach(attr -> {
if (attr instanceof JSONObject) {
values.add(((JSONObject)attr).getString("id"));
} else {
values.add((String) attr);
}
});
}
item.setValue(values);
} else {
item.setValue(value);
}
}
}
});
return JSONObject.toJSONString(customFields);
}
private String getStatus(JSONObject fields) {
@ -253,7 +292,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
customFields.forEach(item -> {
String fieldName = item.getCustomData();
if (StringUtils.isNotBlank(fieldName)) {
if (StringUtils.isNotBlank(item.getValue())) {
if (item.getValue() != null) {
if (StringUtils.isNotBlank(item.getType()) &&
StringUtils.equalsAny(item.getType(), "select", "radio", "member")) {
JSONObject param = new JSONObject();
@ -266,8 +305,8 @@ public class JiraPlatform extends AbstractIssuePlatform {
} else if (StringUtils.isNotBlank(item.getType()) &&
StringUtils.equalsAny(item.getType(), "multipleSelect", "checkbox", "multipleMember")) {
JSONArray attrs = new JSONArray();
if (StringUtils.isNotBlank(item.getValue())) {
JSONArray values = JSONObject.parseArray(item.getValue());
if (item.getValue() != null) {
JSONArray values = (JSONArray)item.getValue();
values.forEach(v -> {
JSONObject param = new JSONObject();
param.put("id", v);
@ -327,11 +366,12 @@ public class JiraPlatform extends AbstractIssuePlatform {
setConfig();
try {
IssuesWithBLOBs issuesWithBLOBs = issuesMapper.selectByPrimaryKey(item.getId());
parseIssue(item, jiraClientV2.getIssues(item.getId()));
parseIssue(item, jiraClientV2.getIssues(item.getId()), issuesWithBLOBs.getCustomFields());
String desc = htmlDesc2MsDesc(item.getDescription());
// 保留之前上传的图片
String images = getImages(issuesWithBLOBs.getDescription());
item.setDescription(desc + "\n" + images);
issuesMapper.updateByPrimaryKeySelective(item);
} catch (HttpClientErrorException e) {
if (e.getRawStatusCode() == 404) {
@ -339,6 +379,8 @@ public class JiraPlatform extends AbstractIssuePlatform {
item.setPlatformStatus(IssuesStatus.DELETE.toString());
issuesMapper.deleteByPrimaryKey(item.getId());
}
} catch (Exception e) {
LogUtil.error(e);
}
});
}

View File

@ -87,7 +87,7 @@ public class TapdPlatform extends AbstractIssuePlatform {
@Override
public void addIssue(IssuesUpdateRequest issuesRequest) {
MultiValueMap<String, String> param = buildUpdateParam(issuesRequest);
MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest);
TapdBug bug = tapdClient.addIssue(param);
Map<String, String> statusMap = tapdClient.getStatusMap(getProjectId(this.projectId));
issuesRequest.setPlatformStatus(statusMap.get(bug.getStatus()));
@ -102,18 +102,16 @@ public class TapdPlatform extends AbstractIssuePlatform {
@Override
public void updateIssue(IssuesUpdateRequest request) {
MultiValueMap<String, String> param = buildUpdateParam(request);
MultiValueMap<String, Object> param = buildUpdateParam(request);
param.add("id", request.getId());
handleIssueUpdate(request);
tapdClient.updateIssue(param);
}
private MultiValueMap<String, String> buildUpdateParam(IssuesUpdateRequest issuesRequest) {
private MultiValueMap<String, Object> buildUpdateParam(IssuesUpdateRequest issuesRequest) {
issuesRequest.setPlatform(IssuesManagePlatform.Tapd.toString());
setConfig();
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
String tapdId = getProjectId(issuesRequest.getProjectId());
if (StringUtils.isBlank(tapdId)) {
@ -131,17 +129,14 @@ public class TapdPlatform extends AbstractIssuePlatform {
reporter = SessionUtils.getUser().getName();
}
MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("title", issuesRequest.getTitle());
paramMap.add("workspace_id", tapdId);
paramMap.add("description", msDescription2Tapd(issuesRequest.getDescription()));
paramMap.add("current_owner", usersStr);
customFields.forEach(item -> {
if (StringUtils.isNotBlank(item.getCustomData())) {
paramMap.add(item.getCustomData(), item.getValue());
}
});
addCustomFields(issuesRequest, paramMap);
paramMap.add("reporter", reporter);
return paramMap;
}

View File

@ -204,7 +204,6 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
private MultiValueMap<String, Object> buildUpdateParam(IssuesUpdateRequest issuesRequest) {
issuesRequest.setPlatform(IssuesManagePlatform.Zentao.toString());
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
zentaoClient.setConfig(getUserConfig());
String projectId = getProjectId(issuesRequest.getProjectId());
if (StringUtils.isBlank(projectId)) {
@ -214,11 +213,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
paramMap.add("product", projectId);
paramMap.add("title", issuesRequest.getTitle());
customFields.forEach(item -> {
if (StringUtils.isNotBlank(item.getCustomData())) {
paramMap.add(item.getCustomData(), item.getValue());
}
});
addCustomFields(issuesRequest, paramMap);
String description = issuesRequest.getDescription();
String zentaoSteps = description;

View File

@ -57,9 +57,9 @@ public class TapdClient extends BaseClient {
return (TapdGetIssueResponse) getResultForObject(TapdGetIssueResponse.class, response);
}
public TapdBug addIssue(MultiValueMap<String, String> paramMap) {
public TapdBug addIssue(MultiValueMap<String, Object> paramMap) {
String url = getBaseUrl() + "/bugs";
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(paramMap, getAuthHeader());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, getAuthHeader());
ResponseEntity<String> response = null;
try {
response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
@ -70,7 +70,7 @@ public class TapdClient extends BaseClient {
return ((AddTapdIssueResponse) getResultForObject(AddTapdIssueResponse.class, response)).getData().getBug();
}
public TapdBug updateIssue(MultiValueMap<String, String> paramMap) {
public TapdBug updateIssue(MultiValueMap<String, Object> paramMap) {
// 带id为更新
return addIssue(paramMap);
}

View File

@ -41,7 +41,7 @@ public abstract class ZentaoClient extends BaseClient {
ResponseEntity<String> response = restTemplate.exchange(loginUrl + sessionId, HttpMethod.POST, requestEntity, String.class);
getUserResponse = (GetUserResponse) getResultForObject(GetUserResponse.class, response);
} catch (Exception e) {
LogUtil.error("get result for object error," + e.getMessage());
LogUtil.error(e);
MSException.throwException(e.getMessage());
}
GetUserResponse.User user = getUserResponse.getUser();

View File

@ -11,5 +11,12 @@ import java.util.List;
public class TestCaseMinderEditRequest {
private String projectId;
private List<String> ids;
List<TestCaseWithBLOBs> data;
List<TestCaseMinderEditItem> data;
@Getter
@Setter
public static class TestCaseMinderEditItem extends TestCaseWithBLOBs {
private String targetId;
private String moveMode;
}
}

View File

@ -10,4 +10,5 @@ import java.util.List;
@Setter
public class AddTestPlanRequest extends TestPlanWithBLOBs {
private List<String> projectIds;
private List<String> principals;
}

View File

@ -576,7 +576,7 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseMapper testCaseMapper = sqlSession.getMapper(TestCaseMapper.class);
testCases.forEach((value) -> {
testCaseMapper.updateByPrimaryKey(value);
testCaseMapper.updateByPrimaryKeySelective(value);
});
sqlSession.flushStatements();
}

View File

@ -294,9 +294,9 @@ public class TestCaseReviewService {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseReviewTestCaseMapper batchMapper = sqlSession.getMapper(TestCaseReviewTestCaseMapper.class);
Long nextOrder = ServiceUtils.getNextOrder(request.getReviewId(), extTestReviewCaseMapper::getLastOrder);
if (!testCaseIds.isEmpty()) {
testCaseIds.forEach(caseId -> {
for (String caseId : testCaseIds) {
TestCaseReviewTestCase caseReview = new TestCaseReviewTestCase();
caseReview.setId(UUID.randomUUID().toString());
caseReview.setReviewer(SessionUtils.getUser().getId());
@ -306,8 +306,10 @@ public class TestCaseReviewService {
caseReview.setUpdateTime(System.currentTimeMillis());
caseReview.setReviewId(request.getReviewId());
caseReview.setStatus(TestCaseReviewStatus.Prepare.name());
caseReview.setOrder(nextOrder);
batchMapper.insert(caseReview);
});
nextOrder += 5000;
}
}
sqlSession.flushStatements();

View File

@ -1427,7 +1427,7 @@ public class TestCaseService {
}
public void minderEdit(TestCaseMinderEditRequest request) {
List<TestCaseWithBLOBs> data = request.getData();
List<TestCaseMinderEditRequest.TestCaseMinderEditItem> data = request.getData();
if (CollectionUtils.isNotEmpty(data)) {
List<String> editIds = data.stream()
.filter(t -> StringUtils.isNotBlank(t.getId()) && t.getId().length() > 20)
@ -1451,12 +1451,14 @@ public class TestCaseService {
item.setId(UUID.randomUUID().toString());
item.setMaintainer(SessionUtils.getUserId());
addTestCase(item);
changeOrder(item, request.getProjectId());
} else {
TestCaseWithBLOBs dbCase = finalTestCaseMap.get(item.getId());
if (editCustomFieldsPriority(dbCase, item.getPriority())) {
item.setCustomFields(dbCase.getCustomFields());
}
editTestCase(item);
changeOrder(item, request.getProjectId());
}
});
}
@ -1468,6 +1470,17 @@ public class TestCaseService {
}
}
private void changeOrder(TestCaseMinderEditRequest.TestCaseMinderEditItem item, String projectId) {
if (StringUtils.isNotBlank(item.getTargetId())) {
ResetOrderRequest resetOrderRequest = new ResetOrderRequest();
resetOrderRequest.setGroupId(projectId);
resetOrderRequest.setMoveId(item.getId());
resetOrderRequest.setTargetId(item.getTargetId());
resetOrderRequest.setMoveMode(item.getMoveMode());
updateOrder(resetOrderRequest);
}
}
/**
* 脑图编辑之后修改用例等级同时修改自定义字段的用例等级
*
@ -1493,7 +1506,7 @@ public class TestCaseService {
public List<TestCase> getTestCaseByProjectId(String projectId) {
TestCaseExample example = new TestCaseExample();
example.createCriteria().andProjectIdEqualTo(projectId);
example.createCriteria().andProjectIdEqualTo(projectId).andStatusNotEqualTo("Trash");
return testCaseMapper.selectByExample(example);
}

View File

@ -50,6 +50,7 @@ import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.IssueTemplateService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.service.TestPlanPrincipalService;
import io.metersphere.track.Factory.ReportComponentFactory;
import io.metersphere.track.domain.ReportComponent;
import io.metersphere.track.dto.*;
@ -183,6 +184,10 @@ public class TestPlanService {
private PerformanceReportService performanceReportService;
@Resource
private MetricQueryService metricQueryService;
@Resource
private TestPlanPrincipalService testPlanPrincipalService;
@Resource
private TestPlanPrincipalMapper testPlanPrincipalMapper;
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
@ -194,6 +199,16 @@ public class TestPlanService {
testPlan.setCreateTime(System.currentTimeMillis());
testPlan.setUpdateTime(System.currentTimeMillis());
testPlan.setCreator(SessionUtils.getUser().getId());
String planId = testPlan.getId();
List<String> principals = testPlan.getPrincipals();
for (String principal : principals) {
TestPlanPrincipal testPlanPrincipal = new TestPlanPrincipal();
testPlanPrincipal.setTestPlanId(planId);
testPlanPrincipal.setPrincipalId(principal);
testPlanPrincipalService.insert(testPlanPrincipal);
}
if (StringUtils.isBlank(testPlan.getProjectId())) {
testPlan.setProjectId(SessionUtils.getCurrentProjectId());
}
@ -214,6 +229,22 @@ public class TestPlanService {
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlanWithBLOBs());
}
public TestPlan editTestPlanWithRequest(AddTestPlanRequest request) {
List<String> principals = request.getPrincipals();
if (!CollectionUtils.isEmpty(principals)) {
if (StringUtils.isNotBlank(request.getId())) {
testPlanPrincipalService.deleteTestPlanPrincipalByPlanId(request.getId());
for (String principal : principals) {
TestPlanPrincipal testPlanPrincipal = new TestPlanPrincipal();
testPlanPrincipal.setTestPlanId(request.getId());
testPlanPrincipal.setPrincipalId(principal);
testPlanPrincipalService.insert(testPlanPrincipal);
}
}
}
return this.editTestPlan(request);
}
public TestPlan editTestPlan(TestPlanWithBLOBs testPlan) {
checkTestPlanExist(testPlan);
TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库
@ -317,7 +348,7 @@ public class TestPlanService {
TestPlanExample example = new TestPlanExample();
example.createCriteria()
.andNameEqualTo(testPlan.getName())
.andWorkspaceIdEqualTo(SessionUtils.getCurrentWorkspaceId())
.andProjectIdEqualTo(testPlan.getProjectId())
.andIdNotEqualTo(testPlan.getId());
if (testPlanMapper.selectByExample(example).size() > 0) {
MSException.throwException(Translator.get("plan_name_already_exists"));
@ -326,6 +357,7 @@ public class TestPlanService {
}
public int deleteTestPlan(String planId) {
testPlanPrincipalService.deleteTestPlanPrincipalByPlanId(planId);
deleteTestCaseByPlanId(planId);
testPlanApiCaseService.deleteByPlanId(planId);
testPlanScenarioCaseService.deleteByPlanId(planId);
@ -1243,7 +1275,6 @@ public class TestPlanService {
targetPlan.setWorkspaceId(testPlan.getWorkspaceId());
targetPlan.setDescription(testPlan.getDescription());
targetPlan.setStage(testPlan.getStage());
targetPlan.setPrincipal(testPlan.getPrincipal());
targetPlan.setTags(testPlan.getTags());
targetPlan.setProjectId(testPlan.getProjectId());
testPlan.setAutomaticStatusUpdate(testPlan.getAutomaticStatusUpdate());
@ -1253,11 +1284,26 @@ public class TestPlanService {
targetPlan.setUpdateTime(System.currentTimeMillis());
testPlanMapper.insert(targetPlan);
copyPlanPrincipal(targetPlanId, planId);
copyPlanCase(sourcePlanId, targetPlanId);
return targetPlan;
}
private void copyPlanPrincipal(String targetPlanId, String sourcePlanId) {
TestPlanPrincipalExample example = new TestPlanPrincipalExample();
example.createCriteria().andTestPlanIdEqualTo(sourcePlanId);
List<TestPlanPrincipal> testPlanPrincipals = testPlanPrincipalMapper.selectByExample(example);
if (!CollectionUtils.isEmpty(testPlanPrincipals)) {
for (TestPlanPrincipal tpp : testPlanPrincipals) {
TestPlanPrincipal testPlanPrincipal = new TestPlanPrincipal();
testPlanPrincipal.setPrincipalId(tpp.getPrincipalId());
testPlanPrincipal.setTestPlanId(targetPlanId);
testPlanPrincipalMapper.insert(testPlanPrincipal);
}
}
}
@Transactional(rollbackFor = Exception.class)
public void copyPlanCase(String sourcePlanId, String targetPlanId) {
TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample();
@ -1992,4 +2038,21 @@ public class TestPlanService {
List<TestPlanLoadCase> testPlanLoadCases = testPlanLoadCaseMapper.selectByExample(loadCaseExample);
return !CollectionUtils.isEmpty(testPlanLoadCases);
}
public List<User> getPlanPrincipal(String planId) {
List<User> result = new ArrayList<>();
if (StringUtils.isBlank(planId)) {
return result;
}
TestPlanPrincipalExample example = new TestPlanPrincipalExample();
example.createCriteria().andTestPlanIdEqualTo(planId);
List<TestPlanPrincipal> testPlanPrincipals = testPlanPrincipalMapper.selectByExample(example);
List<String> userIds = testPlanPrincipals.stream().map(TestPlanPrincipal::getPrincipalId).distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(userIds)) {
return result;
}
UserExample userExample = new UserExample();
userExample.createCriteria().andIdIn(userIds);
return userMapper.selectByExample(userExample);
}
}

Some files were not shown because too many files have changed in this diff Show More