Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
f33de156fc
|
@ -48,7 +48,7 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
|||
文档和演示视频:
|
||||
|
||||
- [完整文档](https://metersphere.io/docs/)
|
||||
- [演示视频](https://www.bilibili.com/video/BV1yp4y1p72C/)
|
||||
- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4)
|
||||
|
||||
## MeterSphere 企业版
|
||||
|
||||
|
|
|
@ -380,7 +380,48 @@
|
|||
<artifactId>json-schema-validator</artifactId>
|
||||
<version>2.2.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 添加jmeter包支持导入的jmx能正常执行 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_bolt</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_jms</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_ftp</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_junit</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_ldap</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_mail</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_components</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_native</artifactId>
|
||||
<version>${jmeter.version}</version>
|
||||
</dependency>
|
||||
<!-- 添加jmeter包支持导入的jmx能正常执行 -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -5,15 +5,12 @@ import com.github.pagehelper.PageHelper;
|
|||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.JmxInfoDTO;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.definition.ApiBatchRequest;
|
||||
import io.metersphere.api.dto.definition.ApiExportResult;
|
||||
import io.metersphere.api.dto.automation.parse.ScenarioImport;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
import io.metersphere.base.domain.ApiScenario;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
|
@ -47,6 +44,13 @@ public class ApiAutomationController {
|
|||
return PageUtils.setPageInfo(page, apiAutomationService.list(request));
|
||||
}
|
||||
|
||||
@PostMapping("/list/all")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER}, logical = Logical.OR)
|
||||
public List<ApiScenarioWithBLOBs> list(@RequestBody ApiScenarioRequest request) {
|
||||
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||
return apiAutomationService.get(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/create")
|
||||
public ApiScenario create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
return apiAutomationService.create(request, bodyFiles);
|
||||
|
@ -153,7 +157,7 @@ public class ApiAutomationController {
|
|||
|
||||
@PostMapping(value = "/import", consumes = {"multipart/form-data"})
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public ApiDefinitionImport testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) {
|
||||
public ScenarioImport scenarioImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) {
|
||||
return apiAutomationService.scenarioImport(file, request);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ImportPoolsDTO {
|
||||
private String envId;
|
||||
|
||||
private Boolean isCreate;
|
||||
|
||||
private EnvironmentConfig envConfig;
|
||||
|
||||
private ApiTestEnvironmentWithBLOBs testEnvironmentWithBLOBs;
|
||||
|
||||
private Map<String, DatabaseConfig> dataSources;
|
||||
}
|
|
@ -0,0 +1,648 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
|
||||
import io.github.ningyu.jmeter.plugin.util.Constants;
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.automation.ImportPoolsDTO;
|
||||
import io.metersphere.api.dto.definition.request.MsScenario;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.assertions.*;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsIfController;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
|
||||
import io.metersphere.api.dto.definition.request.controller.loop.CountController;
|
||||
import io.metersphere.api.dto.definition.request.controller.loop.MsForEachController;
|
||||
import io.metersphere.api.dto.definition.request.controller.loop.MsWhileController;
|
||||
import io.metersphere.api.dto.definition.request.extract.MsExtract;
|
||||
import io.metersphere.api.dto.definition.request.extract.MsExtractJSONPath;
|
||||
import io.metersphere.api.dto.definition.request.extract.MsExtractRegex;
|
||||
import io.metersphere.api.dto.definition.request.extract.MsExtractXPath;
|
||||
import io.metersphere.api.dto.definition.request.processors.MsJSR223Processor;
|
||||
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
|
||||
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConfigCenter;
|
||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConsumerAndService;
|
||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
|
||||
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
|
||||
import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.service.ApiTestEnvironmentService;
|
||||
import io.metersphere.base.domain.ApiScenarioModule;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.ApiTestEnvironmentExample;
|
||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||
import io.metersphere.commons.constants.LoopConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.jmeter.assertions.*;
|
||||
import org.apache.jmeter.config.ConfigTestElement;
|
||||
import org.apache.jmeter.control.ForeachController;
|
||||
import org.apache.jmeter.control.IfController;
|
||||
import org.apache.jmeter.control.LoopController;
|
||||
import org.apache.jmeter.control.WhileController;
|
||||
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
||||
import org.apache.jmeter.extractor.RegexExtractor;
|
||||
import org.apache.jmeter.extractor.XPath2Extractor;
|
||||
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
|
||||
import org.apache.jmeter.modifiers.JSR223PreProcessor;
|
||||
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
|
||||
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
|
||||
import org.apache.jmeter.protocol.java.sampler.JSR223Sampler;
|
||||
import org.apache.jmeter.protocol.jdbc.config.DataSourceElement;
|
||||
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
|
||||
import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jmeter.testelement.TestPlan;
|
||||
import org.apache.jmeter.timers.ConstantTimer;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
public class MsJmeterParser extends ScenarioImportAbstractParser {
|
||||
private final String ENV_NAME = "导入数据环境";
|
||||
|
||||
@Override
|
||||
public ScenarioImport parse(InputStream inputSource, ApiTestImportRequest request) {
|
||||
try {
|
||||
Object scriptWrapper = SaveService.loadElement(inputSource);
|
||||
HashTree testPlan = this.getHashTree(scriptWrapper);
|
||||
// 优先初始化数据源
|
||||
preInitPool(request.getProjectId(), testPlan);
|
||||
|
||||
MsScenario scenario = new MsScenario();
|
||||
scenario.setReferenced("REF");
|
||||
jmterHashTree(testPlan, scenario);
|
||||
this.projectId = request.getProjectId();
|
||||
ScenarioImport scenarioImport = new ScenarioImport();
|
||||
scenarioImport.setData(paseObj(scenario, request));
|
||||
scenarioImport.setProjectid(request.getProjectId());
|
||||
return scenarioImport;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
MSException.throwException("当前JMX版本不兼容");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<ApiScenarioWithBLOBs> paseObj(MsScenario msScenario, ApiTestImportRequest request) {
|
||||
List<ApiScenarioWithBLOBs> scenarioWithBLOBsList = new ArrayList<>();
|
||||
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
||||
ApiScenarioModule module = buildModule(getSelectModule(request.getModuleId()), msScenario.getName());
|
||||
scenarioWithBLOBs.setName(msScenario.getName());
|
||||
scenarioWithBLOBs.setProjectId(request.getProjectId());
|
||||
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
||||
scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size());
|
||||
}
|
||||
if (module != null) {
|
||||
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
||||
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
||||
}
|
||||
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
||||
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
||||
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
||||
return scenarioWithBLOBsList;
|
||||
}
|
||||
|
||||
private HashTree getHashTree(Object scriptWrapper) throws Exception {
|
||||
Field field = scriptWrapper.getClass().getDeclaredField("testPlan");
|
||||
field.setAccessible(true);
|
||||
return (HashTree) field.get(scriptWrapper);
|
||||
}
|
||||
|
||||
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, HTTPSamplerProxy source) {
|
||||
try {
|
||||
BeanUtils.copyBean(samplerProxy, source);
|
||||
if (source != null && source.getHTTPFiles().length > 0) {
|
||||
samplerProxy.getBody().setBinary(new ArrayList<>());
|
||||
samplerProxy.getBody().setType(Body.FORM_DATA);
|
||||
List<KeyValue> keyValues = new LinkedList<>();
|
||||
for (HTTPFileArg arg : source.getHTTPFiles()) {
|
||||
List<BodyFile> files = new LinkedList<>();
|
||||
BodyFile file = new BodyFile();
|
||||
file.setId(arg.getParamName());
|
||||
file.setName(arg.getPath());
|
||||
files.add(file);
|
||||
|
||||
KeyValue keyValue = new KeyValue(arg.getParamName(), arg.getParamName());
|
||||
keyValue.setContentType(arg.getProperty("HTTPArgument.content_type").toString());
|
||||
keyValue.setType("file");
|
||||
keyValue.setFiles(files);
|
||||
keyValues.add(keyValue);
|
||||
}
|
||||
samplerProxy.getBody().setKvs(keyValues);
|
||||
}
|
||||
samplerProxy.setProtocol(RequestType.HTTP);
|
||||
samplerProxy.setPort(source.getPort() + "");
|
||||
if (source.getArguments() != null) {
|
||||
if (source.getPostBodyRaw()) {
|
||||
samplerProxy.getBody().setType(Body.RAW);
|
||||
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
||||
samplerProxy.getBody().setRaw(v);
|
||||
});
|
||||
} else {
|
||||
List<KeyValue> keyValues = new LinkedList<>();
|
||||
source.getArguments().getArgumentsAsMap().forEach((k, v) -> {
|
||||
KeyValue keyValue = new KeyValue(k, v);
|
||||
keyValues.add(keyValue);
|
||||
});
|
||||
if (CollectionUtils.isNotEmpty(keyValues)) {
|
||||
samplerProxy.setArguments(keyValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
samplerProxy.setPath(source.getPath());
|
||||
samplerProxy.setMethod(source.getMethod());
|
||||
if (source.getUrl() != null) {
|
||||
// samplerProxy.setUrl(source.getUrl().toString());
|
||||
}
|
||||
samplerProxy.setId(UUID.randomUUID().toString());
|
||||
samplerProxy.setType("HTTPSamplerProxy");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void convertTCPSampler(MsTCPSampler msTCPSampler, TCPSampler tcpSampler) {
|
||||
msTCPSampler.setName(tcpSampler.getName());
|
||||
msTCPSampler.setType("TCPSampler");
|
||||
msTCPSampler.setServer(tcpSampler.getServer());
|
||||
msTCPSampler.setPort(tcpSampler.getPort() + "");
|
||||
msTCPSampler.setCtimeout(tcpSampler.getConnectTimeout() + "");
|
||||
msTCPSampler.setReUseConnection(tcpSampler.getProperty(TCPSampler.RE_USE_CONNECTION).getBooleanValue());
|
||||
msTCPSampler.setNodelay(tcpSampler.getProperty(TCPSampler.NODELAY).getBooleanValue());
|
||||
msTCPSampler.setCloseConnection(tcpSampler.isCloseConnection());
|
||||
msTCPSampler.setSoLinger(tcpSampler.getSoLinger() + "");
|
||||
msTCPSampler.setEolByte(tcpSampler.getEolByte() + "");
|
||||
msTCPSampler.setRequest(tcpSampler.getRequestData());
|
||||
msTCPSampler.setUsername(tcpSampler.getProperty(ConfigTestElement.USERNAME).getStringValue());
|
||||
msTCPSampler.setPassword(tcpSampler.getProperty(ConfigTestElement.PASSWORD).getStringValue());
|
||||
}
|
||||
|
||||
private void convertDubboSample(MsDubboSampler elementNode, DubboSample sampler) {
|
||||
elementNode.setName(sampler.getName());
|
||||
elementNode.setType("DubboSampler");
|
||||
elementNode.setProtocol("dubbo://");
|
||||
elementNode.set_interface(sampler.getPropertyAsString("FIELD_DUBBO_INTERFACE"));
|
||||
elementNode.setMethod(sampler.getPropertyAsString("FIELD_DUBBO_METHOD"));
|
||||
|
||||
MsConfigCenter configCenter = new MsConfigCenter();
|
||||
configCenter.setProtocol(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_PROTOCOL"));
|
||||
configCenter.setGroup(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_GROUP"));
|
||||
configCenter.setNamespace(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_NAMESPACE"));
|
||||
configCenter.setUsername(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_USER_NAME"));
|
||||
configCenter.setPassword(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_PASSWORD"));
|
||||
configCenter.setAddress(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_ADDRESS"));
|
||||
configCenter.setTimeout(sampler.getPropertyAsString("FIELD_DUBBO_CONFIG_CENTER_TIMEOUT"));
|
||||
elementNode.setConfigCenter(configCenter);
|
||||
|
||||
MsRegistryCenter registryCenter = new MsRegistryCenter();
|
||||
registryCenter.setProtocol(sampler.getPropertyAsString("FIELD_DUBBO_REGISTRY_PROTOCOL"));
|
||||
registryCenter.setAddress(sampler.getPropertyAsString("FIELD_DUBBO_ADDRESS"));
|
||||
registryCenter.setGroup(sampler.getPropertyAsString("FIELD_DUBBO_REGISTRY_GROUP"));
|
||||
registryCenter.setUsername(sampler.getPropertyAsString("FIELD_DUBBO_REGISTRY_USER_NAME"));
|
||||
registryCenter.setPassword(sampler.getPropertyAsString("FIELD_DUBBO_REGISTRY_PASSWORD"));
|
||||
registryCenter.setTimeout(sampler.getPropertyAsString("FIELD_DUBBO_REGISTRY_TIMEOUT"));
|
||||
elementNode.setRegistryCenter(registryCenter);
|
||||
|
||||
MsConsumerAndService consumerAndService = new MsConsumerAndService();
|
||||
consumerAndService.setAsync(sampler.getPropertyAsString("FIELD_DUBBO_ASYNC"));
|
||||
consumerAndService.setCluster(sampler.getPropertyAsString("FIELD_DUBBO_CLUSTER"));
|
||||
consumerAndService.setConnections(sampler.getPropertyAsString("FIELD_DUBBO_CONNECTIONS"));
|
||||
consumerAndService.setGroup(sampler.getPropertyAsString("FIELD_DUBBO_GROUP"));
|
||||
consumerAndService.setLoadBalance(sampler.getPropertyAsString("FIELD_DUBBO_LOADBALANCE"));
|
||||
consumerAndService.setVersion(sampler.getPropertyAsString("FIELD_DUBBO_VERSION"));
|
||||
consumerAndService.setTimeout(sampler.getPropertyAsString("FIELD_DUBBO_TIMEOUT"));
|
||||
elementNode.setConsumerAndService(consumerAndService);
|
||||
|
||||
List<MethodArgument> methodArguments = Constants.getMethodArgs(sampler);
|
||||
if (CollectionUtils.isNotEmpty(methodArguments)) {
|
||||
List<KeyValue> methodArgs = new LinkedList<>();
|
||||
methodArguments.forEach(item -> {
|
||||
KeyValue keyValue = new KeyValue(item.getParamType(), item.getParamValue());
|
||||
methodArgs.add(keyValue);
|
||||
});
|
||||
elementNode.setArgs(methodArgs);
|
||||
}
|
||||
|
||||
List<MethodArgument> arguments = Constants.getAttachmentArgs(sampler);
|
||||
if (CollectionUtils.isNotEmpty(arguments)) {
|
||||
List<KeyValue> methodArgs = new LinkedList<>();
|
||||
arguments.forEach(item -> {
|
||||
KeyValue keyValue = new KeyValue(item.getParamType(), item.getParamValue());
|
||||
methodArgs.add(keyValue);
|
||||
});
|
||||
elementNode.setAttachmentArgs(methodArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先初始化数据池
|
||||
*/
|
||||
private void preInitPool(String projectId, HashTree hashTree) {
|
||||
// 初始化已有数据池
|
||||
initDataSource(projectId, ENV_NAME);
|
||||
// 添加当前jmx 中新的数据池
|
||||
preCreatePool(hashTree);
|
||||
// 更新数据源
|
||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||
dataPools.getEnvConfig().setDatabaseConfigs(new ArrayList<>(dataPools.getDataSources().values()));
|
||||
if (dataPools.getIsCreate()) {
|
||||
dataPools.getTestEnvironmentWithBLOBs().setConfig(JSON.toJSONString(dataPools.getEnvConfig()));
|
||||
String id = environmentService.add(dataPools.getTestEnvironmentWithBLOBs());
|
||||
dataPools.setEnvId(id);
|
||||
} else {
|
||||
dataPools.getTestEnvironmentWithBLOBs().setConfig(JSON.toJSONString(dataPools.getEnvConfig()));
|
||||
environmentService.update(dataPools.getTestEnvironmentWithBLOBs());
|
||||
}
|
||||
}
|
||||
|
||||
private void preCreatePool(HashTree tree) {
|
||||
for (Object key : tree.keySet()) {
|
||||
// JDBC 数据池
|
||||
if (key instanceof DataSourceElement) {
|
||||
DataSourceElement dataSourceElement = (DataSourceElement) key;
|
||||
if (dataPools != null && dataPools.getDataSources() != null && dataPools.getDataSources().containsKey(dataSourceElement.getPropertyAsString("dataSource"))) {
|
||||
DatabaseConfig config = dataPools.getDataSources().get(dataSourceElement.getPropertyAsString("dataSource"));
|
||||
DatabaseConfig newConfig = new DatabaseConfig();
|
||||
newConfig.setUsername(dataSourceElement.getPropertyAsString("username"));
|
||||
newConfig.setPassword(dataSourceElement.getPropertyAsString("password"));
|
||||
newConfig.setDriver(dataSourceElement.getPropertyAsString("driver"));
|
||||
newConfig.setDbUrl(dataSourceElement.getPropertyAsString("dbUrl"));
|
||||
newConfig.setName(dataSourceElement.getPropertyAsString("dataSource"));
|
||||
newConfig.setPoolMax(dataSourceElement.getPropertyAsInt("poolMax"));
|
||||
newConfig.setTimeout(dataSourceElement.getPropertyAsInt("timeout"));
|
||||
newConfig.setId(config.getId());
|
||||
dataPools.getDataSources().put(dataSourceElement.getPropertyAsString("dataSource"), newConfig);
|
||||
} else {
|
||||
DatabaseConfig newConfig = new DatabaseConfig();
|
||||
newConfig.setId(UUID.randomUUID().toString());
|
||||
newConfig.setUsername(dataSourceElement.getPropertyAsString("username"));
|
||||
newConfig.setPassword(dataSourceElement.getPropertyAsString("password"));
|
||||
newConfig.setDriver(dataSourceElement.getPropertyAsString("driver"));
|
||||
newConfig.setDbUrl(dataSourceElement.getPropertyAsString("dbUrl"));
|
||||
newConfig.setName(dataSourceElement.getPropertyAsString("dataSource"));
|
||||
newConfig.setPoolMax(dataSourceElement.getPropertyAsInt("poolMax"));
|
||||
newConfig.setTimeout(dataSourceElement.getPropertyAsInt("timeout"));
|
||||
if (dataPools.getDataSources() == null) {
|
||||
dataPools.setDataSources(new HashMap<>());
|
||||
}
|
||||
dataPools.getDataSources().put(dataSourceElement.getPropertyAsString("dataSource"), newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归子项
|
||||
HashTree node = tree.get(key);
|
||||
if (node != null) {
|
||||
preCreatePool(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ImportPoolsDTO dataPools;
|
||||
|
||||
private void initDataSource(String projectId, String name) {
|
||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo(name);
|
||||
// 这里的数据只有一条,如果多条则有问题
|
||||
List<ApiTestEnvironmentWithBLOBs> environments = environmentService.selectByExampleWithBLOBs(example);
|
||||
dataPools = new ImportPoolsDTO();
|
||||
if (CollectionUtils.isNotEmpty(environments)) {
|
||||
dataPools.setIsCreate(false);
|
||||
dataPools.setTestEnvironmentWithBLOBs(environments.get(0));
|
||||
Map<String, DatabaseConfig> dataSources = new HashMap<>();
|
||||
environments.forEach(environment -> {
|
||||
if (environment != null && environment.getConfig() != null) {
|
||||
EnvironmentConfig envConfig = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
||||
dataPools.setEnvConfig(envConfig);
|
||||
if (envConfig != null && CollectionUtils.isNotEmpty(envConfig.getDatabaseConfigs())) {
|
||||
envConfig.getDatabaseConfigs().forEach(item -> {
|
||||
dataSources.put(item.getName(), item);
|
||||
});
|
||||
}
|
||||
}
|
||||
dataPools.setEnvId(environment.getId());
|
||||
dataPools.setDataSources(dataSources);
|
||||
});
|
||||
} else {
|
||||
dataPools.setIsCreate(true);
|
||||
ApiTestEnvironmentWithBLOBs apiTestEnvironmentWithBLOBs = new ApiTestEnvironmentWithBLOBs();
|
||||
apiTestEnvironmentWithBLOBs.setId(UUID.randomUUID().toString());
|
||||
dataPools.setEnvId(apiTestEnvironmentWithBLOBs.getId());
|
||||
dataPools.setEnvConfig(new EnvironmentConfig());
|
||||
apiTestEnvironmentWithBLOBs.setName(ENV_NAME);
|
||||
apiTestEnvironmentWithBLOBs.setProjectId(projectId);
|
||||
dataPools.setTestEnvironmentWithBLOBs(apiTestEnvironmentWithBLOBs);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertJDBCSampler(MsJDBCSampler msJDBCSampler, JDBCSampler jdbcSampler) {
|
||||
msJDBCSampler.setType("JDBCSampler");
|
||||
msJDBCSampler.setName(jdbcSampler.getName());
|
||||
msJDBCSampler.setProtocol("SQL");
|
||||
msJDBCSampler.setQuery(jdbcSampler.getPropertyAsString("query"));
|
||||
msJDBCSampler.setQueryTimeout(jdbcSampler.getPropertyAsInt("queryTimeout"));
|
||||
msJDBCSampler.setResultVariable(jdbcSampler.getPropertyAsString("resultVariable"));
|
||||
msJDBCSampler.setVariableNames(jdbcSampler.getPropertyAsString("variableNames"));
|
||||
msJDBCSampler.setEnvironmentId(dataPools.getEnvId());
|
||||
if (dataPools.getDataSources() != null && dataPools.getDataSources().get(jdbcSampler.getPropertyAsString("dataSource")) != null) {
|
||||
msJDBCSampler.setDataSourceId(dataPools.getDataSources().get(jdbcSampler.getPropertyAsString("dataSource")).getId());
|
||||
}
|
||||
msJDBCSampler.setVariables(new LinkedList<>());
|
||||
}
|
||||
|
||||
private void convertMsExtract(MsExtract extract, Object key) {
|
||||
// 提取数据单独处理
|
||||
extract.setType("Extract");
|
||||
extract.setJson(new LinkedList<>());
|
||||
extract.setRegex(new LinkedList<>());
|
||||
extract.setXpath(new LinkedList<>());
|
||||
if (key instanceof RegexExtractor) {
|
||||
MsExtractRegex regex = new MsExtractRegex();
|
||||
RegexExtractor regexExtractor = (RegexExtractor) key;
|
||||
if (regexExtractor.useRequestHeaders()) {
|
||||
regex.setUseHeaders("request_headers");
|
||||
} else if (regexExtractor.useBody()) {
|
||||
regex.setUseHeaders("false");
|
||||
} else if (regexExtractor.useUnescapedBody()) {
|
||||
regex.setUseHeaders("unescaped");
|
||||
} else if (regexExtractor.useBodyAsDocument()) {
|
||||
regex.setUseHeaders("as_document");
|
||||
} else if (regexExtractor.useUrl()) {
|
||||
regex.setUseHeaders("URL");
|
||||
}
|
||||
regex.setExpression(regexExtractor.getRegex());
|
||||
regex.setVariable(regexExtractor.getRefName());
|
||||
extract.setName(regexExtractor.getName());
|
||||
extract.getRegex().add(regex);
|
||||
} else if (key instanceof XPath2Extractor) {
|
||||
XPath2Extractor xPath2Extractor = (XPath2Extractor) key;
|
||||
MsExtractXPath xPath = new MsExtractXPath();
|
||||
xPath.setVariable(xPath2Extractor.getRefName());
|
||||
xPath.setExpression(xPath2Extractor.getXPathQuery());
|
||||
|
||||
extract.setName(xPath2Extractor.getName());
|
||||
extract.getXpath().add(xPath);
|
||||
} else if (key instanceof JSONPostProcessor) {
|
||||
JSONPostProcessor jsonPostProcessor = (JSONPostProcessor) key;
|
||||
MsExtractJSONPath jsonPath = new MsExtractJSONPath();
|
||||
jsonPath.setVariable(jsonPostProcessor.getRefNames());
|
||||
jsonPath.setExpression(jsonPostProcessor.getJsonPathExpressions());
|
||||
extract.setName(jsonPostProcessor.getName());
|
||||
extract.getJson().add(jsonPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertMsAssertions(MsAssertions assertions, Object key) {
|
||||
assertions.setJsonPath(new LinkedList<>());
|
||||
assertions.setJsr223(new LinkedList<>());
|
||||
assertions.setXpath2(new LinkedList<>());
|
||||
assertions.setRegex(new LinkedList<>());
|
||||
assertions.setDuration(new MsAssertionDuration());
|
||||
assertions.setType("Assertions");
|
||||
if (key instanceof ResponseAssertion) {
|
||||
MsAssertionRegex assertionRegex = new MsAssertionRegex();
|
||||
ResponseAssertion assertion = (ResponseAssertion) key;
|
||||
assertionRegex.setDescription(assertion.getName());
|
||||
assertionRegex.setAssumeSuccess(assertion.getAssumeSuccess());
|
||||
if (assertion.getTestStrings() != null && !assertion.getTestStrings().isEmpty()) {
|
||||
assertionRegex.setExpression(assertion.getTestStrings().get(0).getStringValue());
|
||||
}
|
||||
if (assertion.isTestFieldRequestData()) {
|
||||
assertionRegex.setSubject("Response Data");
|
||||
}
|
||||
if (assertion.isTestFieldResponseCode()) {
|
||||
assertionRegex.setSubject("Response Code");
|
||||
}
|
||||
if (assertion.isTestFieldRequestHeaders()) {
|
||||
assertionRegex.setSubject("Response Headers");
|
||||
}
|
||||
assertions.setName(assertion.getName());
|
||||
assertions.getRegex().add(assertionRegex);
|
||||
} else if (key instanceof JSONPathAssertion) {
|
||||
MsAssertionJsonPath assertionJsonPath = new MsAssertionJsonPath();
|
||||
JSONPathAssertion jsonPathAssertion = (JSONPathAssertion) key;
|
||||
assertionJsonPath.setDescription(jsonPathAssertion.getName());
|
||||
assertionJsonPath.setExpression(jsonPathAssertion.getJsonPath());
|
||||
assertionJsonPath.setExpect(jsonPathAssertion.getExpectedValue());
|
||||
assertions.setName(jsonPathAssertion.getName());
|
||||
assertions.getJsonPath().add(assertionJsonPath);
|
||||
} else if (key instanceof XPath2Assertion) {
|
||||
MsAssertionXPath2 assertionXPath2 = new MsAssertionXPath2();
|
||||
XPath2Assertion xPath2Assertion = (XPath2Assertion) key;
|
||||
assertionXPath2.setExpression(xPath2Assertion.getXPathString());
|
||||
assertions.setName(xPath2Assertion.getName());
|
||||
assertions.getXpath2().add(assertionXPath2);
|
||||
} else if (key instanceof JSR223Assertion) {
|
||||
MsAssertionJSR223 msAssertionJSR223 = new MsAssertionJSR223();
|
||||
JSR223Assertion jsr223Assertion = (JSR223Assertion) key;
|
||||
msAssertionJSR223.setName(jsr223Assertion.getName());
|
||||
msAssertionJSR223.setDesc(jsr223Assertion.getName());
|
||||
msAssertionJSR223.setScript(jsr223Assertion.getPropertyAsString("script"));
|
||||
msAssertionJSR223.setScriptLanguage(jsr223Assertion.getPropertyAsString("scriptLanguage"));
|
||||
assertions.setName(jsr223Assertion.getName());
|
||||
|
||||
assertions.getJsr223().add(msAssertionJSR223);
|
||||
} else if (key instanceof DurationAssertion) {
|
||||
MsAssertionDuration assertionDuration = new MsAssertionDuration();
|
||||
DurationAssertion durationAssertion = (DurationAssertion) key;
|
||||
assertionDuration.setValue(durationAssertion.getProperty("DurationAssertion.duration").getIntValue());
|
||||
assertions.setName(durationAssertion.getName());
|
||||
assertions.setDuration(assertionDuration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 把节点对象转成XML,不然执行时无法正常转换
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static String objToXml(Object obj) {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
SaveService.saveElement(obj, baos);
|
||||
return baos.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.warn("HashTree error, can't log jmx scenarioDefinition");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void jmterHashTree(HashTree tree, MsTestElement scenario) {
|
||||
for (Object key : tree.keySet()) {
|
||||
MsTestElement elementNode;
|
||||
if (CollectionUtils.isEmpty(scenario.getHashTree())) {
|
||||
scenario.setHashTree(new LinkedList<>());
|
||||
}
|
||||
// 测试计划
|
||||
if (key instanceof TestPlan) {
|
||||
scenario.setName(((TestPlan) key).getName());
|
||||
elementNode = new MsJmeterElement();
|
||||
elementNode.setName(((TestPlan) key).getName());
|
||||
((MsJmeterElement) elementNode).setJmeterElement(objToXml(key));
|
||||
}
|
||||
// 线程组
|
||||
else if (key instanceof ThreadGroup) {
|
||||
elementNode = new MsScenario(((ThreadGroup) key).getName());
|
||||
}
|
||||
// HTTP请求
|
||||
else if (key instanceof HTTPSamplerProxy) {
|
||||
elementNode = new MsHTTPSamplerProxy();
|
||||
((MsHTTPSamplerProxy) elementNode).setBody(new Body());
|
||||
convertHttpSampler((MsHTTPSamplerProxy) elementNode, (HTTPSamplerProxy) key);
|
||||
}
|
||||
// TCP请求
|
||||
else if (key instanceof TCPSampler) {
|
||||
elementNode = new MsTCPSampler();
|
||||
TCPSampler tcpSampler = (TCPSampler) key;
|
||||
convertTCPSampler((MsTCPSampler) elementNode, tcpSampler);
|
||||
}
|
||||
// DUBBO请求
|
||||
else if (key instanceof DubboSample) {
|
||||
DubboSample sampler = (DubboSample) key;
|
||||
elementNode = new MsDubboSampler();
|
||||
convertDubboSample((MsDubboSampler) elementNode, sampler);
|
||||
}
|
||||
// JDBC请求
|
||||
else if (key instanceof JDBCSampler) {
|
||||
elementNode = new MsJDBCSampler();
|
||||
JDBCSampler jdbcSampler = (JDBCSampler) key;
|
||||
convertJDBCSampler((MsJDBCSampler) elementNode, jdbcSampler);
|
||||
}
|
||||
// JSR自定义脚本
|
||||
else if (key instanceof JSR223Sampler) {
|
||||
JSR223Sampler jsr223Sampler = (JSR223Sampler) key;
|
||||
elementNode = new MsJSR223Processor();
|
||||
BeanUtils.copyBean(elementNode, jsr223Sampler);
|
||||
((MsJSR223Processor) elementNode).setScript(jsr223Sampler.getPropertyAsString("script"));
|
||||
((MsJSR223Processor) elementNode).setScriptLanguage(jsr223Sampler.getPropertyAsString("scriptLanguage"));
|
||||
}
|
||||
// 后置脚本
|
||||
else if (key instanceof JSR223PostProcessor) {
|
||||
JSR223PostProcessor jsr223Sampler = (JSR223PostProcessor) key;
|
||||
elementNode = new MsJSR223PostProcessor();
|
||||
BeanUtils.copyBean(elementNode, jsr223Sampler);
|
||||
((MsJSR223PostProcessor) elementNode).setScript(jsr223Sampler.getPropertyAsString("script"));
|
||||
((MsJSR223PostProcessor) elementNode).setScriptLanguage(jsr223Sampler.getPropertyAsString("scriptLanguage"));
|
||||
}
|
||||
// 前置脚本
|
||||
else if (key instanceof JSR223PreProcessor) {
|
||||
JSR223PreProcessor jsr223Sampler = (JSR223PreProcessor) key;
|
||||
elementNode = new MsJSR223PreProcessor();
|
||||
BeanUtils.copyBean(elementNode, jsr223Sampler);
|
||||
((MsJSR223PreProcessor) elementNode).setScript(jsr223Sampler.getPropertyAsString("script"));
|
||||
((MsJSR223PreProcessor) elementNode).setScriptLanguage(jsr223Sampler.getPropertyAsString("scriptLanguage"));
|
||||
}
|
||||
// 断言规则
|
||||
else if (key instanceof ResponseAssertion || key instanceof JSONPathAssertion || key instanceof XPath2Assertion || key instanceof JSR223Assertion || key instanceof DurationAssertion) {
|
||||
elementNode = new MsAssertions();
|
||||
convertMsAssertions((MsAssertions) elementNode, key);
|
||||
}
|
||||
// 提取参数
|
||||
else if (key instanceof RegexExtractor || key instanceof XPath2Extractor || key instanceof JSONPostProcessor) {
|
||||
elementNode = new MsExtract();
|
||||
convertMsExtract((MsExtract) elementNode, key);
|
||||
}
|
||||
// 定时器
|
||||
else if (key instanceof ConstantTimer) {
|
||||
elementNode = new MsConstantTimer();
|
||||
BeanUtils.copyBean(elementNode, key);
|
||||
elementNode.setType("ConstantTimer");
|
||||
}
|
||||
// IF条件控制器
|
||||
else if (key instanceof IfController) {
|
||||
elementNode = new MsIfController();
|
||||
BeanUtils.copyBean(elementNode, key);
|
||||
elementNode.setType("IfController");
|
||||
}
|
||||
// 次数循环控制器
|
||||
else if (key instanceof LoopController) {
|
||||
elementNode = new MsLoopController();
|
||||
BeanUtils.copyBean(elementNode, key);
|
||||
elementNode.setType("LoopController");
|
||||
((MsLoopController) elementNode).setLoopType(LoopConstants.LOOP_COUNT.name());
|
||||
LoopController loopController = (LoopController) key;
|
||||
CountController countController = new CountController();
|
||||
countController.setLoops(loopController.getLoops());
|
||||
countController.setProceed(true);
|
||||
((MsLoopController) elementNode).setCountController(countController);
|
||||
}
|
||||
// While循环控制器
|
||||
else if (key instanceof WhileController) {
|
||||
elementNode = new MsLoopController();
|
||||
BeanUtils.copyBean(elementNode, key);
|
||||
elementNode.setType("LoopController");
|
||||
((MsLoopController) elementNode).setLoopType(LoopConstants.WHILE.name());
|
||||
WhileController whileController = (WhileController) key;
|
||||
MsWhileController countController = new MsWhileController();
|
||||
countController.setValue(whileController.getCondition());
|
||||
((MsLoopController) elementNode).setWhileController(countController);
|
||||
}
|
||||
// Foreach 循环控制器
|
||||
else if (key instanceof ForeachController) {
|
||||
elementNode = new MsLoopController();
|
||||
BeanUtils.copyBean(elementNode, key);
|
||||
elementNode.setType("LoopController");
|
||||
((MsLoopController) elementNode).setLoopType(LoopConstants.FOREACH.name());
|
||||
ForeachController foreachController = (ForeachController) key;
|
||||
MsForEachController countController = new MsForEachController();
|
||||
countController.setInputVal(foreachController.getInputValString());
|
||||
countController.setReturnVal(foreachController.getReturnValString());
|
||||
((MsLoopController) elementNode).setForEachController(countController);
|
||||
}
|
||||
// 平台不能识别的Jmeter步骤
|
||||
else {
|
||||
elementNode = new MsJmeterElement();
|
||||
elementNode.setType("JmeterElement");
|
||||
TestElement testElement = (TestElement) key;
|
||||
elementNode.setName(testElement.getName());
|
||||
((MsJmeterElement) elementNode).setJmeterElement(objToXml(key));
|
||||
}
|
||||
elementNode.setEnable(((TestElement) key).isEnabled());
|
||||
elementNode.setResourceId(UUID.randomUUID().toString());
|
||||
elementNode.setId(UUID.randomUUID().toString());
|
||||
elementNode.setIndex(scenario.getHashTree().size() + 1 + "");
|
||||
// 提取参数
|
||||
if (elementNode instanceof MsExtract) {
|
||||
if (CollectionUtils.isNotEmpty(((MsExtract) elementNode).getJson()) || CollectionUtils.isNotEmpty(((MsExtract) elementNode).getRegex()) || CollectionUtils.isNotEmpty(((MsExtract) elementNode).getXpath())) {
|
||||
scenario.getHashTree().add(elementNode);
|
||||
}
|
||||
}
|
||||
//断言规则
|
||||
else if (elementNode instanceof MsAssertions) {
|
||||
if (CollectionUtils.isNotEmpty(((MsAssertions) elementNode).getRegex()) || CollectionUtils.isNotEmpty(((MsAssertions) elementNode).getJsonPath())
|
||||
|| CollectionUtils.isNotEmpty(((MsAssertions) elementNode).getJsr223()) || CollectionUtils.isNotEmpty(((MsAssertions) elementNode).getXpath2()) || ((MsAssertions) elementNode).getDuration() != null) {
|
||||
scenario.getHashTree().add(elementNode);
|
||||
}
|
||||
}
|
||||
// 争取其他请求
|
||||
else {
|
||||
scenario.getHashTree().add(elementNode);
|
||||
}
|
||||
// 递归子项
|
||||
HashTree node = tree.get(key);
|
||||
if (node != null) {
|
||||
jmterHashTree(node, elementNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.definition.request.MsScenario;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.parse.postman.*;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.base.domain.ApiScenarioModule;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.commons.constants.MsRequestBodyType;
|
||||
import io.metersphere.commons.constants.PostmanRequestBodyMode;
|
||||
import io.metersphere.commons.constants.VariableTypeConstants;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MsPostmanParser extends ScenarioImportAbstractParser {
|
||||
|
||||
@Override
|
||||
public ScenarioImport parse(InputStream source, ApiTestImportRequest request) {
|
||||
String testStr = getApiTestStr(source);
|
||||
PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class);
|
||||
List<PostmanKeyValue> variables = postmanCollection.getVariable();
|
||||
ScenarioImport scenarioImport = new ScenarioImport();
|
||||
// 场景步骤
|
||||
LinkedList<MsTestElement> apiScenarioWithBLOBs = new LinkedList<>();
|
||||
PostmanCollectionInfo info = postmanCollection.getInfo();
|
||||
ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs();
|
||||
scenario.setName(info.getName());
|
||||
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setName(info.getName());
|
||||
this.projectId = request.getProjectId();
|
||||
parseItem(postmanCollection.getItem(), variables, msScenario, apiScenarioWithBLOBs);
|
||||
// 生成场景对象
|
||||
List<ApiScenarioWithBLOBs> scenarioWithBLOBs = new LinkedList<>();
|
||||
paseScenario(scenarioWithBLOBs, msScenario, request);
|
||||
scenarioImport.setData(scenarioWithBLOBs);
|
||||
return scenarioImport;
|
||||
}
|
||||
|
||||
private void paseScenario(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
|
||||
ApiScenarioModule module = buildModule(getSelectModule(request.getModuleId()), msScenario.getName());
|
||||
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
||||
scenarioWithBLOBs.setName(msScenario.getName());
|
||||
scenarioWithBLOBs.setProjectId(request.getProjectId());
|
||||
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
||||
scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size());
|
||||
}
|
||||
if (module != null) {
|
||||
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
||||
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
||||
}
|
||||
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
||||
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
||||
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
||||
}
|
||||
|
||||
private void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, MsScenario scenario, LinkedList<MsTestElement> results) {
|
||||
for (PostmanItem item : items) {
|
||||
List<PostmanItem> childItems = item.getItem();
|
||||
if (childItems != null) {
|
||||
parseItem(childItems, variables, scenario, results);
|
||||
} else {
|
||||
MsHTTPSamplerProxy request = parsePostman(item);
|
||||
if (request != null) {
|
||||
results.add(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
scenario.setVariables(parseScenarioVariable(variables));
|
||||
scenario.setHashTree(results);
|
||||
}
|
||||
|
||||
private MsHTTPSamplerProxy parsePostman(PostmanItem requestItem) {
|
||||
PostmanRequest requestDesc = requestItem.getRequest();
|
||||
if (requestDesc == null) {
|
||||
return null;
|
||||
}
|
||||
requestDesc.getAuth(); // todo 认证方式等待优化
|
||||
PostmanUrl url = requestDesc.getUrl();
|
||||
MsHTTPSamplerProxy request = buildRequest(requestItem.getName(), url.getRaw(), requestDesc.getMethod());
|
||||
if (StringUtils.isNotBlank(request.getPath())) {
|
||||
String path = request.getPath().split("\\?")[0];
|
||||
path = path.replace("{{", "${");
|
||||
path = path.replace("}}", "}");
|
||||
request.setPath(path);
|
||||
} else {
|
||||
request.setPath("/");
|
||||
}
|
||||
parseBody(request.getBody(), requestDesc);
|
||||
request.setArguments(parseKeyValue(url.getQuery()));
|
||||
request.setHeaders(parseKeyValue(requestDesc.getHeader()));
|
||||
addBodyHeader(request);
|
||||
addPreScript(request, requestItem.getEvent());
|
||||
return request;
|
||||
}
|
||||
|
||||
private void addPreScript(MsHTTPSamplerProxy request, List<PostmanEvent> event) {
|
||||
if (request != null && CollectionUtils.isNotEmpty(event)) {
|
||||
StringBuilder scriptStr = new StringBuilder();
|
||||
event = event.stream()
|
||||
.filter(item -> item.getScript() != null)
|
||||
.collect(Collectors.toList());
|
||||
event.forEach(item -> {
|
||||
PostmanScript script = item.getScript();
|
||||
if (script != null) {
|
||||
List<String> exec = script.getExec();
|
||||
if (CollectionUtils.isNotEmpty(exec)) {
|
||||
exec.forEach(col -> {
|
||||
if (StringUtils.isNotEmpty(col)) {
|
||||
scriptStr.append(col + "/n");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (StringUtils.isNotBlank(scriptStr)) {
|
||||
MsJSR223PreProcessor jsr223PreProcessor = new MsJSR223PreProcessor();
|
||||
jsr223PreProcessor.setName("JSR223PreProcessor");
|
||||
jsr223PreProcessor.setScriptLanguage("javascript");
|
||||
jsr223PreProcessor.setScript(scriptStr.toString());
|
||||
LinkedList<MsTestElement> hashTree = new LinkedList<>();
|
||||
hashTree.add(jsr223PreProcessor);
|
||||
request.setHashTree(hashTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<KeyValue> parseKeyValue(List<PostmanKeyValue> postmanKeyValues) {
|
||||
if (postmanKeyValues == null) {
|
||||
return null;
|
||||
}
|
||||
List<KeyValue> keyValues = new ArrayList<>();
|
||||
postmanKeyValues.forEach(item -> keyValues.add(new KeyValue(item.getKey(), item.getValue(), item.getDescription(), item.getContentType())));
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
private List<ScenarioVariable> parseScenarioVariable(List<PostmanKeyValue> postmanKeyValues) {
|
||||
if (postmanKeyValues == null) {
|
||||
return null;
|
||||
}
|
||||
List<ScenarioVariable> keyValues = new ArrayList<>();
|
||||
postmanKeyValues.forEach(item -> keyValues.add(new ScenarioVariable(item.getKey(), item.getValue(), item.getDescription(), VariableTypeConstants.CONSTANT.name())));
|
||||
return keyValues;
|
||||
}
|
||||
|
||||
private void parseBody(Body body, PostmanRequest requestDesc) {
|
||||
JSONObject postmanBody = requestDesc.getBody();
|
||||
if (postmanBody == null) {
|
||||
return;
|
||||
}
|
||||
String bodyMode = postmanBody.getString("mode");
|
||||
if (StringUtils.isNotEmpty(bodyMode) && StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) {
|
||||
parseRawBody(body, postmanBody, bodyMode);
|
||||
} else if (StringUtils.isNotEmpty(bodyMode) && StringUtils.equalsAny(bodyMode, PostmanRequestBodyMode.FORM_DATA.value(), PostmanRequestBodyMode.URLENCODED.value())) {
|
||||
List<PostmanKeyValue> postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class);
|
||||
body.setKvs(parseKeyValue(postmanKeyValues));
|
||||
if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value())) {
|
||||
body.setType(Body.FORM_DATA);
|
||||
} else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) {
|
||||
body.setType(Body.WWW_FROM);
|
||||
}
|
||||
} else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FILE.value())) {
|
||||
body.setType(Body.BINARY);
|
||||
body.setKvs(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRawBody(Body body, JSONObject postmanBody, String bodyMode) {
|
||||
body.setRaw(postmanBody.getString(bodyMode));
|
||||
body.setType(MsRequestBodyType.RAW.value());
|
||||
JSONObject options = postmanBody.getJSONObject("options");
|
||||
if (options != null) {
|
||||
JSONObject raw = options.getJSONObject(PostmanRequestBodyMode.RAW.value());
|
||||
if (raw != null && raw.getString("language") != null) {
|
||||
String bodyType = "";
|
||||
switch (raw.getString("language")) {
|
||||
case "json":
|
||||
bodyType = Body.JSON;
|
||||
break;
|
||||
case "xml":
|
||||
bodyType = Body.XML;
|
||||
break;
|
||||
default:
|
||||
bodyType = Body.RAW;
|
||||
}
|
||||
body.setType(bodyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.base.domain.ApiScenarioModule;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MsScenarioParser extends ScenarioImportAbstractParser {
|
||||
|
||||
@Override
|
||||
public ScenarioImport parse(InputStream source, ApiTestImportRequest request) {
|
||||
String testStr = getApiTestStr(source);
|
||||
this.projectId = request.getProjectId();
|
||||
ScenarioImport scenarioImport = parseMsFormat(testStr, request);
|
||||
return scenarioImport;
|
||||
}
|
||||
|
||||
private ScenarioImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
|
||||
ScenarioImport apiDefinitionImport = JSON.parseObject(testStr, ScenarioImport.class);
|
||||
List<ApiScenarioWithBLOBs> data = apiDefinitionImport.getData();
|
||||
if (CollectionUtils.isNotEmpty(data)) {
|
||||
data.forEach(item -> {
|
||||
if (StringUtils.isBlank(item.getModulePath())) {
|
||||
item.setApiScenarioModuleId(null);
|
||||
}
|
||||
parseModule(item, importRequest);
|
||||
item.setId(UUID.randomUUID().toString());
|
||||
item.setProjectId(this.projectId);
|
||||
});
|
||||
}
|
||||
return apiDefinitionImport;
|
||||
}
|
||||
|
||||
private void parseModule(ApiScenarioWithBLOBs apiDefinition, ApiTestImportRequest importRequest) {
|
||||
String modulePath = apiDefinition.getModulePath();
|
||||
if (StringUtils.isEmpty(modulePath)) {
|
||||
return;
|
||||
}
|
||||
if (modulePath.startsWith("/")) {
|
||||
modulePath = modulePath.substring(1, modulePath.length());
|
||||
}
|
||||
if (modulePath.endsWith("/")) {
|
||||
modulePath = modulePath.substring(0, modulePath.length() - 1);
|
||||
}
|
||||
List<String> modules = Arrays.asList(modulePath.split("/"));
|
||||
ApiScenarioModule parent = getSelectModule(importRequest.getModuleId());
|
||||
Iterator<String> iterator = modules.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String item = iterator.next();
|
||||
parent = buildModule(parent, item);
|
||||
if (!iterator.hasNext()) {
|
||||
apiDefinition.setApiScenarioModuleId(parent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ScenarioImport {
|
||||
private String projectid;
|
||||
private List<ApiScenarioWithBLOBs> data;
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import io.metersphere.api.dto.automation.ApiScenarioModuleDTO;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.service.ApiScenarioModuleService;
|
||||
import io.metersphere.base.domain.ApiScenarioModule;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class ScenarioImportAbstractParser implements ScenarioImportParser {
|
||||
protected ApiScenarioModuleService apiModuleService;
|
||||
protected String projectId;
|
||||
|
||||
protected ApiScenarioModule getSelectModule(String moduleId) {
|
||||
apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
||||
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
|
||||
ApiScenarioModule module = new ApiScenarioModule();
|
||||
ApiScenarioModuleDTO moduleDTO = apiModuleService.getNode(moduleId);
|
||||
if (moduleDTO != null) {
|
||||
BeanUtils.copyBean(module, moduleDTO);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ApiScenarioModule buildModule(ApiScenarioModule parentModule, String name) {
|
||||
apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
||||
ApiScenarioModule module;
|
||||
if (parentModule != null) {
|
||||
module = apiModuleService.getNewModule(name, this.projectId, parentModule.getLevel() + 1);
|
||||
module.setParentId(parentModule.getId());
|
||||
} else {
|
||||
module = apiModuleService.getNewModule(name, this.projectId, 1);
|
||||
}
|
||||
createModule(module);
|
||||
return module;
|
||||
}
|
||||
|
||||
protected void createModule(ApiScenarioModule module) {
|
||||
List<ApiScenarioModule> apiModules = apiModuleService.selectSameModule(module);
|
||||
if (CollectionUtils.isEmpty(apiModules)) {
|
||||
apiModuleService.addNode(module);
|
||||
} else {
|
||||
module.setId(apiModules.get(0).getId());
|
||||
}
|
||||
}
|
||||
|
||||
protected String getApiTestStr(InputStream source) {
|
||||
StringBuilder testStr = null;
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8))) {
|
||||
testStr = new StringBuilder();
|
||||
String inputStr;
|
||||
while ((inputStr = bufferedReader.readLine()) != null) {
|
||||
testStr.append(inputStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MSException.throwException(e.getMessage());
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
if (source != null) {
|
||||
source.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MSException.throwException(e.getMessage());
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return testStr.toString();
|
||||
}
|
||||
|
||||
private String formatPath(String url) {
|
||||
try {
|
||||
URL urlObject = new URL(url);
|
||||
StringBuilder pathBuffer = new StringBuilder(urlObject.getPath());
|
||||
if (StringUtils.isNotEmpty(urlObject.getQuery())) {
|
||||
pathBuffer.append("?").append(urlObject.getQuery());
|
||||
}
|
||||
return pathBuffer.toString();
|
||||
} catch (Exception ex) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
protected MsHTTPSamplerProxy buildRequest(String name, String path, String method) {
|
||||
MsHTTPSamplerProxy request = new MsHTTPSamplerProxy();
|
||||
request.setName(name);
|
||||
// 路径去掉域名/IP 地址,保留方法名称及参数
|
||||
request.setPath(formatPath(path));
|
||||
request.setMethod(method);
|
||||
request.setProtocol(RequestType.HTTP);
|
||||
request.setId(UUID.randomUUID().toString());
|
||||
request.setHeaders(new ArrayList<>());
|
||||
request.setArguments(new ArrayList<>());
|
||||
request.setRest(new ArrayList<>());
|
||||
request.setAuthManager(null);
|
||||
Body body = new Body();
|
||||
body.initKvs();
|
||||
body.initBinary();
|
||||
request.setBody(body);
|
||||
return request;
|
||||
}
|
||||
|
||||
protected void addHeader(List<KeyValue> headers, String key, String value, String description, String contentType, boolean required) {
|
||||
boolean hasContentType = false;
|
||||
for (KeyValue header : headers) {
|
||||
if (StringUtils.equalsIgnoreCase(header.getName(), key)) {
|
||||
hasContentType = true;
|
||||
}
|
||||
}
|
||||
if (!hasContentType) {
|
||||
headers.add(new KeyValue(key, value, description, contentType, required));
|
||||
}
|
||||
}
|
||||
|
||||
protected void addHeader(List<KeyValue> headers, String key, String value) {
|
||||
addHeader(headers, key, value, "", "", true);
|
||||
}
|
||||
|
||||
protected void addContentType(List<KeyValue> headers, String contentType) {
|
||||
addHeader(headers, "Content-Type", contentType);
|
||||
}
|
||||
|
||||
protected void addBodyHeader(MsHTTPSamplerProxy request) {
|
||||
String contentType = "";
|
||||
if (request.getBody() != null && StringUtils.isNotBlank(request.getBody().getType())) {
|
||||
switch (request.getBody().getType()) {
|
||||
case Body.JSON:
|
||||
contentType = "application/json";
|
||||
break;
|
||||
case Body.WWW_FROM:
|
||||
contentType = "application/x-www-form-urlencoded";
|
||||
break;
|
||||
case Body.XML:
|
||||
contentType = "application/xml";
|
||||
break;
|
||||
case Body.BINARY:
|
||||
contentType = "application/octet-stream";
|
||||
break;
|
||||
}
|
||||
List<KeyValue> headers = request.getHeaders();
|
||||
if (headers == null) {
|
||||
headers = new ArrayList<>();
|
||||
request.setHeaders(headers);
|
||||
}
|
||||
addContentType(request.getHeaders(), contentType);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ScenarioImportParser {
|
||||
ScenarioImport parse(InputStream source, ApiTestImportRequest request);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package io.metersphere.api.dto.automation.parse;
|
||||
|
||||
import io.metersphere.commons.constants.ApiImportPlatform;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class ScenarioImportParserFactory {
|
||||
public static ScenarioImportParser getImportParser(String platform) {
|
||||
if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) {
|
||||
return new MsScenarioParser();
|
||||
} else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) {
|
||||
return new MsPostmanParser();
|
||||
} else if (StringUtils.equals(ApiImportPlatform.Jmeter.name(), platform)) {
|
||||
return new MsJmeterParser();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -36,8 +36,6 @@ import java.util.stream.Collectors;
|
|||
public class MsScenario extends MsTestElement {
|
||||
|
||||
private String type = "scenario";
|
||||
@JSONField(ordinal = 20)
|
||||
private String name;
|
||||
|
||||
@JSONField(ordinal = 21)
|
||||
private String referenced;
|
||||
|
@ -56,6 +54,16 @@ public class MsScenario extends MsTestElement {
|
|||
|
||||
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
|
||||
|
||||
public MsScenario() {
|
||||
}
|
||||
|
||||
public MsScenario(String name) {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
this.setName("Scenario");
|
||||
}
|
||||
this.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
|
@ -77,7 +85,7 @@ public class MsScenario extends MsTestElement {
|
|||
}
|
||||
}
|
||||
|
||||
config.setStep(this.name);
|
||||
config.setStep(this.getName());
|
||||
config.setStepType("SCENARIO");
|
||||
config.setEnableCookieShare(enableCookieShare);
|
||||
if (StringUtils.isNotEmpty(environmentId)) {
|
||||
|
@ -131,7 +139,7 @@ public class MsScenario extends MsTestElement {
|
|||
private Arguments arguments(ParameterConfig config) {
|
||||
Arguments arguments = new Arguments();
|
||||
arguments.setEnabled(true);
|
||||
arguments.setName(name + "Variables");
|
||||
arguments.setName(this.getName() + "Variables");
|
||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
|||
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
|
||||
import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
|
@ -70,11 +71,12 @@ import java.util.stream.Collectors;
|
|||
@JsonSubTypes.Type(value = MsIfController.class, name = "IfController"),
|
||||
@JsonSubTypes.Type(value = MsScenario.class, name = "scenario"),
|
||||
@JsonSubTypes.Type(value = MsLoopController.class, name = "LoopController"),
|
||||
@JsonSubTypes.Type(value = MsJmeterElement.class, name = "JmeterElement"),
|
||||
|
||||
})
|
||||
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223Processor.class, MsJSR223PostProcessor.class,
|
||||
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
|
||||
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class, MsLoopController.class}, typeKey = "type")
|
||||
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class, MsLoopController.class, MsJmeterElement.class}, typeKey = "type")
|
||||
@Data
|
||||
public abstract class MsTestElement {
|
||||
private String type;
|
||||
|
@ -105,10 +107,14 @@ public abstract class MsTestElement {
|
|||
|
||||
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
|
||||
|
||||
// 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
|
||||
/**
|
||||
* todo 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
|
||||
*/
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
for (MsTestElement el : hashTree) {
|
||||
el.toHashTree(tree, el.hashTree, config);
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
for (MsTestElement el : hashTree) {
|
||||
el.toHashTree(tree, el.hashTree, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,14 +93,16 @@ public class MsDubboSampler extends MsTestElement {
|
|||
Constants.setInterfaceName(this.get_interface(), sampler);
|
||||
Constants.setMethod(this.getMethod(), sampler);
|
||||
|
||||
List<MethodArgument> methodArgs = this.getArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setMethodArgs(methodArgs, sampler);
|
||||
|
||||
List<MethodArgument> attachmentArgs = this.getAttachmentArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setAttachmentArgs(attachmentArgs, sampler);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(this.getArgs())) {
|
||||
List<MethodArgument> methodArgs = this.getArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setMethodArgs(methodArgs, sampler);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(this.getAttachmentArgs())) {
|
||||
List<MethodArgument> attachmentArgs = this.getAttachmentArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setAttachmentArgs(attachmentArgs, sampler);
|
||||
}
|
||||
return sampler;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
||||
if (StringUtils.isNotBlank(this.getPath()) && !isUrl) {
|
||||
envPath += this.getPath();
|
||||
sampler.setPath(envPath);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
||||
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package io.metersphere.api.dto.definition.request.unknown;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONType;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestPlan;
|
||||
import org.apache.jmeter.threads.ThreadGroup;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 暂时存放所有未知的Jmeter Element对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@JSONType(typeName = "JmeterElement")
|
||||
public class MsJmeterElement extends MsTestElement {
|
||||
private String type = "JmeterElement";
|
||||
|
||||
private String jmeterElement;
|
||||
|
||||
@Override
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||
if (!this.isEnable()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
InputStream inputSource = getStrToStream(jmeterElement);
|
||||
if (inputSource != null) {
|
||||
Object scriptWrapper = SaveService.loadElement(inputSource);
|
||||
HashTree elementTree = tree;
|
||||
if (!(scriptWrapper instanceof TestPlan) && !(scriptWrapper instanceof ThreadGroup)) {
|
||||
elementTree = tree.add(scriptWrapper);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
for (MsTestElement el : hashTree) {
|
||||
el.toHashTree(elementTree, el.getHashTree(), config);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static InputStream getStrToStream(String sInputString) {
|
||||
if (StringUtils.isNotEmpty(sInputString)) {
|
||||
try {
|
||||
ByteArrayInputStream tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
|
||||
return tInputStringStream;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,13 @@ public class ScenarioVariable {
|
|||
private String minNumber;
|
||||
private String maxNumber;
|
||||
|
||||
public ScenarioVariable(String key, String value, String description, String type) {
|
||||
this.name = key;
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isConstantValid() {
|
||||
if (StringUtils.equals(this.type, VariableTypeConstants.CONSTANT.name()) && StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
|
||||
return true;
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package io.metersphere.api.parse;
|
||||
|
||||
import io.metersphere.commons.constants.ApiImportPlatform;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class ApiScenarioImportParserFactory {
|
||||
public static ApiImportParser getApiImportParser(String platform) {
|
||||
if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) {
|
||||
return new MsParser();
|
||||
} else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) {
|
||||
return new ScenarioPostmanParser();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -5,8 +5,6 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.parser.Feature;
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
||||
import io.metersphere.api.dto.definition.ApiExportResult;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
|
@ -26,6 +24,7 @@ import java.io.InputStream;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MsParser extends ApiImportAbstractParser {
|
||||
|
||||
|
@ -56,7 +55,7 @@ public class MsParser extends ApiImportAbstractParser {
|
|||
if (StringUtils.isBlank(apiDefinition.getModulePath())) {
|
||||
apiDefinition.setModuleId(null);
|
||||
}
|
||||
parseModule(apiDefinition, importRequest);
|
||||
parseModule(apiDefinition.getModulePath(), importRequest, apiDefinition::setModuleId);
|
||||
apiDefinition.setId(id);
|
||||
apiDefinition.setProjectId(this.projectId);
|
||||
String request = apiDefinition.getRequest();
|
||||
|
@ -72,12 +71,13 @@ public class MsParser extends ApiImportAbstractParser {
|
|||
apiImport.setData(results);
|
||||
testObject.keySet().forEach(tag -> {
|
||||
|
||||
ApiModule module = null;
|
||||
String moduleId = "";
|
||||
if (isCreateModule) {
|
||||
module = buildModule(getSelectModule(importRequest.getModuleId()), tag);
|
||||
moduleId = buildModule(getSelectModule(importRequest.getModuleId()), tag).getId();
|
||||
}
|
||||
JSONObject requests = testObject.getJSONObject(tag);
|
||||
String moduleId = module.getId();
|
||||
|
||||
String finalModuleId = moduleId;
|
||||
|
||||
requests.keySet().forEach(requestName -> {
|
||||
|
||||
|
@ -87,7 +87,8 @@ public class MsParser extends ApiImportAbstractParser {
|
|||
|
||||
MsHTTPSamplerProxy request = buildRequest(requestName, path, method);
|
||||
ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(request.getId(), requestName, path, method,importRequest);
|
||||
apiDefinition.setModuleId(moduleId);
|
||||
|
||||
apiDefinition.setModuleId(finalModuleId);
|
||||
apiDefinition.setProjectId(this.projectId);
|
||||
parseBody(requestObject, request.getBody());
|
||||
parseHeader(requestObject, request.getHeaders());
|
||||
|
@ -167,9 +168,7 @@ public class MsParser extends ApiImportAbstractParser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseModule(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest) {
|
||||
String modulePath = apiDefinition.getModulePath();
|
||||
protected void parseModule(String modulePath, ApiTestImportRequest importRequest, Consumer<String> consumer) {
|
||||
if (StringUtils.isBlank(modulePath)) {
|
||||
return;
|
||||
}
|
||||
|
@ -186,7 +185,7 @@ public class MsParser extends ApiImportAbstractParser {
|
|||
String item = iterator.next();
|
||||
parent = buildModule(parent, item);
|
||||
if (!iterator.hasNext()) {
|
||||
apiDefinition.setModuleId(parent.getId());
|
||||
consumer.accept(parent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ public class ScenarioMsParser extends MsParser {
|
|||
});
|
||||
msScenario.setHashTree(msHTTPSamplerProxies);
|
||||
msScenario.setType("scenario");
|
||||
msScenario.setName("test");
|
||||
apiDefinitionImport.setScenarioDefinition(msScenario);
|
||||
return apiDefinitionImport;
|
||||
}
|
||||
|
@ -60,12 +59,13 @@ public class ScenarioMsParser extends MsParser {
|
|||
if (StringUtils.isBlank(scenario.getModulePath())) {
|
||||
scenario.setApiScenarioModuleId(null);
|
||||
}
|
||||
// parseModule(scenario, importRequest);
|
||||
// parseModule(scenario.getModulePath(), importRequest, scenario::setApiScenarioModuleId);
|
||||
scenario.setId(id);
|
||||
scenario.setProjectId(this.projectId);
|
||||
String scenarioDefinition = scenario.getScenarioDefinition();
|
||||
JSONObject scenarioDefinitionObj = JSONObject.parseObject(scenarioDefinition);
|
||||
scenarioDefinitionObj.put("id", id);
|
||||
scenarioDefinitionObj.put("name", scenario.getName());
|
||||
scenario.setScenarioDefinition(JSONObject.toJSONString(scenarioDefinitionObj));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
package io.metersphere.api.parse;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.definition.request.MsScenario;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.parse.postman.PostmanCollection;
|
||||
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
||||
import io.metersphere.base.domain.ApiModule;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ScenarioPostmanParser extends PostmanParser {
|
||||
|
||||
@Override
|
||||
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
|
||||
this.projectId = request.getProjectId();
|
||||
ApiDefinitionImport apiImport = new ApiDefinitionImport();
|
||||
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
||||
PostmanCollection postmanCollection = JSON.parseObject(getApiTestStr(source), PostmanCollection.class);
|
||||
parseItem(postmanCollection.getItem(), postmanCollection.getVariable(), results, null, false);
|
||||
|
||||
MsScenario msScenario = new MsScenario();
|
||||
LinkedList<MsTestElement> msHTTPSamplerProxies = new LinkedList<>();
|
||||
results.forEach(res -> {
|
||||
msHTTPSamplerProxies.add(JSONObject.parseObject(res.getRequest(), MsHTTPSamplerProxy.class));
|
||||
});
|
||||
msScenario.setHashTree(msHTTPSamplerProxies);
|
||||
msScenario.setType("scenario");
|
||||
msScenario.setName(postmanCollection.getInfo().getName());
|
||||
apiImport.setScenarioDefinition(msScenario);
|
||||
return apiImport;
|
||||
}
|
||||
}
|
|
@ -9,15 +9,15 @@ import io.metersphere.api.dto.ApiTestImportRequest;
|
|||
import io.metersphere.api.dto.DeleteAPIReportRequest;
|
||||
import io.metersphere.api.dto.JmxInfoDTO;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.automation.parse.ScenarioImport;
|
||||
import io.metersphere.api.dto.automation.parse.ScenarioImportParser;
|
||||
import io.metersphere.api.dto.automation.parse.ScenarioImportParserFactory;
|
||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
import io.metersphere.api.dto.definition.request.*;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.api.parse.ApiScenarioImportParserFactory;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
||||
|
@ -45,9 +45,6 @@ import org.apache.ibatis.session.SqlSession;
|
|||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.apache.jorphan.collections.ListedHashTree;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -518,6 +515,7 @@ public class ApiAutomationService {
|
|||
ParameterConfig config = new ParameterConfig();
|
||||
config.setConfig(envConfig);
|
||||
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
||||
System.out.println(request.getTestElement().getJmx(hashTree));
|
||||
// 调用执行方法
|
||||
createScenarioReport(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
|
||||
SessionUtils.getUserId());
|
||||
|
@ -722,26 +720,98 @@ public class ApiAutomationService {
|
|||
}
|
||||
}
|
||||
|
||||
public ApiDefinitionImport scenarioImport(MultipartFile file, ApiTestImportRequest request) {
|
||||
ApiImportParser apiImportParser = ApiScenarioImportParserFactory.getApiImportParser(request.getPlatform());
|
||||
ApiDefinitionImport apiImport = null;
|
||||
public List<ApiScenarioWithBLOBs> get(ApiScenarioRequest request) {
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
if (CollectionUtils.isNotEmpty(request.getIds())) {
|
||||
example.createCriteria().andIdIn(request.getIds());
|
||||
} else {
|
||||
example.createCriteria().andProjectIdEqualTo(request.getProjectId());
|
||||
}
|
||||
return apiScenarioMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
public List<ApiScenarioWithBLOBs> getWithBLOBs(ApiScenarioWithBLOBs request) {
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andStatusNotEqualTo("Trash").andIdNotEqualTo(request.getId());
|
||||
return apiScenarioMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
private void _importCreate(List<ApiScenarioWithBLOBs> sameRequest, ApiScenarioMapper batchMapper, ApiScenarioWithBLOBs scenarioWithBLOBs, ApiTestImportRequest apiTestImportRequest) {
|
||||
if (CollectionUtils.isEmpty(sameRequest)) {
|
||||
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
||||
batchMapper.insert(scenarioWithBLOBs);
|
||||
} else {
|
||||
//如果存在则修改
|
||||
scenarioWithBLOBs.setId(sameRequest.get(0).getId());
|
||||
batchMapper.updateByPrimaryKeyWithBLOBs(scenarioWithBLOBs);
|
||||
}
|
||||
}
|
||||
|
||||
private ApiScenarioWithBLOBs importCreate(ApiScenarioWithBLOBs request, ApiScenarioMapper batchMapper, ApiTestImportRequest apiTestImportRequest) {
|
||||
final ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
||||
BeanUtils.copyBean(scenarioWithBLOBs, request);
|
||||
scenarioWithBLOBs.setCreateTime(System.currentTimeMillis());
|
||||
scenarioWithBLOBs.setUpdateTime(System.currentTimeMillis());
|
||||
scenarioWithBLOBs.setStatus(APITestStatus.Underway.name());
|
||||
scenarioWithBLOBs.setProjectId(apiTestImportRequest.getProjectId());
|
||||
if (StringUtils.isEmpty(request.getPrincipal())) {
|
||||
scenarioWithBLOBs.setPrincipal(Objects.requireNonNull(SessionUtils.getUser()).getId());
|
||||
}
|
||||
if (request.getUserId() == null) {
|
||||
scenarioWithBLOBs.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
|
||||
} else {
|
||||
scenarioWithBLOBs.setUserId(request.getUserId());
|
||||
}
|
||||
scenarioWithBLOBs.setDescription(request.getDescription());
|
||||
|
||||
List<ApiScenarioWithBLOBs> sameRequest = getWithBLOBs(scenarioWithBLOBs);
|
||||
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
|
||||
_importCreate(sameRequest, batchMapper, scenarioWithBLOBs, apiTestImportRequest);
|
||||
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
|
||||
if (CollectionUtils.isEmpty(sameRequest)) {
|
||||
batchMapper.insert(scenarioWithBLOBs);
|
||||
}
|
||||
|
||||
} else {
|
||||
_importCreate(sameRequest, batchMapper, scenarioWithBLOBs, apiTestImportRequest);
|
||||
}
|
||||
return scenarioWithBLOBs;
|
||||
}
|
||||
|
||||
private void editScenario(ApiTestImportRequest request, ScenarioImport apiImport) {
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioMapper batchMapper = sqlSession.getMapper(ApiScenarioMapper.class);
|
||||
List<ApiScenarioWithBLOBs> data = apiImport.getData();
|
||||
int num = 0;
|
||||
if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) {
|
||||
num = getNextNum(data.get(0).getProjectId());
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
ApiScenarioWithBLOBs item = data.get(i);
|
||||
if (item.getName().length() > 255) {
|
||||
item.setName(item.getName().substring(0, 255));
|
||||
}
|
||||
item.setNum(num++);
|
||||
importCreate(item, batchMapper, request);
|
||||
if (i % 300 == 0) {
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
|
||||
public ScenarioImport scenarioImport(MultipartFile file, ApiTestImportRequest request) {
|
||||
ScenarioImportParser apiImportParser = ScenarioImportParserFactory.getImportParser(request.getPlatform());
|
||||
ScenarioImport apiImport = null;
|
||||
try {
|
||||
apiImport = apiImportParser.parse(file == null ? null : file.getInputStream(), request);
|
||||
apiImport = Objects.requireNonNull(apiImportParser).parse(file == null ? null : file.getInputStream(), request);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException(Translator.get("parse_data_error"));
|
||||
}
|
||||
SaveApiScenarioRequest saveReq = new SaveApiScenarioRequest();
|
||||
saveReq.setScenarioDefinition(apiImport.getScenarioDefinition());
|
||||
saveReq.setName(saveReq.getScenarioDefinition().getName());
|
||||
saveReq.setProjectId(request.getProjectId());
|
||||
saveReq.setApiScenarioModuleId(request.getModuleId());
|
||||
if (StringUtils.isNotBlank(request.getUserId())) {
|
||||
saveReq.setPrincipal(request.getUserId());
|
||||
} else {
|
||||
saveReq.setPrincipal(SessionUtils.getUserId());
|
||||
if (apiImport != null) {
|
||||
editScenario(request, apiImport);
|
||||
}
|
||||
create(saveReq, new ArrayList<>());
|
||||
return apiImport;
|
||||
}
|
||||
|
||||
|
|
|
@ -211,6 +211,33 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
|
|||
return dto;
|
||||
}
|
||||
|
||||
public ApiScenarioModule getNewModule(String name, String projectId, int level) {
|
||||
ApiScenarioModule node = new ApiScenarioModule();
|
||||
node.setCreateTime(System.currentTimeMillis());
|
||||
node.setUpdateTime(System.currentTimeMillis());
|
||||
node.setId(UUID.randomUUID().toString());
|
||||
node.setLevel(level);
|
||||
node.setName(name);
|
||||
node.setProjectId(projectId);
|
||||
return node;
|
||||
}
|
||||
|
||||
public List<ApiScenarioModule> selectSameModule(ApiScenarioModule node) {
|
||||
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
|
||||
ApiScenarioModuleExample.Criteria criteria = example.createCriteria();
|
||||
criteria.andNameEqualTo(node.getName())
|
||||
.andProjectIdEqualTo(node.getProjectId());
|
||||
if (StringUtils.isNotBlank(node.getParentId())) {
|
||||
criteria.andParentIdEqualTo(node.getParentId());
|
||||
} else {
|
||||
criteria.andParentIdIsNull();
|
||||
}
|
||||
if (StringUtils.isNotBlank(node.getId())) {
|
||||
criteria.andIdNotEqualTo(node.getId());
|
||||
}
|
||||
return apiScenarioModuleMapper.selectByExample(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePos(String id, Double pos) {
|
||||
extApiScenarioModuleMapper.updatePos(id, pos);
|
||||
|
|
|
@ -26,6 +26,11 @@ public class ApiTestEnvironmentService {
|
|||
return apiTestEnvironmentMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
public List<ApiTestEnvironmentWithBLOBs> selectByExampleWithBLOBs(ApiTestEnvironmentExample example) {
|
||||
return apiTestEnvironmentMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
|
||||
public ApiTestEnvironmentWithBLOBs get(String id) {
|
||||
return apiTestEnvironmentMapper.selectByPrimaryKey(id);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ApiImportPlatform {
|
||||
Metersphere, Postman, Swagger2, Plugin
|
||||
Metersphere, Postman, Swagger2, Plugin, Jmeter
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 44bcc9893033900f95c99068cd4edec740465dfe
|
||||
Subproject commit 5e0b365f1080197e84055e80071165787e2e79c5
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<ms-container v-if="renderComponent">
|
||||
<ms-container v-if="renderComponent" v-loading="loading">
|
||||
<ms-aside-container>
|
||||
<ms-api-scenario-module
|
||||
@nodeSelectEvent="nodeChange"
|
||||
|
@ -9,6 +9,7 @@
|
|||
@setNodeTree="setNodeTree"
|
||||
@enableTrash="enableTrash"
|
||||
@exportAPI="exportAPI"
|
||||
@refreshAll="refreshAll"
|
||||
:type="'edit'"
|
||||
ref="nodeTree"/>
|
||||
</ms-aside-container>
|
||||
|
@ -64,10 +65,11 @@
|
|||
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsApiScenarioList from "@/business/components/api/automation/scenario/ApiScenarioList";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {getUUID, downloadFile} from "@/common/js/utils";
|
||||
import MsApiScenarioModule from "@/business/components/api/automation/scenario/ApiScenarioModule";
|
||||
import MsEditApiScenario from "./scenario/EditApiScenario";
|
||||
import {getCurrentProjectID} from "../../../../common/js/utils";
|
||||
import {PROJECT_NAME} from "../../../../common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "ApiAutomation",
|
||||
|
@ -102,6 +104,7 @@
|
|||
currentModule: null,
|
||||
moduleOptions: [],
|
||||
tabs: [],
|
||||
loading: false,
|
||||
trashEnable: false,
|
||||
selectNodeIds: [],
|
||||
nodeTree: []
|
||||
|
@ -127,6 +130,27 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
exportAPI() {
|
||||
let obj = {projectName: localStorage.getItem(PROJECT_NAME)}
|
||||
let condition = {projectId: getCurrentProjectID(), ids: this.$refs.apiScenarioList.selection};
|
||||
let url = "/api/automation/list/all";
|
||||
this.loading = true;
|
||||
this.$post(url, condition, response => {
|
||||
obj.data = response.data;
|
||||
this.buildApiPath(obj.data);
|
||||
this.loading = false;
|
||||
downloadFile("Metersphere_Scenario_" + localStorage.getItem(PROJECT_NAME) + ".json", JSON.stringify(obj));
|
||||
});
|
||||
},
|
||||
buildApiPath(apis) {
|
||||
apis.forEach((api) => {
|
||||
this.moduleOptions.forEach(item => {
|
||||
if (api.moduleId === item.id) {
|
||||
api.modulePath = item.path;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
checkRedirectEditPage(redirectParam) {
|
||||
if (redirectParam != null) {
|
||||
let selectParamArr = redirectParam.split("edit:");
|
||||
|
@ -152,13 +176,13 @@
|
|||
},
|
||||
changeRedirectParam(redirectIDParam) {
|
||||
this.redirectID = redirectIDParam;
|
||||
if(redirectIDParam!=null){
|
||||
if(this.redirectFlag == "none"){
|
||||
if (redirectIDParam != null) {
|
||||
if (this.redirectFlag == "none") {
|
||||
this.activeName = "default";
|
||||
this.addListener();
|
||||
this.redirectFlag = "redirected";
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
this.redirectFlag = "none";
|
||||
}
|
||||
},
|
||||
|
@ -189,8 +213,8 @@
|
|||
},
|
||||
addListener() {
|
||||
let index = this.tabs.findIndex(item => item.name === this.activeName); // 找到当前选中tab的index
|
||||
if(index != -1) { // 为当前选中的tab添加监听
|
||||
this.$nextTick(()=>{
|
||||
if (index != -1) { // 为当前选中的tab添加监听
|
||||
this.$nextTick(() => {
|
||||
this.$refs.autoScenarioConfig[index].addListener();
|
||||
});
|
||||
}
|
||||
|
@ -241,6 +265,10 @@
|
|||
this.setTabTitle(data);
|
||||
this.$refs.apiScenarioList.search(data);
|
||||
},
|
||||
refreshAll() {
|
||||
this.$refs.nodeTree.list();
|
||||
this.$refs.apiScenarioList.search();
|
||||
},
|
||||
setTabTitle(data) {
|
||||
for (let index in this.tabs) {
|
||||
let tab = this.tabs[index];
|
||||
|
@ -268,9 +296,6 @@
|
|||
},
|
||||
enableTrash(data) {
|
||||
this.trashEnable = data;
|
||||
},
|
||||
exportAPI() {
|
||||
this.$refs.apiScenarioList.exportApi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -660,17 +660,27 @@ export default {
|
|||
exportApi() {
|
||||
let param = {};
|
||||
this.buildBatchParam(param);
|
||||
this.loading = true;
|
||||
if (param.ids === undefined || param.ids.length < 1) {
|
||||
this.$warning(this.$t("api_test.automation.scenario.check_case"));
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.result = this.$post("/api/automation/export", param, response => {
|
||||
this.loading = false;
|
||||
let obj = response.data;
|
||||
this.buildApiPath(obj.data);
|
||||
downloadFile("Metersphere_Scenario_" + localStorage.getItem(PROJECT_NAME) + ".json", JSON.stringify(obj));
|
||||
});
|
||||
}
|
||||
},
|
||||
buildApiPath(scenarios) {
|
||||
scenarios.forEach((scenario) => {
|
||||
this.moduleOptions.forEach(item => {
|
||||
if (scenario.moduleId === item.id) {
|
||||
scenario.modulePath = item.path;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -16,15 +16,31 @@
|
|||
ref="nodeTree">
|
||||
|
||||
<template v-slot:header>
|
||||
<api-scenario-module-header
|
||||
:condition="condition"
|
||||
:current-module="currentModule"
|
||||
:is-read-only="isReadOnly"
|
||||
:project-id="projectId"
|
||||
@exportAPI="exportAPI"
|
||||
@addScenario="addScenario"
|
||||
@refreshTable="$emit('refreshTable')"
|
||||
@refresh="refresh"/>
|
||||
<el-input :placeholder="$t('test_track.module.search')" v-model="condition.filterText" size="small">
|
||||
<template v-slot:append>
|
||||
<el-dropdown v-if="!isReadOnly" size="small" split-button type="primary" class="ms-api-button" @click="handleCommand('add-api')"
|
||||
v-tester
|
||||
@command="handleCommand">
|
||||
<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="export">{{ $t('report.export') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-input>
|
||||
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
|
||||
<!-- 是否保留这个 -->
|
||||
<!--<api-scenario-module-header-->
|
||||
<!--:condition="condition"-->
|
||||
<!--:current-module="currentModule"-->
|
||||
<!--:is-read-only="isReadOnly"-->
|
||||
<!--:project-id="projectId"-->
|
||||
<!--@exportAPI="exportAPI"-->
|
||||
<!--@addScenario="addScenario"-->
|
||||
<!--@refreshTable="$emit('refreshTable')"-->
|
||||
<!--@refresh="refresh"/>-->
|
||||
</template>
|
||||
|
||||
</ms-node-tree>
|
||||
|
@ -33,6 +49,8 @@
|
|||
@saveAsEdit="saveAsEdit"
|
||||
@refresh="refresh"
|
||||
ref="basisScenario"/>
|
||||
|
||||
<api-import ref="apiImport" :moduleOptions="moduleOptions" @refreshAll="$emit('refreshAll')"/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
@ -45,11 +63,12 @@ import MsNodeTree from "../../../track/common/NodeTree";
|
|||
import {buildNodePath} from "../../definition/model/NodeTree";
|
||||
import ModuleTrashButton from "../../definition/components/module/ModuleTrashButton";
|
||||
import ApiScenarioModuleHeader from "@/business/components/api/automation/scenario/module/ApiScenarioModuleHeader";
|
||||
import ApiImport from "./common/ScenarioImport";
|
||||
|
||||
export default {
|
||||
name: 'MsApiScenarioModule',
|
||||
components: {
|
||||
ApiScenarioModuleHeader,
|
||||
ApiImport,
|
||||
ModuleTrashButton,
|
||||
MsNodeTree,
|
||||
MsAddBasisScenario,
|
||||
|
@ -83,6 +102,7 @@ export default {
|
|||
projectId: "",
|
||||
data: [],
|
||||
currentModule: undefined,
|
||||
moduleOptions: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -104,7 +124,29 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
handleCommand(e) {
|
||||
switch (e) {
|
||||
case "add-scenario":
|
||||
this.addScenario();
|
||||
break;
|
||||
case "import":
|
||||
this.result = this.$get("/api/automation/module/list/" + getCurrentProjectID(), 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.currentModule);
|
||||
break;
|
||||
case "export":
|
||||
this.$emit('exportAPI');
|
||||
break;
|
||||
}
|
||||
},
|
||||
list() {
|
||||
let url = undefined;
|
||||
if (this.isPlanModel) {
|
||||
|
|
|
@ -400,7 +400,7 @@ export default {
|
|||
},
|
||||
{
|
||||
title: this.$t('api_test.automation.scenario_import'),
|
||||
show: this.operatingElements.indexOf('scenario') === 0,
|
||||
show: this.operatingElements && this.operatingElements.indexOf('scenario') === 0,
|
||||
titleColor: "#606266",
|
||||
titleBgColor: "#F4F4F5",
|
||||
icon: "movie",
|
||||
|
@ -445,7 +445,7 @@ export default {
|
|||
},
|
||||
showButton(...names) {
|
||||
for (const name of names) {
|
||||
if (this.operatingElements.includes(name)) {
|
||||
if (name && this.operatingElements && this.operatingElements.includes(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export const ELEMENTS = new Map([
|
|||
['JSR223PostProcessor', []],
|
||||
['Assertions', []],
|
||||
['Extract', []],
|
||||
['JmeterElement', []],
|
||||
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
|
||||
])
|
||||
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
<template>
|
||||
<el-dialog :close-on-click-modal="false" :title="$t('api_test.api_import.title')" width="30%"
|
||||
:visible.sync="visible" class="api-import" v-loading="result.loading" @close="close">
|
||||
|
||||
<div class="header-bar">
|
||||
<div>{{ $t('api_test.api_import.data_format') }}</div>
|
||||
<el-radio-group v-model="selectedPlatformValue">
|
||||
<el-radio v-for="(item, index) in platforms" :key="index" :label="item.value">{{ item.name }}</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<div class="operate-button">
|
||||
<el-button class="save-button" type="primary" plain @click="save">
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
<el-button class="cancel-button" type="warning" plain @click="visible = false">
|
||||
{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form :model="formData" :rules="rules" label-width="100px" v-loading="result.loading" ref="form">
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<el-form-item :label="$t('commons.import_module')">
|
||||
<el-select size="small" v-model="formData.moduleId" class="project-select" clearable>
|
||||
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.import_mode')">
|
||||
<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-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<el-divider direction="vertical"/>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-upload
|
||||
class="api-upload"
|
||||
drag
|
||||
action=""
|
||||
:http-request="upload"
|
||||
:limit="1"
|
||||
:beforeUpload="uploadValidate"
|
||||
:on-remove="handleRemove"
|
||||
:file-list="fileList"
|
||||
:on-exceed="handleExceed"
|
||||
multiple>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
|
||||
<div class="el-upload__tip" slot="tip">{{ $t('api_test.api_import.file_size_limit') }}</div>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<div class="format-tip">
|
||||
<div>
|
||||
<span>{{ $t('api_test.api_import.tip') }}:{{ selectedPlatform.tip }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ $t('api_test.api_import.export_tip') }}:{{ selectedPlatform.exportTip }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||
import {listenGoBack, removeGoBackListener, getCurrentProjectID} from "@/common/js/utils";
|
||||
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
|
||||
|
||||
export default {
|
||||
name: "ScenarioImport",
|
||||
components: {MsDialogFooter},
|
||||
props: {
|
||||
saved: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
moduleOptions: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
swaggerUrlEable: false,
|
||||
swaggerSynchronization: false,
|
||||
showEnvironmentSelect: true,
|
||||
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'])
|
||||
},
|
||||
{
|
||||
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'])
|
||||
},
|
||||
{
|
||||
name: 'Jmeter',
|
||||
value: 'Jmeter',
|
||||
tip: this.$t('api_test.api_import.jmeter_tip'),
|
||||
exportTip: this.$t('api_test.api_import.jmeter_export_tip'),
|
||||
suffixes: new Set(['jmx'])
|
||||
}
|
||||
],
|
||||
selectedPlatform: {},
|
||||
selectedPlatformValue: 'Metersphere',
|
||||
result: {},
|
||||
projects: [],
|
||||
environments: [],
|
||||
useEnvironment: false,
|
||||
formData: {
|
||||
file: undefined,
|
||||
swaggerUrl: '',
|
||||
modeId: this.$t('commons.not_cover'),
|
||||
moduleId: '',
|
||||
},
|
||||
rules: {},
|
||||
currentModule: {},
|
||||
fileList: []
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.selectedPlatform = this.platforms[0];
|
||||
},
|
||||
watch: {
|
||||
selectedPlatformValue() {
|
||||
for (let i in this.platforms) {
|
||||
if (this.platforms[i].value === this.selectedPlatformValue) {
|
||||
this.selectedPlatform = this.platforms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
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;
|
||||
},
|
||||
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() {
|
||||
if (!this.formData.file) {
|
||||
this.$warning("请添加一个文件");
|
||||
return;
|
||||
}
|
||||
let suffix = this.formData.file.name.substring(this.formData.file.name.lastIndexOf('.') + 1);
|
||||
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
|
||||
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
|
||||
return false;
|
||||
}
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
let param = this.buildParam();
|
||||
this.result = this.$fileUpload('/api/automation/import', param.file, null, this.buildParam(), response => {
|
||||
let res = response.data;
|
||||
this.$success(this.$t('test_track.case.import.success'));
|
||||
this.visible = false;
|
||||
this.$emit('refreshAll', res);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
buildParam() {
|
||||
let param = {};
|
||||
Object.assign(param, this.formData);
|
||||
param.platform = this.selectedPlatformValue;
|
||||
param.saved = this.saved;
|
||||
if (this.currentModule) {
|
||||
param.moduleId = this.formData.moduleId
|
||||
this.moduleOptions.filter(item => {
|
||||
if (item.id === this.formData.moduleId) {
|
||||
param.modulePath = item.path
|
||||
}
|
||||
})
|
||||
param.modeId = this.formData.modeId
|
||||
}
|
||||
param.projectId = getCurrentProjectID();
|
||||
if (!this.swaggerUrlEable) {
|
||||
param.swaggerUrl = undefined;
|
||||
}
|
||||
return param;
|
||||
},
|
||||
close() {
|
||||
this.formData = {
|
||||
file: undefined,
|
||||
swaggerUrl: ''
|
||||
};
|
||||
this.fileList = [];
|
||||
removeGoBackListener(this.close);
|
||||
this.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.api-import >>> .el-dialog {
|
||||
min-width: 700px;
|
||||
}
|
||||
|
||||
.format-tip {
|
||||
background: #EDEDED;
|
||||
}
|
||||
|
||||
.api-upload {
|
||||
text-align: center;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.api-upload >>> .el-upload {
|
||||
width: 100%;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.api-upload >>> .el-upload-dragger {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-radio-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.header-bar, .format-tip, .el-form {
|
||||
border: solid #E1E1E1 1px;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
padding: 10px 30px;
|
||||
}
|
||||
|
||||
.api-import >>> .el-dialog__body {
|
||||
padding: 15px 25px;
|
||||
}
|
||||
|
||||
.operate-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.el-form {
|
||||
padding: 30px 10px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.swagger-url-disable {
|
||||
margin-top: 10px;
|
||||
|
||||
margin-left: 80px;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -16,10 +16,11 @@
|
|||
import MsApiComponent from "./ApiComponent";
|
||||
import MsLoopController from "./LoopController";
|
||||
import MsApiScenarioComponent from "./ApiScenarioComponent";
|
||||
import JmeterElementComponent from "./JmeterElementComponent";
|
||||
|
||||
export default {
|
||||
name: "ComponentConfig",
|
||||
components: {MsConstantTimer, MsIfController, MsJsr233Processor, MsApiAssertions, MsApiExtract, MsApiComponent, MsLoopController, MsApiScenarioComponent},
|
||||
components: {MsConstantTimer, MsIfController, MsJsr233Processor, MsApiAssertions, MsApiExtract, MsApiComponent, MsLoopController, MsApiScenarioComponent, JmeterElementComponent},
|
||||
props: {
|
||||
type: String,
|
||||
scenario: {},
|
||||
|
@ -71,6 +72,9 @@
|
|||
break;
|
||||
case "AuthManager":
|
||||
break;
|
||||
case "JmeterElement":
|
||||
name = "JmeterElementComponent";
|
||||
break;
|
||||
default:
|
||||
name = "MsApiComponent";
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<template>
|
||||
<api-base-component
|
||||
@copy="copyRow"
|
||||
@remove="remove"
|
||||
:data="request"
|
||||
:draggable="draggable"
|
||||
:color="defColor"
|
||||
:background-color="defBackgroundColor"
|
||||
:title="defTitle">
|
||||
|
||||
</api-base-component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||
import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon";
|
||||
import MsDropdown from "../../../../common/components/MsDropdown";
|
||||
import ApiBaseComponent from "../common/ApiBaseComponent";
|
||||
import Jsr233ProcessorContent from "../common/Jsr233ProcessorContent";
|
||||
|
||||
export default {
|
||||
name: "JmeterElementComponent",
|
||||
components: {Jsr233ProcessorContent, ApiBaseComponent, MsDropdown, MsInstructionsIcon, MsCodeEdit},
|
||||
props: {
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default:
|
||||
false
|
||||
},
|
||||
request: {
|
||||
type: Object,
|
||||
},
|
||||
defTitle: {type: String, default: "Jmeter组件"},
|
||||
defColor: {type: String, default: "#606260"},
|
||||
defBackgroundColor: {type: String, default: "#F4F4FF"},
|
||||
node: {},
|
||||
},
|
||||
methods: {
|
||||
remove() {
|
||||
this.$emit('remove', this.jsr223Processor, this.node);
|
||||
},
|
||||
copyRow() {
|
||||
this.$emit('copyRow', this.jsr223Processor, this.node);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .el-divider {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -879,6 +879,8 @@ export default {
|
|||
postman_tip: "Only Postman Collection V2.1 json files are supported",
|
||||
postman_export_tip: "Export the test collection by Postman",
|
||||
swagger_export_tip: "Export jSON-formatted files via Swagger website",
|
||||
jmeter_export_tip: "Generating JMX file through JMeter",
|
||||
jmeter_tip: "JMX files supporting JMeter 5.2",
|
||||
suffixFormatErr: "The file format does not meet the requirements",
|
||||
swagger_url_import: "Import using URL",
|
||||
timing_synchronization: "Timing synchronization",
|
||||
|
|
|
@ -882,6 +882,8 @@ export default {
|
|||
swagger_tip: "支持 Swagger 2.0 与 3.0 版本的 json 文件",
|
||||
post_export_tip: "通过 Postman 导出测试集合",
|
||||
swagger_export_tip: "通过 Swagger 页面导出",
|
||||
jmeter_export_tip: "通过 Jmeter 生成JMX文件",
|
||||
jmeter_tip: "支持 Jmeter 5.2版本的JMX 文件",
|
||||
suffixFormatErr: "文件格式不符合要求",
|
||||
swagger_url_import: "使用URL导入",
|
||||
timing_synchronization: "定时同步",
|
||||
|
|
|
@ -881,6 +881,8 @@ export default {
|
|||
swagger_tip: "支持 Swagger 2.0 與 3.0 版本的 json 文件",
|
||||
post_export_tip: "通過 Postman 導出測試集合",
|
||||
swagger_export_tip: "通過 Swagger 頁面導出",
|
||||
jmeter_export_tip: "通過 Jmeter 生成JMX文件",
|
||||
jmeter_tip: "支持 Jmeter 5.2版本的JMX 文件",
|
||||
suffixFormatErr: "文件格式不符合要求",
|
||||
swagger_url_import: "使用URL導入",
|
||||
timing_synchronization: "定時同步",
|
||||
|
|
Loading…
Reference in New Issue