refactor(接口自动化): 场景导入 ms,postman 基本完成
This commit is contained in:
parent
c94aab0219
commit
c74e88c3f3
|
@ -2,14 +2,15 @@ package io.metersphere.api.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
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.automation.parse.ScenarioImport;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
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;
|
||||
|
@ -43,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);
|
||||
|
@ -146,5 +154,12 @@ public class ApiAutomationController {
|
|||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"")
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/import", consumes = {"multipart/form-data"})
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public ScenarioImport scenarioImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) {
|
||||
return apiAutomationService.scenarioImport(file, request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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,18 @@
|
|||
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.Swagger2.name(), platform)) {
|
||||
// return new Swagger2Parser();
|
||||
// }
|
||||
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;
|
||||
|
|
|
@ -5,9 +5,13 @@ import com.alibaba.fastjson.JSONObject;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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.request.*;
|
||||
|
@ -86,23 +90,34 @@ public class ApiAutomationService {
|
|||
private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
||||
|
||||
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
|
||||
request = this.initRequest(request,true,true);
|
||||
request = this.initRequest(request, true, true);
|
||||
List<ApiScenarioDTO> list = extApiScenarioMapper.list(request);
|
||||
return list;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化部分参数
|
||||
*
|
||||
* @param request
|
||||
* @param setDefultOrders
|
||||
* @param checkThisWeekData
|
||||
* @return
|
||||
*/
|
||||
private ApiScenarioRequest initRequest(ApiScenarioRequest request,boolean setDefultOrders, boolean checkThisWeekData) {
|
||||
if(setDefultOrders){
|
||||
private ApiScenarioRequest initRequest(ApiScenarioRequest request, boolean setDefultOrders, boolean checkThisWeekData) {
|
||||
if (setDefultOrders) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
}
|
||||
if(checkThisWeekData){
|
||||
if (checkThisWeekData) {
|
||||
if (request.isSelectThisWeedData()) {
|
||||
Map<String, Date> weekFirstTimeAndLastTime = DateUtils.getWeedFirstTimeAndLastTime(new Date());
|
||||
Date weekFirstTime = weekFirstTimeAndLastTime.get("firstTime");
|
||||
|
@ -217,7 +232,7 @@ public class ApiAutomationService {
|
|||
ids.add(scenarioId);
|
||||
deleteApiScenarioReport(ids);
|
||||
|
||||
scheduleService.deleteScheduleAndJobByResourceId(scenarioId,ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
scheduleService.deleteScheduleAndJobByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
||||
example.createCriteria().andApiScenarioIdEqualTo(scenarioId);
|
||||
List<TestPlanApiScenario> testPlanApiScenarioList = testPlanApiScenarioMapper.selectByExample(example);
|
||||
|
@ -284,7 +299,7 @@ public class ApiAutomationService {
|
|||
extApiScenarioMapper.removeToGc(apiIds);
|
||||
//将这些场景的定时任务删除掉
|
||||
for (String id : apiIds) {
|
||||
scheduleService.deleteScheduleAndJobByResourceId(id,ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
scheduleService.deleteScheduleAndJobByResourceId(id, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,14 +427,14 @@ public class ApiAutomationService {
|
|||
// 创建场景报告
|
||||
if (reportIds != null) {
|
||||
//如果是测试计划页面触发的执行方式,生成报告时createScenarioReport第二个参数需要特殊处理
|
||||
if(StringUtils.equals(request.getRunMode(),ApiRunMode.SCENARIO_PLAN.name())){
|
||||
if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
|
||||
String testPlanScenarioId = item.getId();
|
||||
if(request.getScenarioTestPlanIdMap()!=null&&request.getScenarioTestPlanIdMap().containsKey(item.getId())){
|
||||
if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(item.getId())) {
|
||||
testPlanScenarioId = request.getScenarioTestPlanIdMap().get(item.getId());
|
||||
}
|
||||
createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
||||
}else{
|
||||
} else {
|
||||
createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
||||
}
|
||||
|
@ -635,10 +650,10 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
private void addOrUpdateApiScenarioCronJob(Schedule request) {
|
||||
if(StringUtils.equals(request.getGroup(),ScheduleGroup.TEST_PLAN_TEST.name())){
|
||||
if (StringUtils.equals(request.getGroup(), ScheduleGroup.TEST_PLAN_TEST.name())) {
|
||||
scheduleService.addOrUpdateCronJob(
|
||||
request, TestPlanTestJob.getJobKey(request.getResourceId()), TestPlanTestJob.getTriggerKey(request.getResourceId()), TestPlanTestJob.class);
|
||||
}else{
|
||||
} else {
|
||||
scheduleService.addOrUpdateCronJob(
|
||||
request, ApiScenarioTestJob.getJobKey(request.getResourceId()), ApiScenarioTestJob.getTriggerKey(request.getResourceId()), ApiScenarioTestJob.class);
|
||||
}
|
||||
|
@ -712,4 +727,89 @@ public class ApiAutomationService {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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"));
|
||||
}
|
||||
if (apiImport != null) {
|
||||
editScenario(request, apiImport);
|
||||
}
|
||||
return apiImport;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -215,6 +215,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);
|
||||
|
|
|
@ -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"
|
||||
|
@ -8,6 +8,7 @@
|
|||
@setModuleOptions="setModuleOptions"
|
||||
@setNodeTree="setNodeTree"
|
||||
@enableTrash="enableTrash"
|
||||
@exportAPI="exportAPI"
|
||||
:type="'edit'"
|
||||
ref="nodeTree"/>
|
||||
</ms-aside-container>
|
||||
|
@ -63,10 +64,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",
|
||||
|
@ -101,6 +103,7 @@
|
|||
currentModule: null,
|
||||
moduleOptions: [],
|
||||
tabs: [],
|
||||
loading: false,
|
||||
trashEnable: false,
|
||||
selectNodeIds: [],
|
||||
nodeTree: []
|
||||
|
@ -126,6 +129,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:");
|
||||
|
@ -151,13 +175,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";
|
||||
}
|
||||
},
|
||||
|
@ -188,8 +212,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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -138,6 +138,7 @@
|
|||
this.$refs.apiImport.open(this.currentModule);
|
||||
break;
|
||||
case "export":
|
||||
this.$emit('exportAPI');
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -35,6 +35,23 @@
|
|||
<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>
|
||||
|
@ -182,7 +199,7 @@
|
|||
return;
|
||||
}
|
||||
let param = this.buildParam();
|
||||
this.result = this.$fileUpload('/api/definition/import', param.file, null, this.buildParam(), response => {
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue