merge: 合并dev最新修改
This commit is contained in:
commit
77bfdd1a37
|
@ -9,6 +9,7 @@ import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
|||
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
|
||||
import io.metersphere.commons.constants.TestPlanResourceType;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.track.dto.TestPlanReportExecuteCheckResultDTO;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
@ -20,6 +21,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author song.tianyang
|
||||
|
@ -30,17 +32,16 @@ import java.util.Map;
|
|||
public class TestPlanExecuteInfo {
|
||||
private String reportId;
|
||||
private String creator;
|
||||
private Map<String, String> apiCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> apiScenarioCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> loadCaseExecInfo = new HashMap<>();
|
||||
private Map<String, String> apiCaseExecInfo = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioCaseExecInfo = new ConcurrentHashMap<>();
|
||||
private Map<String, String> loadCaseExecInfo = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseExecuteThreadMap = new HashMap<>();
|
||||
private Map<String, String> apiScenarioThreadMap = new HashMap<>();
|
||||
private Map<String, String> loadCaseReportIdMap = new HashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseReportMap = new HashMap<>();
|
||||
private Map<String, String> apiScenarioReportMap = new HashMap<>();
|
||||
private Map<String, String> apiCaseExecuteThreadMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioThreadMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> loadCaseReportIdMap = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<String, String> apiCaseReportMap = new ConcurrentHashMap<>();
|
||||
private Map<String, String> apiScenarioReportMap = new ConcurrentHashMap<>();
|
||||
private boolean reportDataInDataBase;
|
||||
|
||||
int lastUnFinishedNumCount = 0;
|
||||
|
@ -83,7 +84,8 @@ public class TestPlanExecuteInfo {
|
|||
}
|
||||
}
|
||||
|
||||
public synchronized int countUnFinishedNum() {
|
||||
public synchronized TestPlanReportExecuteCheckResultDTO countUnFinishedNum() {
|
||||
TestPlanReportExecuteCheckResultDTO executeCheck = new TestPlanReportExecuteCheckResultDTO();
|
||||
int unFinishedCount = 0;
|
||||
|
||||
this.isApiCaseAllExecuted = true;
|
||||
|
@ -129,8 +131,22 @@ public class TestPlanExecuteInfo {
|
|||
LoggerUtil.info("执行的报告还在队列中,重置超时时间");
|
||||
lastUnFinishedNumCount = unFinishedCount;
|
||||
lastFinishedNumCountTime = System.currentTimeMillis();
|
||||
executeCheck.setFinishedCaseChanged(true);
|
||||
} else if (unFinishedCount == 0) {
|
||||
executeCheck.setFinishedCaseChanged(true);
|
||||
} else {
|
||||
executeCheck.setFinishedCaseChanged(false);
|
||||
}
|
||||
return unFinishedCount;
|
||||
|
||||
executeCheck.setTimeOut(false);
|
||||
if (unFinishedCount > 0) {
|
||||
//20分钟没有案例执行结果更新,则定位超时
|
||||
long nowTime = System.currentTimeMillis();
|
||||
if (nowTime - lastFinishedNumCountTime > 1200000) {
|
||||
executeCheck.setTimeOut(true);
|
||||
}
|
||||
}
|
||||
return executeCheck;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, String>> getExecutedResult() {
|
||||
|
@ -228,7 +244,7 @@ public class TestPlanExecuteInfo {
|
|||
this.countUnFinishedNum();
|
||||
}
|
||||
|
||||
public void updateReport(Map<String, String> apiCaseExecResultInfo, Map<String, String> apiScenarioCaseExecResultInfo) {
|
||||
public synchronized void updateReport(Map<String, String> apiCaseExecResultInfo, Map<String, String> apiScenarioCaseExecResultInfo) {
|
||||
if (MapUtils.isNotEmpty(apiCaseExecResultInfo)) {
|
||||
this.apiCaseReportMap.putAll(apiCaseExecResultInfo);
|
||||
}
|
||||
|
@ -236,6 +252,35 @@ public class TestPlanExecuteInfo {
|
|||
if (MapUtils.isNotEmpty(apiScenarioCaseExecResultInfo)) {
|
||||
this.apiScenarioReportMap.putAll(apiScenarioCaseExecResultInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getRunningApiCaseReportMap() {
|
||||
//key: reportId, value: testPlanApiCaseId
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : apiCaseExecInfo.entrySet()) {
|
||||
String planCaseId = entry.getKey();
|
||||
String status = entry.getValue();
|
||||
if (StringUtils.equalsIgnoreCase(status, TestPlanApiExecuteStatus.RUNNING.name())) {
|
||||
if (apiCaseExecuteThreadMap.containsKey(planCaseId)) {
|
||||
returnMap.put(apiCaseExecuteThreadMap.get(planCaseId), planCaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
public Map<String, String> getRunningScenarioReportMap() {
|
||||
//key: reportId, value: testPlanApiScenarioId
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : apiScenarioCaseExecInfo.entrySet()) {
|
||||
String planScenarioId = entry.getKey();
|
||||
String status = entry.getValue();
|
||||
if (StringUtils.equalsIgnoreCase(status, TestPlanApiExecuteStatus.RUNNING.name())) {
|
||||
if (apiScenarioThreadMap.containsKey(planScenarioId)) {
|
||||
returnMap.put(apiScenarioThreadMap.get(planScenarioId), planScenarioId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.cache;
|
||||
|
||||
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -50,8 +51,12 @@ public class TestPlanReportExecuteCatch {
|
|||
}
|
||||
|
||||
public synchronized static boolean containsReport(String reportId) {
|
||||
if(StringUtils.isEmpty(reportId)){
|
||||
return false;
|
||||
}else {
|
||||
return testPlanReportMap != null && testPlanReportMap.containsKey(reportId);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void updateApiTestPlanExecuteInfo(String reportId,
|
||||
Map<String, String> apiCaseExecInfo, Map<String, String> apiScenarioCaseExecInfo, Map<String, String> loadCaseExecInfo) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import org.junit.internal.runners.statements.Fail;
|
||||
|
||||
public enum ScenarioStatus {
|
||||
Saved, Success, Fail, Trash,Underway
|
||||
Saved, Success, Error, Timeout, Fail, Trash, Underway
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public class ApiDefinitionImportUtil {
|
|||
if (parentModule != null) {
|
||||
module = apiModuleService.getNewModule(name, projectId, parentModule.getLevel() + 1);
|
||||
module.setParentId(parentModule.getId());
|
||||
module.setProtocol(parentModule.getProtocol());
|
||||
} else {
|
||||
module = apiModuleService.getNewModule(name, projectId, 1);
|
||||
}
|
||||
|
@ -121,6 +122,7 @@ public class ApiDefinitionImportUtil {
|
|||
if (parentModule != null) {
|
||||
module = apiModuleService.getNewModule(name, projectId, parentModule.getLevel() + 1);
|
||||
module.setParentId(parentModule.getId());
|
||||
module.setProtocol(parentModule.getProtocol());
|
||||
} else {
|
||||
module = apiModuleService.getNewModule(name, projectId, 1);
|
||||
}
|
||||
|
|
|
@ -84,8 +84,8 @@ public class JMeterScriptUtil {
|
|||
}
|
||||
|
||||
private static void addItemHashTree(MsTestElement element, HashTree samplerHashTree, ParameterConfig config, String enviromentId) {
|
||||
if (element != null && element.getEnvironmentId() == null) {
|
||||
element.setEnvironmentId(enviromentId);
|
||||
if (element != null) {
|
||||
element.setEnvironmentId(element.getEnvironmentId() == null ? enviromentId : element.getEnvironmentId());
|
||||
element.toHashTree(samplerHashTree, element.getHashTree(), config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,8 +246,8 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
msResponse.setType(RequestType.HTTP);
|
||||
// todo 状态码要调整?
|
||||
msResponse.setStatusCode(new ArrayList<>());
|
||||
ApiResponse apiResponse = responses.get("200");
|
||||
if (responses != null) {
|
||||
ApiResponse apiResponse = responses.get("200");
|
||||
if (apiResponse == null) {
|
||||
responses.forEach((responseCode, response) -> {
|
||||
parseResponseHeader(response, msResponse.getHeaders());
|
||||
|
@ -257,10 +257,10 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
parseResponseHeader(apiResponse, msResponse.getHeaders());
|
||||
parseResponseBody(apiResponse, msResponse.getBody());
|
||||
}
|
||||
}
|
||||
responses.forEach((responseCode, response) -> {
|
||||
parseResponseCode(msResponse.getStatusCode(), responseCode, response);
|
||||
});
|
||||
}
|
||||
return msResponse;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ public class MsTCPSampler extends MsTestElement {
|
|||
});
|
||||
}
|
||||
//根据配置将脚本放置在私有脚本之后
|
||||
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.TCP.name(), enviromentId, config, false);
|
||||
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.TCP.name(), enviromentId, config, true);
|
||||
}
|
||||
|
||||
private void addItemHashTree(MsTestElement element, HashTree samplerHashTree, ParameterConfig config) {
|
||||
|
|
|
@ -136,8 +136,13 @@ public class TestPlanApiExecuteService {
|
|||
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testPlanApiCase.getId(), reportId, request.getTriggerMode(), hashTree);
|
||||
if (request.getConfig() != null) {
|
||||
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()));
|
||||
runRequest.setPoolId(request.getConfig().getResourcePoolId());
|
||||
}
|
||||
runRequest.setTestPlanReportId(request.getPlanReportId());
|
||||
runRequest.setReportType(executionQueue.getReportType());
|
||||
runRequest.setTestPlanReportId(request.getPlanReportId());
|
||||
runRequest.setRunType(RunModeConstants.PARALLEL.toString());
|
||||
runRequest.setQueueId(executionQueue.getId());
|
||||
jMeterService.run(runRequest);
|
||||
} catch (Exception e) {
|
||||
executeErrorList.add(testPlanApiCase.getId());
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.exec.queue;
|
||||
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.jmeter.JmeterThreadUtils;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.dto.JmeterRunRequestDTO;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
|
@ -23,7 +24,7 @@ public class ExecTask implements Runnable {
|
|||
jMeterService.addQueue(request);
|
||||
if (request.getPool() == null || !request.getPool().isPool()) {
|
||||
Object res = PoolExecBlockingQueueUtil.take(request.getReportId());
|
||||
if (res == null) {
|
||||
if (res == null && !JmeterThreadUtils.isRunning(request.getReportId(), request.getTestId())) {
|
||||
LoggerUtil.info("执行报告:【 " + request.getReportId() + " 】,资源ID【 " + request.getTestId() + " 】执行超时");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public class PoolExecBlockingQueueUtil {
|
|||
if (StringUtils.isNotEmpty(key) && !queue.containsKey(key)) {
|
||||
BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
|
||||
queue.put(key, blockingQueue);
|
||||
return blockingQueue.poll(5, TimeUnit.MINUTES);
|
||||
return blockingQueue.poll(10, TimeUnit.MINUTES);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error("初始化队列失败:" + e.getMessage());
|
||||
|
|
|
@ -91,7 +91,6 @@ public class ApiDefinitionExecResultUtil {
|
|||
apiResult.setStartTime(System.currentTimeMillis());
|
||||
apiResult.setType(ApiRunMode.DEFINITION.name());
|
||||
apiResult.setStatus(status);
|
||||
|
||||
return apiResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,10 +31,13 @@ import java.util.Map;
|
|||
public class GenerateHashTreeUtil {
|
||||
|
||||
public static MsScenario parseScenarioDefinition(String scenarioDefinition) {
|
||||
if(StringUtils.isNotEmpty(scenarioDefinition)) {
|
||||
MsScenario scenario = JSONObject.parseObject(scenarioDefinition, MsScenario.class);
|
||||
parse(scenarioDefinition, scenario, scenario.getId(), null);
|
||||
return scenario;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void parse(String scenarioDefinition, MsScenario scenario, String id, String reportType) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
|
|
@ -5,10 +5,12 @@ import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
|
|||
import io.metersphere.api.service.ApiExecutionQueueService;
|
||||
import io.metersphere.api.service.MsResultService;
|
||||
import io.metersphere.api.service.TestResultService;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.dto.ResultDTO;
|
||||
import io.metersphere.jmeter.MsExecListener;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -18,13 +20,19 @@ public class APISingleResultListener extends MsExecListener {
|
|||
LoggerUtil.info("处理单条执行结果报告【" + dto.getReportId() + " 】,资源【 " + dto.getTestId() + " 】");
|
||||
dto.setConsole(CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(dto.getReportId()));
|
||||
CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
|
||||
|
||||
// 更新报告最后接收到请求的时间
|
||||
if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCENARIO.name(),
|
||||
ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(),
|
||||
ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
|
||||
CommonBeanFactory.getBean(TestResultService.class).editReportTime(dto);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testEnded(ResultDTO dto, Map<String, Object> kafkaConfig) {
|
||||
try {
|
||||
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + " 】整体执行完成;" + dto.getRunMode());
|
||||
|
||||
// 全局并发队列
|
||||
PoolExecBlockingQueueUtil.offer(dto.getReportId());
|
||||
dto.setConsole(CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(dto.getReportId()));
|
||||
|
|
|
@ -68,9 +68,9 @@ public class JMeterService {
|
|||
}
|
||||
|
||||
private void addDebugListener(String testId, HashTree testPlan) {
|
||||
MsDebugListener resultCollector = new MsDebugListener();
|
||||
MsResultCollector resultCollector = new MsResultCollector();
|
||||
resultCollector.setName(testId);
|
||||
resultCollector.setProperty(TestElement.TEST_CLASS, MsDebugListener.class.getName());
|
||||
resultCollector.setProperty(TestElement.TEST_CLASS, MsResultCollector.class.getName());
|
||||
resultCollector.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ViewResultsFullVisualizer"));
|
||||
resultCollector.setEnabled(true);
|
||||
testPlan.add(testPlan.getArray()[0], resultCollector);
|
||||
|
@ -139,8 +139,8 @@ public class JMeterService {
|
|||
JvmInfoDTO jvmInfoDTO = resources.get(index);
|
||||
TestResourceDTO testResource = jvmInfoDTO.getTestResource();
|
||||
String configuration = testResource.getConfiguration();
|
||||
request.setCorePoolSize(MessageCache.corePoolSize);
|
||||
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
|
||||
request.setCorePoolSize(node.getMaxConcurrency());
|
||||
String nodeIp = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port);
|
||||
|
|
|
@ -7,9 +7,7 @@ public class JmeterThreadUtils {
|
|||
private final static String THREAD_SPLIT = " ";
|
||||
|
||||
public static String stop(String name) {
|
||||
|
||||
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
|
||||
|
||||
int noThreads = currentGroup.activeCount();
|
||||
Thread[] lstThreads = new Thread[noThreads];
|
||||
currentGroup.enumerate(lstThreads);
|
||||
|
@ -24,4 +22,19 @@ public class JmeterThreadUtils {
|
|||
}
|
||||
return threadNames.toString();
|
||||
}
|
||||
|
||||
public static boolean isRunning(String reportId, String testId) {
|
||||
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
|
||||
int noThreads = currentGroup.activeCount();
|
||||
Thread[] lstThreads = new Thread[noThreads];
|
||||
currentGroup.enumerate(lstThreads);
|
||||
for (int i = 0; i < noThreads; i++) {
|
||||
if (StringUtils.isNotEmpty(reportId) && StringUtils.isNotEmpty(lstThreads[i].getName()) && lstThreads[i].getName().startsWith(reportId)) {
|
||||
return true;
|
||||
} else if (StringUtils.isNotEmpty(testId) && StringUtils.isNotEmpty(lstThreads[i].getName()) && lstThreads[i].getName().startsWith(testId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
|
|||
import io.metersphere.api.service.ApiEnvironmentRunningParamService;
|
||||
import io.metersphere.api.service.ApiExecutionQueueService;
|
||||
import io.metersphere.api.service.TestResultService;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.config.KafkaConfig;
|
||||
import io.metersphere.dto.ResultDTO;
|
||||
|
@ -34,6 +35,13 @@ public class MsKafkaListener {
|
|||
// 全局并发队列
|
||||
PoolExecBlockingQueueUtil.offer(testResult.getReportId());
|
||||
} else {
|
||||
// 更新报告最后接收到请求的时间
|
||||
if (StringUtils.equalsAny(testResult.getRunMode(), ApiRunMode.SCENARIO.name(),
|
||||
ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(),
|
||||
ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
|
||||
CommonBeanFactory.getBean(TestResultService.class).editReportTime(testResult);
|
||||
}
|
||||
|
||||
testResultService.saveResults(testResult);
|
||||
}
|
||||
LoggerUtil.info("执行内容存储结束");
|
||||
|
|
|
@ -23,11 +23,10 @@ import io.metersphere.api.service.MsResultService;
|
|||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.dto.RequestResult;
|
||||
import io.metersphere.dto.ResultDTO;
|
||||
import io.metersphere.jmeter.JMeterBase;
|
||||
import io.metersphere.utils.JMeterVars;
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import io.metersphere.websocket.c.to.c.MsWebSocketClient;
|
||||
import io.metersphere.websocket.c.to.c.WebSocketUtils;
|
||||
import io.metersphere.websocket.c.to.c.util.MsgDto;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -44,7 +43,7 @@ import java.util.Map;
|
|||
/**
|
||||
* 实时结果监听
|
||||
*/
|
||||
public class MsDebugListener extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
|
||||
public class MsResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
|
||||
TestStateListener, Remoteable, NoThreadClone {
|
||||
|
||||
private static final String ERROR_LOGGING = "MsResultCollector.error_logging"; // $NON-NLS-1$
|
||||
|
@ -55,11 +54,9 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
|
|||
|
||||
public static final String TEST_END = "MS_TEST_END";
|
||||
|
||||
private MsWebSocketClient client;
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
MsDebugListener clone = (MsDebugListener) super.clone();
|
||||
MsResultCollector clone = (MsResultCollector) super.clone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
@ -100,28 +97,20 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
|
|||
@Override
|
||||
public void testEnded(String host) {
|
||||
LoggerUtil.debug("TestEnded " + this.getName());
|
||||
SampleResult result = new SampleResult();
|
||||
result.setResponseCode(TEST_END);
|
||||
ResultDTO dto = new ResultDTO();
|
||||
dto.setReportId(this.getName());
|
||||
try {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
MsgDto dto = new MsgDto();
|
||||
dto.setExecEnd(false);
|
||||
dto.setContent(TEST_END);
|
||||
dto.setReportId("send." + this.getName());
|
||||
dto.setToReport(this.getName());
|
||||
LoggerUtil.debug("send. " + this.getName());
|
||||
WebSocketUtils.sendMessageSingle(dto);
|
||||
WebSocketUtils.onClose(this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testStarted(String host) {
|
||||
LogUtil.debug("TestStarted " + this.getName());
|
||||
try {
|
||||
client = new MsWebSocketClient("ws://127.0.0.1:8081/ws/" + "send." + this.getName());
|
||||
client.connect();
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -142,10 +131,9 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
|
|||
dto.setReportId("send." + this.getName());
|
||||
dto.setToReport(this.getName());
|
||||
LoggerUtil.debug("send. " + this.getName());
|
||||
if (client != null) {
|
||||
client.send(JSON.toJSONString(dto));
|
||||
}
|
||||
WebSocketUtils.sendMessageSingle(dto);
|
||||
} catch (Exception ex) {
|
||||
LoggerUtil.error("消息推送失败:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,9 +167,7 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
|
|||
dto.setReportId("send." + this.getName());
|
||||
dto.setToReport(this.getName());
|
||||
LoggerUtil.debug("send. " + this.getName());
|
||||
if (client != null) {
|
||||
client.send(JSON.toJSONString(dto));
|
||||
}
|
||||
WebSocketUtils.sendMessageSingle(dto);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,8 +116,8 @@ public class ApiDefinitionExecResultService {
|
|||
.operator(SessionUtils.getUserId())
|
||||
.context(context)
|
||||
.subject("接口用例通知")
|
||||
.successMailTemplate("api/CaseResult")
|
||||
.failedMailTemplate("api/CaseResult")
|
||||
.successMailTemplate("api/CaseResultSuccess")
|
||||
.failedMailTemplate("api/CaseResultFailed")
|
||||
.paramMap(paramMap)
|
||||
.event(event)
|
||||
.build();
|
||||
|
@ -187,8 +187,6 @@ public class ApiDefinitionExecResultService {
|
|||
* 定时任务时,userID要改为定时任务中的用户
|
||||
*/
|
||||
public void saveApiResultByScheduleTask(List<RequestResult> requestResults, ResultDTO dto) {
|
||||
Map<String, String> apiIdResultMap = new HashMap<>();
|
||||
Map<String, String> caseReportMap = new HashMap<>();
|
||||
boolean isFirst = true;
|
||||
int countExpectProcessResultCount = 0;
|
||||
if (CollectionUtils.isNotEmpty(requestResults)) {
|
||||
|
@ -201,7 +199,7 @@ public class ApiDefinitionExecResultService {
|
|||
|
||||
for (RequestResult item : requestResults) {
|
||||
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
|
||||
ApiDefinitionExecResult saveResult = this.save(item, dto.getReportId(), dto.getConsole(), countExpectProcessResultCount, dto.getRunMode(), dto.getTestId(), isFirst);
|
||||
this.save(item, dto.getReportId(), dto.getConsole(), countExpectProcessResultCount, dto.getRunMode(), dto.getTestId(), isFirst);
|
||||
String status = item.isSuccess() ? "success" : "error";
|
||||
if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
|
||||
TestPlanApiCase apiCase = testPlanApiCaseService.getById(dto.getTestId());
|
||||
|
@ -214,19 +212,19 @@ public class ApiDefinitionExecResultService {
|
|||
testPlanApiCaseService.setExecResult(dto.getTestId(), status, item.getStartTime());
|
||||
testCaseReviewApiCaseService.setExecResult(dto.getTestId(), status, item.getStartTime());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(dto.getTestId())) {
|
||||
apiIdResultMap.put(dto.getTestId(), item.isSuccess() ? TestPlanApiExecuteStatus.SUCCESS.name() : TestPlanApiExecuteStatus.FAILD.name());
|
||||
}
|
||||
//更新报告ID
|
||||
caseReportMap.put(dto.getTestId(), saveResult.getId());
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateTestCaseStates(dto.getTestId());
|
||||
Map<String, String> apiIdResultMap = new HashMap<>();
|
||||
long errorSize = requestResults.stream().filter(requestResult -> requestResult.getError() > 0).count();
|
||||
String status = errorSize > 0 || requestResults.isEmpty() ? TestPlanApiExecuteStatus.FAILD.name() : TestPlanApiExecuteStatus.SUCCESS.name();
|
||||
if (StringUtils.isNotEmpty(dto.getReportId())) {
|
||||
apiIdResultMap.put(dto.getReportId(), status);
|
||||
}
|
||||
testPlanLog.info("TestPlanReportId[" + dto.getTestPlanReportId() + "] APICASE OVER. API CASE STATUS:" + JSONObject.toJSONString(apiIdResultMap));
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(dto.getTestPlanReportId(), apiIdResultMap, null, null);
|
||||
TestPlanReportExecuteCatch.updateTestPlanReport(dto.getTestPlanReportId(), caseReportMap, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,13 +346,13 @@ public class ApiDefinitionExecResultService {
|
|||
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
|
||||
if (prevResult != null) {
|
||||
prevResult.setContent(null);
|
||||
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
|
||||
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(prevResult);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
|
||||
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
|
||||
}
|
||||
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
|
||||
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(saveResult);
|
||||
return saveResult;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -22,6 +22,7 @@ import io.metersphere.api.dto.scenario.request.RequestType;
|
|||
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
|
||||
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
|
||||
import io.metersphere.api.exec.api.ApiExecuteService;
|
||||
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.*;
|
||||
|
@ -102,16 +103,12 @@ public class ApiDefinitionService {
|
|||
@Resource
|
||||
private ApiTestCaseMapper apiTestCaseMapper;
|
||||
@Resource
|
||||
private ApiTestEnvironmentService environmentService;
|
||||
@Resource
|
||||
private EsbApiParamService esbApiParamService;
|
||||
@Resource
|
||||
private TcpApiParamService tcpApiParamService;
|
||||
@Resource
|
||||
private ApiModuleMapper apiModuleMapper;
|
||||
@Resource
|
||||
private SystemParameterService systemParameterService;
|
||||
@Resource
|
||||
private TestPlanMapper testPlanMapper;
|
||||
@Resource
|
||||
private NoticeSendService noticeSendService;
|
||||
|
@ -855,6 +852,15 @@ public class ApiDefinitionService {
|
|||
* @return
|
||||
*/
|
||||
public MsExecResponseDTO run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
||||
if (!request.isDebug()) {
|
||||
String testId = request.getTestElement() != null &&
|
||||
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree()) &&
|
||||
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree().get(0).getHashTree()) ?
|
||||
request.getTestElement().getHashTree().get(0).getHashTree().get(0).getName() : request.getId();
|
||||
ApiDefinitionExecResult result = ApiDefinitionExecResultUtil.add(testId, APITestStatus.Running.name(), request.getId());
|
||||
result.setTriggerMode(TriggerMode.MANUAL.name());
|
||||
apiDefinitionExecResultMapper.insert(result);
|
||||
}
|
||||
return apiExecuteService.debug(request, bodyFiles);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.service;
|
|||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.ScenarioStatus;
|
||||
import io.metersphere.api.exec.queue.DBTestQueue;
|
||||
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
|
||||
import io.metersphere.base.domain.*;
|
||||
|
@ -179,9 +180,8 @@ public class ApiExecutionQueueService {
|
|||
public void timeOut() {
|
||||
final int SECOND_MILLIS = 1000;
|
||||
final int MINUTE_MILLIS = 60 * SECOND_MILLIS;
|
||||
long now = System.currentTimeMillis();
|
||||
// 八分钟前的数据
|
||||
now = now - 8 * MINUTE_MILLIS;
|
||||
// 二十分钟前的超时报告
|
||||
final long now = System.currentTimeMillis() - (20 * MINUTE_MILLIS);
|
||||
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
|
||||
example.createCriteria().andCreateTimeLessThan(now);
|
||||
List<ApiExecutionQueueDetail> queueDetails = executionQueueDetailMapper.selectByExample(example);
|
||||
|
@ -190,14 +190,14 @@ public class ApiExecutionQueueService {
|
|||
queueDetails.forEach(item -> {
|
||||
if (StringUtils.equalsAny(item.getType(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
|
||||
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name())) {
|
||||
report.setStatus("timeout");
|
||||
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name()) && report.getUpdateTime() < now) {
|
||||
report.setStatus(ScenarioStatus.Timeout.name());
|
||||
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
|
||||
}
|
||||
} else {
|
||||
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(item.getReportId());
|
||||
if (result != null && StringUtils.equalsAny(result.getStatus(), TestPlanReportStatus.RUNNING.name())) {
|
||||
result.setStatus("timeout");
|
||||
result.setStatus(ScenarioStatus.Timeout.name());
|
||||
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
|
||||
}
|
||||
}
|
||||
|
@ -211,8 +211,8 @@ public class ApiExecutionQueueService {
|
|||
if (CollectionUtils.isNotEmpty(executionQueues)) {
|
||||
executionQueues.forEach(item -> {
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
|
||||
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name())) {
|
||||
report.setStatus("timeout");
|
||||
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name()) && report.getUpdateTime() < now) {
|
||||
report.setStatus(ScenarioStatus.Timeout.name());
|
||||
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -87,6 +87,7 @@ public class ApiScenarioReportService {
|
|||
apiScenarioReportResultService.save(dto.getReportId(), requestResults);
|
||||
}
|
||||
|
||||
|
||||
public ApiScenarioReport testEnded(ResultDTO dto) {
|
||||
if (!StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
|
||||
// 更新控制台信息
|
||||
|
@ -96,6 +97,15 @@ public class ApiScenarioReportService {
|
|||
example.createCriteria().andReportIdEqualTo(dto.getReportId());
|
||||
List<ApiScenarioReportResult> requestResults = apiScenarioReportResultMapper.selectByExample(example);
|
||||
|
||||
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) {
|
||||
String status = getStatus(requestResults, dto);
|
||||
Map<String, String> reportMap = new HashMap<String, String>() {{
|
||||
this.put(dto.getReportId(), status);
|
||||
}};
|
||||
testPlanLog.info("TestPlanReportId" + JSONArray.toJSONString(dto.getReportId()) + " EXECUTE OVER. SCENARIO STATUS : " + JSONObject.toJSONString(reportMap));
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(dto.getTestPlanReportId(), null, reportMap, null);
|
||||
}
|
||||
|
||||
ApiScenarioReport scenarioReport;
|
||||
if (StringUtils.equals(dto.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
|
||||
scenarioReport = updatePlanCase(requestResults, dto);
|
||||
|
@ -226,7 +236,7 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
|
||||
public ApiScenarioReport updatePlanCase(List<ApiScenarioReportResult> requestResults, ResultDTO dto) {
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Error")).count();
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
|
||||
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(dto.getTestId());
|
||||
if (testPlanApiScenario != null) {
|
||||
if (errorSize > 0) {
|
||||
|
@ -234,7 +244,7 @@ public class ApiScenarioReportService {
|
|||
} else {
|
||||
testPlanApiScenario.setLastResult(ScenarioStatus.Success.name());
|
||||
}
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Success")).count();
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Success.name())).count();
|
||||
|
||||
String passRate = new DecimalFormat("0%").format((float) successSize / requestResults.size());
|
||||
testPlanApiScenario.setPassRate(passRate);
|
||||
|
@ -245,7 +255,7 @@ public class ApiScenarioReportService {
|
|||
// 更新场景状态
|
||||
ApiScenario scenario = apiScenarioMapper.selectByPrimaryKey(testPlanApiScenario.getApiScenarioId());
|
||||
if (scenario != null) {
|
||||
scenario.setLastResult(errorSize > 0 ? "Fail" : "Success");
|
||||
scenario.setLastResult(errorSize > 0 ? "Fail" : ScenarioStatus.Success.name());
|
||||
scenario.setPassRate(passRate);
|
||||
scenario.setReportId(dto.getReportId());
|
||||
int executeTimes = 0;
|
||||
|
@ -256,11 +266,7 @@ public class ApiScenarioReportService {
|
|||
apiScenarioMapper.updateByPrimaryKey(scenario);
|
||||
}
|
||||
}
|
||||
String status = errorSize > 0 || requestResults.isEmpty() ? "Error" : "Success";
|
||||
if (dto != null && dto.getArbitraryData() != null && dto.getArbitraryData().containsKey("TIMEOUT") && (Boolean) dto.getArbitraryData().get("TIMEOUT")) {
|
||||
LoggerUtil.info("报告 【 " + dto.getReportId() + " 】资源 " + dto.getTestId() + " 执行超时");
|
||||
status = "Timeout";
|
||||
}
|
||||
String status = getStatus(requestResults, dto);
|
||||
ApiScenarioReport report = editReport(dto.getReportType(), dto.getReportId(), status, dto.getRunMode());
|
||||
return report;
|
||||
}
|
||||
|
@ -269,15 +275,8 @@ public class ApiScenarioReportService {
|
|||
List<String> testPlanReportIdList = new ArrayList<>();
|
||||
StringBuilder scenarioNames = new StringBuilder();
|
||||
|
||||
Map<String, String> scenarioAndErrorMap = new HashMap<>();
|
||||
Map<String, String> planScenarioReportMap = new HashMap<>();
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Error")).count();
|
||||
|
||||
String status = errorSize > 0 || requestResults.isEmpty() ? "Error" : "Success";
|
||||
if (dto != null && dto.getArbitraryData() != null && dto.getArbitraryData().containsKey("TIMEOUT") && (Boolean) dto.getArbitraryData().get("TIMEOUT")) {
|
||||
LoggerUtil.info("报告 【 " + dto.getReportId() + " 】资源 " + dto.getTestId() + " 执行超时");
|
||||
status = "Timeout";
|
||||
}
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
|
||||
String status = getStatus(requestResults, dto);
|
||||
ApiScenarioReport report = editReport(dto.getReportType(), dto.getReportId(), status, dto.getRunMode());
|
||||
if (report != null) {
|
||||
if (StringUtils.isNotEmpty(dto.getTestPlanReportId()) && !testPlanReportIdList.contains(dto.getTestPlanReportId())) {
|
||||
|
@ -288,15 +287,12 @@ public class ApiScenarioReportService {
|
|||
report.setScenarioId(testPlanApiScenario.getApiScenarioId());
|
||||
report.setEndTime(System.currentTimeMillis());
|
||||
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
|
||||
planScenarioReportMap.put(dto.getTestId(), report.getId());
|
||||
if (errorSize > 0) {
|
||||
scenarioAndErrorMap.put(testPlanApiScenario.getId(), TestPlanApiExecuteStatus.FAILD.name());
|
||||
testPlanApiScenario.setLastResult(ScenarioStatus.Fail.name());
|
||||
} else {
|
||||
scenarioAndErrorMap.put(testPlanApiScenario.getId(), TestPlanApiExecuteStatus.SUCCESS.name());
|
||||
testPlanApiScenario.setLastResult(ScenarioStatus.Success.name());
|
||||
}
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Success")).count();
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Success.name())).count();
|
||||
String passRate = new DecimalFormat("0%").format((float) successSize / requestResults.size());
|
||||
testPlanApiScenario.setPassRate(passRate);
|
||||
|
||||
|
@ -312,7 +308,7 @@ public class ApiScenarioReportService {
|
|||
if (errorSize > 0) {
|
||||
scenario.setLastResult("Fail");
|
||||
} else {
|
||||
scenario.setLastResult("Success");
|
||||
scenario.setLastResult(ScenarioStatus.Success.name());
|
||||
}
|
||||
scenario.setPassRate(passRate);
|
||||
scenario.setReportId(report.getId());
|
||||
|
@ -325,11 +321,6 @@ public class ApiScenarioReportService {
|
|||
apiScenarioMapper.updateByPrimaryKey(scenario);
|
||||
}
|
||||
}
|
||||
testPlanLog.info("TestPlanReportId" + JSONArray.toJSONString(testPlanReportIdList) + " EXECUTE OVER. SCENARIO STATUS : " + JSONObject.toJSONString(scenarioAndErrorMap));
|
||||
for (String item : testPlanReportIdList) {
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(item, null, scenarioAndErrorMap, null);
|
||||
TestPlanReportExecuteCatch.updateTestPlanReport(item, null, planScenarioReportMap);
|
||||
}
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
@ -339,9 +330,9 @@ public class ApiScenarioReportService {
|
|||
if (report != null) {
|
||||
// 更新场景状态
|
||||
ApiScenarioReportResultExample example = new ApiScenarioReportResultExample();
|
||||
example.createCriteria().andReportIdEqualTo(reportId).andStatusEqualTo("Error");
|
||||
example.createCriteria().andReportIdEqualTo(reportId).andStatusEqualTo(ScenarioStatus.Error.name());
|
||||
long size = apiScenarioReportResultMapper.countByExample(example);
|
||||
report.setStatus(size > 0 ? "Error" : "Success");
|
||||
report.setStatus(size > 0 ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name());
|
||||
report.setEndTime(System.currentTimeMillis());
|
||||
// 更新控制台信息
|
||||
apiScenarioReportStructureService.update(reportId, resultService.getJmeterLogger(reportId));
|
||||
|
@ -351,13 +342,10 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
|
||||
public ApiScenarioReport updateScenario(List<ApiScenarioReportResult> requestResults, ResultDTO dto) {
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Error")).count();
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
|
||||
// 更新报告状态
|
||||
String status = errorSize > 0 || requestResults.isEmpty() ? "Error" : "Success";
|
||||
if (dto != null && dto.getArbitraryData() != null && dto.getArbitraryData().containsKey("TIMEOUT") && (Boolean) dto.getArbitraryData().get("TIMEOUT")) {
|
||||
LoggerUtil.info("报告 【 " + dto.getReportId() + " 】资源 " + dto.getTestId() + " 执行超时");
|
||||
status = "Timeout";
|
||||
}
|
||||
String status = getStatus(requestResults, dto);
|
||||
|
||||
ApiScenarioReport report = editReport(dto.getReportType(), dto.getReportId(), status, dto.getRunMode());
|
||||
// 更新场景状态
|
||||
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(dto.getTestId());
|
||||
|
@ -365,8 +353,8 @@ public class ApiScenarioReportService {
|
|||
scenario = apiScenarioMapper.selectByPrimaryKey(report.getScenarioId());
|
||||
}
|
||||
if (scenario != null) {
|
||||
scenario.setLastResult(errorSize > 0 ? "Fail" : "Success");
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), "Success")).count();
|
||||
scenario.setLastResult(errorSize > 0 ? "Fail" : ScenarioStatus.Success.name());
|
||||
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Success.name())).count();
|
||||
scenario.setPassRate(new DecimalFormat("0%").format((float) successSize / requestResults.size()));
|
||||
scenario.setReportId(dto.getReportId());
|
||||
int executeTimes = 0;
|
||||
|
@ -417,7 +405,7 @@ public class ApiScenarioReportService {
|
|||
|
||||
String event;
|
||||
String status;
|
||||
if (StringUtils.equals(scenario.getLastResult(), "Success")) {
|
||||
if (StringUtils.equals(scenario.getLastResult(), ScenarioStatus.Success.name())) {
|
||||
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
|
||||
status = "成功";
|
||||
} else {
|
||||
|
@ -437,8 +425,8 @@ public class ApiScenarioReportService {
|
|||
.operator(userId)
|
||||
.context(context)
|
||||
.subject("接口自动化通知")
|
||||
.successMailTemplate("api/ScenarioResult")
|
||||
.failedMailTemplate("api/ScenarioResult")
|
||||
.successMailTemplate("api/ScenarioResultSuccess")
|
||||
.failedMailTemplate("api/ScenarioResultFailed")
|
||||
.paramMap(paramMap)
|
||||
.event(event)
|
||||
.build();
|
||||
|
@ -707,4 +695,14 @@ public class ApiScenarioReportService {
|
|||
report.setScenarioId(scenarioId);
|
||||
return report;
|
||||
}
|
||||
|
||||
private String getStatus(List<ApiScenarioReportResult> requestResults, ResultDTO dto) {
|
||||
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
|
||||
String status = errorSize > 0 || requestResults.isEmpty() ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name();
|
||||
if (dto != null && dto.getArbitraryData() != null && dto.getArbitraryData().containsKey("TIMEOUT") && (Boolean) dto.getArbitraryData().get("TIMEOUT")) {
|
||||
LoggerUtil.info("报告 【 " + dto.getReportId() + " 】资源 " + dto.getTestId() + " 执行超时");
|
||||
status = ScenarioStatus.Timeout.name();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.api.service;
|
|||
import io.metersphere.api.dto.automation.ApiTestReportVariable;
|
||||
import io.metersphere.api.jmeter.ExecutedHandleSingleton;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.NoticeConstants;
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
|
@ -47,6 +48,8 @@ public class TestResultService {
|
|||
private TestPlanTestCaseService testPlanTestCaseService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
|
||||
public void saveResults(ResultDTO dto) {
|
||||
// 处理环境
|
||||
|
@ -70,6 +73,14 @@ public class TestResultService {
|
|||
updateTestCaseStates(requestResults, dto.getRunMode());
|
||||
}
|
||||
|
||||
public void editReportTime(ResultDTO dto) {
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(dto.getReportId());
|
||||
if (report != null) {
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
apiScenarioReportMapper.updateByPrimaryKey(report);
|
||||
}
|
||||
}
|
||||
|
||||
public void testEnded(ResultDTO dto) {
|
||||
if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
|
||||
ApiScenarioReport scenarioReport = apiScenarioReportService.testEnded(dto);
|
||||
|
|
|
@ -114,6 +114,9 @@
|
|||
<if test="request.platform != null and request.platform != ''">
|
||||
and issues.platform = #{request.platform}
|
||||
</if>
|
||||
<if test="request.id != null and request.id != ''">
|
||||
and issues.id = #{request.id}
|
||||
</if>
|
||||
|
||||
<!-- <if test="request.ids != null and request.ids.size() > 0">-->
|
||||
<!-- and issues.id in-->
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.job.sechedule;
|
|||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.track.service.TestPlanService;
|
||||
import org.quartz.*;
|
||||
|
||||
|
@ -16,25 +17,10 @@ import org.quartz.*;
|
|||
public class TestPlanTestJob extends MsScheduleJob {
|
||||
private String projectID;
|
||||
|
||||
|
||||
// private PerformanceTestService performanceTestService;
|
||||
// private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
||||
// private TestPlanApiCaseService testPlanApiCaseService;
|
||||
// private ApiTestCaseService apiTestCaseService;
|
||||
// private TestPlanReportService testPlanReportService;
|
||||
// private TestPlanLoadCaseService testPlanLoadCaseService;
|
||||
private TestPlanService testPlanService;
|
||||
|
||||
public TestPlanTestJob() {
|
||||
// this.performanceTestService = CommonBeanFactory.getBean(PerformanceTestService.class);
|
||||
// this.testPlanScenarioCaseService = CommonBeanFactory.getBean(TestPlanScenarioCaseService.class);
|
||||
// this.testPlanApiCaseService = CommonBeanFactory.getBean(TestPlanApiCaseService.class);
|
||||
// this.apiTestCaseService = CommonBeanFactory.getBean(ApiTestCaseService.class);
|
||||
// this.testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||
// this.testPlanLoadCaseService = CommonBeanFactory.getBean(TestPlanLoadCaseService.class);
|
||||
this.testPlanService = CommonBeanFactory.getBean(TestPlanService.class);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +49,17 @@ public class TestPlanTestJob extends MsScheduleJob {
|
|||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
String config = jobDataMap.getString("config");
|
||||
|
||||
testPlanService.run(this.resourceId, this.projectID, this.userId, ReportTriggerMode.SCHEDULE.name(),config);
|
||||
String runResourceId = this.resourceId;
|
||||
String runProjectId = this.projectID;
|
||||
String runUserId = this.userId;
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtil.info("Start test_plan_scehdule. test_plan_id:" + runResourceId);
|
||||
testPlanService.run(runResourceId, runProjectId, runUserId, ReportTriggerMode.SCHEDULE.name(),config);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String testId) {
|
||||
|
|
|
@ -68,6 +68,14 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
|||
|
||||
@Value("${jmeter.home}")
|
||||
private String jmeterHome;
|
||||
@Value("${quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock}")
|
||||
private String acquireTriggersWithinLock;
|
||||
@Value("${quartz.enabled}")
|
||||
private boolean quartzEnable;
|
||||
@Value("${quartz.scheduler-name}")
|
||||
private String quartzScheduleName;
|
||||
@Value("${quartz.thread-count}")
|
||||
private int quartzThreadCount;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
|
||||
|
@ -99,7 +107,12 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
|
|||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
LogUtil.info("开始启动定时任务。 相关设置:" +
|
||||
"quartz.acquireTriggersWithinLock :" + acquireTriggersWithinLock + "\r\n" +
|
||||
"quartz.enabled :" + quartzEnable + "\r\n" +
|
||||
"quartz.scheduler-name :" + quartzScheduleName + "\r\n" +
|
||||
"quartz.thread-count :" + quartzThreadCount + "\r\n"
|
||||
);
|
||||
scheduleService.startEnableSchedules();
|
||||
}
|
||||
|
||||
|
|
|
@ -153,16 +153,27 @@ public class ReflexObjectUtil {
|
|||
GsonDiff diff = new GsonDiff();
|
||||
Object originalValue = originalColumns.get(i).getOriginalValue();
|
||||
Object newValue = newColumns.get(i).getOriginalValue();
|
||||
String oldTags = null;
|
||||
if (originalValue != null && !StringUtils.equals("null", originalValue.toString())) {
|
||||
List<String> originalValueArray = JSON.parseArray(originalValue.toString(), String.class);
|
||||
List<String> newValueArray = JSON.parseArray(newValue.toString(), String.class);
|
||||
Collections.sort(originalValueArray);
|
||||
Collections.sort(newValueArray);
|
||||
Object originalObject = JSON.toJSON(originalValueArray);
|
||||
oldTags = ApiDefinitionDiffUtil.JSON_START + ((originalColumns.get(i) != null && originalObject != null) ? originalObject.toString() : "\"\"") + ApiDefinitionDiffUtil.JSON_END;
|
||||
}
|
||||
List<String> newValueArray = JSON.parseArray(newValue.toString(), String.class);
|
||||
Collections.sort(newValueArray);
|
||||
Object newObject = JSON.toJSON(newValueArray);
|
||||
String oldTags = ApiDefinitionDiffUtil.JSON_START + ((originalColumns.get(i) != null && originalObject != null) ? originalObject.toString() : "\"\"") + ApiDefinitionDiffUtil.JSON_END;
|
||||
String newTags = ApiDefinitionDiffUtil.JSON_START + ((newColumns.get(i) != null && newObject != null) ? newObject.toString() : "\"\"") + ApiDefinitionDiffUtil.JSON_END;
|
||||
String diffValue;
|
||||
if (oldTags != null) {
|
||||
String diffStr = diff.diff(oldTags, newTags);
|
||||
String diffValue = diff.apply(newTags, diffStr);
|
||||
diffValue = diff.apply(newTags, diffStr);
|
||||
} else {
|
||||
int indexAdd = newTags.indexOf("[");
|
||||
String substring = newTags.substring(0, indexAdd + 2);
|
||||
String substring1 = newTags.substring(indexAdd + 2);
|
||||
diffValue = substring + "++" + substring1;
|
||||
}
|
||||
column.setDiffValue(diffValue);
|
||||
}
|
||||
// 深度对比
|
||||
|
|
|
@ -19,11 +19,10 @@ import io.metersphere.track.service.TestCaseReviewService;
|
|||
import io.metersphere.track.service.TestCaseService;
|
||||
import io.metersphere.track.service.TestPlanService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import org.apache.commons.text.StringSubstitutor;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -128,29 +127,31 @@ public abstract class AbstractNoticeSender implements NoticeSender {
|
|||
}
|
||||
|
||||
protected String getContent(String template, Map<String, Object> context) {
|
||||
if (MapUtils.isNotEmpty(context)) {
|
||||
for (String k : context.keySet()) {
|
||||
if (context.get(k) != null) {
|
||||
String value = handleTime(k, context);
|
||||
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", value);
|
||||
} else {
|
||||
template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", "");
|
||||
// 处理 null
|
||||
context.forEach((k, v) -> {
|
||||
if (v == null) {
|
||||
context.put(k, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
return template;
|
||||
});
|
||||
// 处理时间格式的数据
|
||||
handleTime(context);
|
||||
StringSubstitutor sub = new StringSubstitutor(context);
|
||||
return sub.replace(template);
|
||||
}
|
||||
|
||||
private String handleTime(String k, Map<String, Object> context) {
|
||||
String value = context.get(k).toString();
|
||||
private void handleTime(Map<String, Object> context) {
|
||||
context.forEach((k, v) -> {
|
||||
if (StringUtils.endsWithIgnoreCase(k, "Time")) {
|
||||
try {
|
||||
String value = v.toString();
|
||||
long time = Long.parseLong(value);
|
||||
value = DateFormatUtils.format(time, "yyyy-MM-dd HH:mm:ss");
|
||||
v = DateFormatUtils.format(time, "yyyy-MM-dd HH:mm:ss");
|
||||
context.put(k, v);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected List<UserDetail> getUserDetails(List<String> userIds) {
|
||||
|
|
|
@ -35,6 +35,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.alibaba.fastjson.serializer.SerializerFeature.WriteMapNullValue;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class SendNoticeAspect {
|
||||
|
@ -81,7 +83,7 @@ public class SendNoticeAspect {
|
|||
Expression titleExp = parser.parseExpression(target);
|
||||
Object v = titleExp.getValue(context, Object.class);
|
||||
Map<String, Object> memberValues = (Map<String, Object>) value.get(invocationHandler);
|
||||
memberValues.put("source", JSON.toJSONString(v));
|
||||
memberValues.put("source", JSON.toJSONString(v, WriteMapNullValue));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
|
@ -119,7 +121,7 @@ public class SendNoticeAspect {
|
|||
Object v = titleExp.getValue(context, Object.class);
|
||||
if (v != null) {
|
||||
Map<String, Object> memberValues = (Map<String, Object>) value.get(invocationHandler);
|
||||
memberValues.put("source", JSON.toJSONString(v));
|
||||
memberValues.put("source", JSON.toJSONString(v, WriteMapNullValue));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.metersphere.performance.engine;
|
|||
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.LoadTestReportWithBLOBs;
|
||||
import io.metersphere.base.domain.TestResource;
|
||||
import io.metersphere.base.domain.TestResourcePool;
|
||||
|
@ -13,6 +12,7 @@ import io.metersphere.commons.constants.ResourceStatusEnum;
|
|||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
import io.metersphere.dto.JmeterRunRequestDTO;
|
||||
import io.metersphere.performance.service.PerformanceTestService;
|
||||
import io.metersphere.service.TestResourcePoolService;
|
||||
import io.metersphere.service.TestResourceService;
|
||||
|
@ -42,7 +42,7 @@ public abstract class AbstractEngine implements Engine {
|
|||
GC_ALGO = CommonBeanFactory.getBean(JmeterProperties.class).getGcAlgo();
|
||||
}
|
||||
|
||||
protected void initApiConfig(RunRequest runRequest) {
|
||||
protected void initApiConfig(JmeterRunRequestDTO runRequest) {
|
||||
String resourcePoolId = runRequest.getPoolId();
|
||||
resourcePool = testResourcePoolService.getResourcePool(resourcePoolId);
|
||||
if (resourcePool == null || StringUtils.equals(resourcePool.getStatus(), ResourceStatusEnum.DELETE.name())) {
|
||||
|
|
|
@ -300,12 +300,20 @@ public class EngineFactory {
|
|||
rootDocument = docBuilder.parse(inputSource);
|
||||
Element jmeterTestPlan = rootDocument.getDocumentElement();
|
||||
NodeList childNodes = jmeterTestPlan.getChildNodes();
|
||||
|
||||
outer:
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node node = childNodes.item(i);
|
||||
if (node instanceof Element) {
|
||||
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
|
||||
NodeList childNodes1 = node.getChildNodes();
|
||||
for (int j = 0; j < childNodes1.getLength(); j++) {
|
||||
Node item = childNodes1.item(j);
|
||||
if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) {
|
||||
hashTree = (Element) node;
|
||||
break;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -320,11 +328,21 @@ public class EngineFactory {
|
|||
NodeList secondChildNodes = secondHashTree.getChildNodes();
|
||||
for (int j = 0; j < secondChildNodes.getLength(); j++) {
|
||||
Node item = secondChildNodes.item(j);
|
||||
Node newNode = item.cloneNode(true);
|
||||
if (StringUtils.equalsIgnoreCase("TestPlan", item.getNodeName())) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) {
|
||||
NodeList itemChildNodes = item.getChildNodes();
|
||||
for (int k = 0; k < itemChildNodes.getLength(); k++) {
|
||||
Node item1 = itemChildNodes.item(k);
|
||||
Node newNode = item1.cloneNode(true);
|
||||
rootDocument.adoptNode(newNode);
|
||||
hashTree.appendChild(newNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.metersphere.commons.exception.MSException;
|
|||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.controller.request.EnvironmentGroupRequest;
|
||||
import io.metersphere.dto.EnvironmentGroupDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -161,7 +162,7 @@ public class EnvironmentGroupService {
|
|||
private void checkEnvironmentGroup(EnvironmentGroupRequest request) {
|
||||
String name = request.getName();
|
||||
if (StringUtils.isBlank(name)) {
|
||||
MSException.throwException("environment group name is null.");
|
||||
MSException.throwException(Translator.get("null_environment_group_name"));
|
||||
}
|
||||
|
||||
EnvironmentGroupExample environmentGroupExample = new EnvironmentGroupExample();
|
||||
|
@ -173,7 +174,7 @@ public class EnvironmentGroupService {
|
|||
}
|
||||
|
||||
if (environmentGroupMapper.countByExample(environmentGroupExample) > 0) {
|
||||
MSException.throwException("环境组名称 " + request.getName() + " 已存在!");
|
||||
MSException.throwException(Translator.get("environment_group_name")+request.getName()+Translator.get("environment_group_exist"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class IssueCommentController {
|
|||
@PostMapping("/save")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#targetClass.get(#request.issuesId)", targetClass = IssuesService.class,
|
||||
event = NoticeConstants.Event.COMMENT, mailTemplate = "track/IssuesCommentUpdate", subject = "缺陷评论更新通知")
|
||||
event = NoticeConstants.Event.COMMENT, mailTemplate = "track/IssuesCommentUpdate", subject = "缺陷")
|
||||
public IssueComment saveComment(@RequestBody IssuesRelevanceRequest request) {
|
||||
request.setId(UUID.randomUUID().toString());
|
||||
return issueCommentService.saveComment(request);
|
||||
|
|
|
@ -133,7 +133,7 @@ public class TestPlanController {
|
|||
@PostMapping("/delete/{testPlanId}")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_PLAN_READ_DELETE)
|
||||
@MsAuditLog(module = "track_test_plan", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#testPlanId)", msClass = TestPlanService.class)
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, target = "#targetClass.getTestPlan(#testPlanId)", targetClass = TestPlanService.class,
|
||||
@SendNotice(taskType = NoticeConstants.TaskType.TEST_PLAN_TASK, target = "#targetClass.get(#testPlanId)", targetClass = TestPlanService.class,
|
||||
event = NoticeConstants.Event.DELETE, mailTemplate = "track/TestPlanDelete", subject = "测试计划通知")
|
||||
public int deleteTestPlan(@PathVariable String testPlanId) {
|
||||
checkPermissionService.checkTestPlanOwner(testPlanId);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package io.metersphere.track.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestPlanReportExecuteCheckResultDTO {
|
||||
private boolean isTimeOut;
|
||||
private boolean isFinishedCaseChanged;
|
||||
}
|
|
@ -81,7 +81,9 @@ public class TestPlanReportService {
|
|||
@Resource
|
||||
ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
|
||||
@Resource
|
||||
ApiTestCaseMapper apiTestCaseMapper;
|
||||
ExtApiDefinitionExecResultMapper extApiDefinitionExecResultMapper;
|
||||
@Resource
|
||||
ExtApiScenarioReportMapper extApiScenarioReportMapper;
|
||||
@Resource
|
||||
LoadTestReportMapper loadTestReportMapper;
|
||||
@Resource
|
||||
|
@ -551,8 +553,6 @@ public class TestPlanReportService {
|
|||
boolean scenarioIsOk = executeInfo.isScenarioAllExecuted();
|
||||
boolean performanceIsOk = executeInfo.isLoadCaseAllExecuted();
|
||||
|
||||
testPlanLog.info("ReportId[" + testPlanReport.getId() + "] count over. Testplan Execute Result: Api is over ->" + apiCaseIsOk + "; scenario is over ->" + scenarioIsOk + "; performance is over ->" + performanceIsOk);
|
||||
|
||||
if (apiCaseIsOk) {
|
||||
testPlanReport.setIsApiCaseExecuting(false);
|
||||
}
|
||||
|
@ -1075,13 +1075,17 @@ public class TestPlanReportService {
|
|||
}
|
||||
|
||||
public void countReport(String planReportId) {
|
||||
boolean isTimeOut = this.checkTestPlanReportIsTimeOut(planReportId);
|
||||
if (isTimeOut) {
|
||||
TestPlanReportExecuteCheckResultDTO checkResult = this.checkTestPlanReportIsTimeOut(planReportId);
|
||||
testPlanLog.info("Check PlanReport:" + planReportId + "; result: "+ JSON.toJSONString(checkResult));
|
||||
if (checkResult.isTimeOut()) {
|
||||
//判断是否超时。超时时强行停止任务
|
||||
TestPlanReportExecuteCatch.finishAllTask(planReportId);
|
||||
checkResult.setFinishedCaseChanged(true);
|
||||
}
|
||||
if(checkResult.isFinishedCaseChanged()){
|
||||
this.updateExecuteApis(planReportId);
|
||||
}
|
||||
}
|
||||
|
||||
public TestPlanSimpleReportDTO getReport(String reportId) {
|
||||
TestPlanReportContentExample example = new TestPlanReportContentExample();
|
||||
|
@ -1216,19 +1220,61 @@ public class TestPlanReportService {
|
|||
testPlanReportContentMapper.updateByExampleSelective(bloBs,example);
|
||||
}
|
||||
|
||||
private boolean checkTestPlanReportIsTimeOut(String planReportId) {
|
||||
private TestPlanReportExecuteCheckResultDTO checkTestPlanReportIsTimeOut(String planReportId) {
|
||||
//同步数据库更新状态信息
|
||||
try {
|
||||
this.syncReportStatus(planReportId);
|
||||
} catch (Exception e) {
|
||||
LogUtil.info("联动数据库同步执行状态失败! " + e.getMessage());
|
||||
LogUtil.error(e);
|
||||
}
|
||||
TestPlanExecuteInfo executeInfo = TestPlanReportExecuteCatch.getTestPlanExecuteInfo(planReportId);
|
||||
int unFinishNum = executeInfo.countUnFinishedNum();
|
||||
if (unFinishNum > 0) {
|
||||
//20分钟没有案例执行结果更新,则定位超时
|
||||
long lastCountTime = executeInfo.getLastFinishedNumCountTime();
|
||||
long nowTime = System.currentTimeMillis();
|
||||
testPlanLog.info("ReportId: ["+planReportId+"]; timeCount:"+ (nowTime - lastCountTime));
|
||||
if (nowTime - lastCountTime > 1200000) {
|
||||
return true;
|
||||
TestPlanReportExecuteCheckResultDTO checkResult = executeInfo.countUnFinishedNum();
|
||||
return checkResult;
|
||||
}
|
||||
|
||||
private void syncReportStatus(String planReportId) {
|
||||
if (TestPlanReportExecuteCatch.containsReport(planReportId)) {
|
||||
TestPlanExecuteInfo executeInfo = TestPlanReportExecuteCatch.getTestPlanExecuteInfo(planReportId);
|
||||
if (executeInfo != null) {
|
||||
//同步接口案例结果
|
||||
Map<String, String> updateCaseStatusMap = new HashMap<>();
|
||||
Map<String, String> apiCaseReportMap = executeInfo.getRunningApiCaseReportMap();
|
||||
if (MapUtils.isNotEmpty(apiCaseReportMap)) {
|
||||
List<ApiDefinitionExecResult> execList = extApiDefinitionExecResultMapper.selectStatusByIdList(apiCaseReportMap.keySet());
|
||||
for (ApiDefinitionExecResult report : execList) {
|
||||
String reportId = report.getId();
|
||||
String status = report.getStatus();
|
||||
if (!StringUtils.equalsAnyIgnoreCase(status, "Running", "Waiting")) {
|
||||
String planCaseId = apiCaseReportMap.get(reportId);
|
||||
if (StringUtils.isNotEmpty(planCaseId)) {
|
||||
updateCaseStatusMap.put(planCaseId, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//同步场景结果
|
||||
Map<String, String> updateScenarioStatusMap = new HashMap<>();
|
||||
Map<String, String> scenarioReportMap = executeInfo.getRunningScenarioReportMap();
|
||||
if (MapUtils.isNotEmpty(scenarioReportMap)) {
|
||||
List<ApiScenarioReport> reportList = extApiScenarioReportMapper.selectStatusByIds(scenarioReportMap.keySet());
|
||||
for (ApiScenarioReport report : reportList) {
|
||||
String reportId = report.getId();
|
||||
String status = report.getStatus();
|
||||
if (!StringUtils.equalsAnyIgnoreCase(status, "Running", "Waiting")) {
|
||||
String planScenarioId = scenarioReportMap.get(reportId);
|
||||
if (StringUtils.isNotEmpty(planScenarioId)) {
|
||||
updateScenarioStatusMap.put(planScenarioId, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
testPlanLog.info("ReportID:"+planReportId+" 本次数据库同步,案例ID:"+JSON.toJSONString(apiCaseReportMap.keySet())+";场景ID:"+JSON.toJSONString(scenarioReportMap.keySet())+"; 同步结果,案例:"+JSON.toJSONString(updateCaseStatusMap)+";场景:"+JSON.toJSONString(updateScenarioStatusMap));
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(planReportId, updateCaseStatusMap, updateScenarioStatusMap, null);
|
||||
}else {
|
||||
testPlanLog.info("同步数据库查询执行信息失败! 报告ID在缓存中未找到!"+planReportId);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void finishTestPlanReport(String planReportId) {
|
||||
|
@ -1239,5 +1285,4 @@ public class TestPlanReportService {
|
|||
}
|
||||
TestPlanReportExecuteCatch.remove(planReportId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -243,6 +243,10 @@ public class TestPlanService {
|
|||
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlanWithBLOBs());
|
||||
}
|
||||
|
||||
public TestPlanWithBLOBs get(String testPlanId) {
|
||||
return testPlanMapper.selectByPrimaryKey(testPlanId);
|
||||
}
|
||||
|
||||
public TestPlan editTestPlanWithRequest(AddTestPlanRequest request) {
|
||||
List<String> principals = request.getPrincipals();
|
||||
if (!CollectionUtils.isEmpty(principals)) {
|
||||
|
@ -1116,8 +1120,8 @@ public class TestPlanService {
|
|||
testPlanLoadCaseService.update(testPlanLoadCase);
|
||||
LogUtil.error(e);
|
||||
}
|
||||
performaneThreadIDMap.put(performanceRequest.getTestPlanLoadId(), reportId);
|
||||
if (StringUtils.isNotEmpty(reportId)) {
|
||||
performaneThreadIDMap.put(performanceRequest.getTestPlanLoadId(), reportId);
|
||||
executePerformanceIdMap.put(performanceRequest.getTestPlanLoadId(), TestPlanApiExecuteStatus.RUNNING.name());
|
||||
} else {
|
||||
executePerformanceIdMap.put(performanceRequest.getTestPlanLoadId(), TestPlanApiExecuteStatus.PREPARE.name());
|
||||
|
|
|
@ -22,7 +22,7 @@ public class IndexWebSocket {
|
|||
public void openSession(@PathParam("reportId") String reportId, Session session) {
|
||||
WebSocketUtils.ONLINE_USER_SESSIONS.put(reportId, session);
|
||||
log.info("客户端: [" + reportId + "] : 连接成功!");
|
||||
WebSocketUtils.sendMessageAll("客户端: [" + reportId + "] : 连接成功!");
|
||||
//WebSocketUtils.sendMessageAll("客户端: [" + reportId + "] : 连接成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,7 +45,7 @@ public class IndexWebSocket {
|
|||
WebSocketUtils.ONLINE_USER_SESSIONS.remove(reportId);
|
||||
log.info("[" + reportId + "] : 断开连接!");
|
||||
//并且通知其他人当前用户已经断开连接了
|
||||
WebSocketUtils.sendMessageAll("[" + reportId + "] : 断开连接!");
|
||||
//WebSocketUtils.sendMessageAll("[" + reportId + "] : 断开连接!");
|
||||
session.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.websocket.c.to.c;
|
||||
|
||||
import io.metersphere.utils.LoggerUtil;
|
||||
import io.metersphere.websocket.c.to.c.util.MsgDto;
|
||||
|
||||
import javax.websocket.RemoteEndpoint;
|
||||
|
@ -12,9 +13,13 @@ public class WebSocketUtils {
|
|||
|
||||
// 单用户推送
|
||||
public static void sendMessage(Session session, String message) {
|
||||
if (session == null) { return; }
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
RemoteEndpoint.Async async = session.getAsyncRemote();
|
||||
if (async == null) { return; }
|
||||
if (async == null) {
|
||||
return;
|
||||
}
|
||||
async.sendText(message);
|
||||
}
|
||||
|
||||
|
@ -30,4 +35,20 @@ public class WebSocketUtils {
|
|||
sendMessage(session, message);
|
||||
});
|
||||
}
|
||||
|
||||
//当前的Session 移除
|
||||
public static void onClose(String reportId) {
|
||||
try {
|
||||
if (WebSocketUtils.ONLINE_USER_SESSIONS.containsKey(reportId)) {
|
||||
WebSocketUtils.ONLINE_USER_SESSIONS.get(reportId).close();
|
||||
WebSocketUtils.ONLINE_USER_SESSIONS.remove(reportId);
|
||||
}
|
||||
if (WebSocketUtils.ONLINE_USER_SESSIONS.containsKey(("send." + reportId))) {
|
||||
WebSocketUtils.ONLINE_USER_SESSIONS.get(("send." + reportId)).close();
|
||||
WebSocketUtils.ONLINE_USER_SESSIONS.remove(("send." + reportId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LoggerUtil.error("关闭socket失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
package io.metersphere.websocket.c.to.c.util;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author: jason
|
||||
* @Date: 2020-12-23
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
public class SocketClient {
|
||||
private Integer userId;
|
||||
private String username;
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit a1e39f9c1baf30f52da50ab34ea1bacbfbeff60c
|
||||
Subproject commit 3cac4fd4c1cb2b3dfb4bd82a6a09cc55ae2f2d34
|
|
@ -12,7 +12,7 @@ server.ssl.key-alias=localhost
|
|||
|
||||
# Hikari
|
||||
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
|
||||
spring.datasource.hikari.maximum-pool-size=100
|
||||
spring.datasource.hikari.maximum-pool-size=200
|
||||
spring.datasource.hikari.auto-commit=true
|
||||
spring.datasource.hikari.idle-timeout=10000
|
||||
spring.datasource.hikari.pool-name=DatebookHikariCP
|
||||
|
@ -23,7 +23,7 @@ spring.datasource.hikari.connection-test-query=SELECT 1
|
|||
spring.datasource.quartz.url=${spring.datasource.url}
|
||||
spring.datasource.quartz.username=${spring.datasource.username}
|
||||
spring.datasource.quartz.password=${spring.datasource.password}
|
||||
spring.datasource.quartz.hikari.maximum-pool-size=50
|
||||
spring.datasource.quartz.hikari.maximum-pool-size=200
|
||||
spring.datasource.quartz.hikari.auto-commit=true
|
||||
spring.datasource.quartz.hikari.idle-timeout=10000
|
||||
spring.datasource.quartz.hikari.pool-name=DatebookHikariCP
|
||||
|
@ -92,7 +92,8 @@ jmeter.home=/opt/jmeter
|
|||
# quartz
|
||||
quartz.enabled=true
|
||||
quartz.scheduler-name=msServerJob
|
||||
quartz.thread-count=30
|
||||
quartz.thread-count=60
|
||||
quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true
|
||||
# file upload
|
||||
spring.servlet.multipart.max-file-size=500MB
|
||||
spring.servlet.multipart.max-request-size=500MB
|
||||
|
|
|
@ -285,6 +285,10 @@ test_case_status=Case status
|
|||
id_not_rightful=ID is not rightful
|
||||
# mock
|
||||
mock_warning=No matching Mock expectation was found
|
||||
zentao_test_type_error=请求方式错误
|
||||
zentao_test_type_error=invalid Zentao request
|
||||
#项目报告
|
||||
enterprise_test_report=Enterprise report
|
||||
#环境组
|
||||
null_environment_group_name = Environment group name is null
|
||||
environment_group_name = Environment group name
|
||||
environment_group_exist = already exists
|
||||
|
|
|
@ -284,6 +284,10 @@ test_case_status=用例状态
|
|||
id_not_rightful=ID 不合法
|
||||
# mock
|
||||
mock_warning=未找到匹配的Mock期望
|
||||
zentao_test_type_error=invalid Zentao request
|
||||
zentao_test_type_error=无效的 Zentao 请求
|
||||
#项目报告
|
||||
enterprise_test_report=项目报告
|
||||
#环境组
|
||||
null_environment_group_name = 环境组名称不存在
|
||||
environment_group_name = 环境组名称
|
||||
environment_group_exist = 已存在
|
|
@ -287,3 +287,7 @@ mock_warning=未找到匹配的Mock期望
|
|||
zentao_test_type_error=請求方式錯誤
|
||||
#项目报告
|
||||
enterprise_test_report=項目報告
|
||||
#环境组
|
||||
null_environment_group_name = 環境組名稱不存在
|
||||
environment_group_name = 環境組名稱
|
||||
environment_group_exist = 已存在
|
|
@ -6,7 +6,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>${operator}执行接口用例: ${name}, 结果: ${status}</p>
|
||||
<p>${operator}执行接口用例失败: ${name}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -6,7 +6,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>${operator}执行接口自动化: ${name}, 结果: ${status}</p>
|
||||
<p>${operator}执行接口用例成功: ${name}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>MeterSphere</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>${operator}执行接口自动化失败: ${name}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>MeterSphere</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p>${operator}执行接口自动化成功: ${name}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -324,6 +324,10 @@ export default {
|
|||
if (data) {
|
||||
this.report = data;
|
||||
if (this.report.reportVersion && this.report.reportVersion > 1) {
|
||||
this.report.status = data.status;
|
||||
if (!this.isNotRunning) {
|
||||
setTimeout(this.getReport, 2000)
|
||||
} else {
|
||||
if (data.content) {
|
||||
let report = JSON.parse(data.content);
|
||||
this.content = report;
|
||||
|
@ -334,6 +338,7 @@ export default {
|
|||
this.totalTime = report.totalTime;
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
} else {
|
||||
this.buildReport();
|
||||
}
|
||||
|
@ -528,10 +533,12 @@ export default {
|
|||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.report-console {
|
||||
height: calc(100vh - 270px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.export-button {
|
||||
float: right;
|
||||
}
|
||||
|
|
|
@ -356,7 +356,7 @@ export default {
|
|||
if (e.data) {
|
||||
this.runningEvaluation(e.data);
|
||||
}
|
||||
if (e.data && e.data.indexOf("断开连接") !== -1) {
|
||||
if (e.data && e.data.indexOf("MS_TEST_END") !== -1) {
|
||||
this.getReport();
|
||||
this.messageWebSocket.close();
|
||||
scenario.$emit('hide', this.scenarioId);
|
||||
|
|
|
@ -454,7 +454,8 @@ export default {
|
|||
permissions: ['PROJECT_API_SCENARIO:READ+DELETE']
|
||||
},
|
||||
{
|
||||
name: "批量恢复", handleClick: this.handleBatchRestore
|
||||
name: this.$t('commons.batch_restore'),
|
||||
handleClick: this.handleBatchRestore
|
||||
},
|
||||
],
|
||||
unTrashButtons: [
|
||||
|
@ -794,7 +795,7 @@ export default {
|
|||
|
||||
// todo 选取全部数据
|
||||
if (this.condition.selectAll) {
|
||||
this.$warning("暂不支持批量添加所有场景到测试计划!");
|
||||
this.$warning(this.$t('api_test.scenario.warning_context'));
|
||||
}
|
||||
|
||||
this.planVisible = false;
|
||||
|
@ -1010,7 +1011,7 @@ export default {
|
|||
this.$get("/api/automation/checkScenarioEnv/" + this.currentScenario.id, res => {
|
||||
let data = res.data;
|
||||
if (!data) {
|
||||
this.$warning("请为场景选择环境!");
|
||||
this.$warning(this.$t('workspace.env_group.please_select_env_for_current_scenario'));
|
||||
return false;
|
||||
}
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
|
|
|
@ -789,7 +789,7 @@ export default {
|
|||
}
|
||||
this.runningEvaluation(e.data);
|
||||
this.message = getUUID();
|
||||
if (e.data && e.data.indexOf("断开连接") !== -1) {
|
||||
if (e.data && e.data.indexOf("MS_TEST_END") !== -1) {
|
||||
this.runScenario = undefined;
|
||||
this.debugLoading = false;
|
||||
this.message = "stop";
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
},
|
||||
getConditions() {
|
||||
let sampleSelectRows = this.selectRows;
|
||||
let param = buildBatchParam(this);
|
||||
let param = buildBatchParam(this, undefined, this.projectId);
|
||||
param.ids = Array.from(sampleSelectRows).map(row => row.id);
|
||||
return param;
|
||||
},
|
||||
|
|
|
@ -282,7 +282,7 @@ export default {
|
|||
},
|
||||
getConditions() {
|
||||
let sampleSelectRows = this.$refs.table.getSelectRows();
|
||||
let batchParam = buildBatchParam(this);
|
||||
let batchParam = buildBatchParam(this, undefined, this.projectId);
|
||||
let param = {};
|
||||
if (batchParam.condition) {
|
||||
param = batchParam.condition;
|
||||
|
|
|
@ -364,7 +364,7 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (databaseConfigsOptions.length > 0) {
|
||||
if (databaseConfigsOptions.length > 0 && this.request.environmentId !== this.environment.id) {
|
||||
this.request.dataSourceId = databaseConfigsOptions[0].id;
|
||||
this.request.environmentId = this.environment.id;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
:placeholder="$t('api_test.definition.request.run_env')"
|
||||
clearable>
|
||||
<el-option v-for="(environment, index) in environments" :key="index"
|
||||
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
|
||||
:label="environment.name"
|
||||
:value="environment.id"/>
|
||||
<template v-slot:empty>
|
||||
<div class="empty-environment">
|
||||
|
|
|
@ -945,7 +945,7 @@ export default {
|
|||
apiNames += ";" + item;
|
||||
}
|
||||
});
|
||||
this.$error("请先恢复[" + apiNames + "]接口");
|
||||
this.$error(this.$t('api_test.definition.case_reduction_error_text') + "[" + apiNames + "]" + this.$t("api_test.home_page.api_details_card.title"));
|
||||
} else {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
}
|
||||
|
@ -971,7 +971,7 @@ export default {
|
|||
apiNames += ";" + item;
|
||||
}
|
||||
});
|
||||
this.$error("请先恢复[" + apiNames + "]接口");
|
||||
this.$error(this.$t('api_test.definition.case_reduction_error_text') + "[" + apiNames + "]" + this.$t("api_test.home_page.api_details_card.title"));
|
||||
} else {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
}
|
||||
|
|
|
@ -302,7 +302,8 @@ export default {
|
|||
permissions: ['PROJECT_API_DEFINITION:READ+DELETE_API']
|
||||
},
|
||||
{
|
||||
name: "批量恢复", handleClick: this.handleBatchRestore
|
||||
name: this.$t('commons.batch_restore'),
|
||||
handleClick: this.handleBatchRestore
|
||||
},
|
||||
],
|
||||
tableOperatorButtons: [],
|
||||
|
|
|
@ -4,12 +4,16 @@
|
|||
<el-col>
|
||||
<div style="font-size: 14px;color: #AAAAAA;float: left">{{ $t('api_report.response_code') }} :</div>
|
||||
<el-tooltip
|
||||
v-if="responseResult.responseCode"
|
||||
:content="responseResult.responseCode"
|
||||
placement="top">
|
||||
<div class="node-title" :class="response && response.success ?'ms-req-success':'ms-req-error'">
|
||||
{{ responseResult && responseResult.responseCode ? responseResult.responseCode : '0' }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div v-else class="node-title" :class="response && response.success ?'ms-req-success':'ms-req-error'">
|
||||
{{ responseResult && responseResult.responseCode ? responseResult.responseCode : '0' }}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<div style="font-size: 14px;color: #AAAAAA;float: left">{{ $t('api_report.response_time') }} :</div>
|
||||
|
|
|
@ -165,7 +165,7 @@ export default {
|
|||
if (now - d.createTime > 10 * 1000) {
|
||||
return;
|
||||
}
|
||||
d.user = this.userMap[d.operator];
|
||||
d.user = this.userMap[d.operator] || {name: 'MS'};
|
||||
let message = d.user.name + getOperation(d.operation) + getResource(d) + ": " + d.resourceName;
|
||||
let title = d.type === 'MENTIONED_ME' ? this.$t('commons.mentioned_me_notice') : this.$t('commons.system_notice');
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -443,7 +443,7 @@ export default {
|
|||
created() {
|
||||
this.isReadOnly = !hasPermission('PROJECT_PERFORMANCE_REPORT:READ+DELETE');
|
||||
this.reportId = this.$route.path.split('/')[4];
|
||||
if (!this.reportId && this.perReportId) {
|
||||
if (this.perReportId) {
|
||||
this.reportId = this.perReportId;
|
||||
}
|
||||
this.getReport(this.reportId);
|
||||
|
@ -452,6 +452,9 @@ export default {
|
|||
'$route'(to) {
|
||||
if (to.name === "perReportView") {
|
||||
this.reportId = to.path.split('/')[4];
|
||||
if (this.perReportId) {
|
||||
this.reportId = this.perReportId;
|
||||
}
|
||||
this.getReport(this.reportId);
|
||||
this.initBreadcrumb((response) => {
|
||||
this.initReportTimeInfo();
|
||||
|
|
|
@ -171,7 +171,6 @@ export default {
|
|||
created() {
|
||||
this.data = [];
|
||||
this.instances = [];
|
||||
this.id = this.$route.path.split('/')[4];
|
||||
this.getResource();
|
||||
},
|
||||
methods: {
|
||||
|
@ -350,13 +349,6 @@ export default {
|
|||
},
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
if (to.name === "perReportView") {
|
||||
this.id = to.path.split('/')[4];
|
||||
this.init = false;
|
||||
this.getResource();
|
||||
}
|
||||
},
|
||||
report: {
|
||||
handler(val) {
|
||||
if (!val.status || !val.id) {
|
||||
|
|
|
@ -251,7 +251,7 @@
|
|||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
|
||||
<ms-chart v-if="rampUpTimeVisible" class="chart-container" ref="chart1" :options="options" :autoresize="true"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
size="lg" @click="unFullScreen"/>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row style="overflow: auto">
|
||||
<el-row>
|
||||
<div class="chart-style">
|
||||
<ms-chart ref="chart1" v-if="!loading" :options="dataOption"
|
||||
:style="{width: chartWidthNumber+'px', height: (h-50) + 'px'}" class="chart-config" :autoresize="true"
|
||||
:style="{width: chartWidthNumber+'px', height: (h-70) + 'px'}" class="chart-config" :autoresize="true"
|
||||
id="picChart"/>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
|
@ -73,7 +75,7 @@ export default {
|
|||
{id: 'pie', name: this.$t('commons.report_statistics.pie')}
|
||||
],
|
||||
order: "",
|
||||
orders: [{id: '', name: '默认排序'}, {id: 'desc', name: this.$t('commons.report_statistics.desc')}, {
|
||||
orders: [{id: '', name: this.$t('commons.sort_default')}, {id: 'desc', name: this.$t('commons.report_statistics.desc')}, {
|
||||
id: 'asc',
|
||||
name: this.$t('commons.report_statistics.asc')
|
||||
}],
|
||||
|
@ -223,6 +225,9 @@ export default {
|
|||
height: calc(100vh / 1.95);
|
||||
}
|
||||
|
||||
.chart-style{
|
||||
overflow: auto;
|
||||
}
|
||||
.tip {
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
chartType: "line",
|
||||
charts: [{id: 'line', name: this.$t('commons.report_statistics.line')}, {id: 'bar', name: this.$t('commons.report_statistics.bar')}],
|
||||
order: "",
|
||||
orders: [{id: '', name: '默认排序'},{id: 'desc', name: this.$t('commons.report_statistics.desc')}, {id: 'asc', name: this.$t('commons.report_statistics.asc')}],
|
||||
orders: [{id: '', name: this.$t('commons.sort_default')},{id: 'desc', name: this.$t('commons.report_statistics.desc')}, {id: 'asc', name: this.$t('commons.report_statistics.asc')}],
|
||||
loading: false,
|
||||
options: {},
|
||||
}
|
||||
|
|
|
@ -88,8 +88,8 @@
|
|||
{id: 'BATCH_UPDATE', label: this.$t('api_test.definition.request.batch_edit')},
|
||||
{id: 'BATCH_ADD', label: this.$t('commons.batch_add')},
|
||||
{id: 'UN_ASSOCIATE_CASE', label: this.$t('test_track.case.unlink')},
|
||||
{id: 'BATCH_RESTORE', label: "批量恢复"},
|
||||
{id: 'BATCH_GC', label: "批量回收"}
|
||||
{id: 'BATCH_RESTORE', label: this.$t('commons.batch_restore')},
|
||||
{id: 'BATCH_GC', label: this.$t('commons.batch_gc')}
|
||||
],
|
||||
LOG_TYPE_MAP: new Map([
|
||||
['CREATE', this.$t('api_test.definition.request.create_info')],
|
||||
|
|
|
@ -60,46 +60,140 @@ export function SYSLIST(){
|
|||
let sysList = [
|
||||
{
|
||||
label: i18n.t('test_track.test_track'), value: i18n.t('test_track.test_track'), children: [
|
||||
{label: i18n.t('permission.project_track_case.name'), value: i18n.t('permission.project_track_case.name'), leaf: true},
|
||||
{
|
||||
label: i18n.t('permission.project_track_case.name'),
|
||||
value: i18n.t('permission.project_track_case.name'),
|
||||
leaf: true
|
||||
},
|
||||
{label: i18n.t('test_track.review.test_review'), value: i18n.t('test_track.review.test_review'), leaf: true},
|
||||
{label: i18n.t('test_track.plan.test_plan'), value: i18n.t('test_track.plan.test_plan'), leaf: true},
|
||||
{label: i18n.t('test_track.issue.issue_management'), value: i18n.t('test_track.issue.issue_management'), leaf: true},
|
||||
{
|
||||
label: i18n.t('test_track.issue.issue_management'),
|
||||
value: i18n.t('test_track.issue.issue_management'),
|
||||
leaf: true
|
||||
},
|
||||
{label: i18n.t('commons.report'), value: i18n.t('commons.report'), leaf: true}]
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.api'), value: i18n.t('commons.api'), children: [
|
||||
{label: i18n.t('workstation.table_name.api_definition'), value: i18n.t('workstation.table_name.api_definition'), leaf: true},
|
||||
{label: i18n.t('workstation.table_name.api_automation'), value: i18n.t('workstation.table_name.api_automation'), leaf: true},
|
||||
{label: i18n.t('permission.project_api_report.name'), value: i18n.t('permission.project_api_report.name'), leaf: true}]
|
||||
{
|
||||
label: i18n.t('workstation.table_name.api_definition'),
|
||||
value: i18n.t('workstation.table_name.api_definition'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('workstation.table_name.performance'), value: i18n.t('workstation.table_name.performance'), children: [
|
||||
{label: i18n.t('workstation.table_name.performance'), value: i18n.t('workstation.table_name.performance'), leaf: true},
|
||||
label: i18n.t('workstation.table_name.api_automation'),
|
||||
value: i18n.t('workstation.table_name.api_automation'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('permission.project_api_report.name'),
|
||||
value: i18n.t('permission.project_api_report.name'),
|
||||
leaf: true
|
||||
}]
|
||||
},
|
||||
{
|
||||
label: i18n.t('workstation.table_name.performance'),
|
||||
value: i18n.t('workstation.table_name.performance'),
|
||||
children: [
|
||||
{
|
||||
label: i18n.t('workstation.table_name.performance'),
|
||||
value: i18n.t('workstation.table_name.performance'),
|
||||
leaf: true
|
||||
},
|
||||
{label: i18n.t('report.load_test_report'), value: i18n.t('report.load_test_report'), leaf: true}]
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.system_setting'), value: i18n.t('commons.system_setting'), children: [
|
||||
{label: i18n.t('commons.system')+"-"+i18n.t('commons.user'), value: i18n.t('commons.system')+"-"+i18n.t('commons.user'), leaf: true},
|
||||
{label: i18n.t('commons.system')+"-"+i18n.t('commons.test_resource_pool'), value: i18n.t('commons.system')+"-"+i18n.t('commons.test_resource_pool'), leaf: true},
|
||||
{label: i18n.t('commons.system')+"-"+i18n.t('commons.system_parameter_setting'), value: i18n.t('commons.system')+"-"+i18n.t('commons.system_parameter_setting'), leaf: true},
|
||||
{label: i18n.t('commons.system')+"-"+i18n.t('commons.quota'), value: i18n.t('commons.system')+"-"+i18n.t('commons.quota'), leaf: true},
|
||||
{label: i18n.t('commons.system')+"-"+i18n.t('license.title'), value: i18n.t('commons.system')+"-"+i18n.t('license.title'), leaf: true},
|
||||
{
|
||||
label: i18n.t('commons.system') + "-" + i18n.t('commons.user'),
|
||||
value: i18n.t('commons.system') + "-" + i18n.t('commons.user'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.system') + "-" + i18n.t('commons.test_resource_pool'),
|
||||
value: i18n.t('commons.system') + "-" + i18n.t('commons.test_resource_pool'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.system') + "-" + i18n.t('commons.system_parameter_setting'),
|
||||
value: i18n.t('commons.system') + "-" + i18n.t('commons.system_parameter_setting'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.system') + "-" + i18n.t('commons.quota'),
|
||||
value: i18n.t('commons.system') + "-" + i18n.t('commons.quota'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.system') + "-" + i18n.t('license.title'),
|
||||
value: i18n.t('commons.system') + "-" + i18n.t('license.title'),
|
||||
leaf: true
|
||||
},
|
||||
|
||||
{label: i18n.t('commons.workspace'), value: i18n.t('commons.workspace'), leaf: true},
|
||||
{label: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_service.name'), value: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_service.name'), leaf: true},
|
||||
{label: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_message.name'), value: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_message.name'), leaf: true},
|
||||
{label: i18n.t('commons.workspace')+"-"+i18n.t('permission.project_user.name'), value: i18n.t('commons.workspace')+"-"+i18n.t('permission.project_user.name'), leaf: true},
|
||||
{label: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_template.name'), value: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_template.name'), leaf: true},
|
||||
{label: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_project_manager.name'), value: i18n.t('commons.workspace')+"-"+i18n.t('permission.workspace_project_manager.name'), leaf: true},
|
||||
{
|
||||
label: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_service.name'),
|
||||
value: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_service.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_message.name'),
|
||||
value: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_message.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.workspace') + "-" + i18n.t('permission.project_user.name'),
|
||||
value: i18n.t('commons.workspace') + "-" + i18n.t('permission.project_user.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_template.name'),
|
||||
value: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_template.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_project_manager.name'),
|
||||
value: i18n.t('commons.workspace') + "-" + i18n.t('permission.workspace_project_manager.name'),
|
||||
leaf: true
|
||||
},
|
||||
|
||||
{label: i18n.t('commons.project')+"-"+i18n.t('project.manager'), value: i18n.t('commons.project')+"-"+i18n.t('project.manager'), leaf: true},
|
||||
{label: i18n.t('commons.project')+"-"+i18n.t('permission.project_user.name'), value: i18n.t('commons.project')+"-"+i18n.t('permission.project_user.name'), leaf: true},
|
||||
{label: i18n.t('commons.project')+"-"+i18n.t('api_test.jar_config.jar_manage'), value: i18n.t('commons.project')+"-"+i18n.t('api_test.jar_config.jar_manage'), leaf: true},
|
||||
{label: i18n.t('commons.project')+"-"+i18n.t('permission.workspace_project_environment.name'), value: i18n.t('commons.project')+"-"+i18n.t('permission.workspace_project_environment.name'), leaf: true},
|
||||
{label: i18n.t('commons.project')+"-"+i18n.t('permission.project_file.name'), value: i18n.t('commons.project')+"-"+i18n.t('permission.project_file.name'), leaf: true},
|
||||
{
|
||||
label: i18n.t('commons.project') + "-" + i18n.t('project.manager'),
|
||||
value: i18n.t('commons.project') + "-" + i18n.t('project.manager'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.project') + "-" + i18n.t('permission.project_user.name'),
|
||||
value: i18n.t('commons.project') + "-" + i18n.t('permission.project_user.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.project') + "-" + i18n.t('api_test.jar_config.jar_manage'),
|
||||
value: i18n.t('commons.project') + "-" + i18n.t('api_test.jar_config.jar_manage'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.project') + "-" + i18n.t('permission.workspace_project_environment.name'),
|
||||
value: i18n.t('commons.project') + "-" + i18n.t('permission.workspace_project_environment.name'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.project') + "-" + i18n.t('permission.project_file.name'),
|
||||
value: i18n.t('commons.project') + "-" + i18n.t('permission.project_file.name'),
|
||||
leaf: true
|
||||
},
|
||||
|
||||
{label: i18n.t('commons.personal_information')+"-"+i18n.t('commons.personal_setting'), value: i18n.t('commons.personal_information')+"-"+i18n.t('commons.personal_setting'), leaf: true},
|
||||
{label: i18n.t('commons.personal_information')+"-API Keys", value: i18n.t('commons.personal_information')+"-API Keys", leaf: true}
|
||||
{
|
||||
label: i18n.t('commons.personal_information') + "-" + i18n.t('commons.personal_setting'),
|
||||
value: i18n.t('commons.personal_information') + "-" + i18n.t('commons.personal_setting'),
|
||||
leaf: true
|
||||
},
|
||||
{
|
||||
label: i18n.t('commons.personal_information') + "-API Keys",
|
||||
value: i18n.t('commons.personal_information') + "-API Keys",
|
||||
leaf: true
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
@ -121,76 +215,120 @@ export function getUrl(d) {
|
|||
}
|
||||
}
|
||||
switch (d.operModule) {
|
||||
case "接口自动化" || "Api automation" || "接口自動化":
|
||||
case "接口自动化" :
|
||||
case "Api automation" :
|
||||
case"接口自動化":
|
||||
url += "/api/automation?resourceId=" + resourceId;
|
||||
break;
|
||||
case "测试计划" || "測試計劃" || "Test plan":
|
||||
case "测试计划" :
|
||||
case "測試計劃" :
|
||||
case "Test plan":
|
||||
url += "/track/plan/view/" + resourceId;
|
||||
break;
|
||||
case "用例评审" || "Case review" || "用例評審":
|
||||
case "用例评审" :
|
||||
case "Case review" :
|
||||
case "用例評審":
|
||||
url += "/track/review/view/" + resourceId;
|
||||
break;
|
||||
case "缺陷管理" || "Defect management":
|
||||
case "缺陷管理" :
|
||||
case "Defect management":
|
||||
url += "/track/issue";
|
||||
break;
|
||||
case "SWAGGER_TASK" :
|
||||
url += "/api/definition";
|
||||
break;
|
||||
case "接口定义" || "接口定義" || "Api definition":
|
||||
case "接口定义" :
|
||||
case "接口定義" :
|
||||
case "Api definition":
|
||||
url += "/api/definition?resourceId=" + resourceId;
|
||||
break;
|
||||
case "接口定义用例" || "接口定義用例" || "Api definition case":
|
||||
case "接口定义用例" :
|
||||
case "接口定義用例":
|
||||
case "Api definition case":
|
||||
url += "/api/definition?caseId=" + resourceId;
|
||||
break;
|
||||
case "测试报告" || "測試報告" || "Test Report":
|
||||
case "测试报告" :
|
||||
case "測試報告" :
|
||||
case "Test Report":
|
||||
url += "/api/automation/report";
|
||||
break;
|
||||
case "性能测试报告" || "性能測試報告" || "Performance test report" :
|
||||
case "性能测试报告" :
|
||||
case "性能測試報告" :
|
||||
case "Performance test report" :
|
||||
url += "/performance/report/all";
|
||||
break;
|
||||
case "性能测试" || "性能測試" || "Performance test" :
|
||||
case "性能测试" :
|
||||
case "性能測試" :
|
||||
case "Performance test" :
|
||||
url += "/performance/test/edit/" + resourceId;
|
||||
break;
|
||||
case "测试用例" || "測試用例" || "Test case":
|
||||
case "测试用例" :
|
||||
case "測試用例" :
|
||||
case "Test case":
|
||||
url += "/track/case/all?resourceId=" + resourceId;
|
||||
break;
|
||||
case "系统-用户" || "系统-用户" || "System user":
|
||||
case "系统-用户":
|
||||
case "System user":
|
||||
url += "/setting/user";
|
||||
break;
|
||||
case "系统-组织" || "系統-組織" || "System organization":
|
||||
case "系统-组织" :
|
||||
case "系統-組織" :
|
||||
case "System organization":
|
||||
url += "/setting/organization";
|
||||
break;
|
||||
case "工作空间" || "系统-工作空间" || "workspace" :
|
||||
case "工作空间" :
|
||||
case "系统-工作空间" :
|
||||
case "workspace" :
|
||||
url += "/setting/systemworkspace";
|
||||
break;
|
||||
case "用户组与权限" || "用戶組與權限" || "Group" :
|
||||
case "用户组与权限" :
|
||||
case "用戶組與權限" :
|
||||
case "Group" :
|
||||
url += "/setting/usergroup";
|
||||
break;
|
||||
case "系统-测试资源池" || "系统-測試資源池" || "System test resource" :
|
||||
case "系统-测试资源池":
|
||||
case "系统-測試資源池" :
|
||||
case "System test resource" :
|
||||
url += "/setting/testresourcepool";
|
||||
break;
|
||||
case "系统-系统参数设置" || "系统-系統參數設置" || "System parameter setting" :
|
||||
case "系统-系统参数设置":
|
||||
case "系统-系統參數設置" :
|
||||
case "System parameter setting" :
|
||||
url += "/setting/systemparametersetting";
|
||||
break;
|
||||
case "工作空间-成员" || "工作空間-成員" || "Workspace member" :
|
||||
case "工作空间-成员" :
|
||||
case "工作空間-成員" :
|
||||
case "Workspace member" :
|
||||
url += "/setting/member";
|
||||
break;
|
||||
case "项目-项目管理" || "項目-項目管理" || "Project project manager" :
|
||||
case "项目-项目管理" :
|
||||
case "項目-項目管理" :
|
||||
case "Project project manager" :
|
||||
url += "/setting/project/:type";
|
||||
break;
|
||||
case "项目-环境设置" || "項目-環境設置" || "Project environment setting" :
|
||||
case "项目-环境设置" :
|
||||
case "項目-環境設置" :
|
||||
case "Project environment setting" :
|
||||
url += "/project/env";
|
||||
break;
|
||||
case "工作空间-模版设置-自定义字段" || "工作空間-模版設置-自定義字段" || "Workspace template settings field" :
|
||||
case "工作空间-模版设置-自定义字段" :
|
||||
case "工作空間-模版設置-自定義字段" :
|
||||
case "Workspace template settings field" :
|
||||
url += "/setting/workspace/template/field";
|
||||
break;
|
||||
case "工作空间-模版设置-用例模版" || "工作空間-模版設置-用例模板" || "Workspace template settings case" :
|
||||
case "工作空间-模版设置-用例模版" :
|
||||
case "工作空間-模版設置-用例模板" :
|
||||
case "Workspace template settings case" :
|
||||
url += "/setting/workspace/template/case";
|
||||
break;
|
||||
case "工作空间-模版设置-缺陷模版" || "工作空間-模版設置-缺陷模板" || "Workspace template settings issue" :
|
||||
case "工作空间-模版设置-缺陷模版" :
|
||||
case "工作空間-模版設置-缺陷模板" :
|
||||
case "Workspace template settings issue" :
|
||||
url += "/setting/workspace/template/issues";
|
||||
break;
|
||||
case "项目-成员" || "項目-成員" || "Project member" :
|
||||
case "项目-成员":
|
||||
case "項目-成員" :
|
||||
case "Project member" :
|
||||
url += "/project/member";
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -339,7 +339,7 @@ export default {
|
|||
this.$warning(this.$t('commons.check_project_tip'));
|
||||
return;
|
||||
}
|
||||
this.showPublic = true
|
||||
this.showPublic = false
|
||||
if (tab.name === 'add') {
|
||||
let label = this.$t('test_track.case.create');
|
||||
let name = getUUID().substring(0, 8);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
:key="index"
|
||||
:comment="comment"
|
||||
:read-only="readOnly"
|
||||
@refresh="getComments()"/>
|
||||
@refresh="getComments()" api-url="/test/case"/>
|
||||
<div v-if="comments.length === 0" style="text-align: center">
|
||||
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
|
||||
<span style="font-size: 15px; color: #8a8b8d;">
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
<review-comment-item v-for="(comment,index) in comments"
|
||||
:key="index"
|
||||
:comment="comment"
|
||||
@refresh="getComments"/>
|
||||
@refresh="getComments" api-url="/test/case"/>
|
||||
<div v-if="comments.length === 0" style="text-align: center">
|
||||
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
|
||||
<span style="font-size: 15px; color: #8a8b8d;">
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<review-comment-item v-for="(comment,index) in comments"
|
||||
:key="index"
|
||||
:comment="comment"
|
||||
@refresh="getComments" :disabled="true"/>
|
||||
@refresh="getComments" :disabled="true" api-url="/test/case"/>
|
||||
<div v-if="comments.length === 0" style="text-align: center">
|
||||
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
|
||||
<span style="font-size: 15px; color: #8a8b8d;">
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<div v-loading="result.loading">
|
||||
<div v-for="pe in data" :key="pe.id" style="margin-left: 20px;">
|
||||
<el-select v-model="pe['selectEnv']" placeholder="请选择环境" style="margin-top: 8px;width: 200px;" size="small">
|
||||
<el-select v-model="pe['selectEnv']" :placeholder="$t('api_test.environment.select_environment')"
|
||||
style="margin-top: 8px;width: 200px;" size="small">
|
||||
<el-option v-for="(environment, index) in pe.envs" :key="index"
|
||||
:label="environment.name"
|
||||
:value="environment.id"/>
|
||||
<el-button class="ms-scenario-button" v-if="isShowConfirmButton(pe.id)" size="mini" type="primary" @click="openEnvironmentConfig(pe.id)">
|
||||
<el-button class="ms-scenario-button" v-if="isShowConfirmButton(pe.id)" size="mini" type="primary"
|
||||
@click="openEnvironmentConfig(pe.id)">
|
||||
{{ $t('api_test.environment.environment_config') }}
|
||||
</el-button>
|
||||
<template v-slot:empty>
|
||||
|
@ -21,7 +23,8 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<el-button type="primary" @click="handleConfirm" size="small" class="env-confirm">确 定</el-button>
|
||||
<el-button type="primary" @click="handleConfirm" size="small" class="env-confirm">{{ $t('commons.confirm') }}
|
||||
</el-button>
|
||||
|
||||
<!-- 环境配置 -->
|
||||
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
|
||||
|
|
|
@ -41,6 +41,9 @@ import {addIssueHotBox, getSelectedNodeData, handleIssueAdd, handleIssueBatch} f
|
|||
import IssueRelateList from "@/business/components/track/case/components/IssueRelateList";
|
||||
import TestPlanIssueEdit from "@/business/components/track/case/components/TestPlanIssueEdit";
|
||||
import {getIssuesById} from "@/network/Issue";
|
||||
|
||||
const {getIssuesListById} = require("@/network/Issue");
|
||||
const {getCurrentWorkspaceId} = require("@/common/js/utils");
|
||||
export default {
|
||||
name: "TestCaseMinder",
|
||||
components: {TestPlanIssueEdit, IssueRelateList, MsModuleMinder},
|
||||
|
@ -84,7 +87,11 @@ name: "TestCaseMinder",
|
|||
moveEnable() {
|
||||
// 如果不是默认的排序条件不能调换位置
|
||||
return !this.condition.orders || this.condition.orders.length < 1;
|
||||
},
|
||||
workspaceId(){
|
||||
return getCurrentWorkspaceId();
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
selectNode() {
|
||||
|
@ -119,7 +126,7 @@ name: "TestCaseMinder",
|
|||
isNotDisableNode = true;
|
||||
}
|
||||
if (node.data.type === 'issue') {
|
||||
getIssuesById(node.data.id, (data) => {
|
||||
getIssuesListById(node.data.id, this.projectId,this.workspaceId,(data) => {
|
||||
data.customFields = JSON.parse(data.customFields);
|
||||
this.$refs.issueEdit.open(data);
|
||||
});
|
||||
|
|
|
@ -88,7 +88,7 @@ export default {
|
|||
}
|
||||
this.result = this.$post('/issues/comment/save', comment, () => {
|
||||
this.$success(this.$t('test_track.comment.send_success'));
|
||||
this.refresh(comment.IssueId);
|
||||
this.refresh(comment.issuesId);
|
||||
this.from.description = '';
|
||||
this.dialogTableVisible = false;
|
||||
});
|
||||
|
|
|
@ -29,10 +29,10 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
open(data) {
|
||||
open(data, type) {
|
||||
this.visible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.issueEditDetail.open(data);
|
||||
this.$refs.issueEditDetail.open(data, type);
|
||||
})
|
||||
},
|
||||
handleClose() {
|
||||
|
|
|
@ -165,7 +165,8 @@ export default {
|
|||
title: '',
|
||||
description: '',
|
||||
creator: null,
|
||||
remark: null
|
||||
remark: null,
|
||||
tapdUsers:[]
|
||||
},
|
||||
tapdUsers: [],
|
||||
zentaoUsers: [],
|
||||
|
@ -234,8 +235,9 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
open(data) {
|
||||
open(data, type) {
|
||||
this.result.loading = true;
|
||||
this.type = type;
|
||||
this.$nextTick(() => {
|
||||
getIssuePartTemplateWithProject((template, project) => {
|
||||
this.currentProject = project;
|
||||
|
@ -254,6 +256,7 @@ export default {
|
|||
}
|
||||
})
|
||||
} else {
|
||||
this.issueId = null;
|
||||
this.form.follows = [];
|
||||
}
|
||||
},
|
||||
|
@ -324,6 +327,7 @@ export default {
|
|||
}
|
||||
}
|
||||
this.customFieldForm = parseCustomField(this.form, this.issueTemplate, this.customFieldRules);
|
||||
this.comments = [];
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.testCaseIssueList) {
|
||||
this.$refs.testCaseIssueList.initTableData();
|
||||
|
@ -421,6 +425,10 @@ export default {
|
|||
}
|
||||
},
|
||||
openComment() {
|
||||
if (!this.issueId) {
|
||||
this.$warning(this.$t('test_track.issue.save_before_open_comment'));
|
||||
return;
|
||||
}
|
||||
this.$refs.issueComment.open();
|
||||
},
|
||||
getComments() {
|
||||
|
|
|
@ -295,17 +295,17 @@ export default {
|
|||
|
||||
},
|
||||
handleEdit(data) {
|
||||
this.$refs.issueEdit.open(data);
|
||||
this.$refs.issueEdit.open(data, 'edit');
|
||||
},
|
||||
handleCreate() {
|
||||
this.$refs.issueEdit.open();
|
||||
this.$refs.issueEdit.open(null, 'add');
|
||||
},
|
||||
handleCopy(data) {
|
||||
let copyData = {};
|
||||
Object.assign(copyData, data);
|
||||
copyData.id = null;
|
||||
copyData.name = data.name + '_copy';
|
||||
this.$refs.issueEdit.open(copyData);
|
||||
this.$refs.issueEdit.open(copyData, 'copy');
|
||||
},
|
||||
handleDelete(data) {
|
||||
this.page.result = this.$get('issues/delete/' + data.id, () => {
|
||||
|
|
|
@ -450,7 +450,9 @@ export default {
|
|||
if (this.planId) {
|
||||
this.$post("/test/plan/scenario/case/run", param, response => {
|
||||
this.runVisible = true;
|
||||
this.reportId = response.data;
|
||||
if (response.data && response.data.length > 0) {
|
||||
this.reportId = response.data[0].reportId;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.reviewId) {
|
||||
|
|
|
@ -19,13 +19,11 @@
|
|||
</el-button>
|
||||
</span>
|
||||
<span class="comment-delete">
|
||||
<el-link icon="el-icon-edit" v-if="!isImage" style="font-size: 9px;margin-right: 6px;" @click="openEdit" :disabled="readOnly"/>
|
||||
<el-link icon="el-icon-edit" style="font-size: 9px;margin-right: 6px;" @click="openEdit" :disabled="readOnly"/>
|
||||
<el-link icon="el-icon-close" @click="deleteComment" :disabled="readOnly"/>
|
||||
</span>
|
||||
<br/>
|
||||
<!-- <div class="comment-desc" style="font-size: 10px;color: #303133">-->
|
||||
<!-- <pre>{{ comment.description }}</pre>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<div v-if="!isImage" class="comment-desc" style="font-size: 10px;color: #303133">
|
||||
<pre>{{ comment.description }}</pre>
|
||||
</div>
|
||||
|
@ -41,24 +39,25 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
<el-dialog :visible.sync="visible"
|
||||
:title="$t('commons.edit')"
|
||||
:visible.sync="visible"
|
||||
width="30%"
|
||||
:destroy-on-close="true"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
show-close>
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
v-model="description">
|
||||
</el-input>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="visible = false"
|
||||
@confirm="editComment"/>
|
||||
</span>
|
||||
append-to-body>
|
||||
|
||||
<div>
|
||||
<div class="editors_div_style">
|
||||
<div id="editorsDiv">
|
||||
<ms-mark-down-text prop="description" :data="comment" :toolbars="toolbars"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" size="mini" class="send-btn" @click="editComment">
|
||||
{{ $t('test_track.comment.send') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -66,10 +65,11 @@
|
|||
<script>
|
||||
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||
import {getCurrentUser} from "@/common/js/utils";
|
||||
import MsMarkDownText from "@/business/components/track/case/components/MsMarkDownText";
|
||||
|
||||
export default {
|
||||
name: "ReviewCommentItem",
|
||||
components: {MsDialogFooter},
|
||||
components: {MsDialogFooter, MsMarkDownText},
|
||||
props: {
|
||||
comment: Object,
|
||||
readOnly: {
|
||||
|
@ -89,6 +89,41 @@ export default {
|
|||
imgNameList: [],
|
||||
description: "",
|
||||
imageMatchPattern: "(\\!\\[)\\S+]\\(\\S+\\)",
|
||||
toolbars: {
|
||||
bold: false, // 粗体
|
||||
italic: false, // 斜体
|
||||
header: false, // 标题
|
||||
underline: false, // 下划线
|
||||
strikethrough: false, // 中划线
|
||||
mark: false, // 标记
|
||||
superscript: false, // 上角标
|
||||
subscript: false, // 下角标
|
||||
quote: false, // 引用
|
||||
ol: false, // 有序列表
|
||||
ul: false, // 无序列表
|
||||
link: false, // 链接
|
||||
imagelink: true, // 图片链接
|
||||
code: false, // code
|
||||
table: false, // 表格
|
||||
fullscreen: false, // 全屏编辑
|
||||
readmodel: false, // 沉浸式阅读
|
||||
htmlcode: false, // 展示html源码
|
||||
help: false, // 帮助
|
||||
/* 1.3.5 */
|
||||
undo: false, // 上一步
|
||||
redo: false, // 下一步
|
||||
trash: false, // 清空
|
||||
save: false, // 保存(触发events中的save事件)
|
||||
/* 1.4.2 */
|
||||
navigation: false, // 导航目录
|
||||
/* 2.1.8 */
|
||||
alignleft: false, // 左对齐
|
||||
aligncenter: false, // 居中
|
||||
alignright: false, // 右对齐
|
||||
/* 2.2.1 */
|
||||
subfield: false, // 单双栏模式
|
||||
preview: false, // 预览
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -121,13 +156,14 @@ export default {
|
|||
this.visible = true;
|
||||
},
|
||||
editComment() {
|
||||
this.$post(this.apiUrl + "/comment/edit", {id: this.comment.id, description: this.description}, () => {
|
||||
this.$post(this.apiUrl + "/comment/edit", {id: this.comment.id, description: this.comment.description}, () => {
|
||||
this.visible = false;
|
||||
this.$success(this.$t('commons.modify_success'));
|
||||
this.$emit("refresh");
|
||||
});
|
||||
},
|
||||
checkImage() {
|
||||
this.srcList = [];
|
||||
let param = this.comment.description;
|
||||
let returnFlag = false;
|
||||
if (param) {
|
||||
|
@ -269,6 +305,11 @@ pre {
|
|||
}
|
||||
|
||||
/deep/ .el-button--mini, .el-button--mini.is-round {
|
||||
padding: 4px 9px;
|
||||
padding: 7px 15px;
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
margin-top: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a2a8dde5beb470590e7860e9d4376a56ce41d791
|
||||
Subproject commit 88b54ba98e8e0bdc6262f63310424263309493ea
|
|
@ -189,7 +189,7 @@ export let CUSTOM_TABLE_HEADER = {
|
|||
{id: 'createUser', key: '7', label: 'commons.create_user'},
|
||||
{id: 'createTime', key: '8', label: 'commons.create_time'},
|
||||
{id: 'desc', key: '9', label: 'test_track.case.case_desc'},
|
||||
{id: 'lastExecResult', key: '10', label: 'test_track.plan_view.execute_result'},
|
||||
{id: 'lastExecResult', key: '0', label: 'test_track.plan_view.execute_result'},
|
||||
],
|
||||
//缺陷列表
|
||||
ISSUE_LIST: [
|
||||
|
|
|
@ -191,14 +191,14 @@ export function getLabel(vueObj, type) {
|
|||
}
|
||||
|
||||
|
||||
export function buildBatchParam(vueObj, selectIds) {
|
||||
export function buildBatchParam(vueObj, selectIds, projectId) {
|
||||
let param = {};
|
||||
if (vueObj.selectRows) {
|
||||
param.ids = selectIds ? selectIds: Array.from(vueObj.selectRows).map(row => row.id);
|
||||
} else {
|
||||
param.ids = selectIds;
|
||||
}
|
||||
param.projectId = getCurrentProjectID();
|
||||
param.projectId = projectId ? projectId : getCurrentProjectID();
|
||||
param.condition = vueObj.condition;
|
||||
return param;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,15 @@ export default {
|
|||
yes: "yes",
|
||||
no: "no",
|
||||
example: "Demo",
|
||||
subject: "Subject",
|
||||
excelFile: "Excel",
|
||||
xmindFile: "Xmind",
|
||||
default: "default",
|
||||
sort_default: "Default",
|
||||
please_select_import_mode: 'Please select import mode',
|
||||
please_select_import_module: 'Please select import module',
|
||||
pass_rate: 'Pass rate',
|
||||
execution_times: 'Execution times',
|
||||
pass_rate: 'Pass Rate',
|
||||
execution_times: 'Execution Times',
|
||||
cover: 'Cover',
|
||||
module_title: 'Default module',
|
||||
save_data_when_page_change: 'Save when page change',
|
||||
|
@ -78,7 +80,7 @@ export default {
|
|||
update_user_id: 'Updater ID',
|
||||
update_time: 'Updated Time',
|
||||
delete_time: 'Delete Time',
|
||||
delete_user: 'Deleted by',
|
||||
delete_user: 'Deleted By',
|
||||
delete_user_id: 'Deleted by id',
|
||||
add: 'Add',
|
||||
preview: 'Preview',
|
||||
|
@ -325,6 +327,11 @@ export default {
|
|||
send: "Send",
|
||||
save_as_draft: "Draft",
|
||||
},
|
||||
table: {
|
||||
draft: "Draft",
|
||||
sended: "Send",
|
||||
send_error: "Send error",
|
||||
},
|
||||
project_report: {
|
||||
create_report: "Create report",
|
||||
report_name: "Report name",
|
||||
|
@ -706,7 +713,7 @@ export default {
|
|||
create: "Create Custom Code",
|
||||
update: "Update Custom Code",
|
||||
delete: "Delete Custom Code",
|
||||
language: "language",
|
||||
language: "Language",
|
||||
relate_tip: "Create in the Project Settings -> Custom Code Snippet menu",
|
||||
select_tip: "Please select a custom code!",
|
||||
none_content: "The custom code snippet is empty!",
|
||||
|
@ -921,11 +928,11 @@ export default {
|
|||
test_name_is_null: 'Test name cannot be empty! ',
|
||||
project_is_null: 'Project cannot be empty! ',
|
||||
jmx_is_null: 'Must contain a JMX file, and can only contain a JMX file!',
|
||||
file_name: 'File name',
|
||||
file_name: 'File Name',
|
||||
file_size: 'File size',
|
||||
file_type: 'File Type',
|
||||
file_status: 'File Status',
|
||||
last_modify_time: 'Modify time',
|
||||
last_modify_time: 'Modify Time',
|
||||
upload_tips: 'Drag files here, or <em> click to upload </em>',
|
||||
upload_type: 'Only JMX/CSV/JAR files can be uploaded',
|
||||
related_file_not_found: "No related test file found!",
|
||||
|
@ -1096,18 +1103,18 @@ export default {
|
|||
api_title: "Api Test",
|
||||
case_title: "Test Case",
|
||||
doc_title: "DOC",
|
||||
api_name: "Api name",
|
||||
api_status: "Api status",
|
||||
api_type: "Api type",
|
||||
api_name: "Api Name",
|
||||
api_status: "Api Status",
|
||||
api_type: "Api Type",
|
||||
api_agreement: "Method",
|
||||
api_path: "Api path",
|
||||
api_path: "Api Path",
|
||||
api_definition_path: "API Path",
|
||||
api_case_path: "Case Path",
|
||||
api_principal: "Api principal",
|
||||
api_last_time: "Last update time",
|
||||
api_principal: "Api Principal",
|
||||
api_last_time: "Last Update Time",
|
||||
api_case_number: "Cases",
|
||||
api_case_status: "Case status",
|
||||
api_case_passing_rate: "Use case pass rate",
|
||||
api_case_status: "Case Status",
|
||||
api_case_passing_rate: "Use Case Pass Rate",
|
||||
create_tip: "Note: Detailed interface information can be filled out on the edit page",
|
||||
api_import: "Api Import",
|
||||
check_select: "Please check the API",
|
||||
|
@ -1264,15 +1271,15 @@ export default {
|
|||
scenario_test: "Scenario test",
|
||||
scenario_list: "Scenario List",
|
||||
add_scenario: "Add scenario",
|
||||
scenario_name: "Scenario name",
|
||||
case_level: "Case level",
|
||||
scenario_name: "Scenario Name",
|
||||
case_level: "Case Level",
|
||||
tag: "Tag",
|
||||
creator: "Creator",
|
||||
update_time: "Update time",
|
||||
update_time: "Update Time",
|
||||
step: "Step",
|
||||
last_result: "Last result",
|
||||
last_result: "Last Result",
|
||||
last_result_id: 'Last result id',
|
||||
passing_rate: "Passing rate",
|
||||
passing_rate: "Passing Rate",
|
||||
success: "Success",
|
||||
fail: "Fail",
|
||||
saved: "Saved",
|
||||
|
@ -1730,7 +1737,7 @@ export default {
|
|||
title: "Updated interfaces in the past 7 days",
|
||||
table_coloum: {
|
||||
index: "ID",
|
||||
api_name: "Api name",
|
||||
api_name: "Api Name",
|
||||
path: "path",
|
||||
api_status: "Api status",
|
||||
update_time: "Update time",
|
||||
|
@ -1843,7 +1850,7 @@ export default {
|
|||
recent_plan: "My recent plan",
|
||||
recent_case: "My recent case",
|
||||
recent_review: "My recent review",
|
||||
pass_rate: "Pass rate",
|
||||
pass_rate: "Pass Rate",
|
||||
execution_result: ": Please select the execution result",
|
||||
actual_result: ": The actual result is empty",
|
||||
cancel_relevance_success: "Unlinked successfully",
|
||||
|
@ -1892,7 +1899,7 @@ export default {
|
|||
manual: "Manual",
|
||||
create: "Create test case",
|
||||
case_type: "Case Type",
|
||||
name: "Test case name",
|
||||
name: "Test Case Name",
|
||||
module: "Module",
|
||||
project: 'Project',
|
||||
maintainer: "Maintainer",
|
||||
|
@ -2078,7 +2085,7 @@ export default {
|
|||
comment: {
|
||||
no_comment: "No Comment",
|
||||
send_comment: "Post a comment (Ctrl + Enter to send)",
|
||||
send: "Send",
|
||||
send: "Confirm",
|
||||
description_is_null: "Comment content cannot be empty!",
|
||||
send_success: "Comment successful!",
|
||||
},
|
||||
|
@ -2194,7 +2201,7 @@ export default {
|
|||
issue: "Issue",
|
||||
issue_management: "Issue Management",
|
||||
platform_status: "Platform Status",
|
||||
issue_resource: "Issue source",
|
||||
issue_resource: "Issue Source",
|
||||
create_issue: "Create Issue",
|
||||
add_issue: "Add Issue",
|
||||
issue_list: "Issue List",
|
||||
|
@ -2229,7 +2236,8 @@ export default {
|
|||
third_party_integrated: "Third-party Platform Integrated",
|
||||
use_third_party: "Enable Jira Issue Template",
|
||||
update_third_party_bugs: "Update the defects of third-party platforms",
|
||||
sync_bugs: "Synchronization Issue"
|
||||
sync_bugs: "Synchronization Issue",
|
||||
save_before_open_comment: "Please save issue before comment",
|
||||
},
|
||||
report: {
|
||||
name: "Test Plan Report",
|
||||
|
|
|
@ -7,9 +7,11 @@ export default {
|
|||
yes: "是",
|
||||
no: "否",
|
||||
example: "示例",
|
||||
subject: "主题",
|
||||
excelFile: "表格文件.xls",
|
||||
xmindFile: "思维导图.xmind",
|
||||
default: "默认值",
|
||||
sort_default: "默认排序",
|
||||
please_select_import_mode: '请选择导入模式',
|
||||
please_select_import_module: '请选择导入模块',
|
||||
pass_rate: '通过率',
|
||||
|
@ -326,6 +328,11 @@ export default {
|
|||
send: "发送",
|
||||
save_as_draft: "保存草稿",
|
||||
},
|
||||
table: {
|
||||
draft: "草稿箱",
|
||||
sended: "已发送",
|
||||
send_error: "发送失败",
|
||||
},
|
||||
project_report: {
|
||||
create_report: "创建报告",
|
||||
report_name: "报告名称",
|
||||
|
@ -2082,7 +2089,7 @@ export default {
|
|||
comment: {
|
||||
no_comment: "暂无评论",
|
||||
send_comment: "发表评论(Ctrl+Enter发送)",
|
||||
send: "发送",
|
||||
send: "确定",
|
||||
description_is_null: "评论内容不能为空!",
|
||||
send_success: "评论成功!",
|
||||
cannot_edit: "无法编辑此评论!",
|
||||
|
@ -2233,7 +2240,8 @@ export default {
|
|||
third_party_integrated: "集成第三方平台",
|
||||
use_third_party: "使用 Jira 缺陷模板",
|
||||
update_third_party_bugs: "更新第三方平台的缺陷",
|
||||
sync_bugs: "同步缺陷"
|
||||
sync_bugs: "同步缺陷",
|
||||
save_before_open_comment: "请先保存缺陷再添加评论",
|
||||
},
|
||||
report: {
|
||||
name: "测试计划报告",
|
||||
|
|
|
@ -7,9 +7,11 @@ export default {
|
|||
yes: "是",
|
||||
no: "否",
|
||||
example: "示例",
|
||||
subject: "主題",
|
||||
excelFile: "表格文件.xls",
|
||||
xmindFile: "思維導圖.xmind",
|
||||
default: "默認值",
|
||||
sort_default: "默認排序",
|
||||
please_select_import_mode: '請選擇導入模式',
|
||||
please_select_import_module: '請選擇導入模塊',
|
||||
pass_rate: '通過率',
|
||||
|
@ -326,6 +328,11 @@ export default {
|
|||
send: "發送",
|
||||
save_as_draft: "保存草稿",
|
||||
},
|
||||
table: {
|
||||
draft: "草稿箱",
|
||||
sended: "已發送",
|
||||
send_error: "發送失敗",
|
||||
},
|
||||
project_report: {
|
||||
create_report: "創建報告",
|
||||
report_name: "報告名稱",
|
||||
|
@ -2082,7 +2089,7 @@ export default {
|
|||
comment: {
|
||||
no_comment: "暫無評論",
|
||||
send_comment: "發表評論(Ctrl+Enter發送)",
|
||||
send: "發送",
|
||||
send: "確定",
|
||||
description_is_null: "評論內容不能為空!",
|
||||
send_success: "評論成功!",
|
||||
cannot_edit: "無法編輯此評論!",
|
||||
|
@ -2233,7 +2240,8 @@ export default {
|
|||
third_party_integrated: "集成第三方平臺",
|
||||
use_third_party: "使用 Jira 缺陷模板",
|
||||
update_third_party_bugs: "更新第三方平臺的缺陷",
|
||||
sync_bugs: "同步缺陷"
|
||||
sync_bugs: "同步缺陷",
|
||||
save_before_open_comment: "請先保存缺陷再添加評論",
|
||||
},
|
||||
report: {
|
||||
name: "測試計劃報告",
|
||||
|
|
|
@ -37,6 +37,19 @@ export function getIssuesById(id, callback) {
|
|||
return id ? baseGet('/issues/get/' + id, callback) : {};
|
||||
}
|
||||
|
||||
export function getIssuesListById(id,projectId,workspaceId,callback) {
|
||||
let condition ={
|
||||
id:id,
|
||||
projectId : projectId,
|
||||
workspaceId: workspaceId
|
||||
};
|
||||
return post('issues/list/' + 1 + '/' + 10, condition, (response) => {
|
||||
if (callback) {
|
||||
callback(response.data.listObject[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getIssuesByPlanId(planId, callback) {
|
||||
return planId ? baseGet('/issues/plan/get/' + planId, callback) : {};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue