Merge branch 'v1.8' of github.com:metersphere/metersphere into v1.8
This commit is contained in:
commit
e56e2e19b5
|
@ -17,7 +17,7 @@
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<shiro.version>1.6.0</shiro.version>
|
<shiro.version>1.6.0</shiro.version>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<jmeter.version>5.2.1</jmeter.version>
|
<jmeter.version>5.4.1</jmeter.version>
|
||||||
<nacos.version>1.1.3</nacos.version>
|
<nacos.version>1.1.3</nacos.version>
|
||||||
<dubbo.version>2.7.8</dubbo.version>
|
<dubbo.version>2.7.8</dubbo.version>
|
||||||
<graalvm.version>20.1.0</graalvm.version>
|
<graalvm.version>20.1.0</graalvm.version>
|
||||||
|
@ -276,18 +276,11 @@
|
||||||
<artifactId>spring-boot-starter-data-ldap</artifactId>
|
<artifactId>spring-boot-starter-data-ldap</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- swagger2 解析 -->
|
<!-- swagger 解析 -->
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-parser</artifactId>
|
|
||||||
<version>1.0.51</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- swagger3 解析 最新版本会有swagger-core版本冲突 -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.swagger.parser.v3</groupId>
|
<groupId>io.swagger.parser.v3</groupId>
|
||||||
<artifactId>swagger-parser</artifactId>
|
<artifactId>swagger-parser</artifactId>
|
||||||
<version>2.0.18</version>
|
<version>2.0.22</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 执行 js 代码依赖 -->
|
<!-- 执行 js 代码依赖 -->
|
||||||
|
@ -674,4 +667,4 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -74,11 +74,21 @@ public class ApiAutomationController {
|
||||||
apiAutomationService.deleteBatch(ids);
|
apiAutomationService.deleteBatch(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/deleteBatchByCondition")
|
||||||
|
public void deleteBatchByCondition(@RequestBody ApiScenarioBatchRequest request) {
|
||||||
|
apiAutomationService.deleteBatchByCondition(request);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/removeToGc")
|
@PostMapping("/removeToGc")
|
||||||
public void removeToGc(@RequestBody List<String> ids) {
|
public void removeToGc(@RequestBody List<String> ids) {
|
||||||
apiAutomationService.removeToGc(ids);
|
apiAutomationService.removeToGc(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/removeToGcByBatch")
|
||||||
|
public void removeToGcByBatch(@RequestBody ApiScenarioBatchRequest request) {
|
||||||
|
apiAutomationService.removeToGcByBatch(request);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/reduction")
|
@PostMapping("/reduction")
|
||||||
public void reduction(@RequestBody List<String> ids) {
|
public void reduction(@RequestBody List<String> ids) {
|
||||||
apiAutomationService.reduction(ids);
|
apiAutomationService.reduction(ids);
|
||||||
|
|
|
@ -7,12 +7,12 @@ import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.service.ApiTestCaseService;
|
import io.metersphere.api.service.ApiTestCaseService;
|
||||||
import io.metersphere.base.domain.ApiTestCase;
|
import io.metersphere.base.domain.ApiTestCase;
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
||||||
import io.metersphere.commons.constants.ApiRunMode;
|
|
||||||
import io.metersphere.commons.constants.RoleConstants;
|
import io.metersphere.commons.constants.RoleConstants;
|
||||||
import io.metersphere.commons.utils.PageUtils;
|
import io.metersphere.commons.utils.PageUtils;
|
||||||
import io.metersphere.commons.utils.Pager;
|
import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
||||||
|
import io.metersphere.track.service.TestPlanApiCaseService;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -29,7 +29,8 @@ public class ApiTestCaseController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ApiTestCaseService apiTestCaseService;
|
private ApiTestCaseService apiTestCaseService;
|
||||||
|
@Resource
|
||||||
|
private TestPlanApiCaseService testPlanApiCaseService;
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
|
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
|
||||||
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||||
|
@ -48,6 +49,12 @@ public class ApiTestCaseController {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@GetMapping("/getStateByTestPlan/{id}")
|
||||||
|
public String getStateByTestPlan(@PathVariable String id ) {
|
||||||
|
String status=testPlanApiCaseService.getState(id);
|
||||||
|
return status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/list/{goPage}/{pageSize}")
|
@PostMapping("/list/{goPage}/{pageSize}")
|
||||||
public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
|
public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
|
||||||
|
@ -131,7 +138,8 @@ public class ApiTestCaseController {
|
||||||
return apiTestCaseService.run(request);
|
return apiTestCaseService.run(request);
|
||||||
}
|
}
|
||||||
@GetMapping(value = "/jenkins/exec/result/{id}")
|
@GetMapping(value = "/jenkins/exec/result/{id}")
|
||||||
public String getExecResult(@PathVariable String id) {
|
public String getExecResult(@PathVariable String id) {
|
||||||
return apiTestCaseService.getExecResult(id);
|
return apiTestCaseService.getExecResult(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,7 @@ public class EsbDataStruct {
|
||||||
private boolean required;
|
private boolean required;
|
||||||
private String description;
|
private String description;
|
||||||
private List<EsbDataStruct> children;
|
private List<EsbDataStruct> children;
|
||||||
|
private String status = "";
|
||||||
|
|
||||||
public void init(){
|
public void init(){
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
|
@ -127,6 +128,9 @@ public class EsbDataStruct {
|
||||||
|
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
if (this.children == null || this.children.isEmpty()) {
|
if (this.children == null || this.children.isEmpty()) {
|
||||||
|
if(this.value == null ){
|
||||||
|
this.value = "";
|
||||||
|
}
|
||||||
element.addText(this.value);
|
element.addText(this.value);
|
||||||
} else {
|
} else {
|
||||||
for (EsbDataStruct child : children) {
|
for (EsbDataStruct child : children) {
|
||||||
|
|
|
@ -75,6 +75,8 @@ import org.apache.jorphan.collections.HashTree;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
|
@ -132,12 +134,68 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
return (HashTree) field.get(scriptWrapper);
|
return (HashTree) field.get(scriptWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isProtocolDefaultPort(HTTPSamplerProxy source) {
|
||||||
|
String portAsString = source.getPropertyAsString("HTTPSampler.port");
|
||||||
|
if (portAsString != null && !portAsString.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String url(String protocol, String host, String port, String file) {
|
||||||
|
protocol = protocol.toLowerCase();
|
||||||
|
if (StringUtils.isNotEmpty(file) && !file.startsWith("/")) {
|
||||||
|
file += "/";
|
||||||
|
}
|
||||||
|
return protocol + "://" + host + ":" + port + file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl(HTTPSamplerProxy source) throws MalformedURLException {
|
||||||
|
String path = source.getPath();
|
||||||
|
if (!path.startsWith("http://") && !path.startsWith("https://")) {
|
||||||
|
String domain = source.getDomain();
|
||||||
|
String protocol = source.getProtocol();
|
||||||
|
String method = source.getMethod();
|
||||||
|
StringBuilder pathAndQuery = new StringBuilder(100);
|
||||||
|
if ("file".equalsIgnoreCase(protocol)) {
|
||||||
|
domain = null;
|
||||||
|
} else if (!path.startsWith("/")) {
|
||||||
|
pathAndQuery.append('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
pathAndQuery.append(path);
|
||||||
|
if ("GET".equals(method) || "DELETE".equals(method) || "OPTIONS".equals(method)) {
|
||||||
|
String queryString = source.getQueryString(source.getContentEncoding());
|
||||||
|
if (queryString.length() > 0) {
|
||||||
|
if (path.contains("?")) {
|
||||||
|
pathAndQuery.append("&");
|
||||||
|
} else {
|
||||||
|
pathAndQuery.append("?");
|
||||||
|
}
|
||||||
|
|
||||||
|
pathAndQuery.append(queryString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String portAsString = source.getPropertyAsString("HTTPSampler.port");
|
||||||
|
return this.isProtocolDefaultPort(source) ? new URL(protocol, domain, pathAndQuery.toString()).toExternalForm() : this.url(protocol, domain, portAsString, pathAndQuery.toString());
|
||||||
|
} else {
|
||||||
|
return new URL(path).toExternalForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) {
|
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) {
|
||||||
try {
|
try {
|
||||||
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
|
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
|
||||||
BeanUtils.copyBean(samplerProxy, source);
|
BeanUtils.copyBean(samplerProxy, source);
|
||||||
|
samplerProxy.setRest(new ArrayList<KeyValue>() {{
|
||||||
|
this.add(new KeyValue());
|
||||||
|
}});
|
||||||
|
samplerProxy.setArguments(new ArrayList<KeyValue>() {{
|
||||||
|
this.add(new KeyValue());
|
||||||
|
}});
|
||||||
if (source != null && source.getHTTPFiles().length > 0) {
|
if (source != null && source.getHTTPFiles().length > 0) {
|
||||||
samplerProxy.getBody().setBinary(new ArrayList<>());
|
samplerProxy.getBody().initBinary();
|
||||||
samplerProxy.getBody().setType(Body.FORM_DATA);
|
samplerProxy.getBody().setType(Body.FORM_DATA);
|
||||||
List<KeyValue> keyValues = new LinkedList<>();
|
List<KeyValue> keyValues = new LinkedList<>();
|
||||||
for (HTTPFileArg arg : source.getHTTPFiles()) {
|
for (HTTPFileArg arg : source.getHTTPFiles()) {
|
||||||
|
@ -156,13 +214,15 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
samplerProxy.getBody().setKvs(keyValues);
|
samplerProxy.getBody().setKvs(keyValues);
|
||||||
}
|
}
|
||||||
samplerProxy.setProtocol(RequestType.HTTP);
|
samplerProxy.setProtocol(RequestType.HTTP);
|
||||||
samplerProxy.setPort(source.getPort() + "");
|
samplerProxy.setPort(source.getPropertyAsString("HTTPSampler.port"));
|
||||||
|
samplerProxy.setDomain(source.getDomain());
|
||||||
if (source.getArguments() != null) {
|
if (source.getArguments() != null) {
|
||||||
if (source.getPostBodyRaw()) {
|
if (source.getPostBodyRaw()) {
|
||||||
samplerProxy.getBody().setType(Body.RAW);
|
samplerProxy.getBody().setType(Body.RAW);
|
||||||
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
||||||
samplerProxy.getBody().setRaw(v);
|
samplerProxy.getBody().setRaw(v);
|
||||||
});
|
});
|
||||||
|
samplerProxy.getBody().initKvs();
|
||||||
} else {
|
} else {
|
||||||
List<KeyValue> keyValues = new LinkedList<>();
|
List<KeyValue> keyValues = new LinkedList<>();
|
||||||
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
||||||
|
@ -173,11 +233,12 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
samplerProxy.setArguments(keyValues);
|
samplerProxy.setArguments(keyValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
samplerProxy.getBody().initBinary();
|
||||||
}
|
}
|
||||||
samplerProxy.setPath("");
|
// samplerProxy.setPath(source.getPath());
|
||||||
samplerProxy.setMethod(source.getMethod());
|
samplerProxy.setMethod(source.getMethod());
|
||||||
if (source.getUrl() != null) {
|
if (this.getUrl(source) != null) {
|
||||||
samplerProxy.setUrl(source.getUrl().toString());
|
samplerProxy.setUrl(this.getUrl(source));
|
||||||
}
|
}
|
||||||
samplerProxy.setId(UUID.randomUUID().toString());
|
samplerProxy.setId(UUID.randomUUID().toString());
|
||||||
samplerProxy.setType("HTTPSamplerProxy");
|
samplerProxy.setType("HTTPSamplerProxy");
|
||||||
|
|
|
@ -58,14 +58,16 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
||||||
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
|
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
|
||||||
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
|
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
|
||||||
Map<String, List<ApiTestCaseWithBLOBs>> caseMap = new HashMap<>();
|
Map<String, List<ApiTestCaseWithBLOBs>> caseMap = new HashMap<>();
|
||||||
apiDefinitionImport.getCases().forEach(item -> {
|
if (apiDefinitionImport.getCases() != null) {
|
||||||
List<ApiTestCaseWithBLOBs> caseList = caseMap.get(item.getApiDefinitionId());
|
apiDefinitionImport.getCases().forEach(item -> {
|
||||||
if (caseList == null) {
|
List<ApiTestCaseWithBLOBs> caseList = caseMap.get(item.getApiDefinitionId());
|
||||||
caseList = new ArrayList<>();
|
if (caseList == null) {
|
||||||
caseMap.put(item.getApiDefinitionId(), caseList);
|
caseList = new ArrayList<>();
|
||||||
}
|
caseMap.put(item.getApiDefinitionId(), caseList);
|
||||||
caseList.add(item);
|
}
|
||||||
});
|
caseList.add(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
apiDefinitionImport.getData().forEach(apiDefinition -> {
|
apiDefinitionImport.getData().forEach(apiDefinition -> {
|
||||||
parseApiDefinition(apiDefinition, importRequest, caseMap);
|
parseApiDefinition(apiDefinition, importRequest, caseMap);
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,8 +70,9 @@ public class Swagger2Parser extends SwaggerAbstractParser {
|
||||||
parseParameters(operation, request);
|
parseParameters(operation, request);
|
||||||
addBodyHeader(request);
|
addBodyHeader(request);
|
||||||
if (StringUtils.isNotBlank(basePath)) {
|
if (StringUtils.isNotBlank(basePath)) {
|
||||||
apiDefinition.setPath(basePath + apiDefinition.getPath());
|
String pathStr = basePath + apiDefinition.getPath().replaceAll("//","/");
|
||||||
request.setPath(basePath + request.getPath());
|
apiDefinition.setPath(pathStr);
|
||||||
|
request.setPath(pathStr);
|
||||||
}
|
}
|
||||||
apiDefinition.setRequest(JSON.toJSONString(request));
|
apiDefinition.setRequest(JSON.toJSONString(request));
|
||||||
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses())));
|
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses())));
|
||||||
|
|
|
@ -114,23 +114,26 @@ public class MsScenario extends MsTestElement {
|
||||||
// 设置共享cookie
|
// 设置共享cookie
|
||||||
config.setEnableCookieShare(enableCookieShare);
|
config.setEnableCookieShare(enableCookieShare);
|
||||||
Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
|
Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
|
||||||
// 兼容历史数据
|
if (config.getConfig() == null) {
|
||||||
if (environmentMap == null || environmentMap.isEmpty()) {
|
// 兼容历史数据
|
||||||
environmentMap = new HashMap<>(16);
|
if (this.environmentMap == null || this.environmentMap.isEmpty()) {
|
||||||
if (StringUtils.isNotBlank(environmentId)) {
|
this.environmentMap = new HashMap<>(16);
|
||||||
environmentMap.put(SessionUtils.getCurrentProjectId(), environmentId);
|
if (StringUtils.isNotBlank(environmentId)) {
|
||||||
}
|
// 兼容1.8之前 没有environmentMap但有environmentId的数据
|
||||||
}
|
this.environmentMap.put("historyProjectID", environmentId);
|
||||||
if (environmentMap != null && !environmentMap.isEmpty()) {
|
|
||||||
environmentMap.keySet().forEach(projectId -> {
|
|
||||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
|
||||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentMap.get(projectId));
|
|
||||||
if (environment != null && environment.getConfig() != null) {
|
|
||||||
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
|
||||||
envConfig.put(projectId, env);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
config.setConfig(envConfig);
|
if (this.environmentMap != null && !this.environmentMap.isEmpty()) {
|
||||||
|
this.environmentMap.keySet().forEach(projectId -> {
|
||||||
|
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||||
|
ApiTestEnvironmentWithBLOBs environment = environmentService.get(this.environmentMap.get(projectId));
|
||||||
|
if (environment != null && environment.getConfig() != null) {
|
||||||
|
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
||||||
|
envConfig.put(projectId, env);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
config.setConfig(envConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||||
config.setVariables(this.variables);
|
config.setVariables(this.variables);
|
||||||
|
|
|
@ -213,7 +213,7 @@ public abstract class MsTestElement {
|
||||||
csvDataSet.setName(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName());
|
csvDataSet.setName(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName());
|
||||||
csvDataSet.setProperty("fileEncoding", StringUtils.isEmpty(item.getEncoding()) ? "UTF-8" : item.getEncoding());
|
csvDataSet.setProperty("fileEncoding", StringUtils.isEmpty(item.getEncoding()) ? "UTF-8" : item.getEncoding());
|
||||||
if (CollectionUtils.isNotEmpty(item.getFiles())) {
|
if (CollectionUtils.isNotEmpty(item.getFiles())) {
|
||||||
if (!config.isOperating() && new File(BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName()).exists()) {
|
if (!config.isOperating() && !new File(BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName()).exists()) {
|
||||||
MSException.throwException(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName() + ":[ CSV文件不存在 ]");
|
MSException.throwException(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName() + ":[ CSV文件不存在 ]");
|
||||||
}
|
}
|
||||||
csvDataSet.setProperty("filename", BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName());
|
csvDataSet.setProperty("filename", BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName());
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class MsIfController extends MsTestElement {
|
||||||
ifController.setName(this.getName());
|
ifController.setName(this.getName());
|
||||||
ifController.setProperty(TestElement.TEST_CLASS, IfController.class.getName());
|
ifController.setProperty(TestElement.TEST_CLASS, IfController.class.getName());
|
||||||
ifController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("IfControllerPanel"));
|
ifController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("IfControllerPanel"));
|
||||||
ifController.setCondition("true");
|
ifController.setCondition(this.getCondition());
|
||||||
ifController.setEvaluateAll(false);
|
ifController.setEvaluateAll(false);
|
||||||
ifController.setUseExpression(true);
|
ifController.setUseExpression(true);
|
||||||
return ifController;
|
return ifController;
|
||||||
|
|
|
@ -91,6 +91,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
@JSONField(ordinal = 36)
|
@JSONField(ordinal = 36)
|
||||||
private MsAuthManager authManager;
|
private MsAuthManager authManager;
|
||||||
|
|
||||||
|
@JSONField(ordinal = 37)
|
||||||
|
private boolean urlOrPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
// 非导出操作,且不是启用状态则跳过执行
|
// 非导出操作,且不是启用状态则跳过执行
|
||||||
|
@ -126,6 +129,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
config.setConfig(getEnvironmentConfig(useEnvironment));
|
config.setConfig(getEnvironmentConfig(useEnvironment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.8 之前历史数据
|
||||||
|
if(StringUtils.isEmpty(this.getProjectId()) && config.getConfig()!= null && !config.getConfig().isEmpty()){
|
||||||
|
this.setProjectId("historyProjectID");
|
||||||
|
}
|
||||||
|
|
||||||
// 添加环境中的公共变量
|
// 添加环境中的公共变量
|
||||||
Arguments arguments = this.addArguments(config);
|
Arguments arguments = this.addArguments(config);
|
||||||
if (arguments != null) {
|
if (arguments != null) {
|
||||||
|
@ -140,23 +148,26 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
url = this.getUrl();
|
url = this.getUrl();
|
||||||
isUrl = true;
|
isUrl = true;
|
||||||
}
|
}
|
||||||
URL urlObject = new URL(url);
|
|
||||||
if (isUrl) {
|
if (isUrl) {
|
||||||
|
if (StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
url.replaceAll(this.getPort(), "10990");
|
||||||
|
}
|
||||||
|
URL urlObject = new URL(url);
|
||||||
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
||||||
if (urlObject.getPort() > 0) {
|
if (urlObject.getPort() > 0 && urlObject.getPort() != 10990 && StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
sampler.setPort(urlObject.getPort());
|
sampler.setPort(urlObject.getPort());
|
||||||
|
} else {
|
||||||
|
sampler.setProperty("HTTPSampler.port", this.getPort());
|
||||||
}
|
}
|
||||||
sampler.setProtocol(urlObject.getProtocol());
|
sampler.setProtocol(urlObject.getProtocol());
|
||||||
|
sampler.setPath(urlObject.getPath());
|
||||||
} else {
|
} else {
|
||||||
sampler.setDomain(config.getConfig().get(this.getProjectId()).getHttpConfig().getDomain());
|
sampler.setDomain(config.getConfig().get(this.getProjectId()).getHttpConfig().getDomain());
|
||||||
sampler.setPort(config.getConfig().get(this.getProjectId()).getHttpConfig().getPort());
|
sampler.setPort(config.getConfig().get(this.getProjectId()).getHttpConfig().getPort());
|
||||||
sampler.setProtocol(config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol());
|
sampler.setProtocol(config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol());
|
||||||
|
sampler.setPath(this.getPath());
|
||||||
}
|
}
|
||||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
String envPath = sampler.getPath();
|
||||||
if (StringUtils.isNotBlank(this.getPath()) && !isUrl) {
|
|
||||||
envPath += this.getPath();
|
|
||||||
sampler.setPath(envPath);
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
||||||
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
|
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
|
||||||
sampler.setPath(envPath);
|
sampler.setPath(envPath);
|
||||||
|
@ -177,9 +188,16 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||||
url = "http://" + url;
|
url = "http://" + url;
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
url.replaceAll(this.getPort(), "10990");
|
||||||
|
}
|
||||||
URL urlObject = new URL(url);
|
URL urlObject = new URL(url);
|
||||||
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
||||||
sampler.setPort(urlObject.getPort());
|
if (urlObject.getPort() > 0 && urlObject.getPort() != 10990 && StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
sampler.setPort(urlObject.getPort());
|
||||||
|
} else {
|
||||||
|
sampler.setProperty("HTTPSampler.port", this.getPort());
|
||||||
|
}
|
||||||
sampler.setProtocol(urlObject.getProtocol());
|
sampler.setProtocol(urlObject.getProtocol());
|
||||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
||||||
sampler.setPath(envPath);
|
sampler.setPath(envPath);
|
||||||
|
@ -327,10 +345,16 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isURL(String str) {
|
public boolean isURL(String str) {
|
||||||
//转换为小写
|
|
||||||
try {
|
try {
|
||||||
new URL(str);
|
String regex = "^((https|http|ftp|rtsp|mms)?://)"
|
||||||
return true;
|
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?"
|
||||||
|
+ "(([0-9]{1,3}\\.){3}[0-9]{1,3}" + "|" + "([0-9a-z_!~*'()-]+\\.)*"
|
||||||
|
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\."
|
||||||
|
+ "[a-z]{2,6})"
|
||||||
|
+ "(:[0-9]{1,5})?"
|
||||||
|
+ "((/?)|"
|
||||||
|
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
|
||||||
|
return str.matches(regex) || (str.matches("^(http|https|ftp)://.*$") && str.matches(".*://\\$\\{.*$"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -339,5 +363,5 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
private boolean isRest() {
|
private boolean isRest() {
|
||||||
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;
|
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.request.sampler;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
|
import io.metersphere.api.dto.automation.EsbDataStruct;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
|
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
|
||||||
|
@ -70,6 +71,12 @@ public class MsTCPSampler extends MsTestElement {
|
||||||
@JSONField(ordinal = 39)
|
@JSONField(ordinal = 39)
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新加两个参数,场景保存/修改时需要的参数。不会传递JMeter,只是用于最后的保留。
|
||||||
|
*/
|
||||||
|
private List<EsbDataStruct> esbDataStruct;
|
||||||
|
private List<EsbDataStruct> backEsbDataStruct;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
// 非导出操作,且不是启用状态则跳过执行
|
// 非导出操作,且不是启用状态则跳过执行
|
||||||
|
|
|
@ -66,14 +66,11 @@ public class Body {
|
||||||
sampler.setDoMultipart(true);
|
sampler.setDoMultipart(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!this.isJson()) {
|
if (StringUtils.isNotEmpty(this.format) && "JSON-SCHEMA".equals(this.format) && this.getJsonSchema() != null) {
|
||||||
sampler.setPostBodyRaw(true);
|
this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema()));
|
||||||
} else {
|
|
||||||
if (StringUtils.isNotEmpty(this.format) && "JSON-SCHEMA".equals(this.format) && this.getJsonSchema() != null) {
|
|
||||||
this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
KeyValue keyValue = new KeyValue("", "JSON-SCHEMA", this.getRaw(), true, true);
|
KeyValue keyValue = new KeyValue("", "JSON-SCHEMA", this.getRaw(), true, true);
|
||||||
|
sampler.setPostBodyRaw(true);
|
||||||
keyValue.setEnable(true);
|
keyValue.setEnable(true);
|
||||||
keyValue.setEncode(false);
|
keyValue.setEncode(false);
|
||||||
body.add(keyValue);
|
body.add(keyValue);
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package io.metersphere.api.jmeter;
|
package io.metersphere.api.jmeter;
|
||||||
|
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseInfo;
|
|
||||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||||
import io.metersphere.api.service.*;
|
import io.metersphere.api.service.*;
|
||||||
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
||||||
import io.metersphere.base.domain.ApiScenarioReport;
|
import io.metersphere.base.domain.ApiScenarioReport;
|
||||||
import io.metersphere.base.domain.ApiTestReport;
|
import io.metersphere.base.domain.ApiTestReport;
|
||||||
import io.metersphere.base.domain.TestPlanReport;
|
|
||||||
import io.metersphere.commons.constants.*;
|
import io.metersphere.commons.constants.*;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
@ -16,7 +14,6 @@ import io.metersphere.notice.sender.NoticeModel;
|
||||||
import io.metersphere.notice.service.NoticeSendService;
|
import io.metersphere.notice.service.NoticeSendService;
|
||||||
import io.metersphere.service.SystemParameterService;
|
import io.metersphere.service.SystemParameterService;
|
||||||
import io.metersphere.track.service.TestPlanReportService;
|
import io.metersphere.track.service.TestPlanReportService;
|
||||||
import io.metersphere.track.service.TestPlanService;
|
|
||||||
import io.metersphere.track.service.TestPlanTestCaseService;
|
import io.metersphere.track.service.TestPlanTestCaseService;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -201,11 +198,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
apiDefinitionService.addResult(testResult);
|
apiDefinitionService.addResult(testResult);
|
||||||
|
|
||||||
//测试计划定时任务-接口执行逻辑的话,需要同步测试计划的报告数据
|
//测试计划定时任务-接口执行逻辑的话,需要同步测试计划的报告数据
|
||||||
if (StringUtils.equals(this.runMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
if (StringUtils.equalsAny(this.runMode, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
|
||||||
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, ApiRunMode.SCHEDULE_API_PLAN.name());
|
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, ApiRunMode.SCHEDULE_API_PLAN.name());
|
||||||
List<String> testPlanReportIdList = new ArrayList<>();
|
List<String> testPlanReportIdList = new ArrayList<>();
|
||||||
testPlanReportIdList.add(debugReportId);
|
testPlanReportIdList.add(debugReportId);
|
||||||
for(String testPlanReportId : testPlanReportIdList) { // 更新每个测试计划的状态
|
for (String testPlanReportId : testPlanReportIdList) { // 更新每个测试计划的状态
|
||||||
testPlanReportService.checkTestPlanStatus(testPlanReportId);
|
testPlanReportService.checkTestPlanStatus(testPlanReportId);
|
||||||
}
|
}
|
||||||
testPlanReportService.updateReport(testPlanReportIdList, ApiRunMode.SCHEDULE_API_PLAN.name(), ReportTriggerMode.SCHEDULE.name());
|
testPlanReportService.updateReport(testPlanReportIdList, ApiRunMode.SCHEDULE_API_PLAN.name(), ReportTriggerMode.SCHEDULE.name());
|
||||||
|
@ -250,10 +247,16 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendTask(report, reportUrl, testResult);
|
if (StringUtils.equals(ReportTriggerMode.API.name(), report.getTriggerMode())||StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), report.getTriggerMode())) {
|
||||||
|
sendTask(report, reportUrl, testResult);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
|
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
|
||||||
|
if (report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||||
NoticeSendService noticeSendService = CommonBeanFactory.getBean(NoticeSendService.class);
|
NoticeSendService noticeSendService = CommonBeanFactory.getBean(NoticeSendService.class);
|
||||||
assert systemParameterService != null;
|
assert systemParameterService != null;
|
||||||
|
|
|
@ -90,6 +90,8 @@ public class ApiAutomationService {
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy
|
@Lazy
|
||||||
private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
||||||
|
@Resource
|
||||||
|
private EsbApiParamService esbApiParamService;
|
||||||
|
|
||||||
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
|
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
|
||||||
request = this.initRequest(request, true, true);
|
request = this.initRequest(request, true, true);
|
||||||
|
@ -184,6 +186,9 @@ public class ApiAutomationService {
|
||||||
scenario.setCreateTime(System.currentTimeMillis());
|
scenario.setCreateTime(System.currentTimeMillis());
|
||||||
scenario.setNum(getNextNum(request.getProjectId()));
|
scenario.setNum(getNextNum(request.getProjectId()));
|
||||||
|
|
||||||
|
//检查场景的请求步骤。如果含有ESB请求步骤的话,要做参数计算处理。
|
||||||
|
esbApiParamService.checkScenarioRequests(request);
|
||||||
|
|
||||||
apiScenarioMapper.insert(scenario);
|
apiScenarioMapper.insert(scenario);
|
||||||
|
|
||||||
List<String> bodyUploadIds = request.getBodyUploadIds();
|
List<String> bodyUploadIds = request.getBodyUploadIds();
|
||||||
|
@ -205,6 +210,9 @@ public class ApiAutomationService {
|
||||||
List<String> bodyUploadIds = request.getBodyUploadIds();
|
List<String> bodyUploadIds = request.getBodyUploadIds();
|
||||||
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
|
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
|
||||||
|
|
||||||
|
//检查场景的请求步骤。如果含有ESB请求步骤的话,要做参数计算处理。
|
||||||
|
esbApiParamService.checkScenarioRequests(request);
|
||||||
|
|
||||||
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
|
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
|
||||||
apiScenarioMapper.updateByPrimaryKeySelective(scenario);
|
apiScenarioMapper.updateByPrimaryKeySelective(scenario);
|
||||||
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name,同步到修改首页定时任务
|
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name,同步到修改首页定时任务
|
||||||
|
@ -234,6 +242,10 @@ public class ApiAutomationService {
|
||||||
} else {
|
} else {
|
||||||
scenario.setUserId(request.getUserId());
|
scenario.setUserId(request.getUserId());
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isEmpty(request.getApiScenarioModuleId()) || StringUtils.isEmpty(request.getModulePath())) {
|
||||||
|
scenario.setApiScenarioModuleId("root");
|
||||||
|
scenario.setModulePath("/默认模块");
|
||||||
|
}
|
||||||
return scenario;
|
return scenario;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +281,7 @@ public class ApiAutomationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteApiScenarioReport(List<String> scenarioIds) {
|
private void deleteApiScenarioReport(List<String> scenarioIds) {
|
||||||
if(scenarioIds == null || scenarioIds.isEmpty()){
|
if (scenarioIds == null || scenarioIds.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ApiScenarioReportExample scenarioReportExample = new ApiScenarioReportExample();
|
ApiScenarioReportExample scenarioReportExample = new ApiScenarioReportExample();
|
||||||
|
@ -371,6 +383,9 @@ public class ApiAutomationService {
|
||||||
|
|
||||||
public APIScenarioReportResult createScenarioReport(String id, String scenarioId, String scenarioName, String triggerMode, String execType, String projectId, String userID) {
|
public APIScenarioReportResult createScenarioReport(String id, String scenarioId, String scenarioName, String triggerMode, String execType, String projectId, String userID) {
|
||||||
APIScenarioReportResult report = new APIScenarioReportResult();
|
APIScenarioReportResult report = new APIScenarioReportResult();
|
||||||
|
if (triggerMode.equals(ApiRunMode.SCENARIO.name()) || triggerMode.equals(ApiRunMode.DEFINITION.name())) {
|
||||||
|
triggerMode = ReportTriggerMode.MANUAL.name();
|
||||||
|
}
|
||||||
report.setId(id);
|
report.setId(id);
|
||||||
report.setTestId(id);
|
report.setTestId(id);
|
||||||
if (StringUtils.isNotEmpty(scenarioName)) {
|
if (StringUtils.isNotEmpty(scenarioName)) {
|
||||||
|
@ -998,4 +1013,18 @@ public class ApiAutomationService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeToGcByBatch(ApiScenarioBatchRequest request) {
|
||||||
|
ServiceUtils.getSelectAllIds(request, request.getCondition(),
|
||||||
|
(query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query));
|
||||||
|
|
||||||
|
this.removeToGc(request.getIds());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteBatchByCondition(ApiScenarioBatchRequest request) {
|
||||||
|
ServiceUtils.getSelectAllIds(request, request.getCondition(),
|
||||||
|
(query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query));
|
||||||
|
|
||||||
|
this.deleteBatch(request.getIds());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,7 @@ package io.metersphere.api.service;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
|
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
|
||||||
import io.metersphere.api.jmeter.TestResult;
|
import io.metersphere.api.jmeter.TestResult;
|
||||||
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.domain.ApiDefinitionExecResultExample;
|
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
|
||||||
import io.metersphere.base.domain.TestPlanApiCase;
|
|
||||||
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
|
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
|
||||||
import io.metersphere.base.mapper.ApiTestCaseMapper;
|
import io.metersphere.base.mapper.ApiTestCaseMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
|
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
|
||||||
|
@ -43,7 +40,7 @@ public class ApiDefinitionExecResultService {
|
||||||
@Resource
|
@Resource
|
||||||
private ApiTestCaseMapper apiTestCaseMapper;
|
private ApiTestCaseMapper apiTestCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private TestCaseReviewApiCaseService testCaseReviewApiCaseService;
|
private TestCaseReviewApiCaseService testCaseReviewApiCaseService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
SqlSessionFactory sqlSessionFactory;
|
SqlSessionFactory sqlSessionFactory;
|
||||||
|
@ -73,6 +70,13 @@ public class ApiDefinitionExecResultService {
|
||||||
testCaseReviewApiCaseService.setExecResult(item.getName(), status);
|
testCaseReviewApiCaseService.setExecResult(item.getName(), status);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空上次执行结果的内容,只保留当前最新一条内容
|
||||||
|
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
|
||||||
|
if (prevResult != null) {
|
||||||
|
prevResult.setContent(null);
|
||||||
|
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
|
||||||
|
}
|
||||||
// 更新用例最后执行结果
|
// 更新用例最后执行结果
|
||||||
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = new ApiTestCaseWithBLOBs();
|
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = new ApiTestCaseWithBLOBs();
|
||||||
apiTestCaseWithBLOBs.setId(saveResult.getResourceId());
|
apiTestCaseWithBLOBs.setId(saveResult.getResourceId());
|
||||||
|
@ -94,7 +98,7 @@ public class ApiDefinitionExecResultService {
|
||||||
*/
|
*/
|
||||||
public void saveApiResultByScheduleTask(TestResult result, String type) {
|
public void saveApiResultByScheduleTask(TestResult result, String type) {
|
||||||
String saveResultType = type;
|
String saveResultType = type;
|
||||||
if(StringUtils.equalsAny(ApiRunMode.SCHEDULE_API_PLAN.name(),saveResultType)){
|
if (StringUtils.equalsAny(ApiRunMode.SCHEDULE_API_PLAN.name(), saveResultType)) {
|
||||||
saveResultType = ApiRunMode.API_PLAN.name();
|
saveResultType = ApiRunMode.API_PLAN.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +131,12 @@ public class ApiDefinitionExecResultService {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveResult.setUserId(userID);
|
saveResult.setUserId(userID);
|
||||||
|
// 前一条数据内容清空
|
||||||
|
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), finalSaveResultType);
|
||||||
|
if (prevResult != null) {
|
||||||
|
prevResult.setContent(null);
|
||||||
|
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
|
||||||
|
}
|
||||||
apiDefinitionExecResultMapper.insert(saveResult);
|
apiDefinitionExecResultMapper.insert(saveResult);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,10 @@ public class ApiDefinitionService {
|
||||||
test.setEnvironmentId(request.getEnvironmentId());
|
test.setEnvironmentId(request.getEnvironmentId());
|
||||||
test.setUserId(request.getUserId());
|
test.setUserId(request.getUserId());
|
||||||
test.setTags(request.getTags());
|
test.setTags(request.getTags());
|
||||||
|
if (StringUtils.isEmpty(request.getModulePath()) || StringUtils.isEmpty(request.getModuleId())) {
|
||||||
|
test.setModulePath("/默认模块");
|
||||||
|
test.setModuleId("root");
|
||||||
|
}
|
||||||
apiDefinitionMapper.updateByPrimaryKeySelective(test);
|
apiDefinitionMapper.updateByPrimaryKeySelective(test);
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +282,6 @@ public class ApiDefinitionService {
|
||||||
test.setProtocol(request.getProtocol());
|
test.setProtocol(request.getProtocol());
|
||||||
test.setMethod(request.getMethod());
|
test.setMethod(request.getMethod());
|
||||||
test.setPath(request.getPath());
|
test.setPath(request.getPath());
|
||||||
test.setModuleId(request.getModuleId());
|
|
||||||
test.setProjectId(request.getProjectId());
|
test.setProjectId(request.getProjectId());
|
||||||
request.getRequest().setId(request.getId());
|
request.getRequest().setId(request.getId());
|
||||||
test.setRequest(JSONObject.toJSONString(request.getRequest()));
|
test.setRequest(JSONObject.toJSONString(request.getRequest()));
|
||||||
|
@ -287,6 +289,11 @@ public class ApiDefinitionService {
|
||||||
test.setUpdateTime(System.currentTimeMillis());
|
test.setUpdateTime(System.currentTimeMillis());
|
||||||
test.setStatus(APITestStatus.Underway.name());
|
test.setStatus(APITestStatus.Underway.name());
|
||||||
test.setModulePath(request.getModulePath());
|
test.setModulePath(request.getModulePath());
|
||||||
|
test.setModuleId(request.getModuleId());
|
||||||
|
if (StringUtils.isEmpty(request.getModulePath()) || StringUtils.isEmpty(request.getModuleId())) {
|
||||||
|
test.setModulePath("/默认模块");
|
||||||
|
test.setModuleId("root");
|
||||||
|
}
|
||||||
test.setResponse(JSONObject.toJSONString(request.getResponse()));
|
test.setResponse(JSONObject.toJSONString(request.getResponse()));
|
||||||
test.setEnvironmentId(request.getEnvironmentId());
|
test.setEnvironmentId(request.getEnvironmentId());
|
||||||
test.setNum(getNextNum(request.getProjectId()));
|
test.setNum(getNextNum(request.getProjectId()));
|
||||||
|
@ -344,13 +351,13 @@ public class ApiDefinitionService {
|
||||||
private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition,
|
private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition,
|
||||||
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases) {
|
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases) {
|
||||||
if (CollectionUtils.isEmpty(sameRequest)) {
|
if (CollectionUtils.isEmpty(sameRequest)) {
|
||||||
if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){
|
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), RequestType.HTTP)) {
|
||||||
String request = setImportHashTree(apiDefinition);
|
String request = setImportHashTree(apiDefinition);
|
||||||
batchMapper.insert(apiDefinition);
|
batchMapper.insert(apiDefinition);
|
||||||
apiDefinition.setRequest(request);
|
apiDefinition.setRequest(request);
|
||||||
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
|
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
|
||||||
}else{
|
} else {
|
||||||
if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){
|
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
|
||||||
String request = setImportTCPHashTree(apiDefinition);
|
String request = setImportTCPHashTree(apiDefinition);
|
||||||
}
|
}
|
||||||
batchMapper.insert(apiDefinition);
|
batchMapper.insert(apiDefinition);
|
||||||
|
@ -358,7 +365,7 @@ public class ApiDefinitionService {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String originId = apiDefinition.getId();
|
String originId = apiDefinition.getId();
|
||||||
if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){
|
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), RequestType.HTTP)) {
|
||||||
//如果存在则修改
|
//如果存在则修改
|
||||||
apiDefinition.setId(sameRequest.get(0).getId());
|
apiDefinition.setId(sameRequest.get(0).getId());
|
||||||
String request = setImportHashTree(apiDefinition);
|
String request = setImportHashTree(apiDefinition);
|
||||||
|
@ -373,9 +380,9 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
apiDefinition.setId(sameRequest.get(0).getId());
|
apiDefinition.setId(sameRequest.get(0).getId());
|
||||||
if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){
|
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
|
||||||
String request = setImportTCPHashTree(apiDefinition);
|
String request = setImportTCPHashTree(apiDefinition);
|
||||||
}
|
}
|
||||||
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
|
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
|
||||||
|
@ -392,6 +399,7 @@ public class ApiDefinitionService {
|
||||||
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
|
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String setImportTCPHashTree(ApiDefinitionWithBLOBs apiDefinition) {
|
private String setImportTCPHashTree(ApiDefinitionWithBLOBs apiDefinition) {
|
||||||
String request = apiDefinition.getRequest();
|
String request = apiDefinition.getRequest();
|
||||||
MsTCPSampler tcpSampler = JSONObject.parseObject(request, MsTCPSampler.class);
|
MsTCPSampler tcpSampler = JSONObject.parseObject(request, MsTCPSampler.class);
|
||||||
|
@ -411,7 +419,7 @@ public class ApiDefinitionService {
|
||||||
if (CollectionUtils.isNotEmpty(cases)) {
|
if (CollectionUtils.isNotEmpty(cases)) {
|
||||||
int batchCount = 0;
|
int batchCount = 0;
|
||||||
cases.forEach(item -> {
|
cases.forEach(item -> {
|
||||||
if(!existCaseName.contains(item.getName())) {
|
if (!existCaseName.contains(item.getName())) {
|
||||||
item.setId(UUID.randomUUID().toString());
|
item.setId(UUID.randomUUID().toString());
|
||||||
item.setCreateTime(System.currentTimeMillis());
|
item.setCreateTime(System.currentTimeMillis());
|
||||||
item.setUpdateTime(System.currentTimeMillis());
|
item.setUpdateTime(System.currentTimeMillis());
|
||||||
|
@ -509,7 +517,7 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addResult(TestResult res) {
|
public void addResult(TestResult res) {
|
||||||
if (!res.getScenarios().isEmpty() && !res.getScenarios().get(0).getRequestResults().isEmpty()) {
|
if (res != null && CollectionUtils.isNotEmpty(res.getScenarios()) && res.getScenarios().get(0) != null && CollectionUtils.isNotEmpty(res.getScenarios().get(0).getRequestResults())) {
|
||||||
RequestResult result = res.getScenarios().get(0).getRequestResults().get(0);
|
RequestResult result = res.getScenarios().get(0).getRequestResults().get(0);
|
||||||
if (result.getName().indexOf("<->") != -1) {
|
if (result.getName().indexOf("<->") != -1) {
|
||||||
result.setName(result.getName().substring(0, result.getName().indexOf("<->")));
|
result.setName(result.getName().substring(0, result.getName().indexOf("<->")));
|
||||||
|
@ -596,21 +604,25 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
for (int i = 0; i < data.size(); i++) {
|
for (int i = 0; i < data.size(); i++) {
|
||||||
ApiDefinitionWithBLOBs item = data.get(i);
|
ApiDefinitionWithBLOBs item = data.get(i);
|
||||||
|
if (StringUtils.isEmpty(item.getModuleId()) || StringUtils.isEmpty(item.getModulePath())) {
|
||||||
|
item.setModuleId("root");
|
||||||
|
item.setModulePath("/默认模块");
|
||||||
|
}
|
||||||
if (item.getName().length() > 255) {
|
if (item.getName().length() > 255) {
|
||||||
item.setName(item.getName().substring(0, 255));
|
item.setName(item.getName().substring(0, 255));
|
||||||
}
|
}
|
||||||
item.setNum(num++);
|
item.setNum(num++);
|
||||||
//如果EsbData需要存储,则需要进行接口是否更新的判断
|
//如果EsbData需要存储,则需要进行接口是否更新的判断
|
||||||
if(apiImport.getEsbApiParamsMap()!= null){
|
if (apiImport.getEsbApiParamsMap() != null) {
|
||||||
String apiId = item.getId();
|
String apiId = item.getId();
|
||||||
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
|
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
|
||||||
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
||||||
if(model!=null){
|
if (model != null) {
|
||||||
apiImport.getEsbApiParamsMap().remove(apiId);
|
apiImport.getEsbApiParamsMap().remove(apiId);
|
||||||
model.setResourceId(item.getId());
|
model.setResourceId(item.getId());
|
||||||
apiImport.getEsbApiParamsMap().put(item.getId(),model);
|
apiImport.getEsbApiParamsMap().put(item.getId(), model);
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
||||||
}
|
}
|
||||||
if (i % 300 == 0) {
|
if (i % 300 == 0) {
|
||||||
|
@ -618,15 +630,15 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//判断EsbData是否需要存储
|
//判断EsbData是否需要存储
|
||||||
if(apiImport.getEsbApiParamsMap()!= null && apiImport.getEsbApiParamsMap().size() > 0){
|
if (apiImport.getEsbApiParamsMap() != null && apiImport.getEsbApiParamsMap().size() > 0) {
|
||||||
EsbApiParamsMapper esbApiParamsMapper = sqlSession.getMapper(EsbApiParamsMapper.class);
|
EsbApiParamsMapper esbApiParamsMapper = sqlSession.getMapper(EsbApiParamsMapper.class);
|
||||||
for (EsbApiParamsWithBLOBs model : apiImport.getEsbApiParamsMap().values()) {
|
for (EsbApiParamsWithBLOBs model : apiImport.getEsbApiParamsMap().values()) {
|
||||||
EsbApiParamsExample example = new EsbApiParamsExample();
|
EsbApiParamsExample example = new EsbApiParamsExample();
|
||||||
example.createCriteria().andResourceIdEqualTo(model.getResourceId());
|
example.createCriteria().andResourceIdEqualTo(model.getResourceId());
|
||||||
List<EsbApiParamsWithBLOBs> exiteModelList = esbApiParamsMapper.selectByExampleWithBLOBs(example);
|
List<EsbApiParamsWithBLOBs> exiteModelList = esbApiParamsMapper.selectByExampleWithBLOBs(example);
|
||||||
if(exiteModelList.isEmpty()){
|
if (exiteModelList.isEmpty()) {
|
||||||
esbApiParamsMapper.insert(model);
|
esbApiParamsMapper.insert(model);
|
||||||
}else{
|
} else {
|
||||||
model.setId(exiteModelList.get(0).getId());
|
model.setId(exiteModelList.get(0).getId());
|
||||||
esbApiParamsMapper.updateByPrimaryKeyWithBLOBs(model);
|
esbApiParamsMapper.updateByPrimaryKeyWithBLOBs(model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,216 +86,240 @@ public class ApiDocumentService {
|
||||||
apiInfoDTO.setStatus(apiModel.getStatus());
|
apiInfoDTO.setStatus(apiModel.getStatus());
|
||||||
|
|
||||||
if (apiModel.getRequest() != null) {
|
if (apiModel.getRequest() != null) {
|
||||||
JSONObject requestJsonObj = JSONObject.parseObject(apiModel.getRequest());
|
JSONObject requestObj = this.genJSONObject(apiModel.getRequest());
|
||||||
//head赋值conversionModelToDTO
|
if(requestObj!=null){
|
||||||
if (requestJsonObj.containsKey("headers")) {
|
if (requestObj.containsKey("headers")) {
|
||||||
JSONArray requestHeadDataArr = new JSONArray();
|
JSONArray requestHeadDataArr = new JSONArray();
|
||||||
//head赋值
|
//head赋值
|
||||||
JSONArray headArr = requestJsonObj.getJSONArray("headers");
|
JSONArray headArr = requestObj.getJSONArray("headers");
|
||||||
for (int index = 0; index < headArr.size(); index++) {
|
for (int index = 0; index < headArr.size(); index++) {
|
||||||
JSONObject headObj = headArr.getJSONObject(index);
|
JSONObject headObj = headArr.getJSONObject(index);
|
||||||
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
||||||
requestHeadDataArr.add(headObj);
|
requestHeadDataArr.add(headObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
apiInfoDTO.setRequestHead(requestHeadDataArr.toJSONString());
|
||||||
}
|
}
|
||||||
apiInfoDTO.setRequestHead(requestHeadDataArr.toJSONString());
|
//url参数赋值
|
||||||
}
|
JSONArray urlParamArr = new JSONArray();
|
||||||
//url参数赋值
|
if (requestObj.containsKey("arguments")) {
|
||||||
JSONArray urlParamArr = new JSONArray();
|
try{
|
||||||
if (requestJsonObj.containsKey("arguments")) {
|
JSONArray headArr = requestObj.getJSONArray("arguments");
|
||||||
//urlParam -- query赋值
|
for (int index = 0; index < headArr.size(); index++) {
|
||||||
JSONArray headArr = requestJsonObj.getJSONArray("arguments");
|
|
||||||
for (int index = 0; index < headArr.size(); index++) {
|
|
||||||
JSONObject headObj = headArr.getJSONObject(index);
|
|
||||||
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
|
||||||
urlParamArr.add(headObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requestJsonObj.containsKey("rest")) {
|
|
||||||
//urlParam -- rest赋值
|
|
||||||
JSONArray headArr = requestJsonObj.getJSONArray("rest");
|
|
||||||
for (int index = 0; index < headArr.size(); index++) {
|
|
||||||
JSONObject headObj = headArr.getJSONObject(index);
|
|
||||||
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
|
||||||
urlParamArr.add(headObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apiInfoDTO.setUrlParams(urlParamArr.toJSONString());
|
|
||||||
//请求体参数类型
|
|
||||||
if (requestJsonObj.containsKey("body")) {
|
|
||||||
JSONObject bodyObj = requestJsonObj.getJSONObject("body");
|
|
||||||
if (bodyObj.containsKey("type")) {
|
|
||||||
String type = bodyObj.getString("type");
|
|
||||||
if (StringUtils.equals(type, "WWW_FORM")) {
|
|
||||||
apiInfoDTO.setRequestBodyParamType("x-www-from-urlencoded");
|
|
||||||
} else if (StringUtils.equals(type, "Form Data")) {
|
|
||||||
apiInfoDTO.setRequestBodyParamType("form-data");
|
|
||||||
} else {
|
|
||||||
apiInfoDTO.setRequestBodyParamType(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.equals(type, "JSON")) {
|
JSONObject headObj = headArr.getJSONObject(index);
|
||||||
//判断是否是JsonSchema
|
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
||||||
boolean isJsonSchema = false;
|
urlParamArr.add(headObj);
|
||||||
if (bodyObj.containsKey("format")) {
|
|
||||||
String foramtValue = String.valueOf(bodyObj.get("format"));
|
|
||||||
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
|
|
||||||
isJsonSchema = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isJsonSchema) {
|
|
||||||
apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
|
|
||||||
apiInfoDTO.setJsonSchemaBody(bodyObj);
|
|
||||||
} else {
|
|
||||||
if (bodyObj.containsKey("raw")) {
|
|
||||||
String raw = bodyObj.getString("raw");
|
|
||||||
apiInfoDTO.setRequestBodyStrutureData(raw);
|
|
||||||
//转化jsonObje 或者 jsonArray
|
|
||||||
this.setPreviewData(previewJsonArray, raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (StringUtils.equalsAny(type, "XML", "Raw")) {
|
|
||||||
if (bodyObj.containsKey("raw")) {
|
|
||||||
String raw = bodyObj.getString("raw");
|
|
||||||
apiInfoDTO.setRequestBodyStrutureData(raw);
|
|
||||||
JSONObject previewObj = JSONObject.parseObject(raw);
|
|
||||||
this.setPreviewData(previewJsonArray, raw);
|
|
||||||
}
|
|
||||||
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
|
|
||||||
if (bodyObj.containsKey("kvs")) {
|
|
||||||
JSONArray bodyParamArr = new JSONArray();
|
|
||||||
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
|
||||||
Map<String, String> previewObjMap = new LinkedHashMap<>();
|
|
||||||
for (int i = 0; i < kvsArr.size(); i++) {
|
|
||||||
JSONObject kv = kvsArr.getJSONObject(i);
|
|
||||||
if (kv.containsKey("name") && kv.containsKey("value")) {
|
|
||||||
bodyParamArr.add(kv);
|
|
||||||
previewObjMap.put(String.valueOf(kv.get("name")), String.valueOf(kv.get("value")));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
|
|
||||||
apiInfoDTO.setRequestBodyFormData(bodyParamArr.toJSONString());
|
|
||||||
}
|
}
|
||||||
} else if (StringUtils.equals(type, "BINARY")) {
|
}catch (Exception e){
|
||||||
if (bodyObj.containsKey("binary")) {
|
}
|
||||||
List<Map<String, String>> bodyParamList = new ArrayList<>();
|
}
|
||||||
JSONArray kvsArr = bodyObj.getJSONArray("binary");
|
if (requestObj.containsKey("rest")) {
|
||||||
|
try{
|
||||||
|
//urlParam -- rest赋值
|
||||||
|
JSONArray headArr = requestObj.getJSONArray("rest");
|
||||||
|
for (int index = 0; index < headArr.size(); index++) {
|
||||||
|
JSONObject headObj = headArr.getJSONObject(index);
|
||||||
|
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
||||||
|
urlParamArr.add(headObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiInfoDTO.setUrlParams(urlParamArr.toJSONString());
|
||||||
|
//请求体参数类型
|
||||||
|
if (requestObj.containsKey("body")) {
|
||||||
|
try{
|
||||||
|
JSONObject bodyObj = requestObj.getJSONObject("body");
|
||||||
|
if (bodyObj.containsKey("type")) {
|
||||||
|
String type = bodyObj.getString("type");
|
||||||
|
if (StringUtils.equals(type, "WWW_FORM")) {
|
||||||
|
apiInfoDTO.setRequestBodyParamType("x-www-from-urlencoded");
|
||||||
|
} else if (StringUtils.equals(type, "Form Data")) {
|
||||||
|
apiInfoDTO.setRequestBodyParamType("form-data");
|
||||||
|
} else {
|
||||||
|
apiInfoDTO.setRequestBodyParamType(type);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> previewObjMap = new LinkedHashMap<>();
|
if (StringUtils.equals(type, "JSON")) {
|
||||||
for (int i = 0; i < kvsArr.size(); i++) {
|
//判断是否是JsonSchema
|
||||||
JSONObject kv = kvsArr.getJSONObject(i);
|
boolean isJsonSchema = false;
|
||||||
if (kv.containsKey("description") && kv.containsKey("files")) {
|
if (bodyObj.containsKey("format")) {
|
||||||
Map<String, String> bodyMap = new HashMap<>();
|
String foramtValue = String.valueOf(bodyObj.get("format"));
|
||||||
String name = kv.getString("description");
|
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
|
||||||
JSONArray fileArr = kv.getJSONArray("files");
|
isJsonSchema = true;
|
||||||
String value = "";
|
}
|
||||||
for (int j = 0; j < fileArr.size(); j++) {
|
}
|
||||||
JSONObject fileObj = fileArr.getJSONObject(j);
|
if (isJsonSchema) {
|
||||||
if (fileObj.containsKey("name")) {
|
apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
|
||||||
value += fileObj.getString("name") + " ;";
|
apiInfoDTO.setJsonSchemaBody(bodyObj);
|
||||||
|
} else {
|
||||||
|
if (bodyObj.containsKey("raw")) {
|
||||||
|
String raw = bodyObj.getString("raw");
|
||||||
|
apiInfoDTO.setRequestBodyStrutureData(raw);
|
||||||
|
//转化jsonObje 或者 jsonArray
|
||||||
|
this.setPreviewData(previewJsonArray, raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equalsAny(type, "XML", "Raw")) {
|
||||||
|
if (bodyObj.containsKey("raw")) {
|
||||||
|
String raw = bodyObj.getString("raw");
|
||||||
|
apiInfoDTO.setRequestBodyStrutureData(raw);
|
||||||
|
this.setPreviewData(previewJsonArray, raw);
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
|
||||||
|
if (bodyObj.containsKey("kvs")) {
|
||||||
|
JSONArray bodyParamArr = new JSONArray();
|
||||||
|
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
||||||
|
Map<String, String> previewObjMap = new LinkedHashMap<>();
|
||||||
|
for (int i = 0; i < kvsArr.size(); i++) {
|
||||||
|
JSONObject kv = kvsArr.getJSONObject(i);
|
||||||
|
if (kv.containsKey("name") && kv.containsKey("value")) {
|
||||||
|
bodyParamArr.add(kv);
|
||||||
|
previewObjMap.put(String.valueOf(kv.get("name")), String.valueOf(kv.get("value")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bodyMap.put("name", name);
|
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
|
||||||
bodyMap.put("value", value);
|
apiInfoDTO.setRequestBodyFormData(bodyParamArr.toJSONString());
|
||||||
bodyMap.put("contentType", "File");
|
}
|
||||||
bodyParamList.add(bodyMap);
|
} else if (StringUtils.equals(type, "BINARY")) {
|
||||||
|
if (bodyObj.containsKey("binary")) {
|
||||||
|
List<Map<String, String>> bodyParamList = new ArrayList<>();
|
||||||
|
JSONArray kvsArr = bodyObj.getJSONArray("binary");
|
||||||
|
|
||||||
previewObjMap.put(String.valueOf(name), String.valueOf(value));
|
Map<String, String> previewObjMap = new LinkedHashMap<>();
|
||||||
|
for (int i = 0; i < kvsArr.size(); i++) {
|
||||||
|
JSONObject kv = kvsArr.getJSONObject(i);
|
||||||
|
if (kv.containsKey("description") && kv.containsKey("files")) {
|
||||||
|
Map<String, String> bodyMap = new HashMap<>();
|
||||||
|
String name = kv.getString("description");
|
||||||
|
JSONArray fileArr = kv.getJSONArray("files");
|
||||||
|
String value = "";
|
||||||
|
for (int j = 0; j < fileArr.size(); j++) {
|
||||||
|
JSONObject fileObj = fileArr.getJSONObject(j);
|
||||||
|
if (fileObj.containsKey("name")) {
|
||||||
|
value += fileObj.getString("name") + " ;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bodyMap.put("name", name);
|
||||||
|
bodyMap.put("value", value);
|
||||||
|
bodyMap.put("contentType", "File");
|
||||||
|
bodyParamList.add(bodyMap);
|
||||||
|
|
||||||
|
previewObjMap.put(String.valueOf(name), String.valueOf(value));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
|
||||||
|
apiInfoDTO.setRequestBodyFormData(JSONArray.toJSONString(bodyParamList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
|
|
||||||
apiInfoDTO.setRequestBodyFormData(JSONArray.toJSONString(bodyParamList));
|
|
||||||
}
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//赋值响应头
|
//赋值响应头
|
||||||
if (apiModel.getResponse() != null) {
|
if (apiModel.getResponse() != null) {
|
||||||
JSONObject responseJsonObj = JSONObject.parseObject(apiModel.getResponse());
|
JSONObject responseJsonObj = this.genJSONObject(apiModel.getResponse());
|
||||||
if (responseJsonObj!=null && responseJsonObj.containsKey("headers")) {
|
if (responseJsonObj!=null && responseJsonObj.containsKey("headers")) {
|
||||||
JSONArray responseHeadDataArr = new JSONArray();
|
try{
|
||||||
JSONArray headArr = responseJsonObj.getJSONArray("headers");
|
JSONArray responseHeadDataArr = new JSONArray();
|
||||||
for (int index = 0; index < headArr.size(); index++) {
|
JSONArray headArr = responseJsonObj.getJSONArray("headers");
|
||||||
JSONObject headObj = headArr.getJSONObject(index);
|
for (int index = 0; index < headArr.size(); index++) {
|
||||||
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
JSONObject headObj = headArr.getJSONObject(index);
|
||||||
responseHeadDataArr.add(headObj);
|
if (headObj.containsKey("name") && headObj.containsKey("value")) {
|
||||||
|
responseHeadDataArr.add(headObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
apiInfoDTO.setResponseHead(responseHeadDataArr.toJSONString());
|
||||||
|
}catch (Exception e){
|
||||||
|
|
||||||
}
|
}
|
||||||
apiInfoDTO.setResponseHead(responseHeadDataArr.toJSONString());
|
|
||||||
}
|
}
|
||||||
// 赋值响应体
|
// 赋值响应体
|
||||||
if (responseJsonObj!=null && responseJsonObj.containsKey("body")) {
|
if (responseJsonObj!=null && responseJsonObj.containsKey("body")) {
|
||||||
JSONObject bodyObj = responseJsonObj.getJSONObject("body");
|
try {
|
||||||
if (bodyObj.containsKey("type")) {
|
JSONObject bodyObj = responseJsonObj.getJSONObject("body");
|
||||||
String type = bodyObj.getString("type");
|
if (bodyObj.containsKey("type")) {
|
||||||
if (StringUtils.equals(type, "WWW_FORM")) {
|
String type = bodyObj.getString("type");
|
||||||
apiInfoDTO.setResponseBodyParamType("x-www-from-urlencoded");
|
if (StringUtils.equals(type, "WWW_FORM")) {
|
||||||
} else if (StringUtils.equals(type, "Form Data")) {
|
apiInfoDTO.setResponseBodyParamType("x-www-from-urlencoded");
|
||||||
apiInfoDTO.setResponseBodyParamType("form-data");
|
} else if (StringUtils.equals(type, "Form Data")) {
|
||||||
} else {
|
apiInfoDTO.setResponseBodyParamType("form-data");
|
||||||
apiInfoDTO.setResponseBodyParamType(type);
|
} else {
|
||||||
}
|
apiInfoDTO.setResponseBodyParamType(type);
|
||||||
if (StringUtils.equalsAny(type, "JSON", "XML", "Raw")) {
|
|
||||||
if (bodyObj.containsKey("raw")) {
|
|
||||||
String raw = bodyObj.getString("raw");
|
|
||||||
apiInfoDTO.setResponseBodyStrutureData(raw);
|
|
||||||
}
|
}
|
||||||
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
|
if (StringUtils.equalsAny(type, "JSON", "XML", "Raw")) {
|
||||||
if (bodyObj.containsKey("kvs")) {
|
if (bodyObj.containsKey("raw")) {
|
||||||
JSONArray bodyParamArr = new JSONArray();
|
String raw = bodyObj.getString("raw");
|
||||||
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
apiInfoDTO.setResponseBodyStrutureData(raw);
|
||||||
for (int i = 0; i < kvsArr.size(); i++) {
|
|
||||||
JSONObject kv = kvsArr.getJSONObject(i);
|
|
||||||
if (kv.containsKey("name")) {
|
|
||||||
bodyParamArr.add(kv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
apiInfoDTO.setResponseBodyFormData(bodyParamArr.toJSONString());
|
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
|
||||||
}
|
if (bodyObj.containsKey("kvs")) {
|
||||||
} else if (StringUtils.equals(type, "BINARY")) {
|
JSONArray bodyParamArr = new JSONArray();
|
||||||
if (bodyObj.containsKey("binary")) {
|
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
||||||
List<Map<String, String>> bodyParamList = new ArrayList<>();
|
for (int i = 0; i < kvsArr.size(); i++) {
|
||||||
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
JSONObject kv = kvsArr.getJSONObject(i);
|
||||||
for (int i = 0; i < kvsArr.size(); i++) {
|
if (kv.containsKey("name")) {
|
||||||
JSONObject kv = kvsArr.getJSONObject(i);
|
bodyParamArr.add(kv);
|
||||||
if (kv.containsKey("description") && kv.containsKey("files")) {
|
|
||||||
Map<String, String> bodyMap = new HashMap<>();
|
|
||||||
|
|
||||||
String name = kv.getString("description");
|
|
||||||
JSONArray fileArr = kv.getJSONArray("files");
|
|
||||||
String value = "";
|
|
||||||
for (int j = 0; j < fileArr.size(); j++) {
|
|
||||||
JSONObject fileObj = fileArr.getJSONObject(j);
|
|
||||||
if (fileObj.containsKey("name")) {
|
|
||||||
value += fileObj.getString("name") + " ;";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bodyMap.put("name", name);
|
|
||||||
bodyMap.put("value", value);
|
|
||||||
bodyParamList.add(bodyMap);
|
|
||||||
}
|
}
|
||||||
|
apiInfoDTO.setResponseBodyFormData(bodyParamArr.toJSONString());
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equals(type, "BINARY")) {
|
||||||
|
if (bodyObj.containsKey("binary")) {
|
||||||
|
List<Map<String, String>> bodyParamList = new ArrayList<>();
|
||||||
|
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
|
||||||
|
for (int i = 0; i < kvsArr.size(); i++) {
|
||||||
|
JSONObject kv = kvsArr.getJSONObject(i);
|
||||||
|
if (kv.containsKey("description") && kv.containsKey("files")) {
|
||||||
|
Map<String, String> bodyMap = new HashMap<>();
|
||||||
|
|
||||||
|
String name = kv.getString("description");
|
||||||
|
JSONArray fileArr = kv.getJSONArray("files");
|
||||||
|
String value = "";
|
||||||
|
for (int j = 0; j < fileArr.size(); j++) {
|
||||||
|
JSONObject fileObj = fileArr.getJSONObject(j);
|
||||||
|
if (fileObj.containsKey("name")) {
|
||||||
|
value += fileObj.getString("name") + " ;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bodyMap.put("name", name);
|
||||||
|
bodyMap.put("value", value);
|
||||||
|
bodyParamList.add(bodyMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiInfoDTO.setResponseBodyFormData(JSONArray.toJSONString(bodyParamList));
|
||||||
}
|
}
|
||||||
apiInfoDTO.setResponseBodyFormData(JSONArray.toJSONString(bodyParamList));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 赋值响应码
|
// 赋值响应码
|
||||||
if (responseJsonObj!=null && responseJsonObj.containsKey("statusCode")) {
|
if (responseJsonObj!=null && responseJsonObj.containsKey("statusCode")) {
|
||||||
JSONArray responseStatusDataArr = new JSONArray();
|
try {
|
||||||
JSONArray statusArr = responseJsonObj.getJSONArray("statusCode");
|
JSONArray responseStatusDataArr = new JSONArray();
|
||||||
for (int index = 0; index < statusArr.size(); index++) {
|
JSONArray statusArr = responseJsonObj.getJSONArray("statusCode");
|
||||||
JSONObject statusObj = statusArr.getJSONObject(index);
|
for (int index = 0; index < statusArr.size(); index++) {
|
||||||
if (statusObj.containsKey("name") && statusObj.containsKey("value")) {
|
JSONObject statusObj = statusArr.getJSONObject(index);
|
||||||
responseStatusDataArr.add(statusObj);
|
if (statusObj.containsKey("name") && statusObj.containsKey("value")) {
|
||||||
|
responseStatusDataArr.add(statusObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
apiInfoDTO.setResponseCode(responseStatusDataArr.toJSONString());
|
||||||
|
}catch (Exception e){
|
||||||
|
|
||||||
}
|
}
|
||||||
apiInfoDTO.setResponseCode(responseStatusDataArr.toJSONString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,6 +328,15 @@ public class ApiDocumentService {
|
||||||
return apiInfoDTO;
|
return apiInfoDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JSONObject genJSONObject(String request) {
|
||||||
|
JSONObject returnObj = null;
|
||||||
|
try{
|
||||||
|
returnObj = JSONObject.parseObject(request);
|
||||||
|
}catch (Exception e){
|
||||||
|
}
|
||||||
|
return returnObj;
|
||||||
|
}
|
||||||
|
|
||||||
private void setPreviewData(JSONArray previewArray, String data) {
|
private void setPreviewData(JSONArray previewArray, String data) {
|
||||||
try {
|
try {
|
||||||
JSONObject previewObj = JSONObject.parseObject(data);
|
JSONObject previewObj = JSONObject.parseObject(data);
|
||||||
|
|
|
@ -253,6 +253,13 @@ public class ApiScenarioReportService {
|
||||||
String status = "Success";
|
String status = "Success";
|
||||||
report.setStatus(status);
|
report.setStatus(status);
|
||||||
scenarioReportMapper.updateByPrimaryKeySelective(report);
|
scenarioReportMapper.updateByPrimaryKeySelective(report);
|
||||||
|
// 把上一条调试的数据内容清空
|
||||||
|
ApiScenarioReport prevResult = extApiScenarioReportMapper.selectPreviousReportByScenarioId(report.getScenarioId(), reportId);
|
||||||
|
if (prevResult != null) {
|
||||||
|
ApiScenarioReportDetailExample example = new ApiScenarioReportDetailExample();
|
||||||
|
example.createCriteria().andReportIdEqualTo(prevResult.getId());
|
||||||
|
apiScenarioReportDetailMapper.deleteByExample(example);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
sqlSession.flushStatements();
|
sqlSession.flushStatements();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.*;
|
import io.metersphere.base.mapper.*;
|
||||||
import io.metersphere.base.mapper.ext.*;
|
import io.metersphere.base.mapper.ext.*;
|
||||||
|
import io.metersphere.commons.constants.ApiRunMode;
|
||||||
import io.metersphere.commons.constants.TestPlanStatus;
|
import io.metersphere.commons.constants.TestPlanStatus;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.*;
|
import io.metersphere.commons.utils.*;
|
||||||
|
@ -551,7 +552,14 @@ public class ApiTestCaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String run(RunCaseRequest request) {
|
public String run(RunCaseRequest request) {
|
||||||
ApiTestCaseWithBLOBs testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
|
ApiTestCaseWithBLOBs testCaseWithBLOBs=new ApiTestCaseWithBLOBs();
|
||||||
|
if(StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())){
|
||||||
|
testCaseWithBLOBs= apiTestCaseMapper.selectByPrimaryKey(request.getReportId());
|
||||||
|
request.setCaseId(request.getReportId());
|
||||||
|
}else{
|
||||||
|
testCaseWithBLOBs= apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
|
||||||
|
|
||||||
|
}
|
||||||
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||||
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
|
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -3,11 +3,13 @@ package io.metersphere.api.service;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.automation.EsbDataStruct;
|
import io.metersphere.api.dto.automation.EsbDataStruct;
|
||||||
|
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
|
||||||
import io.metersphere.api.dto.automation.parse.EsbDataParser;
|
import io.metersphere.api.dto.automation.parse.EsbDataParser;
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseResult;
|
import io.metersphere.api.dto.definition.ApiTestCaseResult;
|
||||||
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
|
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
|
||||||
import io.metersphere.api.dto.definition.SaveApiTestCaseRequest;
|
import io.metersphere.api.dto.definition.SaveApiTestCaseRequest;
|
||||||
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
||||||
|
@ -313,6 +315,35 @@ public class EsbApiParamService {
|
||||||
return keyValueList;
|
return keyValueList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<KeyValue> genKeyValueListByDataStruct(MsTCPSampler tcpSampler, List<EsbDataStruct> dataStructRequestList) {
|
||||||
|
List<KeyValue> keyValueList = new ArrayList<>();
|
||||||
|
String sendRequest = tcpSampler.getRequest();
|
||||||
|
String paramRegexStr = "\\$\\{([^}]*)\\}";
|
||||||
|
try {
|
||||||
|
if (StringUtils.isNotEmpty(sendRequest)) {
|
||||||
|
List<String> paramList = new ArrayList<>();
|
||||||
|
Pattern regex = Pattern.compile(paramRegexStr);
|
||||||
|
Matcher matcher = regex.matcher(sendRequest);
|
||||||
|
while (matcher.find()) {
|
||||||
|
paramList.add(matcher.group(1));
|
||||||
|
}
|
||||||
|
for (String param : paramList) {
|
||||||
|
String value = this.genValueFromEsbDataStructByParam(dataStructRequestList, param);
|
||||||
|
if (StringUtils.isNotEmpty(value)) {
|
||||||
|
KeyValue kv = new KeyValue();
|
||||||
|
kv.setName(param);
|
||||||
|
kv.setValue(value);
|
||||||
|
kv.setRequired(true);
|
||||||
|
keyValueList.add(kv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return keyValueList;
|
||||||
|
}
|
||||||
|
|
||||||
//通过报文模版中的变量参数,解析报文数据结构,生成对应的xml数据
|
//通过报文模版中的变量参数,解析报文数据结构,生成对应的xml数据
|
||||||
private String genValueFromEsbDataStructByParam(List<EsbDataStruct> dataStructRequestList, String param) {
|
private String genValueFromEsbDataStructByParam(List<EsbDataStruct> dataStructRequestList, String param) {
|
||||||
String returnValue = "";
|
String returnValue = "";
|
||||||
|
@ -341,10 +372,32 @@ public class EsbApiParamService {
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void handleEsbRequest(MsTCPSampler tcpSampler) {
|
||||||
|
try {
|
||||||
|
//修改reqeust.parameters, 将树结构类型数据转化为表格类型数据,供执行时参数的提取
|
||||||
|
if (tcpSampler.getEsbDataStruct() != null ) {
|
||||||
|
List<KeyValue> keyValueList = this.genKeyValueListByDataStruct(tcpSampler, tcpSampler.getEsbDataStruct());
|
||||||
|
tcpSampler.setParameters(keyValueList);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void deleteByResourceIdIn(List<String> apiIds) {
|
public void deleteByResourceIdIn(List<String> apiIds) {
|
||||||
EsbApiParamsExample example = new EsbApiParamsExample();
|
EsbApiParamsExample example = new EsbApiParamsExample();
|
||||||
example.createCriteria().andResourceIdIn(apiIds);
|
example.createCriteria().andResourceIdIn(apiIds);
|
||||||
esbApiParamsMapper.deleteByExample(example);
|
esbApiParamsMapper.deleteByExample(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkScenarioRequests(SaveApiScenarioRequest request) {
|
||||||
|
if(request.getScenarioDefinition() != null ){
|
||||||
|
List<MsTestElement> hashTreeList = request.getScenarioDefinition().getHashTree();
|
||||||
|
for (MsTestElement testElement :hashTreeList) {
|
||||||
|
if(testElement instanceof MsTCPSampler){
|
||||||
|
this.handleEsbRequest((MsTCPSampler)testElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,12 +76,17 @@ public class HistoricalDataUpgradeService {
|
||||||
return scenario;
|
return scenario;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MsScenario createScenario(Scenario oldScenario) {
|
private MsScenario createScenario(Scenario oldScenario, String projectId) {
|
||||||
MsScenario scenario = new MsScenario();
|
MsScenario scenario = new MsScenario();
|
||||||
scenario.setOldVariables(oldScenario.getVariables());
|
scenario.setOldVariables(oldScenario.getVariables());
|
||||||
scenario.setName(oldScenario.getName());
|
scenario.setName(oldScenario.getName());
|
||||||
scenario.setEnableCookieShare(oldScenario.isEnableCookieShare());
|
scenario.setEnableCookieShare(oldScenario.isEnableCookieShare());
|
||||||
scenario.setEnvironmentId(oldScenario.getEnvironmentId());
|
scenario.setEnvironmentId(oldScenario.getEnvironmentId());
|
||||||
|
if (StringUtils.isNotEmpty(oldScenario.getEnvironmentId())) {
|
||||||
|
HashMap<String, String> envMap = new HashMap<>();
|
||||||
|
envMap.put(projectId, oldScenario.getEnvironmentId());
|
||||||
|
scenario.setEnvironmentMap(envMap);
|
||||||
|
}
|
||||||
scenario.setReferenced("Upgrade");
|
scenario.setReferenced("Upgrade");
|
||||||
scenario.setId(oldScenario.getId());
|
scenario.setId(oldScenario.getId());
|
||||||
scenario.setResourceId(UUID.randomUUID().toString());
|
scenario.setResourceId(UUID.randomUUID().toString());
|
||||||
|
@ -397,6 +402,7 @@ public class HistoricalDataUpgradeService {
|
||||||
MsScenario scenarioTest = createScenarioByTest(test);
|
MsScenario scenarioTest = createScenarioByTest(test);
|
||||||
LinkedList<MsTestElement> listSteps = new LinkedList<>();
|
LinkedList<MsTestElement> listSteps = new LinkedList<>();
|
||||||
List<Scenario> scenarios = JSON.parseArray(test.getScenarioDefinition(), Scenario.class);
|
List<Scenario> scenarios = JSON.parseArray(test.getScenarioDefinition(), Scenario.class);
|
||||||
|
String envId = null;
|
||||||
if (CollectionUtils.isNotEmpty(scenarios)) {
|
if (CollectionUtils.isNotEmpty(scenarios)) {
|
||||||
// 批量处理
|
// 批量处理
|
||||||
for (Scenario scenario : scenarios) {
|
for (Scenario scenario : scenarios) {
|
||||||
|
@ -405,7 +411,7 @@ public class HistoricalDataUpgradeService {
|
||||||
}
|
}
|
||||||
scenario.setId(test.getId() + "=" + scenario.getId());
|
scenario.setId(test.getId() + "=" + scenario.getId());
|
||||||
scenario.setName(test.getName() + "_" + scenario.getName());
|
scenario.setName(test.getName() + "_" + scenario.getName());
|
||||||
MsScenario scenario1 = createScenario(scenario);
|
MsScenario scenario1 = createScenario(scenario, saveHistoricalDataUpgrade.getProjectId());
|
||||||
String scenarioDefinition = JSON.toJSONString(scenario1);
|
String scenarioDefinition = JSON.toJSONString(scenario1);
|
||||||
num++;
|
num++;
|
||||||
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenario.getId(), scenario.getName(), scenario.getRequests().size(), scenarioDefinition, mapper, num);
|
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenario.getId(), scenario.getName(), scenario.getRequests().size(), scenarioDefinition, mapper, num);
|
||||||
|
@ -417,10 +423,20 @@ public class HistoricalDataUpgradeService {
|
||||||
step.setResourceId(UUID.randomUUID().toString());
|
step.setResourceId(UUID.randomUUID().toString());
|
||||||
step.setReferenced("REF");
|
step.setReferenced("REF");
|
||||||
listSteps.add(step);
|
listSteps.add(step);
|
||||||
|
if (StringUtils.isNotEmpty(scenario.getEnvironmentId())) {
|
||||||
|
envId = scenario.getEnvironmentId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num++;
|
num++;
|
||||||
scenarioTest.setHashTree(listSteps);
|
scenarioTest.setHashTree(listSteps);
|
||||||
|
if (StringUtils.isNotEmpty(envId)) {
|
||||||
|
HashMap<String, String> envMap = new HashMap<>();
|
||||||
|
envMap.put(saveHistoricalDataUpgrade.getProjectId(), envId);
|
||||||
|
scenarioTest.setEnvironmentMap(envMap);
|
||||||
|
scenarioTest.setEnvironmentId(envId);
|
||||||
|
}
|
||||||
|
|
||||||
String scenarioDefinition = JSON.toJSONString(scenarioTest);
|
String scenarioDefinition = JSON.toJSONString(scenarioTest);
|
||||||
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenarioTest.getId(), scenarioTest.getName(), listSteps.size(), scenarioDefinition, mapper, num);
|
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenarioTest.getId(), scenarioTest.getName(), listSteps.size(), scenarioDefinition, mapper, num);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package io.metersphere.base.domain;
|
package io.metersphere.base.domain;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class TestCaseWithBLOBs extends TestCase implements Serializable {
|
public class TestCaseWithBLOBs extends TestCase implements Serializable {
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
private String steps;
|
private String steps; //与TestCaseExcelData里的属性名不一致,BeanUtils.copyBean()复制不了值,需要手动赋值
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package io.metersphere.base.mapper.ext;
|
||||||
import io.metersphere.api.dto.QueryAPIReportRequest;
|
import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||||
|
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
||||||
import io.metersphere.base.domain.ApiScenarioReport;
|
import io.metersphere.base.domain.ApiScenarioReport;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
@ -23,4 +24,7 @@ public interface ExtApiScenarioReportMapper {
|
||||||
List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
|
List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
|
||||||
|
|
||||||
List<ApiScenarioReport> selectLastReportByIds(@Param("scenarioIdList") List<String> ids);
|
List<ApiScenarioReport> selectLastReportByIds(@Param("scenarioIdList") List<String> ids);
|
||||||
|
|
||||||
|
ApiScenarioReport selectPreviousReportByScenarioId(@Param("scenarioId") String scenarioId, @Param("nowId") String nowId);
|
||||||
|
|
||||||
}
|
}
|
|
@ -216,4 +216,9 @@
|
||||||
) orderData ON orderData.id = report.id;
|
) orderData ON orderData.id = report.id;
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectPreviousReportByScenarioId" resultType="io.metersphere.base.domain.ApiScenarioReport">
|
||||||
|
select * from api_scenario_report
|
||||||
|
WHERE execute_type in ("Completed","Debug") and scenario_id=#{scenarioId} and id != #{nowId} ORDER BY create_time desc LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
|
@ -91,6 +91,9 @@
|
||||||
<if test="reportRequest.projectId != null">
|
<if test="reportRequest.projectId != null">
|
||||||
AND project.id = #{reportRequest.projectId,jdbcType=VARCHAR}
|
AND project.id = #{reportRequest.projectId,jdbcType=VARCHAR}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="reportRequest.testId != null">
|
||||||
|
AND ltr.test_id = #{reportRequest.testId,jdbcType=VARCHAR}
|
||||||
|
</if>
|
||||||
<if test="reportRequest.filters != null and reportRequest.filters.size() > 0">
|
<if test="reportRequest.filters != null and reportRequest.filters.size() > 0">
|
||||||
<foreach collection="reportRequest.filters.entrySet()" index="key" item="values">
|
<foreach collection="reportRequest.filters.entrySet()" index="key" item="values">
|
||||||
<if test="values != null and values.size() > 0">
|
<if test="values != null and values.size() > 0">
|
||||||
|
|
|
@ -274,7 +274,7 @@
|
||||||
#{value}
|
#{value}
|
||||||
</foreach>
|
</foreach>
|
||||||
</when>
|
</when>
|
||||||
<when test="key=='status'">
|
<when test="key=='reviewStatus'">
|
||||||
and test_case.review_status in
|
and test_case.review_status in
|
||||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||||
#{value}
|
#{value}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.metersphere.commons.user;
|
package io.metersphere.commons.user;
|
||||||
|
|
||||||
import io.metersphere.commons.utils.CodingUtil;
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.dto.UserDTO;
|
import io.metersphere.dto.UserDTO;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
@ -28,7 +29,7 @@ public class SessionUser extends UserDTO implements Serializable {
|
||||||
SessionUser sessionUser = new SessionUser();
|
SessionUser sessionUser = new SessionUser();
|
||||||
BeanUtils.copyProperties(user, sessionUser);
|
BeanUtils.copyProperties(user, sessionUser);
|
||||||
|
|
||||||
List<String> infos = Arrays.asList(user.getId(), RandomStringUtils.random(6), "" + System.currentTimeMillis());
|
List<String> infos = Arrays.asList(user.getId(), RandomStringUtils.randomAlphabetic(6), SessionUtils.getSessionId(), "" + System.currentTimeMillis());
|
||||||
sessionUser.csrfToken = CodingUtil.aesEncrypt(StringUtils.join(infos, "|"), secret, iv);
|
sessionUser.csrfToken = CodingUtil.aesEncrypt(StringUtils.join(infos, "|"), secret, iv);
|
||||||
return sessionUser;
|
return sessionUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.apache.shiro.subject.support.DefaultSubjectContext;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static io.metersphere.commons.constants.SessionConstants.ATTR_USER;
|
import static io.metersphere.commons.constants.SessionConstants.ATTR_USER;
|
||||||
|
|
||||||
|
@ -32,6 +31,10 @@ public class SessionUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getSessionId() {
|
||||||
|
return (String) SecurityUtils.getSubject().getSession().getId();
|
||||||
|
}
|
||||||
|
|
||||||
private static Session getSessionByUsername(String username) {
|
private static Session getSessionByUsername(String username) {
|
||||||
DefaultSessionManager sessionManager = CommonBeanFactory.getBean(DefaultSessionManager.class);
|
DefaultSessionManager sessionManager = CommonBeanFactory.getBean(DefaultSessionManager.class);
|
||||||
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
|
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
public class KafkaProperties {
|
public class KafkaProperties {
|
||||||
public static final String KAFKA_PREFIX = "kafka";
|
public static final String KAFKA_PREFIX = "kafka";
|
||||||
|
|
||||||
private String acks = "all";
|
private String acks = "0"; // 不要设置all
|
||||||
private String topic;
|
private String topic;
|
||||||
private String fields;
|
private String fields;
|
||||||
private String timestamp;
|
private String timestamp;
|
||||||
|
|
|
@ -9,5 +9,7 @@ public class ExcelResponse<T> {
|
||||||
|
|
||||||
private Boolean success;
|
private Boolean success;
|
||||||
private List<ExcelErrData<T>> errList;
|
private List<ExcelErrData<T>> errList;
|
||||||
|
private Boolean isUpdated; //是否有更新过用例
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import lombok.Setter;
|
||||||
@Setter
|
@Setter
|
||||||
public class TestCaseExcelData {
|
public class TestCaseExcelData {
|
||||||
|
|
||||||
|
@ExcelIgnore
|
||||||
|
private Integer num;
|
||||||
@ExcelIgnore
|
@ExcelIgnore
|
||||||
private String name;
|
private String name;
|
||||||
@ExcelIgnore
|
@ExcelIgnore
|
||||||
|
|
|
@ -13,6 +13,10 @@ import javax.validation.constraints.Pattern;
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
public class TestCaseExcelDataCn extends TestCaseExcelData {
|
public class TestCaseExcelDataCn extends TestCaseExcelData {
|
||||||
|
|
||||||
|
@ExcelProperty("ID")
|
||||||
|
@NotRequired
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
@NotBlank(message = "{cannot_be_null}")
|
@NotBlank(message = "{cannot_be_null}")
|
||||||
@Length(max = 255)
|
@Length(max = 255)
|
||||||
@ExcelProperty("用例名称")
|
@ExcelProperty("用例名称")
|
||||||
|
|
|
@ -13,6 +13,10 @@ import javax.validation.constraints.Pattern;
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
public class TestCaseExcelDataTw extends TestCaseExcelData {
|
public class TestCaseExcelDataTw extends TestCaseExcelData {
|
||||||
|
|
||||||
|
@ExcelProperty("ID")
|
||||||
|
@NotRequired
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
@NotBlank(message = "{cannot_be_null}")
|
@NotBlank(message = "{cannot_be_null}")
|
||||||
@Length(max = 255)
|
@Length(max = 255)
|
||||||
@ExcelProperty("用例名稱")
|
@ExcelProperty("用例名稱")
|
||||||
|
|
|
@ -14,6 +14,10 @@ import javax.validation.constraints.Pattern;
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
public class TestCaseExcelDataUs extends TestCaseExcelData {
|
public class TestCaseExcelDataUs extends TestCaseExcelData {
|
||||||
|
|
||||||
|
@ExcelProperty("ID")
|
||||||
|
@NotRequired
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
@NotBlank(message = "{cannot_be_null}")
|
@NotBlank(message = "{cannot_be_null}")
|
||||||
@Length(max = 255)
|
@Length(max = 255)
|
||||||
@ExcelProperty("Name")
|
@ExcelProperty("Name")
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
package io.metersphere.excel.listener;
|
package io.metersphere.excel.listener;
|
||||||
|
|
||||||
|
import com.alibaba.excel.context.AnalysisContext;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
import io.metersphere.commons.constants.TestCaseConstants;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.excel.domain.ExcelErrData;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
|
import io.metersphere.excel.utils.ExcelValidateHelper;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -22,10 +26,18 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
|
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
||||||
|
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
||||||
|
|
||||||
|
protected boolean isUpdated = false; //判断是否更新过用例,将会传给前端
|
||||||
|
|
||||||
Set<String> testCaseNames;
|
Set<String> testCaseNames;
|
||||||
|
|
||||||
Set<String> userIds;
|
Set<String> userIds;
|
||||||
|
|
||||||
|
public boolean isUpdated() {
|
||||||
|
return isUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
public TestCaseDataListener(Class clazz, String projectId, Set<String> testCaseNames, Set<String> userIds) {
|
public TestCaseDataListener(Class clazz, String projectId, Set<String> testCaseNames, Set<String> userIds) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
||||||
|
@ -39,12 +51,15 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
String nodePath = data.getNodePath();
|
String nodePath = data.getNodePath();
|
||||||
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
||||||
|
|
||||||
|
//校验”所属模块"
|
||||||
if (nodePath != null) {
|
if (nodePath != null) {
|
||||||
String[] nodes = nodePath.split("/");
|
String[] nodes = nodePath.split("/");
|
||||||
|
//校验模块深度
|
||||||
if (nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
|
if (nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
|
||||||
stringBuilder.append(Translator.get("test_case_node_level_tip") +
|
stringBuilder.append(Translator.get("test_case_node_level_tip") +
|
||||||
TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level") + "; ");
|
TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level") + "; ");
|
||||||
}
|
}
|
||||||
|
//模块名不能为空
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
for (int i = 0; i < nodes.length; i++) {
|
||||||
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
|
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
|
||||||
stringBuilder.append(Translator.get("module_not_null") + "; ");
|
stringBuilder.append(Translator.get("module_not_null") + "; ");
|
||||||
|
@ -57,10 +72,39 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
// stringBuilder.append(Translator.get("functional_method_tip") + "; ");
|
// stringBuilder.append(Translator.get("functional_method_tip") + "; ");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//校验维护人
|
||||||
if (!userIds.contains(data.getMaintainer())) {
|
if (!userIds.contains(data.getMaintainer())) {
|
||||||
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
校验Excel中是否有ID
|
||||||
|
有的话校验ID是否已在当前项目中存在,存在则更新用例,
|
||||||
|
不存在则继续校验看是否重复,不重复则新建用例。
|
||||||
|
*/
|
||||||
|
if (null != data.getNum()) { //当前读取的数据有ID
|
||||||
|
|
||||||
|
if (null != testCaseService.checkIdExist(data.getNum(), projectId)) { //该ID在当前项目中存在
|
||||||
|
//如果前面所经过的校验都没报错
|
||||||
|
if (StringUtils.isEmpty(stringBuilder)) {
|
||||||
|
updateList.add(data); //将当前数据存入更新列表
|
||||||
|
stringBuilder.append("update_testcase"); //该信息用于在invoke方法中判断是否该更新用例
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
该ID在当前数据库中不存在,应当继续校验用例是否重复,
|
||||||
|
在下面的校验过程中,num的值会被用于判断是否重复,所以应当先设置为null
|
||||||
|
*/
|
||||||
|
data.setNum(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
校验用例
|
||||||
|
*/
|
||||||
if (testCaseNames.contains(data.getName())) {
|
if (testCaseNames.contains(data.getName())) {
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
BeanUtils.copyBean(testCase, data);
|
BeanUtils.copyBean(testCase, data);
|
||||||
|
@ -96,18 +140,27 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
@Override
|
@Override
|
||||||
public void saveData() {
|
public void saveData() {
|
||||||
|
|
||||||
//无错误数据才插入数据
|
//excel中用例都有错误时就返回,只要有用例可用于更新或者插入就不返回
|
||||||
if (!errList.isEmpty()) {
|
if (!errList.isEmpty() && list.size() == 0 && updateList.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.reverse(list);
|
if (!(list.size() == 0)){
|
||||||
|
Collections.reverse(list); //因为saveImportData里面是先分配最大的ID,这个ID应该先发给list中最后的数据,所以要reverse
|
||||||
|
List<TestCaseWithBLOBs> result = list.stream()
|
||||||
|
.map(item -> this.convert2TestCase(item))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
testCaseService.saveImportData(result, projectId);
|
||||||
|
}
|
||||||
|
|
||||||
List<TestCaseWithBLOBs> result = list.stream()
|
if (!(updateList.size() == 0)) {
|
||||||
.map(item -> this.convert2TestCase(item))
|
List<TestCaseWithBLOBs> result2 = updateList.stream()
|
||||||
.collect(Collectors.toList());
|
.map(item -> this.convert2TestCaseForUpdate(item))
|
||||||
|
.collect(Collectors.toList());
|
||||||
testCaseService.saveImportData(result, projectId);
|
testCaseService.updateImportDataCarryId(result2, projectId);
|
||||||
|
this.isUpdated = true;
|
||||||
|
updateList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +184,32 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
testCase.setNodePath(nodePath);
|
testCase.setNodePath(nodePath);
|
||||||
|
|
||||||
|
|
||||||
|
String steps = getSteps(data);
|
||||||
|
testCase.setSteps(steps);
|
||||||
|
|
||||||
|
return testCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Excel中的数据对象转换为用于更新操作的用例数据对象,
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
||||||
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
|
BeanUtils.copyBean(testCase, data);
|
||||||
|
testCase.setProjectId(this.projectId);
|
||||||
|
testCase.setUpdateTime(System.currentTimeMillis());
|
||||||
|
|
||||||
|
String nodePath = data.getNodePath();
|
||||||
|
if (!nodePath.startsWith("/")) {
|
||||||
|
nodePath = "/" + nodePath;
|
||||||
|
}
|
||||||
|
if (nodePath.endsWith("/")) {
|
||||||
|
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
||||||
|
}
|
||||||
|
testCase.setNodePath(nodePath);
|
||||||
|
|
||||||
String steps = getSteps(data);
|
String steps = getSteps(data);
|
||||||
testCase.setSteps(steps);
|
testCase.setSteps(steps);
|
||||||
|
|
||||||
|
@ -189,4 +268,38 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||||
return jsonArray.toJSONString();
|
return jsonArray.toJSONString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(TestCaseExcelData testCaseExcelData, AnalysisContext analysisContext) {
|
||||||
|
String errMsg;
|
||||||
|
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
||||||
|
String updateMsg = "update_testcase";
|
||||||
|
try {
|
||||||
|
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
||||||
|
errMsg = ExcelValidateHelper.validateEntity(testCaseExcelData);
|
||||||
|
//自定义校验规则
|
||||||
|
errMsg = validate(testCaseExcelData, errMsg);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
errMsg = Translator.get("parse_data_error");
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(errMsg)) {
|
||||||
|
|
||||||
|
//如果errMsg只有"update testcase",说明用例待更新
|
||||||
|
if (!errMsg.equals(updateMsg)){
|
||||||
|
ExcelErrData excelErrData = new ExcelErrData(testCaseExcelData, rowIndex,
|
||||||
|
Translator.get("number") + " " + rowIndex + " " + Translator.get("row") + Translator.get("error")
|
||||||
|
+ ":" + errMsg);
|
||||||
|
|
||||||
|
errList.add(excelErrData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list.add(testCaseExcelData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.size() > BATCH_COUNT) {
|
||||||
|
saveData();
|
||||||
|
list.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
||||||
public class ReportRequest {
|
public class ReportRequest {
|
||||||
private String name;
|
private String name;
|
||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
private String testId;
|
||||||
private String userId;
|
private String userId;
|
||||||
private List<OrderRequest> orders;
|
private List<OrderRequest> orders;
|
||||||
private Map<String, List<String>> filters;
|
private Map<String, List<String>> filters;
|
||||||
|
|
|
@ -127,12 +127,18 @@ public class DockerTestEngine extends AbstractEngine {
|
||||||
Integer port = node.getPort();
|
Integer port = node.getPort();
|
||||||
|
|
||||||
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
|
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
|
||||||
ResultHolder result = restTemplateWithTimeOut.getForObject(uri, ResultHolder.class);
|
try {
|
||||||
if (result == null) {
|
ResultHolder result = restTemplateWithTimeOut.getForObject(uri, ResultHolder.class);
|
||||||
MSException.throwException(Translator.get("container_delete_fail"));
|
if (result == null) {
|
||||||
}
|
MSException.throwException(Translator.get("container_delete_fail"));
|
||||||
if (!result.isSuccess()) {
|
}
|
||||||
MSException.throwException(result.getMessage());
|
if (!result.isSuccess()) {
|
||||||
|
MSException.throwException(result.getMessage());
|
||||||
|
}
|
||||||
|
} catch (MSException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
MSException.throwException("Please check node-controller status.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,11 +71,14 @@ public class CsrfFilter extends AnonymousFilter {
|
||||||
csrfToken = CodingUtil.aesDecrypt(csrfToken, SessionUser.secret, SessionUser.iv);
|
csrfToken = CodingUtil.aesDecrypt(csrfToken, SessionUser.secret, SessionUser.iv);
|
||||||
|
|
||||||
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(csrfToken), "|");
|
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(csrfToken), "|");
|
||||||
if (signatureArray.length != 3) {
|
if (signatureArray.length != 4) {
|
||||||
throw new RuntimeException("invalid token");
|
throw new RuntimeException("invalid token");
|
||||||
}
|
}
|
||||||
if (!StringUtils.equals(SessionUtils.getUserId(), signatureArray[0])) {
|
if (!StringUtils.equals(SessionUtils.getUserId(), signatureArray[0])) {
|
||||||
throw new RuntimeException("Please check csrf token.");
|
throw new RuntimeException("Please check csrf token.");
|
||||||
}
|
}
|
||||||
|
if (!StringUtils.equals(SessionUtils.getSessionId(), signatureArray[2])) {
|
||||||
|
throw new RuntimeException("Please check csrf token.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ import io.metersphere.base.mapper.TestResourceMapper;
|
||||||
import io.metersphere.commons.constants.ResourceStatusEnum;
|
import io.metersphere.commons.constants.ResourceStatusEnum;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
import io.metersphere.controller.ResultHolder;
|
||||||
import io.metersphere.dto.NodeDTO;
|
import io.metersphere.dto.NodeDTO;
|
||||||
import io.metersphere.dto.TestResourcePoolDTO;
|
import io.metersphere.dto.TestResourcePoolDTO;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
@ -71,12 +71,18 @@ public class NodeResourcePoolService {
|
||||||
|
|
||||||
private boolean validateNode(NodeDTO node) {
|
private boolean validateNode(NodeDTO node) {
|
||||||
try {
|
try {
|
||||||
ResponseEntity<String> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class);
|
ResponseEntity<ResultHolder> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), ResultHolder.class);
|
||||||
return HttpStatus.OK.equals(entity.getStatusCode());
|
ResultHolder body = entity.getBody();
|
||||||
|
if (body == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (body.getData() != null && StringUtils.equalsIgnoreCase("OK", body.getData().toString())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e.getMessage(), e);
|
LogUtil.error(e.getMessage(), e);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTestResource(TestResource testResource) {
|
private void updateTestResource(TestResource testResource) {
|
||||||
|
|
|
@ -14,13 +14,11 @@ import io.metersphere.excel.domain.ExcelResponse;
|
||||||
import io.metersphere.service.CheckPermissionService;
|
import io.metersphere.service.CheckPermissionService;
|
||||||
import io.metersphere.service.FileService;
|
import io.metersphere.service.FileService;
|
||||||
import io.metersphere.track.dto.TestCaseDTO;
|
import io.metersphere.track.dto.TestCaseDTO;
|
||||||
import io.metersphere.track.dto.TestPlanCaseDTO;
|
|
||||||
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseMinderEditRequest;
|
import io.metersphere.track.request.testcase.TestCaseMinderEditRequest;
|
||||||
import io.metersphere.track.request.testplan.FileOperationRequest;
|
import io.metersphere.track.request.testplan.FileOperationRequest;
|
||||||
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
|
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
|
@ -126,8 +124,8 @@ public class TestCaseController {
|
||||||
|
|
||||||
@PostMapping(value = "/edit", consumes = {"multipart/form-data"})
|
@PostMapping(value = "/edit", consumes = {"multipart/form-data"})
|
||||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
public void editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file") List<MultipartFile> files) {
|
public String editTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file") List<MultipartFile> files) {
|
||||||
testCaseService.edit(request, files);
|
return testCaseService.edit(request, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/delete/{testCaseId}")
|
@PostMapping("/delete/{testCaseId}")
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class TestPlanController {
|
||||||
@PostMapping("/edit")
|
@PostMapping("/edit")
|
||||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
public void editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
|
public void editTestPlan(@RequestBody TestPlanDTO testPlanDTO) {
|
||||||
testPlanService.editTestPlan(testPlanDTO);
|
testPlanService.editTestPlan(testPlanDTO, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/edit/status/{planId}")
|
@PostMapping("/edit/status/{planId}")
|
||||||
|
|
|
@ -2,22 +2,20 @@ package io.metersphere.track.controller;
|
||||||
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.base.domain.TestCaseReport;
|
|
||||||
import io.metersphere.base.domain.TestPlanReport;
|
import io.metersphere.base.domain.TestPlanReport;
|
||||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||||
import io.metersphere.commons.utils.PageUtils;
|
import io.metersphere.commons.utils.PageUtils;
|
||||||
import io.metersphere.commons.utils.Pager;
|
import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.track.dto.TestCaseReportMetricDTO;
|
|
||||||
import io.metersphere.track.dto.TestPlanDTOWithMetric;
|
|
||||||
import io.metersphere.track.dto.TestPlanReportDTO;
|
import io.metersphere.track.dto.TestPlanReportDTO;
|
||||||
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
|
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
import io.metersphere.track.request.report.TestPlanReportSaveRequest;
|
||||||
import io.metersphere.track.service.TestPlanReportService;
|
import io.metersphere.track.service.TestPlanReportService;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author song.tianyang
|
* @author song.tianyang
|
||||||
|
@ -62,14 +60,18 @@ public class TestPlanReportController {
|
||||||
|
|
||||||
@GetMapping("/apiExecuteFinish/{planId}/{userId}")
|
@GetMapping("/apiExecuteFinish/{planId}/{userId}")
|
||||||
public void apiExecuteFinish(@PathVariable String planId,@PathVariable String userId) {
|
public void apiExecuteFinish(@PathVariable String planId,@PathVariable String userId) {
|
||||||
TestPlanReport report = testPlanReportService.genTestPlanReport(planId,userId,ReportTriggerMode.API.name());
|
String reportId = UUID.randomUUID().toString();
|
||||||
|
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId,planId,userId,ReportTriggerMode.API.name());
|
||||||
|
TestPlanReport report = testPlanReportService.genTestPlanReport(saveRequest);
|
||||||
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, ReportTriggerMode.API.name());
|
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, ReportTriggerMode.API.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/saveTestPlanReport/{planId}/{triggerMode}")
|
@GetMapping("/saveTestPlanReport/{planId}/{triggerMode}")
|
||||||
public String saveTestPlanReport(@PathVariable String planId,@PathVariable String triggerMode) {
|
public String saveTestPlanReport(@PathVariable String planId,@PathVariable String triggerMode) {
|
||||||
String userId = SessionUtils.getUser().getId();
|
String userId = SessionUtils.getUser().getId();
|
||||||
TestPlanReport report = testPlanReportService.genTestPlanReport(planId,userId,triggerMode);
|
String reportId = UUID.randomUUID().toString();
|
||||||
|
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId,planId,userId,triggerMode);
|
||||||
|
TestPlanReport report = testPlanReportService.genTestPlanReport(saveRequest);
|
||||||
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, triggerMode);
|
testPlanReportService.countReportByTestPlanReportId(report.getId(),null, triggerMode);
|
||||||
return "success";
|
return "success";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package io.metersphere.track.request.report;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author song.tianyang
|
||||||
|
* @Date 2021/1/8 4:36 下午
|
||||||
|
* @Description
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TestPlanReportSaveRequest {
|
||||||
|
private String reportID;
|
||||||
|
private String planId;
|
||||||
|
private String userId;
|
||||||
|
private String triggerMode;
|
||||||
|
|
||||||
|
private boolean countResources;
|
||||||
|
private boolean apiCaseIsExecuting;
|
||||||
|
private boolean scenarioIsExecuting;
|
||||||
|
private boolean performanceIsExecuting;
|
||||||
|
|
||||||
|
private String apiCaseIdListJSON;
|
||||||
|
private String scenarioIdListJSON;
|
||||||
|
private String performanceIdListJSON;
|
||||||
|
|
||||||
|
public TestPlanReportSaveRequest(String reportID, String planId, String userId, String triggerMode) {
|
||||||
|
this.reportID = reportID;
|
||||||
|
this.planId = planId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.triggerMode = triggerMode;
|
||||||
|
|
||||||
|
this.countResources = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestPlanReportSaveRequest(String reportID, String planId, String userId, String triggerMode, boolean apiCaseIsExecuting, boolean scenarioIsExecuting, boolean performanceIsExecuting, String apiCaseIdListJSON, String scenarioIdListJSON, String performanceIdListJSON) {
|
||||||
|
this.reportID = reportID;
|
||||||
|
this.planId = planId;
|
||||||
|
this.userId = userId;
|
||||||
|
this.triggerMode = triggerMode;
|
||||||
|
|
||||||
|
this.countResources = false;
|
||||||
|
|
||||||
|
this.apiCaseIsExecuting = apiCaseIsExecuting;
|
||||||
|
this.scenarioIsExecuting = scenarioIsExecuting;
|
||||||
|
this.performanceIsExecuting = performanceIsExecuting;
|
||||||
|
|
||||||
|
this.apiCaseIdListJSON = apiCaseIdListJSON;
|
||||||
|
this.scenarioIdListJSON = scenarioIdListJSON;
|
||||||
|
this.performanceIdListJSON = performanceIdListJSON;
|
||||||
|
}
|
||||||
|
}
|
|
@ -331,20 +331,6 @@ public class TestCaseReviewService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReviewRelevance(ReviewRelevanceRequest request) {
|
public void testReviewRelevance(ReviewRelevanceRequest request) {
|
||||||
String reviewId = request.getReviewId();
|
|
||||||
List<String> userIds = getTestCaseReviewerIds(reviewId);
|
|
||||||
|
|
||||||
String creator = "";
|
|
||||||
TestCaseReview review = testCaseReviewMapper.selectByPrimaryKey(reviewId);
|
|
||||||
if (review != null) {
|
|
||||||
creator = review.getCreator();
|
|
||||||
}
|
|
||||||
|
|
||||||
String currentId = SessionUtils.getUser().getId();
|
|
||||||
if (!userIds.contains(currentId) && !StringUtils.equals(creator, currentId)) {
|
|
||||||
MSException.throwException("没有权限,不能关联用例!");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> testCaseIds = request.getTestCaseIds();
|
List<String> testCaseIds = request.getTestCaseIds();
|
||||||
|
|
||||||
if (testCaseIds.isEmpty()) {
|
if (testCaseIds.isEmpty()) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import io.metersphere.excel.domain.ExcelErrData;
|
||||||
import io.metersphere.excel.domain.ExcelResponse;
|
import io.metersphere.excel.domain.ExcelResponse;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelDataFactory;
|
import io.metersphere.excel.domain.TestCaseExcelDataFactory;
|
||||||
import io.metersphere.excel.listener.EasyExcelListener;
|
|
||||||
import io.metersphere.excel.listener.TestCaseDataListener;
|
import io.metersphere.excel.listener.TestCaseDataListener;
|
||||||
import io.metersphere.excel.utils.EasyExcelExporter;
|
import io.metersphere.excel.utils.EasyExcelExporter;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
|
@ -126,11 +125,26 @@ public class TestCaseService {
|
||||||
|
|
||||||
// 全部字段值相同才判断为用例存在
|
// 全部字段值相同才判断为用例存在
|
||||||
if (testCase != null) {
|
if (testCase != null) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
例如对于“/模块5”,用户的输入可能为“模块5”或者“/模块5/”或者“模块5/”。
|
||||||
|
不这样处理的话,下面进行判断时就会用用户输入的错误格式进行判断,而模块名为“/模块5”、
|
||||||
|
“模块5”、“/模块5/”、“模块5/”时,它们应该被认为是同一个模块。
|
||||||
|
数据库存储的node_path都是“/模块5”这种格式的
|
||||||
|
*/
|
||||||
|
String nodePath = testCase.getNodePath();
|
||||||
|
if (!nodePath.startsWith("/")) {
|
||||||
|
nodePath = "/" + nodePath;
|
||||||
|
}
|
||||||
|
if (nodePath.endsWith("/")) {
|
||||||
|
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
TestCaseExample example = new TestCaseExample();
|
TestCaseExample example = new TestCaseExample();
|
||||||
TestCaseExample.Criteria criteria = example.createCriteria();
|
TestCaseExample.Criteria criteria = example.createCriteria();
|
||||||
criteria.andNameEqualTo(testCase.getName())
|
criteria.andNameEqualTo(testCase.getName())
|
||||||
.andProjectIdEqualTo(testCase.getProjectId())
|
.andProjectIdEqualTo(testCase.getProjectId())
|
||||||
.andNodePathEqualTo(testCase.getNodePath())
|
.andNodePathEqualTo(nodePath)
|
||||||
.andTypeEqualTo(testCase.getType())
|
.andTypeEqualTo(testCase.getType())
|
||||||
.andMaintainerEqualTo(testCase.getMaintainer())
|
.andMaintainerEqualTo(testCase.getMaintainer())
|
||||||
.andPriorityEqualTo(testCase.getPriority());
|
.andPriorityEqualTo(testCase.getPriority());
|
||||||
|
@ -165,7 +179,7 @@ public class TestCaseService {
|
||||||
String steps = tc.getSteps();
|
String steps = tc.getSteps();
|
||||||
String remark = tc.getRemark();
|
String remark = tc.getRemark();
|
||||||
if (StringUtils.equals(steps, testCase.getSteps()) && StringUtils.equals(remark, caseRemark)) {
|
if (StringUtils.equals(steps, testCase.getSteps()) && StringUtils.equals(remark, caseRemark)) {
|
||||||
MSException.throwException(Translator.get("test_case_already_exists"));
|
//MSException.throwException(Translator.get("test_case_already_exists"));
|
||||||
isExt = true;
|
isExt = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +191,26 @@ public class TestCaseService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id和pojectId查询id是否在数据库中存在。
|
||||||
|
* 在数据库中单id的话是可重复的,id与projectId的组合是唯一的
|
||||||
|
*/
|
||||||
|
public Integer checkIdExist(Integer id, String projectId){
|
||||||
|
TestCaseExample example = new TestCaseExample();
|
||||||
|
TestCaseExample.Criteria criteria = example.createCriteria();
|
||||||
|
if (null != id) {
|
||||||
|
criteria.andNumEqualTo(id);
|
||||||
|
criteria.andProjectIdEqualTo(projectId);
|
||||||
|
long count = testCaseMapper.countByExample(example); //查询是否有包含此ID的数据
|
||||||
|
if(count == 0){ //如果ID不存在
|
||||||
|
return null;
|
||||||
|
}else { //有对应ID的数据
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public int deleteTestCase(String testCaseId) {
|
public int deleteTestCase(String testCaseId) {
|
||||||
TestPlanTestCaseExample example = new TestPlanTestCaseExample();
|
TestPlanTestCaseExample example = new TestPlanTestCaseExample();
|
||||||
example.createCriteria().andCaseIdEqualTo(testCaseId);
|
example.createCriteria().andCaseIdEqualTo(testCaseId);
|
||||||
|
@ -286,6 +320,7 @@ public class TestCaseService {
|
||||||
public ExcelResponse testCaseImport(MultipartFile multipartFile, String projectId, String userId) {
|
public ExcelResponse testCaseImport(MultipartFile multipartFile, String projectId, String userId) {
|
||||||
|
|
||||||
ExcelResponse excelResponse = new ExcelResponse();
|
ExcelResponse excelResponse = new ExcelResponse();
|
||||||
|
boolean isUpdated = false; //判断是否更新了用例
|
||||||
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
||||||
QueryTestCaseRequest queryTestCaseRequest = new QueryTestCaseRequest();
|
QueryTestCaseRequest queryTestCaseRequest = new QueryTestCaseRequest();
|
||||||
queryTestCaseRequest.setProjectId(projectId);
|
queryTestCaseRequest.setProjectId(projectId);
|
||||||
|
@ -338,10 +373,15 @@ public class TestCaseService {
|
||||||
Set<String> userIds = userRoleMapper.selectByExample(userRoleExample).stream().map(UserRole::getUserId).collect(Collectors.toSet());
|
Set<String> userIds = userRoleMapper.selectByExample(userRoleExample).stream().map(UserRole::getUserId).collect(Collectors.toSet());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
//根据本地语言环境选择用哪种数据对象进行存放读取的数据
|
||||||
Class clazz = new TestCaseExcelDataFactory().getExcelDataByLocal();
|
Class clazz = new TestCaseExcelDataFactory().getExcelDataByLocal();
|
||||||
EasyExcelListener easyExcelListener = new TestCaseDataListener(clazz, projectId, testCaseNames, userIds);
|
|
||||||
|
TestCaseDataListener easyExcelListener = new TestCaseDataListener(clazz, projectId, testCaseNames, userIds);
|
||||||
|
//读取excel数据
|
||||||
EasyExcelFactory.read(multipartFile.getInputStream(), clazz, easyExcelListener).sheet().doRead();
|
EasyExcelFactory.read(multipartFile.getInputStream(), clazz, easyExcelListener).sheet().doRead();
|
||||||
|
|
||||||
errList = easyExcelListener.getErrList();
|
errList = easyExcelListener.getErrList();
|
||||||
|
isUpdated = easyExcelListener.isUpdated();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e.getMessage(), e);
|
LogUtil.error(e.getMessage(), e);
|
||||||
MSException.throwException(e.getMessage());
|
MSException.throwException(e.getMessage());
|
||||||
|
@ -352,6 +392,7 @@ public class TestCaseService {
|
||||||
if (!errList.isEmpty()) {
|
if (!errList.isEmpty()) {
|
||||||
excelResponse.setSuccess(false);
|
excelResponse.setSuccess(false);
|
||||||
excelResponse.setErrList(errList);
|
excelResponse.setErrList(errList);
|
||||||
|
excelResponse.setIsUpdated(isUpdated);
|
||||||
} else {
|
} else {
|
||||||
excelResponse.setSuccess(true);
|
excelResponse.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
@ -374,7 +415,7 @@ public class TestCaseService {
|
||||||
testcase.setSort(sort.getAndIncrement());
|
testcase.setSort(sort.getAndIncrement());
|
||||||
testcase.setNum(num.decrementAndGet());
|
testcase.setNum(num.decrementAndGet());
|
||||||
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
mapper.insert(testcase);
|
mapper.insert(testcase);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sqlSession.flushStatements();
|
sqlSession.flushStatements();
|
||||||
|
@ -400,6 +441,43 @@ public class TestCaseService {
|
||||||
sqlSession.flushStatements();
|
sqlSession.flushStatements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把Excel中带ID的数据更新到数据库
|
||||||
|
* @param testCases
|
||||||
|
* @param projectId
|
||||||
|
*/
|
||||||
|
public void updateImportDataCarryId(List<TestCaseWithBLOBs> testCases, String projectId) {
|
||||||
|
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||||
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
|
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取用例的“网页上所显示id”与“数据库ID”映射。
|
||||||
|
*/
|
||||||
|
List<Integer> nums = testCases.stream()
|
||||||
|
.map(TestCase::getNum)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
TestCaseExample example = new TestCaseExample();
|
||||||
|
example.createCriteria().andNumIn(nums)
|
||||||
|
.andProjectIdEqualTo(projectId);
|
||||||
|
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
||||||
|
Map<Integer, String> numIdMap = testCasesList.stream()
|
||||||
|
.collect(Collectors.toMap(TestCase::getNum, TestCase::getId));
|
||||||
|
|
||||||
|
|
||||||
|
if (!testCases.isEmpty()) {
|
||||||
|
AtomicInteger sort = new AtomicInteger();
|
||||||
|
testCases.forEach(testcase -> {
|
||||||
|
testcase.setUpdateTime(System.currentTimeMillis());
|
||||||
|
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||||
|
testcase.setSort(sort.getAndIncrement());
|
||||||
|
testcase.setId(numIdMap.get(testcase.getNum()));
|
||||||
|
mapper.updateByPrimaryKeySelective(testcase);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sqlSession.flushStatements();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testCaseTemplateExport(HttpServletResponse response) {
|
public void testCaseTemplateExport(HttpServletResponse response) {
|
||||||
try {
|
try {
|
||||||
|
@ -510,6 +588,7 @@ public class TestCaseService {
|
||||||
StringBuilder result = new StringBuilder("");
|
StringBuilder result = new StringBuilder("");
|
||||||
TestCaseList.forEach(t -> {
|
TestCaseList.forEach(t -> {
|
||||||
TestCaseExcelData data = new TestCaseExcelData();
|
TestCaseExcelData data = new TestCaseExcelData();
|
||||||
|
data.setNum(t.getNum());
|
||||||
data.setName(t.getName());
|
data.setName(t.getName());
|
||||||
data.setNodePath(t.getNodePath());
|
data.setNodePath(t.getNodePath());
|
||||||
data.setPriority(t.getPriority());
|
data.setPriority(t.getPriority());
|
||||||
|
@ -533,12 +612,15 @@ public class TestCaseService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < jsonArray.size(); j++) {
|
if (CollectionUtils.isNotEmpty(jsonArray)) {
|
||||||
int num = j + 1;
|
for (int j = 0; j < jsonArray.size(); j++) {
|
||||||
step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\r\n");
|
int num = j + 1;
|
||||||
result.append(num + "." + jsonArray.getJSONObject(j).getString("result") + "\r\n");
|
step.append(num + "." + jsonArray.getJSONObject(j).getString("desc") + "\r\n");
|
||||||
|
result.append(num + "." + jsonArray.getJSONObject(j).getString("result") + "\r\n");
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.setStepDesc(step.toString());
|
data.setStepDesc(step.toString());
|
||||||
data.setStepResult(result.toString());
|
data.setStepResult(result.toString());
|
||||||
step.setLength(0);
|
step.setLength(0);
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
package io.metersphere.track.service;
|
package io.metersphere.track.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
||||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
|
||||||
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
|
||||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
|
||||||
import io.metersphere.api.dto.definition.request.MsThreadGroup;
|
|
||||||
import io.metersphere.api.service.ApiDefinitionExecResultService;
|
import io.metersphere.api.service.ApiDefinitionExecResultService;
|
||||||
import io.metersphere.api.service.ApiDefinitionService;
|
import io.metersphere.api.service.ApiDefinitionService;
|
||||||
import io.metersphere.api.service.ApiTestCaseService;
|
import io.metersphere.api.service.ApiTestCaseService;
|
||||||
import io.metersphere.base.domain.ApiTestCaseExample;
|
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
|
||||||
import io.metersphere.base.domain.TestPlanApiCase;
|
import io.metersphere.base.domain.TestPlanApiCase;
|
||||||
import io.metersphere.base.domain.TestPlanApiCaseExample;
|
import io.metersphere.base.domain.TestPlanApiCaseExample;
|
||||||
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
|
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
|
||||||
|
@ -25,15 +17,16 @@ import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.ServiceUtils;
|
import io.metersphere.commons.utils.ServiceUtils;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
||||||
import org.apache.jmeter.testelement.TestElement;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@ -150,4 +143,11 @@ public class TestPlanApiCaseService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getState(String id) {
|
||||||
|
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||||
|
example.createCriteria().andApiCaseIdEqualTo(id);
|
||||||
|
return testPlanApiCaseMapper.selectByExample(example).get(0).getStatus();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,6 @@ package io.metersphere.track.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
|
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
|
||||||
import io.metersphere.api.jmeter.TestResult;
|
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.*;
|
import io.metersphere.base.mapper.*;
|
||||||
import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper;
|
import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper;
|
||||||
|
@ -21,15 +18,14 @@ import io.metersphere.track.Factory.ReportComponentFactory;
|
||||||
import io.metersphere.track.domain.ReportComponent;
|
import io.metersphere.track.domain.ReportComponent;
|
||||||
import io.metersphere.track.dto.*;
|
import io.metersphere.track.dto.*;
|
||||||
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
|
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
|
||||||
|
import io.metersphere.track.request.report.TestPlanReportSaveRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
||||||
import io.metersphere.track.request.testplan.LoadCaseRequest;
|
import io.metersphere.track.request.testplan.LoadCaseRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.python.bouncycastle.pqc.math.linearalgebra.IntUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
@ -80,36 +76,25 @@ public class TestPlanReportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成测试计划
|
* @param reportId 报告ID(外部传入)
|
||||||
* @param planId
|
* @param planId 测试计划ID
|
||||||
* @param userId
|
* @param userId 用户ID
|
||||||
* @param triggerMode
|
* @param triggerMode 执行方式
|
||||||
|
* @param countResources 是否统计资源-false的话, 下面三个不同资源是否运行则由参数决定。 true的话则由统计后的结果决定
|
||||||
|
* @param apiCaseIsExecuting 接口案例是否执行中
|
||||||
|
* @param scenarioIsExecuting 场景案例是否执行中
|
||||||
|
* @param performanceIsExecuting 性能案例是否执行中
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public TestPlanReport genTestPlanReport(String planId, String userId,String triggerMode) {
|
public TestPlanReport genTestPlanReport(TestPlanReportSaveRequest saveRequest) {
|
||||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId);
|
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(saveRequest.getPlanId());
|
||||||
testPlan.setExecutionTimes(1);
|
testPlan.setExecutionTimes(1);
|
||||||
testPlan.setExecutionTimes(testPlan.getExecutionTimes() + 1);
|
testPlan.setExecutionTimes(testPlan.getExecutionTimes() + 1);
|
||||||
testPlanMapper.updateByPrimaryKey(testPlan);
|
testPlanMapper.updateByPrimaryKey(testPlan);
|
||||||
TestPlanApiCaseExample apiExample = new TestPlanApiCaseExample();
|
|
||||||
apiExample.createCriteria().andTestPlanIdEqualTo(planId);
|
|
||||||
List<String> apiCaseIdList = testPlanApiCaseMapper.selectByExample(apiExample)
|
|
||||||
.stream().map(TestPlanApiCase::getApiCaseId).collect(Collectors.toList());
|
|
||||||
|
|
||||||
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
String testPlanReportID = saveRequest.getReportID();
|
||||||
example.createCriteria().andTestPlanIdEqualTo(planId);
|
|
||||||
List<String> scenarioIdList = testPlanScenarioCaseMapper.selectByExample(example)
|
|
||||||
.stream().map(TestPlanApiScenario::getApiScenarioId).collect(Collectors.toList());
|
|
||||||
|
|
||||||
LoadCaseRequest loadCaseRequest = new LoadCaseRequest();
|
|
||||||
loadCaseRequest.setTestPlanId(planId);
|
|
||||||
loadCaseRequest.setProjectId(testPlan.getProjectId());
|
|
||||||
List<String> performanceIdList = testPlanLoadCaseService.list(loadCaseRequest)
|
|
||||||
.stream().map(TestPlanLoadCaseDTO::getLoadCaseId).collect(Collectors.toList());
|
|
||||||
|
|
||||||
String testPlanReportID = UUID.randomUUID().toString();
|
|
||||||
TestPlanReport testPlanReport = new TestPlanReport();
|
TestPlanReport testPlanReport = new TestPlanReport();
|
||||||
testPlanReport.setTestPlanId(planId);
|
testPlanReport.setTestPlanId(saveRequest.getPlanId());
|
||||||
testPlanReport.setId(testPlanReportID);
|
testPlanReport.setId(testPlanReportID);
|
||||||
testPlanReport.setCreateTime(System.currentTimeMillis());
|
testPlanReport.setCreateTime(System.currentTimeMillis());
|
||||||
testPlanReport.setUpdateTime(System.currentTimeMillis());
|
testPlanReport.setUpdateTime(System.currentTimeMillis());
|
||||||
|
@ -117,41 +102,68 @@ public class TestPlanReportService {
|
||||||
testPlanReport.setName(testPlan.getName() + "-" + DateUtils.getTimeString(new Date()));
|
testPlanReport.setName(testPlan.getName() + "-" + DateUtils.getTimeString(new Date()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
testPlanReport.setTriggerMode(triggerMode);
|
testPlanReport.setTriggerMode(saveRequest.getTriggerMode());
|
||||||
testPlanReport.setCreator(userId);
|
testPlanReport.setCreator(saveRequest.getUserId());
|
||||||
testPlanReport.setStartTime(System.currentTimeMillis());
|
testPlanReport.setStartTime(System.currentTimeMillis());
|
||||||
testPlanReport.setEndTime(System.currentTimeMillis());
|
testPlanReport.setEndTime(System.currentTimeMillis());
|
||||||
if (apiCaseIdList.isEmpty()) {
|
|
||||||
testPlanReport.setIsApiCaseExecuting(false);
|
|
||||||
} else {
|
|
||||||
testPlanReport.setIsApiCaseExecuting(true);
|
|
||||||
}
|
|
||||||
if (scenarioIdList.isEmpty()) {
|
|
||||||
testPlanReport.setIsScenarioExecuting(false);
|
|
||||||
} else {
|
|
||||||
testPlanReport.setIsScenarioExecuting(true);
|
|
||||||
}
|
|
||||||
if (performanceIdList.isEmpty()) {
|
|
||||||
testPlanReport.setIsPerformanceExecuting(false);
|
|
||||||
} else {
|
|
||||||
testPlanReport.setIsPerformanceExecuting(true);
|
|
||||||
}
|
|
||||||
testPlanReport.setPrincipal(testPlan.getPrincipal());
|
|
||||||
|
|
||||||
if(testPlanReport.getIsScenarioExecuting() || testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting()){
|
|
||||||
testPlanReport.setStatus(APITestStatus.Starting.name());
|
|
||||||
}else {
|
|
||||||
testPlanReport.setStatus(APITestStatus.Completed.name());
|
|
||||||
}
|
|
||||||
testPlanReportMapper.insert(testPlanReport);
|
|
||||||
|
|
||||||
TestPlanReportDataWithBLOBs testPlanReportData = new TestPlanReportDataWithBLOBs();
|
TestPlanReportDataWithBLOBs testPlanReportData = new TestPlanReportDataWithBLOBs();
|
||||||
testPlanReportData.setId(UUID.randomUUID().toString());
|
testPlanReportData.setId(UUID.randomUUID().toString());
|
||||||
testPlanReportData.setTestPlanReportId(testPlanReportID);
|
testPlanReportData.setTestPlanReportId(testPlanReportID);
|
||||||
|
|
||||||
testPlanReportData.setApiCaseInfo(JSONArray.toJSONString(apiCaseIdList));
|
if (saveRequest.isCountResources()) {
|
||||||
testPlanReportData.setScenarioInfo(JSONArray.toJSONString(scenarioIdList));
|
TestPlanApiCaseExample apiExample = new TestPlanApiCaseExample();
|
||||||
testPlanReportData.setPerformanceInfo(JSONArray.toJSONString(performanceIdList));
|
apiExample.createCriteria().andTestPlanIdEqualTo(saveRequest.getPlanId());
|
||||||
|
List<String> apiCaseIdList = testPlanApiCaseMapper.selectByExample(apiExample)
|
||||||
|
.stream().map(TestPlanApiCase::getApiCaseId).collect(Collectors.toList());
|
||||||
|
if (apiCaseIdList.isEmpty()) {
|
||||||
|
testPlanReport.setIsApiCaseExecuting(false);
|
||||||
|
} else {
|
||||||
|
testPlanReport.setIsApiCaseExecuting(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
||||||
|
example.createCriteria().andTestPlanIdEqualTo(saveRequest.getPlanId());
|
||||||
|
List<String> scenarioIdList = testPlanScenarioCaseMapper.selectByExample(example)
|
||||||
|
.stream().map(TestPlanApiScenario::getApiScenarioId).collect(Collectors.toList());
|
||||||
|
if (scenarioIdList.isEmpty()) {
|
||||||
|
testPlanReport.setIsScenarioExecuting(false);
|
||||||
|
} else {
|
||||||
|
testPlanReport.setIsScenarioExecuting(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadCaseRequest loadCaseRequest = new LoadCaseRequest();
|
||||||
|
loadCaseRequest.setTestPlanId(saveRequest.getPlanId());
|
||||||
|
loadCaseRequest.setProjectId(testPlan.getProjectId());
|
||||||
|
List<String> performanceIdList = testPlanLoadCaseService.list(loadCaseRequest)
|
||||||
|
.stream().map(TestPlanLoadCaseDTO::getLoadCaseId).collect(Collectors.toList());
|
||||||
|
if (performanceIdList.isEmpty()) {
|
||||||
|
testPlanReport.setIsPerformanceExecuting(false);
|
||||||
|
} else {
|
||||||
|
testPlanReport.setIsPerformanceExecuting(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
testPlanReportData.setApiCaseInfo(JSONArray.toJSONString(apiCaseIdList));
|
||||||
|
testPlanReportData.setScenarioInfo(JSONArray.toJSONString(scenarioIdList));
|
||||||
|
testPlanReportData.setPerformanceInfo(JSONArray.toJSONString(performanceIdList));
|
||||||
|
} else {
|
||||||
|
testPlanReport.setIsApiCaseExecuting(saveRequest.isApiCaseIsExecuting());
|
||||||
|
testPlanReport.setIsScenarioExecuting(saveRequest.isScenarioIsExecuting());
|
||||||
|
testPlanReport.setIsPerformanceExecuting(saveRequest.isPerformanceIsExecuting());
|
||||||
|
|
||||||
|
testPlanReportData.setApiCaseInfo(saveRequest.getApiCaseIdListJSON());
|
||||||
|
testPlanReportData.setScenarioInfo(saveRequest.getScenarioIdListJSON());
|
||||||
|
testPlanReportData.setPerformanceInfo(saveRequest.getPerformanceIdListJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
testPlanReport.setPrincipal(testPlan.getPrincipal());
|
||||||
|
if (testPlanReport.getIsScenarioExecuting() || testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting()) {
|
||||||
|
testPlanReport.setStatus(APITestStatus.Starting.name());
|
||||||
|
} else {
|
||||||
|
testPlanReport.setStatus(APITestStatus.Completed.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
testPlanReportMapper.insert(testPlanReport);
|
||||||
testPlanReportDataMapper.insert(testPlanReportData);
|
testPlanReportDataMapper.insert(testPlanReportData);
|
||||||
|
|
||||||
//更新TestPlan状态,改为进行中
|
//更新TestPlan状态,改为进行中
|
||||||
|
@ -203,9 +215,9 @@ public class TestPlanReportService {
|
||||||
return returnDTO;
|
return returnDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void updateReport(List<String> testPlanReportIdList, String runMode,String triggerMode) {
|
public synchronized void updateReport(List<String> testPlanReportIdList, String runMode, String triggerMode) {
|
||||||
for (String planReportId : testPlanReportIdList) {
|
for (String planReportId : testPlanReportIdList) {
|
||||||
this.countReportByTestPlanReportId(planReportId,runMode,triggerMode);
|
this.countReportByTestPlanReportId(planReportId, runMode, triggerMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,12 +231,11 @@ public class TestPlanReportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @param planReportId 测试计划报告ID
|
||||||
* @param planReportId 测试计划报告ID
|
* @param resourceRunMode 资源的运行模式,triggerMode非Scedule可以为null
|
||||||
* @param resourceRunMode 资源的运行模式,triggerMode非Scedule可以为null
|
* @param triggerMode 触发方式 ReportTriggerMode.enum
|
||||||
* @param triggerMode 触发方式 ReportTriggerMode.enum
|
|
||||||
*/
|
*/
|
||||||
public void countReportByTestPlanReportId(String planReportId,String resourceRunMode,String triggerMode) {
|
public void countReportByTestPlanReportId(String planReportId, String resourceRunMode, String triggerMode) {
|
||||||
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(planReportId);
|
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(planReportId);
|
||||||
|
|
||||||
QueryTestPlanRequest queryTestPlanRequest = new QueryTestPlanRequest();
|
QueryTestPlanRequest queryTestPlanRequest = new QueryTestPlanRequest();
|
||||||
|
@ -233,26 +244,26 @@ public class TestPlanReportService {
|
||||||
String issuesInfo = null;
|
String issuesInfo = null;
|
||||||
|
|
||||||
//因为接口案例的定时任务是单个案例开线程运行, 所以要检查是否都执行完成。全部执行完成时才会进行统一整理
|
//因为接口案例的定时任务是单个案例开线程运行, 所以要检查是否都执行完成。全部执行完成时才会进行统一整理
|
||||||
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(),triggerMode)
|
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), triggerMode)
|
||||||
&&StringUtils.equalsAny(resourceRunMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
&& StringUtils.equalsAny(resourceRunMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
||||||
List<String> statusList = extTestPlanApiCaseMapper.getStatusByTestPlanId(testPlan.getId());
|
List<String> statusList = extTestPlanApiCaseMapper.getStatusByTestPlanId(testPlan.getId());
|
||||||
for (String status : statusList) {
|
for (String status : statusList) {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if(StringUtils.equals(ReportTriggerMode.TEST_PLAN_SCHEDULE.name(),triggerMode)){
|
} else if (StringUtils.equals(ReportTriggerMode.TEST_PLAN_SCHEDULE.name(), triggerMode)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
testPlanReport.setEndTime(System.currentTimeMillis());
|
testPlanReport.setEndTime(System.currentTimeMillis());
|
||||||
testPlanReport.setUpdateTime(System.currentTimeMillis());
|
testPlanReport.setUpdateTime(System.currentTimeMillis());
|
||||||
|
|
||||||
//手动触发的需要保存手工执行的信息
|
//手动触发的需要保存手工执行的信息
|
||||||
int [] componentIndexArr = null;
|
int[] componentIndexArr = null;
|
||||||
if(StringUtils.equals(ReportTriggerMode.MANUAL.name(),triggerMode)){
|
if (StringUtils.equals(ReportTriggerMode.MANUAL.name(), triggerMode)) {
|
||||||
componentIndexArr = new int[]{1,2,3,4,5};
|
componentIndexArr = new int[]{1, 2, 3, 4, 5};
|
||||||
}else {
|
} else {
|
||||||
componentIndexArr = new int[]{1,3,4};
|
componentIndexArr = new int[]{1, 3, 4};
|
||||||
}
|
}
|
||||||
testPlanReport.setComponents(JSONArray.toJSONString(componentIndexArr));
|
testPlanReport.setComponents(JSONArray.toJSONString(componentIndexArr));
|
||||||
|
|
||||||
|
@ -263,23 +274,23 @@ public class TestPlanReportService {
|
||||||
testPlanService.buildScenarioCaseReport(testPlanReport.getTestPlanId(), components);
|
testPlanService.buildScenarioCaseReport(testPlanReport.getTestPlanId(), components);
|
||||||
testPlanService.buildLoadCaseReport(testPlanReport.getTestPlanId(), components);
|
testPlanService.buildLoadCaseReport(testPlanReport.getTestPlanId(), components);
|
||||||
|
|
||||||
if(StringUtils.equals(ReportTriggerMode.MANUAL.name(),triggerMode)){
|
if (StringUtils.equals(ReportTriggerMode.MANUAL.name(), triggerMode)) {
|
||||||
List<Issues> issues = testPlanService.buildFunctionalCaseReport(testPlanReport.getTestPlanId(), components);
|
List<Issues> issues = testPlanService.buildFunctionalCaseReport(testPlanReport.getTestPlanId(), components);
|
||||||
issuesInfo = JSONArray.toJSONString(issues);
|
issuesInfo = JSONArray.toJSONString(issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//只针对定时任务做处理
|
//只针对定时任务做处理
|
||||||
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(),triggerMode)
|
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), triggerMode)
|
||||||
&&StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
&& StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
||||||
testPlanReport.setIsApiCaseExecuting(false);
|
testPlanReport.setIsApiCaseExecuting(false);
|
||||||
} else if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(),triggerMode)
|
} else if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), triggerMode)
|
||||||
&&StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
|
&& StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
|
||||||
testPlanReport.setIsScenarioExecuting(false);
|
testPlanReport.setIsScenarioExecuting(false);
|
||||||
} else if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(),triggerMode)
|
} else if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), triggerMode)
|
||||||
&&StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name())) {
|
&& StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name())) {
|
||||||
testPlanReport.setIsPerformanceExecuting(false);
|
testPlanReport.setIsPerformanceExecuting(false);
|
||||||
}else {
|
} else {
|
||||||
testPlanReport.setIsPerformanceExecuting(false);
|
testPlanReport.setIsPerformanceExecuting(false);
|
||||||
testPlanReport.setIsScenarioExecuting(false);
|
testPlanReport.setIsScenarioExecuting(false);
|
||||||
testPlanReport.setIsApiCaseExecuting(false);
|
testPlanReport.setIsApiCaseExecuting(false);
|
||||||
|
@ -289,12 +300,12 @@ public class TestPlanReportService {
|
||||||
component.afterBuild(testCaseReportMetricDTO);
|
component.afterBuild(testCaseReportMetricDTO);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(),triggerMode)
|
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), triggerMode)
|
||||||
&&StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name())) {
|
&& StringUtils.equals(resourceRunMode, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name())) {
|
||||||
//如果是性能测试作为触发,由于延迟原因可能会出现报告已经结束但是状态还是进行中的状态
|
//如果是性能测试作为触发,由于延迟原因可能会出现报告已经结束但是状态还是进行中的状态
|
||||||
List<TestCaseReportStatusResultDTO> loadResult = testCaseReportMetricDTO.getExecuteResult().getLoadResult();
|
List<TestCaseReportStatusResultDTO> loadResult = testCaseReportMetricDTO.getExecuteResult().getLoadResult();
|
||||||
for (TestCaseReportStatusResultDTO dto: loadResult) {
|
for (TestCaseReportStatusResultDTO dto : loadResult) {
|
||||||
if(StringUtils.equals(dto.getStatus(),TestPlanTestCaseStatus.Underway.name())){
|
if (StringUtils.equals(dto.getStatus(), TestPlanTestCaseStatus.Underway.name())) {
|
||||||
dto.setStatus(TestPlanTestCaseStatus.Pass.name());
|
dto.setStatus(TestPlanTestCaseStatus.Pass.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,49 +322,50 @@ public class TestPlanReportService {
|
||||||
testPlanReportData.setExecuteResult(JSONObject.toJSONString(testCaseReportMetricDTO.getExecuteResult()));
|
testPlanReportData.setExecuteResult(JSONObject.toJSONString(testCaseReportMetricDTO.getExecuteResult()));
|
||||||
testPlanReportData.setFailurTestCases(JSONObject.toJSONString(testCaseReportMetricDTO.getFailureTestCases()));
|
testPlanReportData.setFailurTestCases(JSONObject.toJSONString(testCaseReportMetricDTO.getFailureTestCases()));
|
||||||
testPlanReportData.setModuleExecuteResult(JSONArray.toJSONString(testCaseReportMetricDTO.getModuleExecuteResult()));
|
testPlanReportData.setModuleExecuteResult(JSONArray.toJSONString(testCaseReportMetricDTO.getModuleExecuteResult()));
|
||||||
if(issuesInfo!=null){
|
if (issuesInfo != null) {
|
||||||
testPlanReportData.setIssuesInfo(issuesInfo);
|
testPlanReportData.setIssuesInfo(issuesInfo);
|
||||||
}
|
}
|
||||||
testPlanReportDataMapper.updateByPrimaryKeyWithBLOBs(testPlanReportData);
|
testPlanReportDataMapper.updateByPrimaryKeyWithBLOBs(testPlanReportData);
|
||||||
}
|
}
|
||||||
|
|
||||||
String testPlanStatus = this.getTestPlanReportStatus(testPlanReport,testPlanReportData);
|
String testPlanStatus = this.getTestPlanReportStatus(testPlanReport, testPlanReportData);
|
||||||
testPlanReport.setStatus(testPlanStatus);
|
testPlanReport.setStatus(testPlanStatus);
|
||||||
this.update(testPlanReport);
|
this.update(testPlanReport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算测试计划的状态
|
* 计算测试计划的状态
|
||||||
|
*
|
||||||
* @param testPlanReport
|
* @param testPlanReport
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String getTestPlanReportStatus(TestPlanReport testPlanReport, TestPlanReportDataWithBLOBs testPlanReportData) {
|
private String getTestPlanReportStatus(TestPlanReport testPlanReport, TestPlanReportDataWithBLOBs testPlanReportData) {
|
||||||
String status = TestPlanReportStatus.COMPLETED.name();
|
String status = TestPlanReportStatus.COMPLETED.name();
|
||||||
if(testPlanReport!=null){
|
if (testPlanReport != null) {
|
||||||
if(testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting() || testPlanReport.getIsScenarioExecuting()){
|
if (testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting() || testPlanReport.getIsScenarioExecuting()) {
|
||||||
status = TestPlanReportStatus.RUNNING.name();
|
status = TestPlanReportStatus.RUNNING.name();
|
||||||
}else {
|
} else {
|
||||||
if(testPlanReportData == null){
|
if (testPlanReportData == null) {
|
||||||
String failCaseString = testPlanReportData.getFailurTestCases();
|
String failCaseString = testPlanReportData.getFailurTestCases();
|
||||||
status = TestPlanReportStatus.SUCCESS.name();
|
status = TestPlanReportStatus.SUCCESS.name();
|
||||||
try {
|
try {
|
||||||
JSONObject failurCaseObject = JSONObject.parseObject(failCaseString);
|
JSONObject failurCaseObject = JSONObject.parseObject(failCaseString);
|
||||||
if(failurCaseObject.containsKey("apiTestCases")&&failurCaseObject.getJSONArray("apiTestCases").size()>=0){
|
if (failurCaseObject.containsKey("apiTestCases") && failurCaseObject.getJSONArray("apiTestCases").size() >= 0) {
|
||||||
status = TestPlanReportStatus.FAILED.name();
|
status = TestPlanReportStatus.FAILED.name();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if(failurCaseObject.containsKey("loadTestCases")&&failurCaseObject.getJSONArray("loadTestCases").size()>=0){
|
if (failurCaseObject.containsKey("loadTestCases") && failurCaseObject.getJSONArray("loadTestCases").size() >= 0) {
|
||||||
status = TestPlanReportStatus.FAILED.name();
|
status = TestPlanReportStatus.FAILED.name();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
if(failurCaseObject.containsKey("scenarioTestCases")&&failurCaseObject.getJSONArray("scenarioTestCases").size()>=0){
|
if (failurCaseObject.containsKey("scenarioTestCases") && failurCaseObject.getJSONArray("scenarioTestCases").size() >= 0) {
|
||||||
status = TestPlanReportStatus.FAILED.name();
|
status = TestPlanReportStatus.FAILED.name();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
status = TestPlanReportStatus.FAILED.name();
|
status = TestPlanReportStatus.FAILED.name();
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
status = TestPlanReportStatus.COMPLETED.name();
|
status = TestPlanReportStatus.COMPLETED.name();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,7 +383,7 @@ public class TestPlanReportService {
|
||||||
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
testPlanMapper.updateByPrimaryKeySelective(testPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(StringUtils.equalsAny(report.getTriggerMode(),ReportTriggerMode.SCHEDULE.name())){
|
if (StringUtils.equalsAny(report.getTriggerMode(), ReportTriggerMode.SCHEDULE.name())) {
|
||||||
//发送通知
|
//发送通知
|
||||||
sendMessage(report);
|
sendMessage(report);
|
||||||
}
|
}
|
||||||
|
@ -379,7 +391,7 @@ public class TestPlanReportService {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
}
|
}
|
||||||
testPlanReportMapper.updateByPrimaryKey(report);
|
testPlanReportMapper.updateByPrimaryKey(report);
|
||||||
}
|
}
|
||||||
|
@ -417,7 +429,7 @@ public class TestPlanReportService {
|
||||||
String successfulMailTemplate = "";
|
String successfulMailTemplate = "";
|
||||||
String errfoMailTemplate = "";
|
String errfoMailTemplate = "";
|
||||||
|
|
||||||
if(StringUtils.equals(testPlanReport.getTriggerMode(),ReportTriggerMode.SCHEDULE.name())){
|
if (StringUtils.equals(testPlanReport.getTriggerMode(), ReportTriggerMode.SCHEDULE.name())) {
|
||||||
successfulMailTemplate = "TestPlanSuccessfulNotification";
|
successfulMailTemplate = "TestPlanSuccessfulNotification";
|
||||||
errfoMailTemplate = "TestPlanFailedNotification";
|
errfoMailTemplate = "TestPlanFailedNotification";
|
||||||
}
|
}
|
||||||
|
@ -446,7 +458,7 @@ public class TestPlanReportService {
|
||||||
* @param testPlanReport
|
* @param testPlanReport
|
||||||
* @param performaneReportIDList
|
* @param performaneReportIDList
|
||||||
*/
|
*/
|
||||||
public void updatePerformanceInfo(TestPlanReport testPlanReport, List<String> performaneReportIDList,String triggerMode) {
|
public void updatePerformanceInfo(TestPlanReport testPlanReport, List<String> performaneReportIDList, String triggerMode) {
|
||||||
TestPlanReportDataExample example = new TestPlanReportDataExample();
|
TestPlanReportDataExample example = new TestPlanReportDataExample();
|
||||||
example.createCriteria().andTestPlanReportIdEqualTo(testPlanReport.getId());
|
example.createCriteria().andTestPlanReportIdEqualTo(testPlanReport.getId());
|
||||||
List<TestPlanReportDataWithBLOBs> reportDataList = testPlanReportDataMapper.selectByExampleWithBLOBs(example);
|
List<TestPlanReportDataWithBLOBs> reportDataList = testPlanReportDataMapper.selectByExampleWithBLOBs(example);
|
||||||
|
@ -462,36 +474,36 @@ public class TestPlanReportService {
|
||||||
List<String> updatePerformaneReportIDList = new ArrayList<>(performaneReportIDList);
|
List<String> updatePerformaneReportIDList = new ArrayList<>(performaneReportIDList);
|
||||||
executorService.submit(() -> {
|
executorService.submit(() -> {
|
||||||
//错误数据检查集合。 如果错误数据出现超过20次,则取消该条数据的检查
|
//错误数据检查集合。 如果错误数据出现超过20次,则取消该条数据的检查
|
||||||
Map<String,Integer> errorDataCheckMap = new HashMap<>();
|
Map<String, Integer> errorDataCheckMap = new HashMap<>();
|
||||||
while (performaneReportIDList.size()>0) {
|
while (performaneReportIDList.size() > 0) {
|
||||||
List<String> selectList = new ArrayList<>(performaneReportIDList);
|
List<String> selectList = new ArrayList<>(performaneReportIDList);
|
||||||
for (String loadTestReportId:selectList) {
|
for (String loadTestReportId : selectList) {
|
||||||
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReportId);
|
LoadTestReportWithBLOBs loadTestReportFromDatabase = loadTestReportMapper.selectByPrimaryKey(loadTestReportId);
|
||||||
if(loadTestReportFromDatabase == null){
|
if (loadTestReportFromDatabase == null) {
|
||||||
//检查错误数据
|
//检查错误数据
|
||||||
if(errorDataCheckMap.containsKey(loadTestReportId)){
|
if (errorDataCheckMap.containsKey(loadTestReportId)) {
|
||||||
if(errorDataCheckMap.get(loadTestReportId)>10){
|
if (errorDataCheckMap.get(loadTestReportId) > 10) {
|
||||||
performaneReportIDList.remove(loadTestReportId);
|
performaneReportIDList.remove(loadTestReportId);
|
||||||
}else {
|
} else {
|
||||||
errorDataCheckMap.put(loadTestReportId,errorDataCheckMap.get(loadTestReportId)+1);
|
errorDataCheckMap.put(loadTestReportId, errorDataCheckMap.get(loadTestReportId) + 1);
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
errorDataCheckMap.put(loadTestReportId,1);
|
errorDataCheckMap.put(loadTestReportId, 1);
|
||||||
}
|
}
|
||||||
}else if (StringUtils.equalsAny(loadTestReportFromDatabase.getStatus(),
|
} else if (StringUtils.equalsAny(loadTestReportFromDatabase.getStatus(),
|
||||||
PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) {
|
PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) {
|
||||||
performaneReportIDList.remove(loadTestReportId);
|
performaneReportIDList.remove(loadTestReportId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(performaneReportIDList.isEmpty()){
|
if (performaneReportIDList.isEmpty()) {
|
||||||
for (String string: updatePerformaneReportIDList) {
|
for (String string : updatePerformaneReportIDList) {
|
||||||
TestPlanLoadCaseEventDTO eventDTO = new TestPlanLoadCaseEventDTO();
|
TestPlanLoadCaseEventDTO eventDTO = new TestPlanLoadCaseEventDTO();
|
||||||
eventDTO.setReportId(string);
|
eventDTO.setReportId(string);
|
||||||
eventDTO.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
eventDTO.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||||
eventDTO.setStatus(PerformanceTestStatus.Completed.name());
|
eventDTO.setStatus(PerformanceTestStatus.Completed.name());
|
||||||
this.updatePerformanceTestStatus(eventDTO);
|
this.updatePerformanceTestStatus(eventDTO);
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
try {
|
try {
|
||||||
//查询定时任务是否关闭
|
//查询定时任务是否关闭
|
||||||
Thread.sleep(1000 * 10);// 检查 loadtest 的状态
|
Thread.sleep(1000 * 10);// 检查 loadtest 的状态
|
||||||
|
@ -505,7 +517,7 @@ public class TestPlanReportService {
|
||||||
|
|
||||||
public void updatePerformanceTestStatus(TestPlanLoadCaseEventDTO eventDTO) {
|
public void updatePerformanceTestStatus(TestPlanLoadCaseEventDTO eventDTO) {
|
||||||
List<String> testPlanReportId = extTestPlanMapper.findIdByPerformanceReportId(eventDTO.getReportId());
|
List<String> testPlanReportId = extTestPlanMapper.findIdByPerformanceReportId(eventDTO.getReportId());
|
||||||
this.updateReport(testPlanReportId, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name(),eventDTO.getTriggerMode());
|
this.updateReport(testPlanReportId, ApiRunMode.SCHEDULE_PERFORMANCE_TEST.name(), eventDTO.getTriggerMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(List<String> testPlanReportIdList) {
|
public void delete(List<String> testPlanReportIdList) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import io.metersphere.service.SystemParameterService;
|
||||||
import io.metersphere.track.Factory.ReportComponentFactory;
|
import io.metersphere.track.Factory.ReportComponentFactory;
|
||||||
import io.metersphere.track.domain.ReportComponent;
|
import io.metersphere.track.domain.ReportComponent;
|
||||||
import io.metersphere.track.dto.*;
|
import io.metersphere.track.dto.*;
|
||||||
|
import io.metersphere.track.request.report.TestPlanReportSaveRequest;
|
||||||
import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest;
|
import io.metersphere.track.request.testcase.PlanCaseRelevanceRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
|
||||||
import io.metersphere.track.request.testplan.AddTestPlanRequest;
|
import io.metersphere.track.request.testplan.AddTestPlanRequest;
|
||||||
|
@ -128,6 +129,8 @@ public class TestPlanService {
|
||||||
private ApiScenarioMapper apiScenarioMapper;
|
private ApiScenarioMapper apiScenarioMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private TestCaseTestMapper testCaseTestMapper;
|
private TestCaseTestMapper testCaseTestMapper;
|
||||||
|
@Resource
|
||||||
|
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||||
|
|
||||||
public synchronized String addTestPlan(AddTestPlanRequest testPlan) {
|
public synchronized String addTestPlan(AddTestPlanRequest testPlan) {
|
||||||
if (getTestPlanByName(testPlan.getName()).size() > 0) {
|
if (getTestPlanByName(testPlan.getName()).size() > 0) {
|
||||||
|
@ -173,7 +176,7 @@ public class TestPlanService {
|
||||||
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlan());
|
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlan());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int editTestPlan(TestPlanDTO testPlan) {
|
public int editTestPlan(TestPlanDTO testPlan, Boolean isSendMessage) {
|
||||||
checkTestPlanExist(testPlan);
|
checkTestPlanExist(testPlan);
|
||||||
TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库
|
TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库
|
||||||
testPlan.setUpdateTime(System.currentTimeMillis());
|
testPlan.setUpdateTime(System.currentTimeMillis());
|
||||||
|
@ -211,7 +214,7 @@ public class TestPlanService {
|
||||||
extScheduleMapper.updateNameByResourceID(testPlan.getId(), testPlan.getName());// 同步更新该测试的定时任务的name
|
extScheduleMapper.updateNameByResourceID(testPlan.getId(), testPlan.getName());// 同步更新该测试的定时任务的name
|
||||||
i = testPlanMapper.updateByPrimaryKeyWithBLOBs(testPlan); // 更新
|
i = testPlanMapper.updateByPrimaryKeyWithBLOBs(testPlan); // 更新
|
||||||
}
|
}
|
||||||
if (!StringUtils.isBlank(testPlan.getStatus())) {
|
if (!StringUtils.isBlank(testPlan.getStatus()) && isSendMessage) {
|
||||||
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
|
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
|
||||||
String context = getTestPlanContext(testPlans, NoticeConstants.Event.UPDATE);
|
String context = getTestPlanContext(testPlans, NoticeConstants.Event.UPDATE);
|
||||||
User user = userMapper.selectByPrimaryKey(testPlans.getCreator());
|
User user = userMapper.selectByPrimaryKey(testPlans.getCreator());
|
||||||
|
@ -397,7 +400,7 @@ public class TestPlanService {
|
||||||
testPlanDTO.setId(testPlanId);
|
testPlanDTO.setId(testPlanId);
|
||||||
if(statusList.size() == 0) { // 原先status不是prepare, 但删除所有关联用例的情况
|
if(statusList.size() == 0) { // 原先status不是prepare, 但删除所有关联用例的情况
|
||||||
testPlanDTO.setStatus(TestPlanStatus.Prepare.name());
|
testPlanDTO.setStatus(TestPlanStatus.Prepare.name());
|
||||||
editTestPlan(testPlanDTO);
|
editTestPlan(testPlanDTO, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int passNum = 0, prepareNum = 0, failNum = 0;
|
int passNum = 0, prepareNum = 0, failNum = 0;
|
||||||
|
@ -406,7 +409,7 @@ public class TestPlanService {
|
||||||
|| StringUtils.equals(res, "success")
|
|| StringUtils.equals(res, "success")
|
||||||
|| StringUtils.equals(res, ScenarioStatus.Success.name())) {
|
|| StringUtils.equals(res, ScenarioStatus.Success.name())) {
|
||||||
passNum++;
|
passNum++;
|
||||||
} else if (res == null) {
|
} else if (res == null || StringUtils.equals(TestPlanStatus.Prepare.name(), res)) {
|
||||||
prepareNum++;
|
prepareNum++;
|
||||||
} else {
|
} else {
|
||||||
failNum++;
|
failNum++;
|
||||||
|
@ -414,13 +417,13 @@ public class TestPlanService {
|
||||||
}
|
}
|
||||||
if(passNum == statusList.size()) { // 全部通过
|
if(passNum == statusList.size()) { // 全部通过
|
||||||
testPlanDTO.setStatus(TestPlanStatus.Completed.name());
|
testPlanDTO.setStatus(TestPlanStatus.Completed.name());
|
||||||
this.editTestPlan(testPlanDTO);
|
this.editTestPlan(testPlanDTO, false);
|
||||||
} else if(prepareNum == 0 && passNum + failNum == statusList.size()) { // 已结束
|
} else if(prepareNum == 0 && passNum + failNum == statusList.size()) { // 已结束
|
||||||
testPlanDTO.setStatus(TestPlanStatus.Finished.name());
|
testPlanDTO.setStatus(TestPlanStatus.Finished.name());
|
||||||
editTestPlan(testPlanDTO);
|
editTestPlan(testPlanDTO, false);
|
||||||
} else if(prepareNum != 0) { // 进行中
|
} else if(prepareNum != 0) { // 进行中
|
||||||
testPlanDTO.setStatus(TestPlanStatus.Underway.name());
|
testPlanDTO.setStatus(TestPlanStatus.Underway.name());
|
||||||
editTestPlan(testPlanDTO);
|
editTestPlan(testPlanDTO, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,12 +866,13 @@ public class TestPlanService {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String runScenarioCase(SchedulePlanScenarioExecuteRequest request) {
|
public String runScenarioCase(SchedulePlanScenarioExecuteRequest request) {
|
||||||
|
String returnId = "";
|
||||||
MsTestPlan testPlan = new MsTestPlan();
|
MsTestPlan testPlan = new MsTestPlan();
|
||||||
testPlan.setHashTree(new LinkedList<>());
|
testPlan.setHashTree(new LinkedList<>());
|
||||||
HashTree jmeterHashTree = new ListedHashTree();
|
HashTree jmeterHashTree = new ListedHashTree();
|
||||||
Map<String, Map<String, String>> testPlanScenarioIdMap = request.getTestPlanScenarioIDMap();
|
Map<String, Map<String, String>> testPlanScenarioIdMap = request.getTestPlanScenarioIDMap();
|
||||||
|
|
||||||
for (Map.Entry<String, Map<String, String>> entry : testPlanScenarioIdMap.entrySet()) {
|
for (Map.Entry<String, Map<String, String>> entry : testPlanScenarioIdMap.entrySet()) {
|
||||||
String testPlanID = entry.getKey();
|
|
||||||
Map<String, String> planScenarioIdMap = entry.getValue();
|
Map<String, String> planScenarioIdMap = entry.getValue();
|
||||||
List<ApiScenarioWithBLOBs> apiScenarios = extApiScenarioMapper.selectIds(new ArrayList<>(planScenarioIdMap.keySet()));
|
List<ApiScenarioWithBLOBs> apiScenarios = extApiScenarioMapper.selectIds(new ArrayList<>(planScenarioIdMap.keySet()));
|
||||||
try {
|
try {
|
||||||
|
@ -918,23 +922,27 @@ public class TestPlanService {
|
||||||
scenarios.add(scenario);
|
scenarios.add(scenario);
|
||||||
// 创建场景报告
|
// 创建场景报告
|
||||||
//不同的运行模式,第二个参数入参不同
|
//不同的运行模式,第二个参数入参不同
|
||||||
apiAutomationService.createScenarioReport(group.getName(),
|
APIScenarioReportResult report = apiAutomationService.createScenarioReport(group.getName(),
|
||||||
planScenarioID + ":" + request.getTestPlanReportId(),
|
planScenarioID + ":" + request.getTestPlanReportId(),
|
||||||
item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
||||||
group.setHashTree(scenarios);
|
group.setHashTree(scenarios);
|
||||||
testPlan.getHashTree().add(group);
|
testPlan.getHashTree().add(group);
|
||||||
|
apiScenarioReportMapper.insert(report);
|
||||||
|
returnId = request.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
MSException.throwException(ex.getMessage());
|
MSException.throwException(ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
|
||||||
|
String runMode = ApiRunMode.SCHEDULE_SCENARIO_PLAN.name();
|
||||||
|
// 调用执行方法
|
||||||
|
jMeterService.runDefinition(request.getId(), jmeterHashTree, request.getReportId(), runMode);
|
||||||
}
|
}
|
||||||
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
|
|
||||||
String runMode = ApiRunMode.SCHEDULE_SCENARIO_PLAN.name();
|
return returnId;
|
||||||
// 调用执行方法
|
|
||||||
jMeterService.runDefinition(request.getId(), jmeterHashTree, request.getReportId(), runMode);
|
|
||||||
return request.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(String testPlanID, String projectID, String userId, String triggerMode) {
|
public void run(String testPlanID, String projectID, String userId, String triggerMode) {
|
||||||
|
@ -966,37 +974,21 @@ public class TestPlanService {
|
||||||
|
|
||||||
LogUtil.info("-------------- start testplan schedule ----------");
|
LogUtil.info("-------------- start testplan schedule ----------");
|
||||||
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||||
//首先创建testPlanReport,然后返回的ID重新赋值为resourceID,作为后续的参数
|
|
||||||
TestPlanReport testPlanReport = testPlanReportService.genTestPlanReport(testPlanID, userId, triggerMode);
|
|
||||||
//执行接口案例任务
|
|
||||||
for (Map.Entry<String, String> entry : apiTestCaseIdMap.entrySet()) {
|
|
||||||
String apiCaseID = entry.getKey();
|
|
||||||
String planCaseID = entry.getValue();
|
|
||||||
ApiTestCaseWithBLOBs blobs = apiTestCaseService.get(apiCaseID);
|
|
||||||
//需要更新这里来保证PlanCase的状态能正常更改
|
|
||||||
apiTestCaseService.run(blobs, UUID.randomUUID().toString(), testPlanReport.getId(), testPlanID, ApiRunMode.SCHEDULE_API_PLAN.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
//执行场景执行任务
|
boolean apiCaseIsExcuting = false;
|
||||||
if (!planScenarioIdMap.isEmpty()) {
|
boolean scenarioIsExcuting = false;
|
||||||
LogUtil.info("-------------- testplan schedule ---------- api case over -----------------");
|
boolean performaceIsExcuting = false;
|
||||||
SchedulePlanScenarioExecuteRequest scenarioRequest = new SchedulePlanScenarioExecuteRequest();
|
String apiCaseIdArray = "";
|
||||||
String senarionReportID = UUID.randomUUID().toString();
|
String scenarioCaseIdArray = "";
|
||||||
scenarioRequest.setId(senarionReportID);
|
String performanceCaseIdArray = "";
|
||||||
scenarioRequest.setReportId(senarionReportID);
|
String planReportId = UUID.randomUUID().toString();
|
||||||
scenarioRequest.setProjectId(projectID);
|
//创建测试报告,然后返回的ID重新赋值为resourceID,作为后续的参数
|
||||||
scenarioRequest.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(planReportId,testPlanID,userId,triggerMode,
|
||||||
scenarioRequest.setExecuteType(ExecuteType.Saved.name());
|
apiTestCaseIdMap.size()>0,planScenarioIdMap.size()>0,performanceIdMap.size()>0,
|
||||||
Map<String, Map<String, String>> testPlanScenarioIdMap = new HashMap<>();
|
JSONArray.toJSONString(new ArrayList<>(apiTestCaseIdMap.keySet())),JSONArray.toJSONString(new ArrayList<>(planScenarioIdMap.keySet())),JSONArray.toJSONString(new ArrayList<>(performanceIdMap.values())));
|
||||||
testPlanScenarioIdMap.put(testPlanID, planScenarioIdMap);
|
|
||||||
scenarioRequest.setTestPlanScenarioIDMap(testPlanScenarioIdMap);
|
TestPlanReport testPlanReport = testPlanReportService.genTestPlanReport(saveRequest);
|
||||||
scenarioRequest.setReportUserID(userId);
|
|
||||||
scenarioRequest.setTestPlanID(testPlanID);
|
|
||||||
scenarioRequest.setRunMode(ApiRunMode.SCHEDULE_SCENARIO_PLAN.name());
|
|
||||||
scenarioRequest.setTestPlanReportId(testPlanReport.getId());
|
|
||||||
this.runScenarioCase(scenarioRequest);
|
|
||||||
LogUtil.info("-------------- testplan schedule ---------- scenario case over -----------------");
|
|
||||||
}
|
|
||||||
//执行性能测试任务
|
//执行性能测试任务
|
||||||
List<String> performaneReportIDList = new ArrayList<>();
|
List<String> performaneReportIDList = new ArrayList<>();
|
||||||
for (Map.Entry<String, String> entry : performanceIdMap.entrySet()) {
|
for (Map.Entry<String, String> entry : performanceIdMap.entrySet()) {
|
||||||
|
@ -1016,20 +1008,76 @@ public class TestPlanService {
|
||||||
testPlanLoadCase.setId(performanceRequest.getTestPlanLoadId());
|
testPlanLoadCase.setId(performanceRequest.getTestPlanLoadId());
|
||||||
testPlanLoadCase.setLoadReportId(reportId);
|
testPlanLoadCase.setLoadReportId(reportId);
|
||||||
testPlanLoadCaseService.update(testPlanLoadCase);
|
testPlanLoadCaseService.update(testPlanLoadCase);
|
||||||
|
|
||||||
|
//更新关联处的报告
|
||||||
|
TestPlanLoadCase loadCase = new TestPlanLoadCaseDTO();
|
||||||
|
loadCase.setId(id);
|
||||||
|
loadCase.setLoadReportId(reportId);
|
||||||
|
testPlanLoadCaseService.update(loadCase);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
//更新关联处的报告
|
if(StringUtils.isEmpty(reportId)){
|
||||||
TestPlanLoadCase loadCase = new TestPlanLoadCaseDTO();
|
performaceIsExcuting = false;
|
||||||
loadCase.setId(id);
|
}
|
||||||
loadCase.setLoadReportId(reportId);
|
}
|
||||||
testPlanLoadCaseService.update(loadCase);
|
|
||||||
|
if(performaceIsExcuting){
|
||||||
|
performanceCaseIdArray= JSONArray.toJSONString(new ArrayList<>(performanceIdMap.values()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!performaneReportIDList.isEmpty()) {
|
if (!performaneReportIDList.isEmpty()) {
|
||||||
//性能测试时保存性能测试报告ID,在结果返回时用于捕捉并进行
|
//性能测试时保存性能测试报告ID,在结果返回时用于捕捉并进行
|
||||||
testPlanReportService.updatePerformanceInfo(testPlanReport, performaneReportIDList, ReportTriggerMode.SCHEDULE.name());
|
testPlanReportService.updatePerformanceInfo(testPlanReport, performaneReportIDList, ReportTriggerMode.SCHEDULE.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//执行接口案例任务
|
||||||
|
for (Map.Entry<String, String> entry : apiTestCaseIdMap.entrySet()) {
|
||||||
|
String apiCaseID = entry.getKey();
|
||||||
|
String planCaseID = entry.getValue();
|
||||||
|
ApiTestCaseWithBLOBs blobs = apiTestCaseService.get(apiCaseID);
|
||||||
|
//需要更新这里来保证PlanCase的状态能正常更改
|
||||||
|
apiTestCaseService.run(blobs, UUID.randomUUID().toString(), planReportId, testPlanID, ApiRunMode.SCHEDULE_API_PLAN.name());
|
||||||
|
apiCaseIsExcuting = true;
|
||||||
|
}
|
||||||
|
if(apiCaseIsExcuting){
|
||||||
|
apiCaseIdArray = JSONArray.toJSONString(new ArrayList<>(apiTestCaseIdMap.keySet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行场景执行任务
|
||||||
|
if (!planScenarioIdMap.isEmpty()) {
|
||||||
|
LogUtil.info("-------------- testplan schedule ---------- api case over -----------------");
|
||||||
|
SchedulePlanScenarioExecuteRequest scenarioRequest = new SchedulePlanScenarioExecuteRequest();
|
||||||
|
String senarionReportID = UUID.randomUUID().toString();
|
||||||
|
scenarioRequest.setId(senarionReportID);
|
||||||
|
scenarioRequest.setReportId(senarionReportID);
|
||||||
|
scenarioRequest.setProjectId(projectID);
|
||||||
|
scenarioRequest.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||||
|
scenarioRequest.setExecuteType(ExecuteType.Saved.name());
|
||||||
|
Map<String, Map<String, String>> testPlanScenarioIdMap = new HashMap<>();
|
||||||
|
testPlanScenarioIdMap.put(testPlanID, planScenarioIdMap);
|
||||||
|
scenarioRequest.setTestPlanScenarioIDMap(testPlanScenarioIdMap);
|
||||||
|
scenarioRequest.setReportUserID(userId);
|
||||||
|
scenarioRequest.setTestPlanID(testPlanID);
|
||||||
|
scenarioRequest.setRunMode(ApiRunMode.SCHEDULE_SCENARIO_PLAN.name());
|
||||||
|
scenarioRequest.setTestPlanReportId(planReportId);
|
||||||
|
String scenarioReportID = this.runScenarioCase(scenarioRequest);
|
||||||
|
if(StringUtils.isNotEmpty(scenarioReportID)){
|
||||||
|
scenarioIsExcuting = true;
|
||||||
|
scenarioCaseIdArray= JSONArray.toJSONString(new ArrayList<>(planScenarioIdMap.keySet()));
|
||||||
|
}
|
||||||
|
LogUtil.info("-------------- testplan schedule ---------- scenario case over -----------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//如果report参数和预期不对(某些原因执行失败),则更新report
|
||||||
|
if(saveRequest.isApiCaseIsExecuting() != apiCaseIsExcuting ||saveRequest.isScenarioIsExecuting()!=scenarioIsExcuting ||saveRequest.isPerformanceIsExecuting() != performaceIsExcuting){
|
||||||
|
testPlanReport.setIsApiCaseExecuting(apiCaseIsExcuting);
|
||||||
|
testPlanReport.setIsScenarioExecuting(scenarioIsExcuting);
|
||||||
|
testPlanReport.setIsPerformanceExecuting(performaceIsExcuting);
|
||||||
|
testPlanReportService.update(testPlanReport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
|
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
|
||||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||||
import MsApiScenarioList from "@/business/components/api/automation/scenario/ApiScenarioList";
|
import MsApiScenarioList from "@/business/components/api/automation/scenario/ApiScenarioList";
|
||||||
import {getUUID, downloadFile, checkoutTestManagerOrTestUser} from "@/common/js/utils";
|
import {getUUID, downloadFile, checkoutTestManagerOrTestUser,getCurrentUser} from "@/common/js/utils";
|
||||||
import MsApiScenarioModule from "@/business/components/api/automation/scenario/ApiScenarioModule";
|
import MsApiScenarioModule from "@/business/components/api/automation/scenario/ApiScenarioModule";
|
||||||
import MsEditApiScenario from "./scenario/EditApiScenario";
|
import MsEditApiScenario from "./scenario/EditApiScenario";
|
||||||
|
|
||||||
|
@ -127,7 +127,6 @@
|
||||||
'$route'(to, from) { // 路由改变时,把接口定义界面中的 ctrl s 保存快捷键监听移除
|
'$route'(to, from) { // 路由改变时,把接口定义界面中的 ctrl s 保存快捷键监听移除
|
||||||
if (to.path.indexOf('/api/automation') == -1) {
|
if (to.path.indexOf('/api/automation') == -1) {
|
||||||
if (this.$refs && this.$refs.autoScenarioConfig) {
|
if (this.$refs && this.$refs.autoScenarioConfig) {
|
||||||
// console.log(this.$refs.autoScenarioConfig);
|
|
||||||
this.$refs.autoScenarioConfig.forEach(item => {
|
this.$refs.autoScenarioConfig.forEach(item => {
|
||||||
item.removeListener();
|
item.removeListener();
|
||||||
});
|
});
|
||||||
|
@ -189,7 +188,16 @@
|
||||||
let label = this.$t('api_test.automation.add_scenario');
|
let label = this.$t('api_test.automation.add_scenario');
|
||||||
let name = getUUID().substring(0, 8);
|
let name = getUUID().substring(0, 8);
|
||||||
this.activeName = name;
|
this.activeName = name;
|
||||||
this.tabs.push({label: label, name: name, currentScenario: {apiScenarioModuleId: "", id: getUUID()}});
|
let currentScenario = {
|
||||||
|
status: "Underway", principal: getCurrentUser().id,
|
||||||
|
apiScenarioModuleId: "root", id: getUUID(),
|
||||||
|
modulePath: "/" + this.$t("commons.module_title")
|
||||||
|
};
|
||||||
|
if (this.nodeTree && this.nodeTree.length > 0) {
|
||||||
|
currentScenario.apiScenarioModuleId = this.nodeTree[0].id;
|
||||||
|
currentScenario.modulePath = this.nodeTree[0].path;
|
||||||
|
}
|
||||||
|
this.tabs.push({label: label, name: name, currentScenario: currentScenario});
|
||||||
}
|
}
|
||||||
if (tab.name === 'edit') {
|
if (tab.name === 'edit') {
|
||||||
let label = this.$t('api_test.automation.add_scenario');
|
let label = this.$t('api_test.automation.add_scenario');
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,32 +16,9 @@
|
||||||
ref="nodeTree">
|
ref="nodeTree">
|
||||||
|
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<el-input :placeholder="$t('test_track.module.search')" v-model="condition.filterText" size="small">
|
<ms-search-bar
|
||||||
<template v-slot:append>
|
:condition="condition"
|
||||||
<el-dropdown v-if="!isReadOnly" size="small" split-button type="primary" class="ms-api-button" @click="handleCommand('add-api')"
|
:commands="operators"/>
|
||||||
v-tester
|
|
||||||
@command="handleCommand" trigger="click">
|
|
||||||
<el-button icon="el-icon-folder-add" @click="addScenario"></el-button>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item command="add-scenario">{{ $t('api_test.automation.add_scenario') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="import">{{ $t('api_test.api_import.label') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="exports">
|
|
||||||
<el-dropdown placement="right-start" @command="chooseExportType">
|
|
||||||
<span>
|
|
||||||
{{ $t('report.export') }} <i class="el-icon-arrow-down el-icon--right"></i>
|
|
||||||
</span>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<template>
|
|
||||||
<el-dropdown-item command="export">{{ $t('report.export_to_ms_format') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="exportJmx">{{ $t('report.export') }} JMETER 格式</el-dropdown-item>
|
|
||||||
</template>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
|
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -52,7 +29,7 @@
|
||||||
@refresh="refresh"
|
@refresh="refresh"
|
||||||
ref="basisScenario"/>
|
ref="basisScenario"/>
|
||||||
|
|
||||||
<api-import ref="apiImport" :moduleOptions="moduleOptions" @refreshAll="$emit('refreshAll')"/>
|
<api-import ref="apiImport" :moduleOptions="extendTreeNodes" @refreshAll="$emit('refreshAll')"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -61,13 +38,15 @@
|
||||||
import SelectMenu from "../../../track/common/SelectMenu";
|
import SelectMenu from "../../../track/common/SelectMenu";
|
||||||
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
|
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
|
||||||
import MsNodeTree from "../../../track/common/NodeTree";
|
import MsNodeTree from "../../../track/common/NodeTree";
|
||||||
import {buildNodePath} from "../../definition/model/NodeTree";
|
import {buildNodePath, buildTree} from "../../definition/model/NodeTree";
|
||||||
import ModuleTrashButton from "../../definition/components/module/ModuleTrashButton";
|
import ModuleTrashButton from "../../definition/components/module/ModuleTrashButton";
|
||||||
import ApiImport from "./common/ScenarioImport";
|
import ApiImport from "./common/ScenarioImport";
|
||||||
|
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MsApiScenarioModule',
|
name: 'MsApiScenarioModule',
|
||||||
components: {
|
components: {
|
||||||
|
MsSearchBar,
|
||||||
ApiImport,
|
ApiImport,
|
||||||
ModuleTrashButton,
|
ModuleTrashButton,
|
||||||
MsNodeTree,
|
MsNodeTree,
|
||||||
|
@ -103,8 +82,36 @@
|
||||||
trashEnable: false
|
trashEnable: false
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
|
extendTreeNodes: [],
|
||||||
currentModule: undefined,
|
currentModule: undefined,
|
||||||
moduleOptions: [],
|
moduleOptions: [],
|
||||||
|
operators: [
|
||||||
|
{
|
||||||
|
label: this.$t('api_test.automation.add_scenario'),
|
||||||
|
callback: this.addScenario
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('api_test.api_import.label'),
|
||||||
|
callback: this.handleImport
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('report.export'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: this.$t('report.export_to_ms_format'),
|
||||||
|
callback: () => {
|
||||||
|
this.$emit('exportAPI');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('report.export') + 'JMETER 格式',
|
||||||
|
callback: () => {
|
||||||
|
this.$emit('exportJmx');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -151,14 +158,19 @@
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chooseExportType(e) {
|
handleImport() {
|
||||||
switch (e) {
|
if (this.projectId) {
|
||||||
case "export":
|
this.result = this.$get("/api/automation/module/list/" + this.projectId, response => {
|
||||||
this.$emit('exportAPI');
|
if (response.data != undefined && response.data != null) {
|
||||||
break;
|
this.data = response.data;
|
||||||
case "exportJmx":
|
let moduleOptions = [];
|
||||||
this.$emit('exportJmx');
|
this.data.forEach(node => {
|
||||||
break;
|
buildNodePath(node, {path: ''}, moduleOptions);
|
||||||
|
});
|
||||||
|
this.moduleOptions = moduleOptions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.$refs.apiImport.open(this.currentModule);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
list(projectId) {
|
list(projectId) {
|
||||||
|
@ -176,11 +188,17 @@
|
||||||
this.result = this.$get(url, response => {
|
this.result = this.$get(url, response => {
|
||||||
if (response.data != undefined && response.data != null) {
|
if (response.data != undefined && response.data != null) {
|
||||||
this.data = response.data;
|
this.data = response.data;
|
||||||
let moduleOptions = [];
|
this.extendTreeNodes = [];
|
||||||
this.data.forEach(node => {
|
this.extendTreeNodes.unshift({
|
||||||
buildNodePath(node, {path: ''}, moduleOptions);
|
"id": "root",
|
||||||
|
"name": this.$t('commons.module_title'),
|
||||||
|
"level": 0,
|
||||||
|
"children": this.data,
|
||||||
});
|
});
|
||||||
this.$emit('setModuleOptions', moduleOptions);
|
this.extendTreeNodes.forEach(node => {
|
||||||
|
buildTree(node, {path: ''});
|
||||||
|
});
|
||||||
|
this.$emit('setModuleOptions', this.extendTreeNodes);
|
||||||
this.$emit('setNodeTree', this.data);
|
this.$emit('setNodeTree', this.data);
|
||||||
if (this.$refs.nodeTree) {
|
if (this.$refs.nodeTree) {
|
||||||
this.$refs.nodeTree.filter(this.condition.filterText);
|
this.$refs.nodeTree.filter(this.condition.filterText);
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
<el-form-item :label="$t('test_track.module.module')" prop="apiScenarioModuleId">
|
<el-form-item :label="$t('test_track.module.module')" prop="apiScenarioModuleId">
|
||||||
<el-select class="ms-scenario-input" size="small" v-model="currentScenario.apiScenarioModuleId">
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="currentScenario.apiScenarioModuleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
|
@ -201,7 +199,8 @@
|
||||||
@closePage="close" @unFullScreen="unFullScreen" @showAllBtn="showAllBtn" @runDebug="runDebug" @setProjectEnvMap="setProjectEnvMap" @showScenarioParameters="showScenarioParameters" @setCookieShare="setCookieShare" ref="maximizeHeader"/>
|
@closePage="close" @unFullScreen="unFullScreen" @showAllBtn="showAllBtn" @runDebug="runDebug" @setProjectEnvMap="setProjectEnvMap" @showScenarioParameters="showScenarioParameters" @setCookieShare="setCookieShare" ref="maximizeHeader"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions" :currentScenario="currentScenario" :type="type" ref="maximizeScenario" @openScenario="openScenario"/>
|
<maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions"
|
||||||
|
:currentScenario="currentScenario" :type="type" ref="maximizeScenario" @openScenario="openScenario"/>
|
||||||
</ms-drawer>
|
</ms-drawer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,6 +237,7 @@
|
||||||
import MaximizeScenario from "./maximize/MaximizeScenario";
|
import MaximizeScenario from "./maximize/MaximizeScenario";
|
||||||
import ScenarioHeader from "./maximize/ScenarioHeader";
|
import ScenarioHeader from "./maximize/ScenarioHeader";
|
||||||
import MsDrawer from "../../../common/components/MsDrawer";
|
import MsDrawer from "../../../common/components/MsDrawer";
|
||||||
|
import MsSelectTree from "../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
let jsonPath = require('jsonpath');
|
let jsonPath = require('jsonpath');
|
||||||
export default {
|
export default {
|
||||||
|
@ -260,7 +260,8 @@
|
||||||
EnvPopover,
|
EnvPopover,
|
||||||
MaximizeScenario,
|
MaximizeScenario,
|
||||||
ScenarioHeader,
|
ScenarioHeader,
|
||||||
MsDrawer
|
MsDrawer,
|
||||||
|
MsSelectTree
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -268,6 +269,10 @@
|
||||||
label: "label",
|
label: "label",
|
||||||
children: "hashTree"
|
children: "hashTree"
|
||||||
},
|
},
|
||||||
|
moduleObj: {
|
||||||
|
id: 'id',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
rules: {
|
rules: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
|
@ -442,6 +447,10 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setModule(id,data) {
|
||||||
|
this.currentScenario.apiScenarioModuleId = id;
|
||||||
|
this.currentScenario.modulePath = data.path;
|
||||||
|
},
|
||||||
setHideBtn() {
|
setHideBtn() {
|
||||||
this.isBtnHide = false;
|
this.isBtnHide = false;
|
||||||
},
|
},
|
||||||
|
@ -577,13 +586,14 @@
|
||||||
recursiveSorting(arr, scenarioProjectId) {
|
recursiveSorting(arr, scenarioProjectId) {
|
||||||
for (let i in arr) {
|
for (let i in arr) {
|
||||||
arr[i].index = Number(i) + 1;
|
arr[i].index = Number(i) + 1;
|
||||||
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].hashTree && arr[i].hashTree.length > 1) {
|
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].loopType === "LOOP_COUNT" && arr[i].hashTree && arr[i].hashTree.length > 1) {
|
||||||
arr[i].countController.proceed = true;
|
arr[i].countController.proceed = true;
|
||||||
}
|
}
|
||||||
if (!arr[i].projectId) {
|
if (!arr[i].projectId) {
|
||||||
// 如果自身没有ID并且场景有ID则赋值场景ID,否则赋值当前项目ID
|
// 如果自身没有ID并且场景有ID则赋值场景ID,否则赋值当前项目ID
|
||||||
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
|
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
|
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
|
||||||
this.recursiveSorting(arr[i].hashTree, arr[i].projectId);
|
this.recursiveSorting(arr[i].hashTree, arr[i].projectId);
|
||||||
}
|
}
|
||||||
|
@ -606,6 +616,7 @@
|
||||||
if (!this.scenarioDefinition[i].projectId) {
|
if (!this.scenarioDefinition[i].projectId) {
|
||||||
this.scenarioDefinition[i].projectId = this.projectId;
|
this.scenarioDefinition[i].projectId = this.projectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
|
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
|
||||||
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
|
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
|
||||||
}
|
}
|
||||||
|
@ -753,6 +764,7 @@
|
||||||
if (!sign) {
|
if (!sign) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$refs['currentScenario'].validate((valid) => {
|
this.$refs['currentScenario'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
|
@ -841,15 +853,6 @@
|
||||||
this.expandedNode.splice(this.expandedNode.indexOf(data.resourceId), 1);
|
this.expandedNode.splice(this.expandedNode.indexOf(data.resourceId), 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getPath(id) {
|
|
||||||
if (id === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let path = this.moduleOptions.filter(function (item) {
|
|
||||||
return item.id === id ? item.path : "";
|
|
||||||
});
|
|
||||||
return path[0].path;
|
|
||||||
},
|
|
||||||
setFiles(item, bodyUploadFiles, obj) {
|
setFiles(item, bodyUploadFiles, obj) {
|
||||||
if (item.body) {
|
if (item.body) {
|
||||||
if (item.body.kvs) {
|
if (item.body.kvs) {
|
||||||
|
@ -926,7 +929,7 @@
|
||||||
return bodyUploadFiles;
|
return bodyUploadFiles;
|
||||||
},
|
},
|
||||||
editScenario() {
|
editScenario() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
document.getElementById("inputDelay").focus(); // 保存前在input框自动失焦,以免保存失败
|
document.getElementById("inputDelay").focus(); // 保存前在input框自动失焦,以免保存失败
|
||||||
this.$refs['currentScenario'].validate((valid) => {
|
this.$refs['currentScenario'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
@ -1008,7 +1011,6 @@
|
||||||
setParameter() {
|
setParameter() {
|
||||||
this.currentScenario.stepTotal = this.scenarioDefinition.length;
|
this.currentScenario.stepTotal = this.scenarioDefinition.length;
|
||||||
this.currentScenario.projectId = this.projectId;
|
this.currentScenario.projectId = this.projectId;
|
||||||
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
|
|
||||||
// 构建一个场景对象 方便引用处理
|
// 构建一个场景对象 方便引用处理
|
||||||
let scenario = {
|
let scenario = {
|
||||||
id: this.currentScenario.id,
|
id: this.currentScenario.id,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
width="400"
|
width="400"
|
||||||
|
:disabled="isReadOnly"
|
||||||
@show="showPopover"
|
@show="showPopover"
|
||||||
trigger="click">
|
trigger="click">
|
||||||
<env-select :project-ids="projectIds" :env-map="envMap" @close="visible = false"
|
<env-select :project-ids="projectIds" :env-map="envMap" @close="visible = false"
|
||||||
|
@ -24,6 +25,12 @@ export default {
|
||||||
envMap: Map,
|
envMap: Map,
|
||||||
projectIds: Set,
|
projectIds: Set,
|
||||||
projectList: Array,
|
projectList: Array,
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
<el-option v-for="(environment, index) in pe.envs" :key="index"
|
<el-option v-for="(environment, index) in pe.envs" :key="index"
|
||||||
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
|
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
|
||||||
:value="environment.id"/>
|
:value="environment.id"/>
|
||||||
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig(pe.id)">
|
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig(pe.id, pe['selectEnv'])">
|
||||||
{{ $t('api_test.environment.environment_config') }}
|
{{ $t('api_test.environment.environment_config') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<template v-slot:empty>
|
<template v-slot:empty>
|
||||||
<div class="empty-environment">
|
<div class="empty-environment">
|
||||||
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig(pe.id)">
|
<el-button class="ms-scenario-button" size="mini" type="primary" @click="openEnvironmentConfig(pe.id, pe['selectEnv'])">
|
||||||
{{ $t('api_test.environment.environment_config') }}
|
{{ $t('api_test.environment.environment_config') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -78,12 +78,12 @@ export default {
|
||||||
const project = this.projectList.find(p => p.id === id);
|
const project = this.projectList.find(p => p.id === id);
|
||||||
return project ? project.name : "";
|
return project ? project.name : "";
|
||||||
},
|
},
|
||||||
openEnvironmentConfig(projectId) {
|
openEnvironmentConfig(projectId, envId) {
|
||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
this.$error(this.$t('api_test.select_project'));
|
this.$error(this.$t('api_test.select_project'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$refs.environmentConfig.open(projectId);
|
this.$refs.environmentConfig.open(projectId, envId);
|
||||||
},
|
},
|
||||||
handleConfirm() {
|
handleConfirm() {
|
||||||
let map = new Map();
|
let map = new Map();
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const ELEMENTS = new Map([
|
||||||
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
|
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
|
||||||
['MaxSamplerProxy', ["JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
|
['MaxSamplerProxy', ["JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
|
||||||
['AllSamplerProxy', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"]],
|
['AllSamplerProxy', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"]],
|
||||||
|
['AllCanExecType', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor"]]
|
||||||
])
|
])
|
||||||
|
|
||||||
export const ELEMENT_TYPE = {
|
export const ELEMENT_TYPE = {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
||||||
<ms-select-tree size="small" :data="moduleOptions" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="httpForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('commons.description')" prop="description" style="margin-bottom: 29px">
|
<el-form-item :label="$t('commons.description')" prop="description" style="margin-bottom: 29px">
|
||||||
|
@ -64,6 +64,7 @@
|
||||||
import {createComponent, Request} from "../../../definition/components/jmeter/components";
|
import {createComponent, Request} from "../../../definition/components/jmeter/components";
|
||||||
import {getUUID} from "@/common/js/utils";
|
import {getUUID} from "@/common/js/utils";
|
||||||
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
|
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
|
||||||
|
import {buildTree} from "../../../definition/model/NodeTree";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -83,7 +84,7 @@
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
httpForm: {environmentId: ""},
|
httpForm: {environmentId: "", moduleId: "root"},
|
||||||
moduleOptions: [],
|
moduleOptions: [],
|
||||||
httpVisible: false,
|
httpVisible: false,
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
|
@ -250,13 +251,23 @@
|
||||||
let url = "/api/module/list/" + getCurrentProjectID() + "/" + data.protocol;
|
let url = "/api/module/list/" + getCurrentProjectID() + "/" + data.protocol;
|
||||||
this.result = this.$get(url, response => {
|
this.result = this.$get(url, response => {
|
||||||
if (response.data != undefined && response.data != null) {
|
if (response.data != undefined && response.data != null) {
|
||||||
this.moduleOptions = response.data;
|
let data = response.data;
|
||||||
|
this.moduleOptions = [];
|
||||||
|
this.moduleOptions.unshift({
|
||||||
|
"id": "root",
|
||||||
|
"name": this.$t('commons.module_title'),
|
||||||
|
"level": 0,
|
||||||
|
"children": data,
|
||||||
|
});
|
||||||
|
this.moduleOptions.forEach(node => {
|
||||||
|
buildTree(node, {path: ''});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setModule(id) {
|
setModule(id, data) {
|
||||||
this.httpForm.moduleId = id;
|
this.httpForm.moduleId = id;
|
||||||
//this.reload();
|
this.httpForm.modulePath = data.path;
|
||||||
},
|
},
|
||||||
reload() {
|
reload() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
@ -271,7 +282,7 @@
|
||||||
data.protocol = "DUBBO";
|
data.protocol = "DUBBO";
|
||||||
}
|
}
|
||||||
data.id = getUUID();
|
data.id = getUUID();
|
||||||
this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data};
|
this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data, moduleId: "root"};
|
||||||
this.getMaintainerOptions();
|
this.getMaintainerOptions();
|
||||||
this.list(data);
|
this.list(data);
|
||||||
this.httpVisible = true;
|
this.httpVisible = true;
|
||||||
|
|
|
@ -101,25 +101,25 @@ export default {
|
||||||
|
|
||||||
let requestObj = JSON.parse(item.request);
|
let requestObj = JSON.parse(item.request);
|
||||||
if(requestObj.esbDataStruct != null ){
|
if(requestObj.esbDataStruct != null ){
|
||||||
//ESB接口
|
// //ESB接口
|
||||||
let param = {};
|
// let param = {};
|
||||||
param.request = requestObj;
|
// param.request = requestObj;
|
||||||
param.method = "ESB";
|
// param.method = "ESB";
|
||||||
param.esbDataStruct = JSON.stringify(requestObj.esbDataStruct);
|
// param.esbDataStruct = JSON.stringify(requestObj.esbDataStruct);
|
||||||
if(requestObj.backEsbDataStruct != null){
|
// if(requestObj.backEsbDataStruct != null){
|
||||||
param.backEsbDataStruct = JSON.stringify(requestObj.backEsbDataStruct);
|
// param.backEsbDataStruct = JSON.stringify(requestObj.backEsbDataStruct);
|
||||||
}else{
|
// }else{
|
||||||
param.backEsbDataStruct = "";
|
// param.backEsbDataStruct = "";
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.$post("/api/definition/updateEsbRequest", param, response => {
|
// this.$post("/api/definition/updateEsbRequest", param, response => {
|
||||||
if(response.data!=null){
|
// if(response.data!=null){
|
||||||
if(response.data.request!=null){
|
// if(response.data.request!=null){
|
||||||
item.request = JSON.stringify(response.data.request);
|
// item.request = JSON.stringify(response.data.request);
|
||||||
param.method = "TCP";
|
// param.method = "TCP";
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.$emit('save', apiCases, 'CASE', reference);
|
this.$emit('save', apiCases, 'CASE', reference);
|
||||||
|
|
|
@ -28,9 +28,12 @@
|
||||||
<div class="header-right" @click.stop>
|
<div class="header-right" @click.stop>
|
||||||
<slot name="message"></slot>
|
<slot name="message"></slot>
|
||||||
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn">
|
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn">
|
||||||
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root"/>
|
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root" style="width: 30px"/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<slot name="button"></slot>
|
<slot name="button"></slot>
|
||||||
|
<el-tooltip content="Copy" placement="top">
|
||||||
|
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow" style="padding: 5px"/>
|
||||||
|
</el-tooltip>
|
||||||
<step-extend-btns style="display: contents" :data="data" @copy="copyRow" @remove="remove" @openScenario="openScenario" v-if="showBtn && (!data.disabled || data.root)"/>
|
<step-extend-btns style="display: contents" :data="data" @copy="copyRow" @remove="remove" @openScenario="openScenario" v-if="showBtn && (!data.disabled || data.root)"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,9 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="11">
|
<el-col :span="11">
|
||||||
<el-form-item :label="$t('commons.import_module')">
|
<el-form-item :label="$t('commons.import_module')">
|
||||||
<el-select size="small" v-model="formData.moduleId" class="project-select" clearable>
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="formData.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="!isHar" :label="$t('commons.import_mode')">
|
<el-form-item v-if="!isHar" :label="$t('commons.import_mode')">
|
||||||
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
|
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
|
||||||
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
@ -70,16 +68,17 @@
|
||||||
<script>
|
<script>
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||||
|
import MsSelectTree from "../../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ScenarioImport",
|
name: "ScenarioImport",
|
||||||
components: {MsDialogFooter},
|
components: {MsDialogFooter, MsSelectTree},
|
||||||
props: {
|
props: {
|
||||||
saved: {
|
saved: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
moduleOptions: {}
|
moduleOptions: Array,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -140,7 +139,11 @@
|
||||||
},
|
},
|
||||||
rules: {},
|
rules: {},
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
fileList: []
|
fileList: [],
|
||||||
|
moduleObj: {
|
||||||
|
id: 'id',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
activated() {
|
activated() {
|
||||||
|
@ -257,7 +260,11 @@
|
||||||
this.fileList = [];
|
this.fileList = [];
|
||||||
removeGoBackListener(this.close);
|
removeGoBackListener(this.close);
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
}
|
},
|
||||||
|
setModule(id, data) {
|
||||||
|
this.formData.moduleId = id;
|
||||||
|
this.formData.modulePath = data.path;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<template v-slot:button>
|
<template v-slot:button>
|
||||||
<el-tooltip :content="$t('api_test.run')" placement="top">
|
<el-tooltip :content="$t('api_test.run')" placement="top">
|
||||||
<el-button @click="run" icon="el-icon-video-play" class="ms-btn" size="mini" circle/>
|
<el-button @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -289,6 +289,9 @@
|
||||||
},
|
},
|
||||||
active(item) {
|
active(item) {
|
||||||
this.request.active = !this.request.active;
|
this.request.active = !this.request.active;
|
||||||
|
if (this.node) {
|
||||||
|
this.node.expanded = this.request.active;
|
||||||
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
},
|
},
|
||||||
run() {
|
run() {
|
||||||
|
|
|
@ -105,11 +105,11 @@
|
||||||
remove() {
|
remove() {
|
||||||
this.$emit('remove', this.scenario, this.node);
|
this.$emit('remove', this.scenario, this.node);
|
||||||
},
|
},
|
||||||
active(item) {
|
active() {
|
||||||
if (item && item.active) {
|
if (this.node) {
|
||||||
item.active = !item.active;
|
this.node.expanded = !this.node.expanded;
|
||||||
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
copyRow() {
|
copyRow() {
|
||||||
this.$emit('copyRow', this.scenario, this.node);
|
this.$emit('copyRow', this.scenario, this.node);
|
||||||
|
|
|
@ -61,6 +61,9 @@
|
||||||
},
|
},
|
||||||
active() {
|
active() {
|
||||||
this.request.active = !this.request.active;
|
this.request.active = !this.request.active;
|
||||||
|
if (this.node) {
|
||||||
|
this.node.expanded = this.request.active;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:button>
|
<template v-slot:button>
|
||||||
<el-button @click="runDebug" :tip="$t('api_test.run')" icon="el-icon-video-play" style="background-color: #409EFF;color: white;" size="mini" circle/>
|
<el-button @click="runDebug" :tip="$t('api_test.run')" icon="el-icon-video-play" style="background-color: #409EFF;color: white;padding: 5px" size="mini" circle/>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="controller.loopType==='LOOP_COUNT'" draggable>
|
<div v-if="controller.loopType==='LOOP_COUNT'" draggable>
|
||||||
<el-row>
|
<el-row>
|
||||||
|
@ -246,6 +246,9 @@
|
||||||
},
|
},
|
||||||
active(item) {
|
active(item) {
|
||||||
item.active = !item.active;
|
item.active = !item.active;
|
||||||
|
if (this.node) {
|
||||||
|
this.node.expanded = item.active;
|
||||||
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
},
|
},
|
||||||
changeRadio() {
|
changeRadio() {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<el-icon class="el-icon-more"></el-icon>
|
<el-icon class="el-icon-more"></el-icon>
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item command="copy">复制步骤</el-dropdown-item>
|
<!--<el-dropdown-item command="copy">复制步骤</el-dropdown-item>-->
|
||||||
<el-dropdown-item command="remove" v-tester>删除步骤</el-dropdown-item>
|
<el-dropdown-item command="remove" v-tester>删除步骤</el-dropdown-item>
|
||||||
<el-dropdown-item command="scenarioVar" v-tester v-if="data.type==='scenario'">查看场景变量</el-dropdown-item>
|
<el-dropdown-item command="scenarioVar" v-tester v-if="data.type==='scenario'">查看场景变量</el-dropdown-item>
|
||||||
<el-dropdown-item command="openScenario" v-tester v-if="data.type==='scenario' && data.referenced==='REF'">打开场景</el-dropdown-item>
|
<el-dropdown-item command="openScenario" v-tester v-if="data.type==='scenario' && data.referenced==='REF'">打开场景</el-dropdown-item>
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
this.$emit('remove');
|
this.$emit('remove');
|
||||||
break;
|
break;
|
||||||
case "scenarioVar":
|
case "scenarioVar":
|
||||||
this.$refs.scenarioParameters.open(this.data.variables, this.data.headers, true);
|
this.$refs.scenarioParameters.open(this.data.variables, this.data.headers, this.data.referenced === 'REF');
|
||||||
break;
|
break;
|
||||||
case "openScenario":
|
case "openScenario":
|
||||||
this.getScenario();
|
this.getScenario();
|
||||||
|
|
|
@ -50,39 +50,41 @@
|
||||||
</div>
|
</div>
|
||||||
</ms-aside-container>
|
</ms-aside-container>
|
||||||
|
|
||||||
<ms-main-container v-if="!loading">
|
<ms-main-container v-loading="loading">
|
||||||
<!-- 第一层当前节点内容-->
|
<div v-if="!loading">
|
||||||
<ms-component-config
|
<!-- 第一层当前节点内容-->
|
||||||
:isMax="false"
|
<ms-component-config
|
||||||
:showBtn="false"
|
:isMax="false"
|
||||||
:type="selectedTreeNode.type"
|
:showBtn="false"
|
||||||
:scenario="selectedTreeNode"
|
:type="selectedTreeNode.type"
|
||||||
:response="response"
|
:scenario="selectedTreeNode"
|
||||||
:currentScenario="currentScenario"
|
:response="response"
|
||||||
:currentEnvironmentId="currentEnvironmentId"
|
:currentScenario="currentScenario"
|
||||||
:node="selectedNode"
|
:currentEnvironmentId="currentEnvironmentId"
|
||||||
:project-list="projectList"
|
:node="selectedNode"
|
||||||
:env-map="projectEnvMap"
|
:project-list="projectList"
|
||||||
:draggable="false"
|
:env-map="projectEnvMap"
|
||||||
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick" @refReload="refReload" @openScenario="openScenario"
|
:draggable="false"
|
||||||
v-if="selectedTreeNode && selectedNode"/>
|
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick" @refReload="refReload" @openScenario="openScenario"
|
||||||
<!-- 请求下还有的子步骤-->
|
v-if="selectedTreeNode && selectedNode"/>
|
||||||
<div v-if="selectedTreeNode && selectedTreeNode.hashTree && showNode(selectedTreeNode)">
|
<!-- 请求下还有的子步骤-->
|
||||||
<div v-for="item in selectedTreeNode.hashTree" :key="item.id" class="ms-col-one">
|
<div v-if="selectedTreeNode && selectedTreeNode.hashTree && showNode(selectedTreeNode)">
|
||||||
<ms-component-config
|
<div v-for="item in selectedTreeNode.hashTree" :key="item.id" class="ms-col-one">
|
||||||
:showBtn="false"
|
<ms-component-config
|
||||||
:isMax="false"
|
:showBtn="false"
|
||||||
:type="item.type"
|
:isMax="false"
|
||||||
:scenario="item"
|
:type="item.type"
|
||||||
:response="response"
|
:scenario="item"
|
||||||
:currentScenario="currentScenario"
|
:response="response"
|
||||||
:currentEnvironmentId="currentEnvironmentId"
|
:currentScenario="currentScenario"
|
||||||
:project-list="projectList"
|
:currentEnvironmentId="currentEnvironmentId"
|
||||||
:env-map="projectEnvMap"
|
:project-list="projectList"
|
||||||
:draggable="false"
|
:env-map="projectEnvMap"
|
||||||
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick"
|
:draggable="false"
|
||||||
@refReload="refReload" @openScenario="openScenario"
|
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick"
|
||||||
v-if="selectedTreeNode && selectedNode"/>
|
@refReload="refReload" @openScenario="openScenario"
|
||||||
|
v-if="selectedTreeNode && selectedNode"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
|
@ -474,6 +476,7 @@
|
||||||
}
|
}
|
||||||
this.selectedTreeNode = data;
|
this.selectedTreeNode = data;
|
||||||
this.selectedNode = node;
|
this.selectedNode = node;
|
||||||
|
this.reload();
|
||||||
},
|
},
|
||||||
suggestClick(node) {
|
suggestClick(node) {
|
||||||
this.response = {};
|
this.response = {};
|
||||||
|
@ -493,7 +496,7 @@
|
||||||
recursiveSorting(arr, scenarioProjectId) {
|
recursiveSorting(arr, scenarioProjectId) {
|
||||||
for (let i in arr) {
|
for (let i in arr) {
|
||||||
arr[i].index = Number(i) + 1;
|
arr[i].index = Number(i) + 1;
|
||||||
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].hashTree && arr[i].hashTree.length > 1) {
|
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].loopType === "LOOP_COUNT" && arr[i].hashTree && arr[i].hashTree.length > 1) {
|
||||||
arr[i].countController.proceed = true;
|
arr[i].countController.proceed = true;
|
||||||
}
|
}
|
||||||
if (!arr[i].projectId) {
|
if (!arr[i].projectId) {
|
||||||
|
@ -521,6 +524,7 @@
|
||||||
if (!this.scenarioDefinition[i].projectId) {
|
if (!this.scenarioDefinition[i].projectId) {
|
||||||
this.scenarioDefinition[i].projectId = this.projectId;
|
this.scenarioDefinition[i].projectId = this.projectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
|
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
|
||||||
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
|
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -296,8 +296,12 @@
|
||||||
}
|
}
|
||||||
let api = {
|
let api = {
|
||||||
status: "Underway", method: "GET", userId: getCurrentUser().id,
|
status: "Underway", method: "GET", userId: getCurrentUser().id,
|
||||||
url: "", protocol: this.currentProtocol, environmentId: ""
|
url: "", protocol: this.currentProtocol, environmentId: "", moduleId: 'root', modulePath: "/" + this.$t("commons.module_title")
|
||||||
};
|
};
|
||||||
|
if (this.nodeTree && this.nodeTree.length > 0) {
|
||||||
|
api.moduleId = this.nodeTree[0].id;
|
||||||
|
api.modulePath = this.nodeTree[0].path;
|
||||||
|
}
|
||||||
this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api);
|
this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api);
|
||||||
},
|
},
|
||||||
handleTabClose() {
|
handleTabClose() {
|
||||||
|
|
|
@ -185,9 +185,6 @@ export default {
|
||||||
}
|
}
|
||||||
this.response.body = body;
|
this.response.body = body;
|
||||||
}
|
}
|
||||||
if (this.currentApi.moduleId && this.currentApi.moduleId === "root") {
|
|
||||||
this.currentApi.moduleId = "";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
saveApi(data) {
|
saveApi(data) {
|
||||||
this.setParameters(data);
|
this.setParameters(data);
|
||||||
|
|
|
@ -68,8 +68,8 @@
|
||||||
|
|
||||||
let projectId = "";
|
let projectId = "";
|
||||||
// 如果envMap不存在,是单接口调用
|
// 如果envMap不存在,是单接口调用
|
||||||
if (!this.envMap) {
|
if (!this.envMap || this.envMap.size === 0) {
|
||||||
projectId = getCurrentProjectID();
|
projectId = this.$store.state.projectId;
|
||||||
} else {
|
} else {
|
||||||
// 场景步骤下接口调用
|
// 场景步骤下接口调用
|
||||||
projectId = this.runData.projectId;
|
projectId = this.runData.projectId;
|
||||||
|
|
|
@ -275,19 +275,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addModule(row) {
|
addModule(row) {
|
||||||
let url = '/api/module/getModuleByName/' + getCurrentProjectID() + "/" + this.api.protocol;
|
this.saveApi(row, "root");
|
||||||
this.$get(url, response => {
|
|
||||||
if (response.data) {
|
|
||||||
this.$emit('refreshModule');
|
|
||||||
this.saveApi(row, response.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
saveApi(row, module) {
|
saveApi(row, module) {
|
||||||
let data = this.api;
|
let data = this.api;
|
||||||
data.name = this.apiCase.name;
|
data.name = this.apiCase.name;
|
||||||
data.moduleId = module.id;
|
data.moduleId = module;
|
||||||
data.modulePath = '/bug';
|
data.modulePath ="/"+ this.$t('commons.module_title');
|
||||||
this.setParameters(data);
|
this.setParameters(data);
|
||||||
let bodyFiles = this.getBodyUploadFiles(data);
|
let bodyFiles = this.getBodyUploadFiles(data);
|
||||||
this.$fileUpload("/api/definition/create", null, bodyFiles, data, () => {
|
this.$fileUpload("/api/definition/create", null, bodyFiles, data, () => {
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
this.$error(this.$t('api_test.select_project'));
|
this.$error(this.$t('api_test.select_project'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$refs.environmentConfig.open(this.projectId);
|
this.$refs.environmentConfig.open(this.projectId, this.environmentId);
|
||||||
},
|
},
|
||||||
environmentChange(value) {
|
environmentChange(value) {
|
||||||
for (let i in this.environments) {
|
for (let i in this.environments) {
|
||||||
|
|
|
@ -10,20 +10,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
||||||
<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="basicForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
<div v-if="moduleOptions.length>0">
|
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<el-option :key="0" :value="''">
|
|
||||||
<div style="margin-left: 40px">
|
|
||||||
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
|
|
||||||
</span>
|
|
||||||
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
|
|
||||||
</div>
|
|
||||||
</el-option>
|
|
||||||
</div>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -73,70 +60,79 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {API_STATUS} from "../../model/JsonData";
|
import {API_STATUS} from "../../model/JsonData";
|
||||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||||
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
||||||
|
import MsSelectTree from "../../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsBasisApi",
|
name: "MsBasisApi",
|
||||||
components: {MsInputTag},
|
components: {MsInputTag, MsSelectTree},
|
||||||
props: {
|
props: {
|
||||||
currentProtocol: {
|
currentProtocol: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "HTTP"
|
default: "HTTP"
|
||||||
},
|
},
|
||||||
moduleOptions: Array,
|
moduleOptions: Array,
|
||||||
basisData: {},
|
basisData: {},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getMaintainerOptions();
|
this.getMaintainerOptions();
|
||||||
this.basicForm = this.basisData;
|
this.basicForm = this.basisData;
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
basicForm: {},
|
basicForm: {},
|
||||||
httpVisible: false,
|
httpVisible: false,
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
maintainerOptions: [],
|
maintainerOptions: [],
|
||||||
loading: false,
|
moduleObj: {
|
||||||
rule: {
|
id: 'id',
|
||||||
name: [
|
label: 'name',
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
},
|
||||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
loading: false,
|
||||||
],
|
rule: {
|
||||||
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
name: [
|
||||||
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
|
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||||
|
],
|
||||||
|
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||||
|
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
||||||
|
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
|
||||||
|
},
|
||||||
|
value: API_STATUS[0].id,
|
||||||
|
options: API_STATUS,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMaintainerOptions() {
|
||||||
|
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||||
|
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
||||||
|
this.maintainerOptions = response.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
reload() {
|
||||||
|
this.loading = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setModule(id,data) {
|
||||||
|
this.basicForm.moduleId = id;
|
||||||
|
this.basisData.modulePath = data.path;
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
this.$refs['basicForm'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$emit('callback');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
createModules() {
|
||||||
|
this.$emit("createRootModelInTree");
|
||||||
},
|
},
|
||||||
value: API_STATUS[0].id,
|
|
||||||
options: API_STATUS,
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getMaintainerOptions() {
|
|
||||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
|
||||||
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
|
||||||
this.maintainerOptions = response.data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
reload() {
|
|
||||||
this.loading = true
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
validate() {
|
|
||||||
this.$refs['basicForm'].validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.$emit('callback');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
createModules() {
|
|
||||||
this.$emit("createRootModelInTree");
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -49,20 +49,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
||||||
<el-select class="ms-http-select" size="small" v-model="httpForm.moduleId">
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="httpForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
<div v-if="moduleOptions.length>0">
|
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<el-option :key="0" :value="''">
|
|
||||||
<div style="margin-left: 40px">
|
|
||||||
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
|
|
||||||
</span>
|
|
||||||
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
|
|
||||||
</div>
|
|
||||||
</el-option>
|
|
||||||
</div>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
@ -109,25 +96,26 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
|
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
|
||||||
import MsResponseText from "../response/ResponseText";
|
import MsResponseText from "../response/ResponseText";
|
||||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||||
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
|
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
|
||||||
import {KeyValue} from "../../model/ApiTestModel";
|
import {KeyValue} from "../../model/ApiTestModel";
|
||||||
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
||||||
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
|
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
|
||||||
|
import MsSelectTree from "../../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsAddCompleteHttpApi",
|
name: "MsAddCompleteHttpApi",
|
||||||
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag},
|
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag, MsSelectTree},
|
||||||
data() {
|
data() {
|
||||||
let validateURL = (rule, value, callback) => {
|
let validateURL = (rule, value, callback) => {
|
||||||
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
|
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
|
||||||
callback(this.$t('api_test.definition.request.path_valid_info'));
|
callback(this.$t('api_test.definition.request.path_valid_info'));
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
rule: {
|
rule: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
|
@ -147,6 +135,11 @@ export default {
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
reqOptions: REQ_METHOD,
|
reqOptions: REQ_METHOD,
|
||||||
options: API_STATUS,
|
options: API_STATUS,
|
||||||
|
moduleObj: {
|
||||||
|
id: 'id',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array},
|
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array},
|
||||||
|
@ -190,7 +183,6 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setParameter() {
|
setParameter() {
|
||||||
this.httpForm.modulePath = this.getPath(this.httpForm.moduleId);
|
|
||||||
this.request.path = this.httpForm.path;
|
this.request.path = this.httpForm.path;
|
||||||
this.request.method = this.httpForm.method;
|
this.request.method = this.httpForm.method;
|
||||||
this.httpForm.request.useEnvironment = undefined;
|
this.httpForm.request.useEnvironment = undefined;
|
||||||
|
@ -211,15 +203,6 @@ export default {
|
||||||
createModules() {
|
createModules() {
|
||||||
this.$emit("createRootModelInTree");
|
this.$emit("createRootModelInTree");
|
||||||
},
|
},
|
||||||
getPath(id) {
|
|
||||||
if (id === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let path = this.moduleOptions.filter(function (item) {
|
|
||||||
return item.id === id ? item.path : "";
|
|
||||||
});
|
|
||||||
return path[0].path;
|
|
||||||
},
|
|
||||||
urlChange() {
|
urlChange() {
|
||||||
if (!this.httpForm.path || this.httpForm.path.indexOf('?') === -1) return;
|
if (!this.httpForm.path || this.httpForm.path.indexOf('?') === -1) return;
|
||||||
let url = this.getURL(this.addProtocol(this.httpForm.path));
|
let url = this.getURL(this.addProtocol(this.httpForm.path));
|
||||||
|
@ -248,6 +231,10 @@ export default {
|
||||||
this.$error(this.$t('api_test.request.url_invalid'), 2000);
|
this.$error(this.$t('api_test.request.url_invalid'), 2000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setModule(id,data) {
|
||||||
|
this.httpForm.moduleId = id;
|
||||||
|
this.httpForm.modulePath = data.path;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
|
@ -255,7 +242,6 @@ export default {
|
||||||
if (!this.basisData.environmentId) {
|
if (!this.basisData.environmentId) {
|
||||||
this.basisData.environmentId = "";
|
this.basisData.environmentId = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.httpForm = JSON.parse(JSON.stringify(this.basisData));
|
this.httpForm = JSON.parse(JSON.stringify(this.basisData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item :label="$t('commons.name')" prop="name">
|
<el-form-item :label="$t('commons.name')" prop="name">
|
||||||
<!-- <el-input class="ms-http-input" size="small" v-model="basicForm.name"/>-->
|
<!-- <el-input class="ms-http-input" size="small" v-model="basicForm.name"/>-->
|
||||||
<el-input v-model="basicForm.name" class="ms-http-input" size="small">
|
<el-input v-model="basicForm.name" class="ms-http-input" size="small">
|
||||||
<el-select v-model="basicForm.method" slot="prepend" style="width: 100px" size="small" @change="methodChange">
|
<el-select v-model="basicForm.method" slot="prepend" style="width: 100px" size="small" @change="methodChange">
|
||||||
<el-option v-for="item in methodTypes" :key="item" :label="item" :value="item"/>
|
<el-option v-for="item in methodTypes" :key="item" :label="item" :value="item"/>
|
||||||
|
@ -16,20 +16,22 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
|
||||||
<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">
|
<!--<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">-->
|
||||||
<div v-if="moduleOptions.length>0">
|
<!--<div v-if="moduleOptions.length>0">-->
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
<!--<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>-->
|
||||||
</div>
|
<!--</div>-->
|
||||||
<div v-else>
|
<!--<div v-else>-->
|
||||||
<el-option :key="0" :value="''">
|
<!--<el-option :key="0" :value="''">-->
|
||||||
<div style="margin-left: 40px">
|
<!--<div style="margin-left: 40px">-->
|
||||||
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
|
<!--<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},-->
|
||||||
</span>
|
<!--</span>-->
|
||||||
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
|
<!--<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>-->
|
||||||
</div>
|
<!--</div>-->
|
||||||
</el-option>
|
<!--</el-option>-->
|
||||||
</div>
|
<!--</div>-->
|
||||||
</el-select>
|
<!--</el-select>-->
|
||||||
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="basicForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -79,77 +81,87 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {API_STATUS} from "../../model/JsonData";
|
import {API_STATUS} from "../../model/JsonData";
|
||||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||||
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
||||||
|
import MsSelectTree from "../../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsTcpBasicApi",
|
name: "MsTcpBasicApi",
|
||||||
components: {MsInputTag},
|
components: {MsInputTag, MsSelectTree},
|
||||||
props: {
|
props: {
|
||||||
currentProtocol: {
|
currentProtocol: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "HTTP"
|
default: "HTTP"
|
||||||
},
|
},
|
||||||
moduleOptions: Array,
|
moduleOptions: Array,
|
||||||
methodTypes: Array,
|
methodTypes: Array,
|
||||||
basisData: {},
|
basisData: {},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getMaintainerOptions();
|
this.getMaintainerOptions();
|
||||||
this.basicForm = this.basisData;
|
this.basicForm = this.basisData;
|
||||||
if(this.basicForm.protocol == null){
|
if (this.basicForm.protocol == null) {
|
||||||
this.basicForm.protocol = "TCP";
|
this.basicForm.protocol = "TCP";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
basicForm: {},
|
basicForm: {},
|
||||||
httpVisible: false,
|
httpVisible: false,
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
maintainerOptions: [],
|
maintainerOptions: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
rule: {
|
rule: {
|
||||||
name: [
|
name: [
|
||||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||||
],
|
],
|
||||||
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||||
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
||||||
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
|
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
|
||||||
|
},
|
||||||
|
value: API_STATUS[0].id,
|
||||||
|
options: API_STATUS,
|
||||||
|
moduleObj: {
|
||||||
|
id: 'id',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMaintainerOptions() {
|
||||||
|
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||||
|
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
||||||
|
this.maintainerOptions = response.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
reload() {
|
||||||
|
this.loading = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
this.$refs['basicForm'].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$emit('callback');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
createModules() {
|
||||||
|
this.$emit("createRootModelInTree");
|
||||||
|
},
|
||||||
|
methodChange() {
|
||||||
|
this.$emit("changeApiProtocol", this.basicForm.method);
|
||||||
|
},
|
||||||
|
setModule(id,data) {
|
||||||
|
this.basisData.modulePath = data.path;
|
||||||
|
this.basisData.moduleId = id;
|
||||||
},
|
},
|
||||||
value: API_STATUS[0].id,
|
|
||||||
options: API_STATUS,
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getMaintainerOptions() {
|
|
||||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
|
||||||
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
|
|
||||||
this.maintainerOptions = response.data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
reload() {
|
|
||||||
this.loading = true
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
validate() {
|
|
||||||
this.$refs['basicForm'].validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.$emit('callback');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
createModules() {
|
|
||||||
this.$emit("createRootModelInTree");
|
|
||||||
},
|
|
||||||
methodChange() {
|
|
||||||
this.$emit("changeApiProtocol",this.basicForm.method);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -178,6 +178,10 @@
|
||||||
<div v-else-if="apiInfo.requestBodyParamType == 'JSON-SCHEMA'" style="margin-left: 10px">
|
<div v-else-if="apiInfo.requestBodyParamType == 'JSON-SCHEMA'" style="margin-left: 10px">
|
||||||
<ms-json-code-edit :body="apiInfo.jsonSchemaBody" ref="jsonCodeEdit"/>
|
<ms-json-code-edit :body="apiInfo.jsonSchemaBody" ref="jsonCodeEdit"/>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- <div v-else-if="apiInfo.requestBodyParamType == 'XML'" style="margin-left: 10px">-->
|
||||||
|
<!-- <ms-json-code-edit :body="apiInfo.jsonSchemaBody" ref="jsonCodeEdit"/>-->
|
||||||
|
<!-- <editor v-model="formatData" :lang="mode" @init="editorInit" :theme="theme" :height="height"/>-->
|
||||||
|
<!-- </div>-->
|
||||||
<div v-else class="showDataDiv">
|
<div v-else class="showDataDiv">
|
||||||
<br/>
|
<br/>
|
||||||
<p style="margin: 0px 20px;"
|
<p style="margin: 0px 20px;"
|
||||||
|
@ -423,7 +427,12 @@ export default {
|
||||||
formatRowData(dataType, data) {
|
formatRowData(dataType, data) {
|
||||||
var returnData = data;
|
var returnData = data;
|
||||||
if (data) {
|
if (data) {
|
||||||
returnData = data.replace(/\n/g, '<br>');
|
|
||||||
|
if(dataType === 'XML'){
|
||||||
|
returnData = "<xmp>"+returnData+"</xmp>";
|
||||||
|
}else{
|
||||||
|
returnData = data.replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return returnData;
|
return returnData;
|
||||||
},
|
},
|
||||||
|
@ -643,7 +652,7 @@ export default {
|
||||||
|
|
||||||
if(lastIndex < this.currentApiIndexInApiShowArray){
|
if(lastIndex < this.currentApiIndexInApiShowArray){
|
||||||
//上移
|
//上移
|
||||||
if(this.needAsyncSelect){
|
// if(this.needAsyncSelect){
|
||||||
//进行判断:是否还需要为apiShowArray 增加数据。 由于在当前数据前后最多展现2条数据,
|
//进行判断:是否还需要为apiShowArray 增加数据。 由于在当前数据前后最多展现2条数据,
|
||||||
//可得: apiStepIndex-1- 2 < apiInfoArray,需要添加数据
|
//可得: apiStepIndex-1- 2 < apiInfoArray,需要添加数据
|
||||||
let dataIndex = this.apiStepIndex -3;
|
let dataIndex = this.apiStepIndex -3;
|
||||||
|
@ -657,11 +666,11 @@ export default {
|
||||||
if(this.apiShowArray.length > (this.currentApiIndexInApiShowArray+3)){
|
if(this.apiShowArray.length > (this.currentApiIndexInApiShowArray+3)){
|
||||||
this.apiShowArray.pop();
|
this.apiShowArray.pop();
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
this.apiStepIndex --;
|
this.apiStepIndex --;
|
||||||
}else if(lastIndex > this.currentApiIndexInApiShowArray){
|
}else if(lastIndex > this.currentApiIndexInApiShowArray){
|
||||||
//下滚
|
//下滚
|
||||||
if(this.needAsyncSelect){
|
// if(this.needAsyncSelect){
|
||||||
//进行判断:是否还需要为apiShowArray 增加数据。 由于在当前数据前后最多展现2条数据,
|
//进行判断:是否还需要为apiShowArray 增加数据。 由于在当前数据前后最多展现2条数据,
|
||||||
//可得: apiStepIndex+1+ 2 < apiInfoArray,需要添加数据
|
//可得: apiStepIndex+1+ 2 < apiInfoArray,需要添加数据
|
||||||
let dataIndex = this.apiStepIndex +3;
|
let dataIndex = this.apiStepIndex +3;
|
||||||
|
@ -678,7 +687,7 @@ export default {
|
||||||
let itemHeight = this.$refs.apiDocInfoDivItem[0].offsetHeight+10;
|
let itemHeight = this.$refs.apiDocInfoDivItem[0].offsetHeight+10;
|
||||||
this.$refs.apiDocInfoDiv.scrollTop = (apiDocDivScrollTop-itemHeight);
|
this.$refs.apiDocInfoDiv.scrollTop = (apiDocDivScrollTop-itemHeight);
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
this.apiStepIndex ++;
|
this.apiStepIndex ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,13 +46,15 @@
|
||||||
icon: 'el-icon-delete',
|
icon: 'el-icon-delete',
|
||||||
func: this.deleteEnvironment
|
func: this.deleteEnvironment
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
selectEnvironmentId: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
open: function (projectId) {
|
open: function (projectId, envId) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.projectId = projectId;
|
this.projectId = projectId;
|
||||||
|
this.selectEnvironmentId = envId;
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
listenGoBack(this.close);
|
listenGoBack(this.close);
|
||||||
},
|
},
|
||||||
|
@ -114,7 +116,16 @@
|
||||||
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
|
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
|
||||||
this.environments = response.data;
|
this.environments = response.data;
|
||||||
if (this.environments.length > 0) {
|
if (this.environments.length > 0) {
|
||||||
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
if (this.selectEnvironmentId) {
|
||||||
|
const index = this.environments.findIndex(e => e.id === this.selectEnvironmentId);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.$refs.environmentItems.itemSelected(index, this.environments[index]);
|
||||||
|
} else {
|
||||||
|
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let item = new Environment({
|
let item = new Environment({
|
||||||
projectId: this.projectId
|
projectId: this.projectId
|
||||||
|
|
|
@ -25,12 +25,10 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="11">
|
<el-col :span="11">
|
||||||
<el-form-item :label="$t('commons.import_module')" prop="moduleId">
|
<el-form-item :label="$t('commons.import_module')" prop="moduleId">
|
||||||
<el-select size="small" v-model="formData.moduleId" class="project-select" clearable>
|
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="formData.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
|
||||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="!isScenarioModel&&showImportModel" :label="$t('commons.import_mode')" prop="modeId">
|
<el-form-item v-if="!isScenarioModel&&showImportModel" :label="$t('commons.import_mode')" prop="modeId">
|
||||||
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
|
<el-select size="small" v-model="formData.modeId" clearable style="width: 100%">
|
||||||
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -59,7 +57,7 @@
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="swaggerSynchronization"
|
v-model="swaggerSynchronization"
|
||||||
@click.native="scheduleEdit"
|
@click.native="scheduleEdit"
|
||||||
>
|
>
|
||||||
</el-switch>
|
</el-switch>
|
||||||
<span style="color: #6C317C;cursor: pointer;font-weight: bold;margin-left: 10px" @click="scheduleEditByText">{{$t('api_test.api_import.timing_synchronization')}}</span>
|
<span style="color: #6C317C;cursor: pointer;font-weight: bold;margin-left: 10px" @click="scheduleEditByText">{{$t('api_test.api_import.timing_synchronization')}}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -98,337 +96,338 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||||
import ScheduleImport from "@/business/components/api/definition/components/import/ImportScheduleEdit";
|
import ScheduleImport from "@/business/components/api/definition/components/import/ImportScheduleEdit";
|
||||||
|
import MsSelectTree from "../../../../common/select-tree/SelectTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ApiImport",
|
name: "ApiImport",
|
||||||
components: {ScheduleImport, MsDialogFooter},
|
components: {ScheduleImport, MsDialogFooter, MsSelectTree},
|
||||||
props: {
|
props: {
|
||||||
saved: {
|
saved: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
|
||||||
moduleOptions: {},
|
|
||||||
propotal:String,
|
|
||||||
model: {
|
|
||||||
type: String,
|
|
||||||
default: 'definition'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible: false,
|
|
||||||
swaggerUrlEnable: false,
|
|
||||||
swaggerSynchronization: false,
|
|
||||||
showEnvironmentSelect: true,
|
|
||||||
modeOptions: [{
|
|
||||||
id: 'fullCoverage',
|
|
||||||
name: this.$t('commons.cover')
|
|
||||||
},
|
},
|
||||||
{
|
moduleOptions: Array,
|
||||||
id: 'incrementalMerge',
|
propotal: String,
|
||||||
name: this.$t('commons.not_cover')
|
model: {
|
||||||
}],
|
type: String,
|
||||||
protocol: "",
|
default: 'definition'
|
||||||
platforms: [
|
}
|
||||||
{
|
},
|
||||||
name: 'MeterSphere',
|
data() {
|
||||||
value: 'Metersphere',
|
return {
|
||||||
tip: this.$t('api_test.api_import.ms_tip'),
|
visible: false,
|
||||||
exportTip: this.$t('api_test.api_import.ms_export_tip'),
|
swaggerUrlEnable: false,
|
||||||
|
swaggerSynchronization: false,
|
||||||
|
showEnvironmentSelect: true,
|
||||||
|
moduleObj: {
|
||||||
|
id: 'id',
|
||||||
|
label: 'name',
|
||||||
|
},
|
||||||
|
modeOptions: [{
|
||||||
|
id: 'fullCoverage',
|
||||||
|
name: this.$t('commons.cover')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'incrementalMerge',
|
||||||
|
name: this.$t('commons.not_cover')
|
||||||
|
}],
|
||||||
|
protocol: "",
|
||||||
|
platforms: [
|
||||||
|
{
|
||||||
|
name: 'MeterSphere',
|
||||||
|
value: 'Metersphere',
|
||||||
|
tip: this.$t('api_test.api_import.ms_tip'),
|
||||||
|
exportTip: this.$t('api_test.api_import.ms_export_tip'),
|
||||||
|
suffixes: new Set(['json'])
|
||||||
|
},
|
||||||
|
],
|
||||||
|
postmanPlanform: {
|
||||||
|
name: 'Postman',
|
||||||
|
value: 'Postman',
|
||||||
|
tip: this.$t('api_test.api_import.postman_tip'),
|
||||||
|
exportTip: this.$t('api_test.api_import.post_export_tip'),
|
||||||
suffixes: new Set(['json'])
|
suffixes: new Set(['json'])
|
||||||
},
|
},
|
||||||
],
|
swaggerPlanform: {
|
||||||
postmanPlanform:{
|
name: 'Swagger',
|
||||||
name: 'Postman',
|
value: 'Swagger2',
|
||||||
value: 'Postman',
|
tip: this.$t('api_test.api_import.swagger_tip'),
|
||||||
tip: this.$t('api_test.api_import.postman_tip'),
|
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
|
||||||
exportTip: this.$t('api_test.api_import.post_export_tip'),
|
suffixes: new Set(['json'])
|
||||||
suffixes: new Set(['json'])
|
},
|
||||||
},
|
harPlanform: {
|
||||||
swaggerPlanform:{
|
name: 'HAR',
|
||||||
name: 'Swagger',
|
value: 'Har',
|
||||||
value: 'Swagger2',
|
tip: this.$t('api_test.api_import.har_tip'),
|
||||||
tip: this.$t('api_test.api_import.swagger_tip'),
|
exportTip: this.$t('api_test.api_import.har_export_tip'),
|
||||||
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
|
suffixes: new Set(['har'])
|
||||||
suffixes: new Set(['json'])
|
},
|
||||||
},
|
esbPlanform: {
|
||||||
harPlanform:{
|
name: 'ESB',
|
||||||
name: 'HAR',
|
value: 'ESB',
|
||||||
value: 'Har',
|
tip: this.$t('api_test.api_import.esb_tip'),
|
||||||
tip: this.$t('api_test.api_import.har_tip'),
|
exportTip: this.$t('api_test.api_import.esb_export_tip'),
|
||||||
exportTip: this.$t('api_test.api_import.har_export_tip'),
|
suffixes: new Set(['xlsx', 'xls'])
|
||||||
suffixes: new Set(['har'])
|
},
|
||||||
},
|
selectedPlatform: {},
|
||||||
esbPlanform : {
|
selectedPlatformValue: 'Metersphere',
|
||||||
name: 'ESB',
|
result: {},
|
||||||
value: 'ESB',
|
projects: [],
|
||||||
tip: this.$t('api_test.api_import.esb_tip'),
|
environments: [],
|
||||||
exportTip: this.$t('api_test.api_import.esb_export_tip'),
|
useEnvironment: false,
|
||||||
suffixes: new Set(['xlsx','xls'])
|
formData: {
|
||||||
},
|
file: undefined,
|
||||||
selectedPlatform: {},
|
swaggerUrl: '',
|
||||||
selectedPlatformValue: 'Metersphere',
|
modeId: this.$t('commons.not_cover'),
|
||||||
result: {},
|
moduleId: '',
|
||||||
projects: [],
|
},
|
||||||
environments: [],
|
rules: {
|
||||||
useEnvironment: false,
|
modeId: [
|
||||||
formData: {
|
{required: true, message: this.$t('commons.please_select_import_mode'), trigger: 'change'},
|
||||||
file: undefined,
|
],
|
||||||
swaggerUrl: '',
|
},
|
||||||
modeId: this.$t('commons.not_cover'),
|
currentModule: {},
|
||||||
moduleId: '',
|
fileList: []
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
modeId: [
|
|
||||||
{required: true, message: this.$t('commons.please_select_import_mode'), trigger: 'change'},
|
|
||||||
],
|
|
||||||
moduleId: [
|
|
||||||
{required: true, message: this.$t('commons.please_select_import_module'), trigger: 'change'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
currentModule: {},
|
|
||||||
fileList: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
activated() {
|
|
||||||
this.selectedPlatform = this.platforms[0];
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.platforms.push(this.postmanPlanform);
|
|
||||||
this.platforms.push(this.swaggerPlanform);
|
|
||||||
this.platforms.push(this.harPlanform);
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
selectedPlatformValue() {
|
|
||||||
for (let i in this.platforms) {
|
|
||||||
if (this.platforms[i].value === this.selectedPlatformValue) {
|
|
||||||
this.selectedPlatform = this.platforms[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
propotal(){
|
activated() {
|
||||||
let postmanIndex = this.platforms.indexOf(this.postmanPlanform);
|
this.selectedPlatform = this.platforms[0];
|
||||||
let swaggerPlanformIndex = this.platforms.indexOf(this.swaggerPlanform);
|
|
||||||
let harPlanformIndex = this.platforms.indexOf(this.harPlanform);
|
|
||||||
let esbPlanformIndex = this.platforms.indexOf(this.esbPlanform);
|
|
||||||
if(postmanIndex>=0){
|
|
||||||
this.platforms.splice(this.platforms.indexOf(this.postmanPlanform),1);
|
|
||||||
}
|
|
||||||
if(swaggerPlanformIndex>=0){
|
|
||||||
this.platforms.splice(this.platforms.indexOf(this.swaggerPlanform),1);
|
|
||||||
}
|
|
||||||
if(harPlanformIndex>=0){
|
|
||||||
this.platforms.splice(this.platforms.indexOf(this.harPlanform),1);
|
|
||||||
}
|
|
||||||
if(esbPlanformIndex>=0){
|
|
||||||
this.platforms.splice(this.platforms.indexOf(this.esbPlanform),1);
|
|
||||||
}
|
|
||||||
if(this.propotal === 'TCP'){
|
|
||||||
this.platforms.push(this.esbPlanform);
|
|
||||||
return true;
|
|
||||||
}else if(this.propotal === 'HTTP'){
|
|
||||||
this.platforms.push(this.postmanPlanform);
|
|
||||||
this.platforms.push(this.swaggerPlanform);
|
|
||||||
this.platforms.push(this.harPlanform);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isSwagger2() {
|
|
||||||
return this.selectedPlatformValue === 'Swagger2';
|
|
||||||
},
|
},
|
||||||
showImportModel() {
|
created() {
|
||||||
return this.selectedPlatformValue != 'Har' && this.selectedPlatformValue != 'ESB';
|
this.platforms.push(this.postmanPlanform);
|
||||||
|
this.platforms.push(this.swaggerPlanform);
|
||||||
|
this.platforms.push(this.harPlanform);
|
||||||
},
|
},
|
||||||
showTemplate() {
|
watch: {
|
||||||
return this.selectedPlatformValue === 'ESB';
|
selectedPlatformValue() {
|
||||||
},
|
for (let i in this.platforms) {
|
||||||
isScenarioModel() {
|
if (this.platforms[i].value === this.selectedPlatformValue) {
|
||||||
return this.model === 'scenario';
|
this.selectedPlatform = this.platforms[i];
|
||||||
},
|
break;
|
||||||
projectId() {
|
|
||||||
return this.$store.state.projectId
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
scheduleEdit() {
|
|
||||||
if (!this.formData.swaggerUrl) {
|
|
||||||
this.$warning(this.$t('commons.please_fill_path'));
|
|
||||||
this.swaggerSynchronization = !this.swaggerSynchronization
|
|
||||||
} else {
|
|
||||||
if (this.swaggerSynchronization) {
|
|
||||||
this.$refs.scheduleEdit.open(this.buildParam());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scheduleEditByText(){
|
|
||||||
this.$refs.scheduleEdit.open(this.buildParam());
|
|
||||||
},
|
|
||||||
open(module) {
|
|
||||||
this.currentModule = module;
|
|
||||||
this.visible = true;
|
|
||||||
listenGoBack(this.close);
|
|
||||||
|
|
||||||
},
|
|
||||||
upload(file) {
|
|
||||||
this.formData.file = file.file;
|
|
||||||
},
|
|
||||||
handleExceed(files, fileList) {
|
|
||||||
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
|
||||||
},
|
|
||||||
handleRemove(file, fileList) {
|
|
||||||
this.formData.file = undefined;
|
|
||||||
},
|
|
||||||
downloadTemplate(){
|
|
||||||
if(this.selectedPlatformValue == "ESB"){
|
|
||||||
this.$fileDownload('/api/definition/export/esbExcelTemplate');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uploadValidate(file, fileList) {
|
|
||||||
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
|
|
||||||
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
|
|
||||||
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (file.size / 1024 / 1024 > 20) {
|
|
||||||
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
save() {
|
|
||||||
this.$refs.form.validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEnable)) && !this.formData.file) {
|
|
||||||
this.$warning(this.$t('commons.please_upload'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
let url = '/api/definition/import';
|
}
|
||||||
if (this.isScenarioModel) {
|
},
|
||||||
url = '/api/automation/import';
|
propotal() {
|
||||||
}
|
let postmanIndex = this.platforms.indexOf(this.postmanPlanform);
|
||||||
let param = this.buildParam();
|
let swaggerPlanformIndex = this.platforms.indexOf(this.swaggerPlanform);
|
||||||
this.result = this.$fileUpload(url, param.file, null, this.buildParam(), response => {
|
let harPlanformIndex = this.platforms.indexOf(this.harPlanform);
|
||||||
let res = response.data;
|
let esbPlanformIndex = this.platforms.indexOf(this.esbPlanform);
|
||||||
this.$success(this.$t('test_track.case.import.success'));
|
if (postmanIndex >= 0) {
|
||||||
this.visible = false;
|
this.platforms.splice(this.platforms.indexOf(this.postmanPlanform), 1);
|
||||||
this.$emit('refresh', res);
|
}
|
||||||
});
|
if (swaggerPlanformIndex >= 0) {
|
||||||
} else {
|
this.platforms.splice(this.platforms.indexOf(this.swaggerPlanform), 1);
|
||||||
|
}
|
||||||
|
if (harPlanformIndex >= 0) {
|
||||||
|
this.platforms.splice(this.platforms.indexOf(this.harPlanform), 1);
|
||||||
|
}
|
||||||
|
if (esbPlanformIndex >= 0) {
|
||||||
|
this.platforms.splice(this.platforms.indexOf(this.esbPlanform), 1);
|
||||||
|
}
|
||||||
|
if (this.propotal === 'TCP') {
|
||||||
|
this.platforms.push(this.esbPlanform);
|
||||||
|
return true;
|
||||||
|
} else if (this.propotal === 'HTTP') {
|
||||||
|
this.platforms.push(this.postmanPlanform);
|
||||||
|
this.platforms.push(this.swaggerPlanform);
|
||||||
|
this.platforms.push(this.harPlanform);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
buildParam() {
|
computed: {
|
||||||
let param = {};
|
isSwagger2() {
|
||||||
Object.assign(param, this.formData);
|
return this.selectedPlatformValue === 'Swagger2';
|
||||||
param.platform = this.selectedPlatformValue;
|
},
|
||||||
param.saved = this.saved;
|
showImportModel() {
|
||||||
param.model = this.model;
|
return this.selectedPlatformValue != 'Har' && this.selectedPlatformValue != 'ESB';
|
||||||
if (this.currentModule) {
|
},
|
||||||
param.moduleId = this.formData.moduleId
|
showTemplate() {
|
||||||
this.moduleOptions.filter(item => {
|
return this.selectedPlatformValue === 'ESB';
|
||||||
if (item.id === this.formData.moduleId) {
|
},
|
||||||
param.modulePath = item.path
|
isScenarioModel() {
|
||||||
|
return this.model === 'scenario';
|
||||||
|
},
|
||||||
|
projectId() {
|
||||||
|
return this.$store.state.projectId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
scheduleEdit() {
|
||||||
|
if (!this.formData.swaggerUrl) {
|
||||||
|
this.$warning(this.$t('commons.please_fill_path'));
|
||||||
|
this.swaggerSynchronization = !this.swaggerSynchronization
|
||||||
|
} else {
|
||||||
|
if (this.swaggerSynchronization) {
|
||||||
|
this.$refs.scheduleEdit.open(this.buildParam());
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
param.modeId = this.formData.modeId
|
},
|
||||||
|
scheduleEditByText() {
|
||||||
|
this.$refs.scheduleEdit.open(this.buildParam());
|
||||||
|
},
|
||||||
|
open(module) {
|
||||||
|
this.currentModule = module;
|
||||||
|
this.visible = true;
|
||||||
|
listenGoBack(this.close);
|
||||||
|
|
||||||
|
},
|
||||||
|
upload(file) {
|
||||||
|
this.formData.file = file.file;
|
||||||
|
},
|
||||||
|
handleExceed(files, fileList) {
|
||||||
|
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
|
||||||
|
},
|
||||||
|
handleRemove(file, fileList) {
|
||||||
|
this.formData.file = undefined;
|
||||||
|
},
|
||||||
|
downloadTemplate() {
|
||||||
|
if (this.selectedPlatformValue == "ESB") {
|
||||||
|
this.$fileDownload('/api/definition/export/esbExcelTemplate');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uploadValidate(file, fileList) {
|
||||||
|
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||||
|
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
|
||||||
|
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (file.size / 1024 / 1024 > 20) {
|
||||||
|
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEnable)) && !this.formData.file) {
|
||||||
|
this.$warning(this.$t('commons.please_upload'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let url = '/api/definition/import';
|
||||||
|
if (this.isScenarioModel) {
|
||||||
|
url = '/api/automation/import';
|
||||||
|
}
|
||||||
|
let param = this.buildParam();
|
||||||
|
this.result = this.$fileUpload(url, param.file, null, this.buildParam(), response => {
|
||||||
|
let res = response.data;
|
||||||
|
this.$success(this.$t('test_track.case.import.success'));
|
||||||
|
this.visible = false;
|
||||||
|
this.$emit('refresh', res);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setModule(id, data) {
|
||||||
|
this.formData.moduleId = id;
|
||||||
|
this.formData.modulePath = data.path;
|
||||||
|
},
|
||||||
|
buildParam() {
|
||||||
|
let param = {};
|
||||||
|
Object.assign(param, this.formData);
|
||||||
|
param.platform = this.selectedPlatformValue;
|
||||||
|
param.saved = this.saved;
|
||||||
|
param.model = this.model;
|
||||||
|
if (this.currentModule) {
|
||||||
|
param.moduleId = this.formData.moduleId
|
||||||
|
param.modeId = this.formData.modeId
|
||||||
|
}
|
||||||
|
param.projectId = this.projectId;
|
||||||
|
if (!this.swaggerUrlEnable) {
|
||||||
|
param.swaggerUrl = undefined;
|
||||||
|
}
|
||||||
|
return param;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.formData = {
|
||||||
|
file: undefined,
|
||||||
|
swaggerUrl: ''
|
||||||
|
};
|
||||||
|
this.fileList = [];
|
||||||
|
removeGoBackListener(this.close);
|
||||||
|
this.visible = false;
|
||||||
}
|
}
|
||||||
param.projectId = this.projectId;
|
|
||||||
if (!this.swaggerUrlEnable) {
|
|
||||||
param.swaggerUrl = undefined;
|
|
||||||
}
|
|
||||||
return param;
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.formData = {
|
|
||||||
file: undefined,
|
|
||||||
swaggerUrl: ''
|
|
||||||
};
|
|
||||||
this.fileList = [];
|
|
||||||
removeGoBackListener(this.close);
|
|
||||||
this.visible = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.api-import >>> .el-dialog {
|
.api-import >>> .el-dialog {
|
||||||
min-width: 750px;
|
min-width: 750px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.format-tip {
|
.format-tip {
|
||||||
background: #EDEDED;
|
background: #EDEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-upload {
|
.api-upload {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: auto 0;
|
margin: auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-upload >>> .el-upload {
|
.api-upload >>> .el-upload {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-upload >>> .el-upload-dragger {
|
.api-upload >>> .el-upload-dragger {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-radio-group {
|
.el-radio-group {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-radio {
|
.el-radio {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-bar, .format-tip, .el-form {
|
.header-bar, .format-tip, .el-form {
|
||||||
border: solid #E1E1E1 1px;
|
border: solid #E1E1E1 1px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-bar {
|
.header-bar {
|
||||||
padding: 10px 30px;
|
padding: 10px 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-import >>> .el-dialog__body {
|
.api-import >>> .el-dialog__body {
|
||||||
padding: 15px 25px;
|
padding: 15px 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.operate-button {
|
.operate-button {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.save-button {
|
.save-button {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-form {
|
.el-form {
|
||||||
padding: 30px 10px;
|
padding: 30px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.swagger-url-disable {
|
.swagger-url-disable {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
margin-left: 80px;
|
margin-left: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-divider {
|
.el-divider {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -235,7 +235,7 @@
|
||||||
import {
|
import {
|
||||||
_handleSelect,
|
_handleSelect,
|
||||||
_handleSelectAll, buildBatchParam, getLabel,
|
_handleSelectAll, buildBatchParam, getLabel,
|
||||||
getSelectDataCounts, getSystemLabel, initCondition,
|
getSelectDataCounts, initCondition,
|
||||||
setUnSelectIds, toggleAllSelection
|
setUnSelectIds, toggleAllSelection
|
||||||
} from "@/common/js/tableUtils";
|
} from "@/common/js/tableUtils";
|
||||||
import {_filter, _sort} from "@/common/js/tableUtils";
|
import {_filter, _sort} from "@/common/js/tableUtils";
|
||||||
|
@ -380,16 +380,16 @@
|
||||||
} else {
|
} else {
|
||||||
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
|
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
|
||||||
}
|
}
|
||||||
this.getSystemLabel(this.type)
|
|
||||||
this.initTable();
|
this.initTable();
|
||||||
this.getMaintainerOptions();
|
this.getMaintainerOptions();
|
||||||
getLabel(this, API_LIST);
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
selectNodeIds() {
|
selectNodeIds() {
|
||||||
|
initCondition(this.condition,false);
|
||||||
this.initTable();
|
this.initTable();
|
||||||
},
|
},
|
||||||
currentProtocol() {
|
currentProtocol() {
|
||||||
|
initCondition(this.condition,false);
|
||||||
this.initTable();
|
this.initTable();
|
||||||
},
|
},
|
||||||
trashEnable() {
|
trashEnable() {
|
||||||
|
@ -399,21 +399,12 @@
|
||||||
} else {
|
} else {
|
||||||
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
|
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
|
||||||
}
|
}
|
||||||
|
initCondition(this.condition,false);
|
||||||
this.initTable();
|
this.initTable();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getSystemLabel(type) {
|
|
||||||
let param = {}
|
|
||||||
param.type = type
|
|
||||||
this.$post('/system/system/header', param, response => {
|
|
||||||
if (response.data != null) {
|
|
||||||
this.tableLabel = eval(response.data.props);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
customHeader() {
|
customHeader() {
|
||||||
getLabel(this, API_LIST);
|
|
||||||
this.$refs.headerCustom.open(this.tableLabel)
|
this.$refs.headerCustom.open(this.tableLabel)
|
||||||
},
|
},
|
||||||
handleBatchMove() {
|
handleBatchMove() {
|
||||||
|
@ -421,7 +412,7 @@
|
||||||
},
|
},
|
||||||
initTable() {
|
initTable() {
|
||||||
this.selectRows = new Set();
|
this.selectRows = new Set();
|
||||||
initCondition(this.condition);
|
initCondition(this.condition,this.condition.selectAll);
|
||||||
this.selectDataCounts = 0;
|
this.selectDataCounts = 0;
|
||||||
this.condition.moduleIds = this.selectNodeIds;
|
this.condition.moduleIds = this.selectNodeIds;
|
||||||
this.condition.projectId = this.projectId;
|
this.condition.projectId = this.projectId;
|
||||||
|
@ -464,13 +455,42 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (this.$refs.apiDefinitionTable) {
|
if (this.$refs.apiDefinitionTable) {
|
||||||
this.$refs.apiDefinitionTable.doLayout()
|
setTimeout(() => {
|
||||||
|
this.$refs.apiDefinitionTable.doLayout();
|
||||||
|
this.result.loading = false;
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
|
// nexttick:表格加载完成之后触发。判断是否需要勾选行
|
||||||
|
this.$nextTick(function(){
|
||||||
|
this.checkTableRowIsSelect();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getLabel(this, API_LIST);
|
getLabel(this, API_LIST);
|
||||||
},
|
},
|
||||||
|
checkTableRowIsSelect(){
|
||||||
|
//如果默认全选的话,则选中应该选中的行
|
||||||
|
if(this.condition.selectAll){
|
||||||
|
let unSelectIds = this.condition.unSelectIds;
|
||||||
|
this.tableData.forEach(row=>{
|
||||||
|
if(unSelectIds.indexOf(row.id)<0){
|
||||||
|
this.$refs.apiDefinitionTable.toggleRowSelection(row,true);
|
||||||
|
|
||||||
|
//默认全选,需要把选中对行添加到selectRows中。不然会影响到勾选函数统计
|
||||||
|
if (!this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", true);
|
||||||
|
this.selectRows.add(row);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//不勾选的行,也要判断是否被加入了selectRow中。加入了的话就去除。
|
||||||
|
if (this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", false);
|
||||||
|
this.selectRows.delete(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
genProtocalFilter(protocalType) {
|
genProtocalFilter(protocalType) {
|
||||||
if (protocalType === "HTTP") {
|
if (protocalType === "HTTP") {
|
||||||
this.methodFilters = [
|
this.methodFilters = [
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
:condition="condition"
|
:condition="condition"
|
||||||
:current-module="currentModule"
|
:current-module="currentModule"
|
||||||
:is-read-only="isReadOnly"
|
:is-read-only="isReadOnly"
|
||||||
|
:moduleOptions="extendTreeNodes"
|
||||||
@exportAPI="exportAPI"
|
@exportAPI="exportAPI"
|
||||||
@saveAsEdit="saveAsEdit"
|
@saveAsEdit="saveAsEdit"
|
||||||
@refreshTable="$emit('refreshTable')"
|
@refreshTable="$emit('refreshTable')"
|
||||||
|
@ -34,25 +35,25 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsAddBasisApi from "../basis/AddBasisApi";
|
import MsAddBasisApi from "../basis/AddBasisApi";
|
||||||
import SelectMenu from "../../../../track/common/SelectMenu";
|
import SelectMenu from "../../../../track/common/SelectMenu";
|
||||||
import {OPTIONS} from "../../model/JsonData";
|
import {OPTIONS} from "../../model/JsonData";
|
||||||
import ApiImport from "../import/ApiImport";
|
import ApiImport from "../import/ApiImport";
|
||||||
import MsNodeTree from "../../../../track/common/NodeTree";
|
import MsNodeTree from "../../../../track/common/NodeTree";
|
||||||
import ApiModuleHeader from "./ApiModuleHeader";
|
import ApiModuleHeader from "./ApiModuleHeader";
|
||||||
import {buildNodePath} from "../../model/NodeTree";
|
import {buildNodePath, buildTree} from "../../model/NodeTree";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MsApiModule',
|
name: 'MsApiModule',
|
||||||
components: {
|
components: {
|
||||||
ApiModuleHeader,
|
ApiModuleHeader,
|
||||||
MsNodeTree,
|
MsNodeTree,
|
||||||
MsAddBasisApi,
|
MsAddBasisApi,
|
||||||
SelectMenu,
|
SelectMenu,
|
||||||
ApiImport
|
ApiImport
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
result: {},
|
result: {},
|
||||||
condition: {
|
condition: {
|
||||||
protocol: OPTIONS[0].value,
|
protocol: OPTIONS[0].value,
|
||||||
|
@ -61,6 +62,7 @@ export default {
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
currentModule: {},
|
currentModule: {},
|
||||||
|
extendTreeNodes: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -129,11 +131,17 @@ export default {
|
||||||
this.result = this.$get(url, response => {
|
this.result = this.$get(url, response => {
|
||||||
if (response.data != undefined && response.data != null) {
|
if (response.data != undefined && response.data != null) {
|
||||||
this.data = response.data;
|
this.data = response.data;
|
||||||
let moduleOptions = [];
|
this.extendTreeNodes = [];
|
||||||
this.data.forEach(node => {
|
this.extendTreeNodes.unshift({
|
||||||
buildNodePath(node, {path: ''}, moduleOptions);
|
"id": "root",
|
||||||
|
"name": this.$t('commons.module_title'),
|
||||||
|
"level": 0,
|
||||||
|
"children": this.data,
|
||||||
});
|
});
|
||||||
this.$emit('setModuleOptions', moduleOptions);
|
this.extendTreeNodes.forEach(node => {
|
||||||
|
buildTree(node, {path: ''});
|
||||||
|
});
|
||||||
|
this.$emit('setModuleOptions', this.extendTreeNodes);
|
||||||
this.$emit('setNodeTree', this.data);
|
this.$emit('setNodeTree', this.data);
|
||||||
if (this.$refs.nodeTree) {
|
if (this.$refs.nodeTree) {
|
||||||
this.$refs.nodeTree.filter(this.condition.filterText);
|
this.$refs.nodeTree.filter(this.condition.filterText);
|
||||||
|
|
|
@ -1,46 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-select class="protocol-select" size="small" v-model="condition.protocol">
|
<el-row>
|
||||||
<el-option
|
<el-col class="protocol-col" :span="9">
|
||||||
v-for="item in options"
|
<el-select class="protocol-select" size="small" v-model="condition.protocol">
|
||||||
:key="item.value"
|
<el-option
|
||||||
:name="item.name"
|
v-for="item in options"
|
||||||
:value="item.value"
|
:key="item.value"
|
||||||
:disabled="item.disabled">
|
:name="item.name"
|
||||||
</el-option>
|
:value="item.value"
|
||||||
</el-select>
|
:disabled="item.disabled">
|
||||||
<el-input class="filter-input" :class="{'read-only': isReadOnly}" :placeholder="$t('test_track.module.search')" v-model="condition.filterText"
|
</el-option>
|
||||||
size="small">
|
</el-select>
|
||||||
<template v-slot:append>
|
</el-col>
|
||||||
<el-dropdown v-if="!isReadOnly" size="small" split-button type="primary" class="ms-api-button" @click="handleCommand('add-api')"
|
<el-col :span="15">
|
||||||
v-tester
|
<ms-search-bar
|
||||||
@command="handleCommand"
|
:condition="condition"
|
||||||
:hide-on-click='false'
|
:commands="operators"/>
|
||||||
trigger="click">
|
</el-col>
|
||||||
<el-button icon="el-icon-folder-add" @click="addApi"></el-button>
|
</el-row>
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item command="add-api">{{ $t('api_test.definition.request.title') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="debug">{{ $t('api_test.definition.request.fast_debug') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="import">{{ $t('api_test.api_import.label') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="export">
|
|
||||||
<el-dropdown placement="right-start" @command="chooseExportType">
|
|
||||||
<span>
|
|
||||||
{{ $t('report.export') }} <i class="el-icon-arrow-down el-icon--right"></i>
|
|
||||||
</span>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<template>
|
|
||||||
<el-dropdown-item command="export-MS">{{ $t('report.export_to_ms_format') }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="export-Swagger" v-show="condition.protocol=='HTTP'">
|
|
||||||
{{ $t('report.export_to_swagger3_format') }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</template>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
|
|
||||||
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
|
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
|
||||||
|
|
||||||
|
@ -54,127 +31,128 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {OPTIONS} from "../../model/JsonData";
|
import {OPTIONS} from "../../model/JsonData";
|
||||||
import MsAddBasisApi from "../basis/AddBasisApi";
|
import MsAddBasisApi from "../basis/AddBasisApi";
|
||||||
import ApiImport from "../import/ApiImport";
|
import ApiImport from "../import/ApiImport";
|
||||||
import ModuleTrashButton from "./ModuleTrashButton";
|
import ModuleTrashButton from "./ModuleTrashButton";
|
||||||
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
|
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
|
||||||
import TemplateComponent from "../../../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
|
import TemplateComponent from "../../../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
|
||||||
|
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
|
||||||
export default {
|
export default {
|
||||||
name: "ApiModuleHeader",
|
name: "ApiModuleHeader",
|
||||||
components: {TemplateComponent, ModuleTrashButton, ApiImport, MsAddBasisApi},
|
components: {MsSearchBar, TemplateComponent, ModuleTrashButton, ApiImport, MsAddBasisApi},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
options: OPTIONS,
|
options: OPTIONS,
|
||||||
moduleOptions: {}
|
operators: [
|
||||||
}
|
{
|
||||||
},
|
label: this.$t('api_test.definition.request.title'),
|
||||||
props: {
|
callback: this.addApi
|
||||||
condition: {
|
},
|
||||||
type: Object,
|
{
|
||||||
default() {
|
label: this.$t('api_test.definition.request.fast_debug'),
|
||||||
return {}
|
callback: () => {this.$emit('debug')}
|
||||||
}
|
},
|
||||||
},
|
{
|
||||||
currentModule: {
|
label: this.$t('api_test.api_import.label'),
|
||||||
type: Object,
|
callback: this.handleImport
|
||||||
default() {
|
},
|
||||||
return {}
|
{
|
||||||
}
|
label: this.$t('report.export'),
|
||||||
},
|
children: [
|
||||||
isReadOnly: {
|
{
|
||||||
type: Boolean,
|
label: this.$t('report.export_to_ms_format') ,
|
||||||
default() {
|
callback: () => {
|
||||||
return false
|
if (!this.projectId) {
|
||||||
}
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
},
|
return;
|
||||||
},
|
}
|
||||||
computed: {
|
this.$emit('exportAPI', 'MS');
|
||||||
projectId() {
|
}
|
||||||
return this.$store.state.projectId
|
},
|
||||||
},
|
{
|
||||||
},
|
label: this.$t('report.export_to_swagger3_format'),
|
||||||
methods: {
|
callback: () => {
|
||||||
|
if (!this.projectId) {
|
||||||
handleCommand(e) {
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
switch (e) {
|
return;
|
||||||
case "debug":
|
}
|
||||||
this.$emit('debug');
|
this.$emit('exportAPI', 'Swagger');
|
||||||
break;
|
}
|
||||||
case "add-api":
|
}
|
||||||
this.addApi();
|
]
|
||||||
break;
|
|
||||||
case "add-module":
|
|
||||||
break;
|
|
||||||
case "import":
|
|
||||||
if (!this.projectId) {
|
|
||||||
this.$warning(this.$t('commons.check_project_tip'));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
this.protocol = "HTTP";
|
]
|
||||||
this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.condition.protocol, response => {
|
|
||||||
if (response.data != undefined && response.data != null) {
|
|
||||||
this.data = response.data;
|
|
||||||
let moduleOptions = [];
|
|
||||||
this.data.forEach(node => {
|
|
||||||
buildNodePath(node, {path: ''}, moduleOptions);
|
|
||||||
});
|
|
||||||
this.moduleOptions = moduleOptions
|
|
||||||
}
|
|
||||||
this.$refs.apiImport.open(this.moduleOptions);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chooseExportType(e) {
|
props: {
|
||||||
if (!this.projectId) {
|
condition: {
|
||||||
this.$warning(this.$t('commons.check_project_tip'));
|
type: Object,
|
||||||
return;
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
moduleOptions: Array,
|
||||||
|
currentModule: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
projectId() {
|
||||||
|
return this.$store.state.projectId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleImport() {
|
||||||
|
if (!this.projectId) {
|
||||||
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.protocol = "HTTP";
|
||||||
|
this.$refs.apiImport.open(this.moduleOptions);
|
||||||
|
},
|
||||||
|
addApi() {
|
||||||
|
if (!this.projectId) {
|
||||||
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$refs.basisApi.open(this.currentModule);
|
||||||
|
},
|
||||||
|
saveAsEdit(data) {
|
||||||
|
this.$emit('saveAsEdit', data);
|
||||||
|
},
|
||||||
|
refresh() {
|
||||||
|
this.$emit('refresh');
|
||||||
|
},
|
||||||
|
enableTrash() {
|
||||||
|
this.condition.trashEnable = true;
|
||||||
}
|
}
|
||||||
switch (e) {
|
|
||||||
case "export-MS":
|
|
||||||
this.$emit('exportAPI', 'MS');
|
|
||||||
break;
|
|
||||||
case "export-Swagger":
|
|
||||||
this.$emit('exportAPI', 'Swagger');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addApi() {
|
|
||||||
if (!this.projectId) {
|
|
||||||
this.$warning(this.$t('commons.check_project_tip'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$refs.basisApi.open(this.currentModule);
|
|
||||||
},
|
|
||||||
saveAsEdit(data) {
|
|
||||||
this.$emit('saveAsEdit', data);
|
|
||||||
},
|
|
||||||
refresh() {
|
|
||||||
this.$emit('refresh');
|
|
||||||
},
|
|
||||||
enableTrash() {
|
|
||||||
this.condition.trashEnable = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.protocol-select {
|
||||||
.protocol-select {
|
width: 92px;
|
||||||
width: 92px;
|
height: 30px;
|
||||||
height: 30px;
|
}
|
||||||
}
|
.protocol-col {
|
||||||
|
min-width: 93px;
|
||||||
.read-only {
|
}
|
||||||
width: 150px !important;
|
.read-only {
|
||||||
}
|
width: 150px !important;
|
||||||
|
}
|
||||||
.filter-input {
|
.filter-input {
|
||||||
width: 174px;
|
width: 174px;
|
||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -9,4 +9,16 @@ export function buildNodePath(node, option, moduleOptions) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 构建树
|
||||||
|
export function buildTree(node, option) {
|
||||||
|
option.id = node.id;
|
||||||
|
option.name = node.name;
|
||||||
|
option.path = option.path + '/' + node.name;
|
||||||
|
node.path = option.path;
|
||||||
|
if (node.children) {
|
||||||
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
buildTree(node.children[i], {path: option.path});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,15 @@
|
||||||
icon: 'el-icon-delete',
|
icon: 'el-icon-delete',
|
||||||
func: this.deleteEnvironment
|
func: this.deleteEnvironment
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
selectEnvironmentId: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
open: function (projectId) {
|
open: function (projectId, envId) {
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.projectId = projectId;
|
this.projectId = projectId;
|
||||||
|
this.selectEnvironmentId = envId;
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
listenGoBack(this.close);
|
listenGoBack(this.close);
|
||||||
},
|
},
|
||||||
|
@ -114,7 +116,16 @@
|
||||||
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
|
this.result = this.$get('/api/environment/list/' + this.projectId, response => {
|
||||||
this.environments = response.data;
|
this.environments = response.data;
|
||||||
if (this.environments.length > 0) {
|
if (this.environments.length > 0) {
|
||||||
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
if (this.selectEnvironmentId) {
|
||||||
|
const index = this.environments.findIndex(e => e.id === this.selectEnvironmentId);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.$refs.environmentItems.itemSelected(index, this.environments[index]);
|
||||||
|
} else {
|
||||||
|
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$refs.environmentItems.itemSelected(0, this.environments[0]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let item = new Environment({
|
let item = new Environment({
|
||||||
projectId: this.projectId
|
projectId: this.projectId
|
||||||
|
|
|
@ -155,7 +155,7 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: white;
|
background: white;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 999999;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-screen >>> .minder-container {
|
.full-screen >>> .minder-container {
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<el-input class="ms-search-bar" :placeholder="$t('test_track.module.search')" v-model="condition.filterText" size="small">
|
||||||
|
<template v-slot:append>
|
||||||
|
<el-dropdown>
|
||||||
|
<el-button type="primary">
|
||||||
|
<span class="tip-font">{{ $t('commons.more_operator') }}</span>
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"/>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item v-for="(item, index) in commands" :key="index" @click.native.stop="click(item)">
|
||||||
|
<span class="tip-font" v-if="!item.children">
|
||||||
|
{{ item.label }}
|
||||||
|
</span>
|
||||||
|
<el-dropdown placement="right-start" v-else>
|
||||||
|
<span class="tip-font">
|
||||||
|
{{ item.label }}
|
||||||
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<template>
|
||||||
|
<el-dropdown-item v-for="(child, index) in item.children" :key="index" @click.native.stop="click(child)">
|
||||||
|
<span class="tip-font">
|
||||||
|
{{child.label}}
|
||||||
|
</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</template>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MsSearchBar",
|
||||||
|
props: {
|
||||||
|
condition: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
commands: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.$t('api_test.api_import.label'),
|
||||||
|
callback: () => {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click(item) {
|
||||||
|
if (item.callback) {
|
||||||
|
item.callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tip-font {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dropdown .el-button {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -52,6 +52,10 @@ export default {
|
||||||
this.defaultCheckedKeys.push(i.id)
|
this.defaultCheckedKeys.push(i.id)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
if(this.type==='api_list'||this.type==='api_case_list'||this.type==='api_scenario_list'||this.type==='test_plan_function_test_case'
|
||||||
|
||this.type==='test_plan_api_case'||this.type==='test_plan_load_case'||this.type==='test_plan_scenario_case'){
|
||||||
|
this.fieldSelected=items
|
||||||
|
}
|
||||||
},
|
},
|
||||||
saveHeader() {
|
saveHeader() {
|
||||||
let param = {
|
let param = {
|
||||||
|
|
|
@ -81,7 +81,6 @@ export const Test_Case_Review_Case_List = [
|
||||||
{id: 'name', label: i18n.t('commons.name')},
|
{id: 'name', label: i18n.t('commons.name')},
|
||||||
{id: 'priority', label: i18n.t('test_track.case.priority')},
|
{id: 'priority', label: i18n.t('test_track.case.priority')},
|
||||||
{id: 'type', label: i18n.t('test_track.case.type')},
|
{id: 'type', label: i18n.t('test_track.case.type')},
|
||||||
{id: 'method', label: i18n.t('test_track.case.method')},
|
|
||||||
{id: 'nodePath', label: i18n.t('test_track.case.module')},
|
{id: 'nodePath', label: i18n.t('test_track.case.module')},
|
||||||
{id: 'projectName', label: i18n.t('test_track.review.review_project')},
|
{id: 'projectName', label: i18n.t('test_track.review.review_project')},
|
||||||
{id: 'reviewerName', label: i18n.t('test_track.review.reviewer')},
|
{id: 'reviewerName', label: i18n.t('test_track.review.reviewer')},
|
||||||
|
@ -107,7 +106,7 @@ export const Test_Plan_Function_Test_Case = [
|
||||||
//测试计划-api用例
|
//测试计划-api用例
|
||||||
export const Test_Plan_Api_Case = [
|
export const Test_Plan_Api_Case = [
|
||||||
{id: 'num', label: i18n.t('commons.id')},
|
{id: 'num', label: i18n.t('commons.id')},
|
||||||
{id: 'name', label: i18n.t('commons.name')},
|
{id: 'name', label: i18n.t('api_test.definition.api_name')},
|
||||||
{id: 'priority', label: i18n.t('test_track.case.priority')},
|
{id: 'priority', label: i18n.t('test_track.case.priority')},
|
||||||
{id: 'path', label: i18n.t('api_test.definition.api_path')},
|
{id: 'path', label: i18n.t('api_test.definition.api_path')},
|
||||||
{id: 'createUser', label: '创建人'},
|
{id: 'createUser', label: '创建人'},
|
||||||
|
@ -124,12 +123,12 @@ export const Test_Plan_Load_Case = [
|
||||||
{id: 'createTime', label: i18n.t('commons.create_time')},
|
{id: 'createTime', label: i18n.t('commons.create_time')},
|
||||||
{id: 'status', label: i18n.t('commons.status')},
|
{id: 'status', label: i18n.t('commons.status')},
|
||||||
{id: 'caseStatus', label: i18n.t('test_track.plan.load_case.execution_status')},
|
{id: 'caseStatus', label: i18n.t('test_track.plan.load_case.execution_status')},
|
||||||
{id: 'loadReportId', label: i18n.t('test_track.plan.load_case.view_report')},
|
{id: 'loadReportId', label: i18n.t('test_track.plan.load_case.report')},
|
||||||
]
|
]
|
||||||
//测试计划-场景用例
|
//测试计划-场景用例
|
||||||
export const Test_Plan_Scenario_Case = [
|
export const Test_Plan_Scenario_Case = [
|
||||||
{id: 'num', label: i18n.t('commons.id')},
|
{id: 'num', label: i18n.t('commons.id')},
|
||||||
{id: 'name', label: i18n.t('commons.name')},
|
{id: 'name', label: i18n.t('api_test.automation.scenario_name')},
|
||||||
{id: 'level', label: i18n.t('api_test.automation.case_level')},
|
{id: 'level', label: i18n.t('api_test.automation.case_level')},
|
||||||
{id: 'tagNames', label: i18n.t('api_test.automation.tag')},
|
{id: 'tagNames', label: i18n.t('api_test.automation.tag')},
|
||||||
{id: 'userId', label: i18n.t('api_test.automation.creator')},
|
{id: 'userId', label: i18n.t('api_test.automation.creator')},
|
||||||
|
|
|
@ -152,10 +152,13 @@
|
||||||
return JSON.stringify(this.data).indexOf(this.obj.children) !== -1 ? this.data : this.switchTree();
|
return JSON.stringify(this.data).indexOf(this.obj.children) !== -1 ? this.data : this.switchTree();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
outsideClick(e) {
|
outsideClick(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.isShowSelect=false;
|
this.isShowSelect = false;
|
||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
if (this.defaultKey != undefined && this.defaultKey.length > 0) {
|
if (this.defaultKey != undefined && this.defaultKey.length > 0) {
|
||||||
|
@ -233,7 +236,9 @@
|
||||||
setKey(thisKey) {
|
setKey(thisKey) {
|
||||||
this.$refs.tree.setCurrentKey(thisKey);
|
this.$refs.tree.setCurrentKey(thisKey);
|
||||||
let node = this.$refs.tree.getNode(thisKey);
|
let node = this.$refs.tree.getNode(thisKey);
|
||||||
this.setData(node.data);
|
if (node && node.data) {
|
||||||
|
this.setData(node.data);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
//单选:设置、初始化对象
|
//单选:设置、初始化对象
|
||||||
setData(data) {
|
setData(data) {
|
||||||
|
@ -284,7 +289,7 @@
|
||||||
},
|
},
|
||||||
//下拉框关闭执行
|
//下拉框关闭执行
|
||||||
popoverHide() {
|
popoverHide() {
|
||||||
this.$emit('getValue', this.returnDataKeys, this.returnDatas);
|
this.$emit('getValue', this.returnDataKeys, this.returnDatas ? this.returnDatas : {});
|
||||||
},
|
},
|
||||||
// 多选,清空所有勾选
|
// 多选,清空所有勾选
|
||||||
clearSelectedNodes() {
|
clearSelectedNodes() {
|
||||||
|
@ -340,10 +345,13 @@
|
||||||
// 隐藏select自带的下拉框
|
// 隐藏select自带的下拉框
|
||||||
this.$refs.select.blur();
|
this.$refs.select.blur();
|
||||||
},
|
},
|
||||||
treeData() {//监听tree数据
|
treeData: {//监听tree数据
|
||||||
this.$nextTick(() => {
|
handler: function () {
|
||||||
this.init();
|
this.$nextTick(() => {
|
||||||
})
|
this.init();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
},
|
},
|
||||||
filterText(val) {
|
filterText(val) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<ms-container>
|
||||||
|
<ms-main-container>
|
||||||
|
<el-card>
|
||||||
|
|
||||||
|
</el-card>
|
||||||
|
</ms-main-container>
|
||||||
|
</ms-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||||
|
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||||
|
import {checkoutTestManagerOrTestUser} from "@/common/js/utils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PerformanceReportCompare",
|
||||||
|
components: {MsMainContainer, MsContainer},
|
||||||
|
mounted() {
|
||||||
|
let reportId = this.$route.path.split('/')[4];
|
||||||
|
console.log(reportId);
|
||||||
|
let items = localStorage.getItem("compareReportIds");
|
||||||
|
console.log(JSON.parse(items));
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isReadOnly() {
|
||||||
|
return !checkoutTestManagerOrTestUser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -28,10 +28,6 @@
|
||||||
<el-button :disabled="isReadOnly" type="warning" plain size="mini" @click="downloadJtl()">
|
<el-button :disabled="isReadOnly" type="warning" plain size="mini" @click="downloadJtl()">
|
||||||
{{ $t('report.downloadJtl') }}
|
{{ $t('report.downloadJtl') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<!--<el-button :disabled="isReadOnly" type="warning" plain size="mini">-->
|
|
||||||
<!--{{$t('report.compare')}}-->
|
|
||||||
<!--</el-button>-->
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
@ -83,6 +79,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
|
<same-test-reports ref="compareReports"/>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -99,11 +96,13 @@ import {checkoutTestManagerOrTestUser, exportPdf} from "@/common/js/utils";
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
import MsPerformanceReportExport from "./PerformanceReportExport";
|
import MsPerformanceReportExport from "./PerformanceReportExport";
|
||||||
import {Message} from "element-ui";
|
import {Message} from "element-ui";
|
||||||
|
import SameTestReports from "@/business/components/performance/report/components/SameTestReports";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceReportView",
|
name: "PerformanceReportView",
|
||||||
components: {
|
components: {
|
||||||
|
SameTestReports,
|
||||||
MsPerformanceReportExport,
|
MsPerformanceReportExport,
|
||||||
MsReportErrorLog,
|
MsReportErrorLog,
|
||||||
MsReportLogDetails,
|
MsReportLogDetails,
|
||||||
|
@ -312,6 +311,9 @@ export default {
|
||||||
Message.error({message: JSON.parse(data).message || e.message, showClose: true});
|
Message.error({message: JSON.parse(data).message || e.message, showClose: true});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
compareReports() {
|
||||||
|
this.$refs.compareReports.open(this.report);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -25,37 +25,32 @@
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="name"
|
prop="name"
|
||||||
:label="$t('commons.name')"
|
:label="$t('commons.name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="testName"
|
prop="testName"
|
||||||
:label="$t('report.test_name')"
|
:label="$t('report.test_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="projectName"
|
prop="projectName"
|
||||||
:label="$t('report.project_name')"
|
:label="$t('report.project_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="userName"
|
prop="userName"
|
||||||
:label="$t('report.user_name')"
|
:label="$t('report.user_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="createTime"
|
prop="createTime"
|
||||||
sortable
|
sortable
|
||||||
width="250"
|
|
||||||
:label="$t('commons.create_time')">
|
:label="$t('commons.create_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'" column-key="triggerMode"
|
<el-table-column prop="triggerMode" width="150" :label="$t('test_track.report.list.trigger_mode')" column-key="triggerMode"
|
||||||
:filters="triggerFilters">
|
:filters="triggerFilters">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||||
|
@ -85,6 +80,7 @@
|
||||||
:total="total"/>
|
:total="total"/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
|
<same-test-reports ref="compareReports"/>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -101,11 +97,14 @@ import MsTableHeader from "../../common/components/MsTableHeader";
|
||||||
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
||||||
import ShowMoreBtn from "../../track/case/components/ShowMoreBtn";
|
import ShowMoreBtn from "../../track/case/components/ShowMoreBtn";
|
||||||
import {_filter, _sort} from "@/common/js/tableUtils";
|
import {_filter, _sort} from "@/common/js/tableUtils";
|
||||||
|
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||||
|
import SameTestReports from "@/business/components/performance/report/components/SameTestReports";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceTestReportList",
|
name: "PerformanceTestReportList",
|
||||||
components: {
|
components: {
|
||||||
|
SameTestReports,
|
||||||
|
MsDialogFooter,
|
||||||
MsTableHeader,
|
MsTableHeader,
|
||||||
ReportTriggerModeItem,
|
ReportTriggerModeItem,
|
||||||
MsTableOperatorButton,
|
MsTableOperatorButton,
|
||||||
|
@ -200,6 +199,9 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleDiff(report) {
|
||||||
|
this.$refs.compareReports.open(report);
|
||||||
|
},
|
||||||
_handleDeleteNoMsg(report) {
|
_handleDeleteNoMsg(report) {
|
||||||
this.result = this.$post(this.deletePath + report.id, {}, () => {
|
this.result = this.$post(this.deletePath + report.id, {}, () => {
|
||||||
this.initTableData();
|
this.initTableData();
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-loading="result.loading" class="pressure-config-container">
|
<div v-loading="result.loading" class="pressure-config-container">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="10">
|
<el-col :span="12">
|
||||||
|
|
||||||
<el-collapse v-model="activeNames" accordion>
|
<el-collapse v-model="activeNames" accordion>
|
||||||
<el-collapse-item :name="index"
|
<el-collapse-item :name="index"
|
||||||
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
||||||
:key="index">
|
:key="index">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<div style="padding-right: 10px">
|
<el-row>
|
||||||
{{ threadGroup.attributes.testname }}
|
<el-col :span="14">
|
||||||
</div>
|
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
|
||||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
|
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
|
||||||
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
|
{{ threadGroup.attributes.testname }}
|
||||||
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
|
</div>
|
||||||
</el-tag>
|
</el-tooltip>
|
||||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
|
</el-col>
|
||||||
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
|
<el-col :span="10">
|
||||||
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
|
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
|
||||||
</el-tag>
|
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
|
||||||
|
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
|
||||||
|
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
|
||||||
|
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
|
||||||
|
</el-tag>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-form :inline="true">
|
<el-form :inline="true">
|
||||||
<el-form-item :label="$t('load_test.thread_num')">
|
<el-form-item :label="$t('load_test.thread_num')">
|
||||||
|
@ -134,7 +142,7 @@
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="14">
|
<el-col :span="12">
|
||||||
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
|
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -578,4 +586,9 @@ export default {
|
||||||
.title {
|
.title {
|
||||||
margin-left: 60px;
|
margin-left: 60px;
|
||||||
}
|
}
|
||||||
|
.wordwrap {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="ko"
|
prop="ko"
|
||||||
label="KO"
|
label="FAIL"
|
||||||
align="center"
|
align="center"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog :close-on-click-modal="false"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:title="$t('已完成的测试报告')" width="60%"
|
||||||
|
:visible.sync="loadReportVisible">
|
||||||
|
<el-table v-loading="reportLoadingResult.loading"
|
||||||
|
class="basic-config"
|
||||||
|
:data="compareReports"
|
||||||
|
@select-all="handleSelectAll"
|
||||||
|
@select="handleSelectionChange">
|
||||||
|
|
||||||
|
<el-table-column type="selection"/>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
:label="$t('commons.name')"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="userName"
|
||||||
|
:label="$t('report.user_name')"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="triggerMode"
|
||||||
|
:label="$t('test_track.report.list.trigger_mode')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.create_time')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<i class="el-icon-time"/>
|
||||||
|
<span class="last-modified">{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<ms-table-pagination :change="getCompareReports" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||||
|
:total="total"/>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<ms-dialog-footer @cancel="close" @confirm="handleCompare"/>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
|
||||||
|
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||||
|
import ReportTriggerModeItem from "@/business/components/common/tableItem/ReportTriggerModeItem";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SameTestReports",
|
||||||
|
components: {ReportTriggerModeItem, MsDialogFooter, MsTablePagination},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadReportVisible: false,
|
||||||
|
reportLoadingResult: {},
|
||||||
|
compareReports: [],
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
selectIds: new Set,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(report) {
|
||||||
|
this.getCompareReports(report.testId);
|
||||||
|
this.loadReportVisible = true;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.loadReportVisible = false;
|
||||||
|
},
|
||||||
|
getCompareReports(testId) {
|
||||||
|
|
||||||
|
let condition = {
|
||||||
|
testId: testId,
|
||||||
|
filters: {status: ["Completed"]}
|
||||||
|
};
|
||||||
|
this.reportLoadingResult = this.$post('/performance/report/list/all/' + this.currentPage + "/" + this.pageSize, condition, res => {
|
||||||
|
let data = res.data;
|
||||||
|
this.total = data.itemCount;
|
||||||
|
this.compareReports = data.listObject;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleCompare() {
|
||||||
|
let reportIds = [...this.selectIds];
|
||||||
|
localStorage.setItem("compareReportIds", JSON.stringify(reportIds));
|
||||||
|
this.close();
|
||||||
|
this.$router.push({path: '/performance/report/compare/' + reportIds[0]});
|
||||||
|
},
|
||||||
|
handleSelectAll(selection) {
|
||||||
|
if (selection.length > 0) {
|
||||||
|
this.compareReports.forEach(item => {
|
||||||
|
this.selectIds.add(item.id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.compareReports.forEach(item => {
|
||||||
|
if (this.selectIds.has(item.id)) {
|
||||||
|
this.selectIds.delete(item.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSelectionChange(selection, row) {
|
||||||
|
if (this.selectIds.has(row.id)) {
|
||||||
|
this.selectIds.delete(row.id);
|
||||||
|
} else {
|
||||||
|
this.selectIds.add(row.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,5 +1,3 @@
|
||||||
import MsProject from "@/business/components/settings/project/MsProject";
|
|
||||||
|
|
||||||
const PerformanceTest = () => import('@/business/components/performance/PerformanceTest')
|
const PerformanceTest = () => import('@/business/components/performance/PerformanceTest')
|
||||||
const PerformanceTestHome = () => import('@/business/components/performance/home/PerformanceTestHome')
|
const PerformanceTestHome = () => import('@/business/components/performance/home/PerformanceTestHome')
|
||||||
const EditPerformanceTest = () => import('@/business/components/performance/test/EditPerformanceTest')
|
const EditPerformanceTest = () => import('@/business/components/performance/test/EditPerformanceTest')
|
||||||
|
@ -7,6 +5,7 @@ const PerformanceTestList = () => import('@/business/components/performance/test
|
||||||
const PerformanceTestReportList = () => import('@/business/components/performance/report/PerformanceTestReportList')
|
const PerformanceTestReportList = () => import('@/business/components/performance/report/PerformanceTestReportList')
|
||||||
const PerformanceChart = () => import('@/business/components/performance/report/components/PerformanceChart')
|
const PerformanceChart = () => import('@/business/components/performance/report/components/PerformanceChart')
|
||||||
const PerformanceReportView = () => import('@/business/components/performance/report/PerformanceReportView')
|
const PerformanceReportView = () => import('@/business/components/performance/report/PerformanceReportView')
|
||||||
|
const PerformanceReportCompare = () => import('@/business/components/performance/report/PerformanceReportCompare')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
path: "/performance",
|
path: "/performance",
|
||||||
|
@ -62,6 +61,11 @@ export default {
|
||||||
path: "report/view/:reportId",
|
path: "report/view/:reportId",
|
||||||
name: "perReportView",
|
name: "perReportView",
|
||||||
component: PerformanceReportView
|
component: PerformanceReportView
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: "report/compare/:reportId",
|
||||||
|
name: "ReportCompare",
|
||||||
|
component: PerformanceReportCompare,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ export default {
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
let row = rows[i];
|
let row = rows[i];
|
||||||
if (this.tableData.filter(f => f.name === row.name).length > 0) {
|
if (this.tableData.filter(f => f.name === row.name).length > 0) {
|
||||||
this.$error(this.$t('load_test.delete_file'));
|
this.$error(this.$t('load_test.delete_file') + ', name: ' + row.name);
|
||||||
this.selectIds.clear();
|
this.selectIds.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
if (this.tableData.filter(f => f.name === file.name).length > 0) {
|
||||||
this.$error(this.$t('load_test.delete_file'));
|
this.$error(this.$t('load_test.delete_file') + ', name: ' + file.name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default {
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
let row = rows[i];
|
let row = rows[i];
|
||||||
if (this.tableData.filter(f => f.name === row.name + ".jmx").length > 0) {
|
if (this.tableData.filter(f => f.name === row.name + ".jmx").length > 0) {
|
||||||
this.$error(this.$t('load_test.delete_file'));
|
this.$error(this.$t('load_test.delete_file') + ', name: ' + row.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<el-col>
|
<el-col>
|
||||||
<el-form :inline="true">
|
<el-form :inline="true">
|
||||||
<el-form-item :label="$t('load_test.select_resource_pool')">
|
<el-form-item :label="$t('load_test.select_resource_pool')">
|
||||||
<el-select v-model="resourcePool" :disabled="isReadOnly" size="mini">
|
<el-select v-model="resourcePool" :disabled="isReadOnly" size="mini" @change="resourcePoolChange">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in resourcePools"
|
v-for="item in resourcePools"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
@ -23,17 +23,25 @@
|
||||||
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
|
||||||
:key="index">
|
:key="index">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<div style="padding-right: 20px; font-size: 16px;">
|
<el-row>
|
||||||
{{ threadGroup.attributes.testname }}
|
<el-col :span="14">
|
||||||
</div>
|
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
|
||||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
|
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
|
||||||
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
|
{{ threadGroup.attributes.testname }}
|
||||||
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
|
</div>
|
||||||
</el-tag>
|
</el-tooltip>
|
||||||
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
|
</el-col>
|
||||||
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
|
<el-col :span="10">
|
||||||
{{$t('load_test.iterate_num')}} {{threadGroup.iterateNum}}
|
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
|
||||||
</el-tag>
|
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
|
||||||
|
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
|
||||||
|
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
|
||||||
|
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
|
||||||
|
</el-tag>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-form :inline="true">
|
<el-form :inline="true">
|
||||||
<el-form-item :label="$t('load_test.thread_num')">
|
<el-form-item :label="$t('load_test.thread_num')">
|
||||||
|
@ -42,6 +50,7 @@
|
||||||
v-model="threadGroup.threadNumber"
|
v-model="threadGroup.threadNumber"
|
||||||
@change="calculateTotalChart(threadGroup)"
|
@change="calculateTotalChart(threadGroup)"
|
||||||
:min="resourcePoolResourceLength"
|
:min="resourcePoolResourceLength"
|
||||||
|
:max="maxThreadNumbers"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<br>
|
<br>
|
||||||
|
@ -109,6 +118,7 @@
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
:min="1"
|
:min="1"
|
||||||
|
:max="threadGroup.duration"
|
||||||
v-model="threadGroup.rampUpTime"
|
v-model="threadGroup.rampUpTime"
|
||||||
@change="calculateTotalChart(threadGroup)"
|
@change="calculateTotalChart(threadGroup)"
|
||||||
size="mini"/>
|
size="mini"/>
|
||||||
|
@ -219,7 +229,8 @@ export default {
|
||||||
resourcePools: [],
|
resourcePools: [],
|
||||||
activeNames: ["0"],
|
activeNames: ["0"],
|
||||||
threadGroups: [],
|
threadGroups: [],
|
||||||
resourcePoolResourceLength: 1
|
resourcePoolResourceLength: 1,
|
||||||
|
maxThreadNumbers: 5000,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -336,6 +347,22 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
resourcePoolChange() {
|
||||||
|
let result = this.resourcePools.filter(p => p.id === this.resourcePool);
|
||||||
|
if (result.length === 1) {
|
||||||
|
let threadNumber = 0;
|
||||||
|
result[0].resources.forEach(resource => {
|
||||||
|
threadNumber += JSON.parse(resource.configuration).maxConcurrency;
|
||||||
|
})
|
||||||
|
this.maxThreadNumbers = threadNumber;
|
||||||
|
this.threadGroups.forEach(tg => {
|
||||||
|
if (tg.threadNumber > threadNumber) {
|
||||||
|
this.$set(tg, "threadNumber", threadNumber);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.calculateTotalChart();
|
||||||
|
}
|
||||||
|
},
|
||||||
calculateTotalChart() {
|
calculateTotalChart() {
|
||||||
let handler = this;
|
let handler = this;
|
||||||
if (handler.duration < handler.rampUpTime) {
|
if (handler.duration < handler.rampUpTime) {
|
||||||
|
@ -344,6 +371,11 @@ export default {
|
||||||
if (handler.rampUpTime < handler.step) {
|
if (handler.rampUpTime < handler.step) {
|
||||||
handler.step = handler.rampUpTime;
|
handler.step = handler.rampUpTime;
|
||||||
}
|
}
|
||||||
|
// 线程数不能小于资源池节点的数量
|
||||||
|
let resourcePool = this.resourcePools.filter(v => v.id === this.resourcePool)[0];
|
||||||
|
if (resourcePool) {
|
||||||
|
this.resourcePoolResourceLength = resourcePool.resources.length;
|
||||||
|
}
|
||||||
let color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
|
let color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
|
||||||
handler.options = {
|
handler.options = {
|
||||||
color: color,
|
color: color,
|
||||||
|
@ -649,7 +681,7 @@ export default {
|
||||||
border-bottom: 1px solid #DCDFE6;
|
border-bottom: 1px solid #DCDFE6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .el-collapse-item__content{
|
/deep/ .el-collapse-item__content {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
border-left-width: 8px;
|
border-left-width: 8px;
|
||||||
|
@ -682,4 +714,10 @@ export default {
|
||||||
.title {
|
.title {
|
||||||
margin-left: 60px;
|
margin-left: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wordwrap {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -216,8 +216,36 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.total = data.itemCount;
|
this.total = data.itemCount;
|
||||||
|
|
||||||
|
this.$nextTick(function(){
|
||||||
|
this.checkTableRowIsSelect();
|
||||||
|
});
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkTableRowIsSelect(){
|
||||||
|
//如果默认全选的话,则选中应该选中的行
|
||||||
|
if(this.condition.selectAll){
|
||||||
|
let unSelectIds = this.condition.unSelectIds;
|
||||||
|
this.tableData.forEach(row=>{
|
||||||
|
if(unSelectIds.indexOf(row.id)<0){
|
||||||
|
this.$refs.userTable.toggleRowSelection(row,true);
|
||||||
|
|
||||||
|
//默认全选,需要把选中对行添加到selectRows中。不然会影响到勾选函数统计
|
||||||
|
if (!this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", true);
|
||||||
|
this.selectRows.add(row);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//不勾选的行,也要判断是否被加入了selectRow中。加入了的话就去除。
|
||||||
|
if (this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", false);
|
||||||
|
this.selectRows.delete(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
buildPagePath(path) {
|
buildPagePath(path) {
|
||||||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||||
},
|
},
|
||||||
|
|
|
@ -598,7 +598,7 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.selectRows = new Set();
|
this.selectRows = new Set();
|
||||||
this.condition.selectAll = false;
|
// this.condition.selectAll = false;
|
||||||
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
|
this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
|
||||||
let data = response.data;
|
let data = response.data;
|
||||||
this.total = data.itemCount;
|
this.total = data.itemCount;
|
||||||
|
@ -615,8 +615,38 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$nextTick(function(){
|
||||||
|
this.checkTableRowIsSelect();
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkTableRowIsSelect(){
|
||||||
|
//如果默认全选的话,则选中应该选中的行
|
||||||
|
if(this.condition.selectAll){
|
||||||
|
let unSelectIds = this.condition.unSelectIds;
|
||||||
|
this.tableData.forEach(row=>{
|
||||||
|
if(unSelectIds.indexOf(row.id)<0){
|
||||||
|
this.$refs.userTable.toggleRowSelection(row,true);
|
||||||
|
|
||||||
|
//默认全选,需要把选中对行添加到selectRows中。不然会影响到勾选函数统计
|
||||||
|
if (!this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", true);
|
||||||
|
this.selectRows.add(row);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//不勾选的行,也要判断是否被加入了selectRow中。加入了的话就去除。
|
||||||
|
if (this.selectRows.has(row)) {
|
||||||
|
this.$set(row, "showMore", false);
|
||||||
|
this.selectRows.delete(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleClose() {
|
handleClose() {
|
||||||
this.form = {roles: [{id: ''}]};
|
this.form = {roles: [{id: ''}]};
|
||||||
this.btnAddRole = false;
|
this.btnAddRole = false;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue