This commit is contained in:
wenyann 2021-02-23 14:11:37 +08:00
commit 7e51a7eb61
73 changed files with 1480 additions and 1533 deletions

View File

@ -10,16 +10,11 @@ import io.metersphere.api.dto.datacount.response.ApiDataCountDTO;
import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO;
import io.metersphere.api.dto.datacount.response.TaskInfoResult;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.PerformanceTestStatus;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CronUtils;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
@ -28,24 +23,14 @@ import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.request.testplan.SaveTestPlanRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.jorphan.collections.HashTree;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
@ -393,7 +378,7 @@ public class APITestController {
String testName = runRequest.getName();
//将jmx处理封装为通用方法
jmxString = apiTestService.updateJmxString(jmxString,testName,true);
jmxString = apiTestService.updateJmxString(jmxString,testName,false);
JmxInfoDTO dto = new JmxInfoDTO();
dto.setName(runRequest.getName() + ".jmx");

View File

@ -44,13 +44,6 @@ 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);
@ -167,5 +160,11 @@ public class ApiAutomationController {
return apiAutomationService.export(request);
}
@PostMapping(value = "/export/jmx")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public List<ApiScenrioExportJmx> exportJmx(@RequestBody ApiScenarioBatchRequest request) {
return apiAutomationService.exportJmx(request);
}
}

View File

@ -14,6 +14,7 @@ public class ApiTestImportRequest {
private String platform;
private Boolean useEnvironment;
private String swaggerUrl;
private String fileName;
//导入策略
private String modeId;
private String userId;

View File

@ -0,0 +1,16 @@
package io.metersphere.api.dto.automation;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ApiScenrioExportJmx {
private String name;
private String jmx;
public ApiScenrioExportJmx(String name, String jmx) {
this.name = name;
this.jmx = jmx;
}
}

View File

@ -0,0 +1,50 @@
package io.metersphere.api.dto.automation.parse;
import io.metersphere.api.dto.automation.ApiScenarioModuleDTO;
import io.metersphere.api.service.ApiScenarioModuleService;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
public class ApiScenarioImportUtil {
public static ApiScenarioModule getSelectModule(String moduleId) {
ApiScenarioModuleService 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;
}
public static ApiScenarioModule buildModule(ApiScenarioModule parentModule, String name, String projectId) {
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
ApiScenarioModule module;
if (parentModule != null) {
module = apiModuleService.getNewModule(name, projectId, parentModule.getLevel() + 1);
module.setParentId(parentModule.getId());
} else {
module = apiModuleService.getNewModule(name, projectId, 1);
}
createModule(module);
return module;
}
public static void createModule(ApiScenarioModule module) {
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
List<ApiScenarioModule> apiModules = apiModuleService.selectSameModule(module);
if (CollectionUtils.isEmpty(apiModules)) {
apiModuleService.addNode(module);
} else {
module.setId(apiModules.get(0).getId());
}
}
}

View File

@ -10,7 +10,6 @@ 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;
@ -37,6 +36,7 @@ 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.parse.ApiImportAbstractParser;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
@ -51,7 +51,6 @@ 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;
@ -76,7 +75,7 @@ import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
public class MsJmeterParser extends ScenarioImportAbstractParser {
public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
private final String ENV_NAME = "导入数据环境";
@Override
@ -88,12 +87,12 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
preInitPool(request.getProjectId(), testPlan);
MsScenario scenario = new MsScenario();
scenario.setReferenced("REF");
scenario.setReferenced("IMPORT");
jmterHashTree(testPlan, scenario);
this.projectId = request.getProjectId();
ScenarioImport scenarioImport = new ScenarioImport();
scenarioImport.setData(paseObj(scenario, request));
scenarioImport.setProjectid(request.getProjectId());
scenarioImport.setProjectId(request.getProjectId());
return scenarioImport;
} catch (Exception e) {
e.printStackTrace();
@ -105,7 +104,7 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
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());
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
scenarioWithBLOBs.setName(msScenario.getName());
scenarioWithBLOBs.setProjectId(request.getProjectId());
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
@ -199,7 +198,6 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
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"));
@ -233,24 +231,24 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
elementNode.setConsumerAndService(consumerAndService);
List<MethodArgument> methodArguments = Constants.getMethodArgs(sampler);
List<KeyValue> methodArgs = new LinkedList<>();
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);
}
elementNode.setArgs(methodArgs);
List<MethodArgument> arguments = Constants.getAttachmentArgs(sampler);
List<KeyValue> attachmentArgs = new LinkedList<>();
if (CollectionUtils.isNotEmpty(arguments)) {
List<KeyValue> methodArgs = new LinkedList<>();
arguments.forEach(item -> {
KeyValue keyValue = new KeyValue(item.getParamType(), item.getParamValue());
methodArgs.add(keyValue);
attachmentArgs.add(keyValue);
});
elementNode.setAttachmentArgs(methodArgs);
}
elementNode.setAttachmentArgs(attachmentArgs);
}
/**
@ -568,12 +566,12 @@ public class MsJmeterParser extends ScenarioImportAbstractParser {
BeanUtils.copyBean(elementNode, key);
elementNode.setType("ConstantTimer");
}
// IF条件控制器
else if (key instanceof IfController) {
elementNode = new MsIfController();
BeanUtils.copyBean(elementNode, key);
elementNode.setType("IfController");
}
// IF条件控制器这里平台方式和jmeter 不同暂时不处理
// else if (key instanceof IfController) {
// elementNode = new MsIfController();
// BeanUtils.copyBean(elementNode, key);
// elementNode.setType("IfController");
// }
// 次数循环控制器
else if (key instanceof LoopController) {
elementNode = new MsLoopController();

View File

@ -1,205 +0,0 @@
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);
}
}
}
}

View File

@ -1,26 +1,49 @@
package io.metersphere.api.dto.automation.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
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.parse.MsAbstractParser;
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;
import java.util.*;
public class MsScenarioParser extends ScenarioImportAbstractParser {
public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
@Override
public ScenarioImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
this.projectId = request.getProjectId();
ScenarioImport scenarioImport = parseMsFormat(testStr, request);
return scenarioImport;
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {
return parseMsFormat(testStr, request);
} else {
ScenarioImport apiImport = new ScenarioImport();
ArrayList<ApiScenarioWithBLOBs> apiScenarioWithBLOBs = new ArrayList<>();
apiScenarioWithBLOBs.add(parsePluginFormat(testObject, request));
apiImport.setData(apiScenarioWithBLOBs);
return apiImport;
}
}
protected ApiScenarioWithBLOBs parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest) {
LinkedList<MsTestElement> results = new LinkedList<>();
testObject.keySet().forEach(tag -> {
results.addAll(parseMsHTTPSamplerProxy(testObject, tag));
});
MsScenario msScenario = new MsScenario();
msScenario.setName(importRequest.getFileName());
msScenario.setHashTree(results);
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
scenarioWithBLOBs.setApiScenarioModuleId(importRequest.getModuleId());
return scenarioWithBLOBs;
}
private ScenarioImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
@ -31,7 +54,7 @@ public class MsScenarioParser extends ScenarioImportAbstractParser {
if (StringUtils.isBlank(item.getModulePath())) {
item.setApiScenarioModuleId(null);
}
parseModule(item, importRequest);
parseModule(item.getModulePath(), importRequest, item);
item.setId(UUID.randomUUID().toString());
item.setProjectId(this.projectId);
});
@ -39,8 +62,7 @@ public class MsScenarioParser extends ScenarioImportAbstractParser {
return apiDefinitionImport;
}
private void parseModule(ApiScenarioWithBLOBs apiDefinition, ApiTestImportRequest importRequest) {
String modulePath = apiDefinition.getModulePath();
protected void parseModule(String modulePath, ApiTestImportRequest importRequest, ApiScenarioWithBLOBs apiScenarioWithBLOBs) {
if (StringUtils.isEmpty(modulePath)) {
return;
}
@ -51,15 +73,14 @@ public class MsScenarioParser extends ScenarioImportAbstractParser {
modulePath = modulePath.substring(0, modulePath.length() - 1);
}
List<String> modules = Arrays.asList(modulePath.split("/"));
ApiScenarioModule parent = getSelectModule(importRequest.getModuleId());
ApiScenarioModule parent = ApiScenarioImportUtil.getSelectModule(importRequest.getModuleId());
Iterator<String> iterator = modules.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
parent = buildModule(parent, item);
parent = ApiScenarioImportUtil.buildModule(parent, item, this.projectId);
if (!iterator.hasNext()) {
apiDefinition.setApiScenarioModuleId(parent.getId());
apiScenarioWithBLOBs.setApiScenarioModuleId(parent.getId());
}
}
}
}

View File

@ -0,0 +1,82 @@
package io.metersphere.api.dto.automation.parse;
import com.alibaba.fastjson.JSON;
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.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.parse.postman.PostmanCollection;
import io.metersphere.api.dto.parse.postman.PostmanCollectionInfo;
import io.metersphere.api.dto.parse.postman.PostmanItem;
import io.metersphere.api.dto.parse.postman.PostmanKeyValue;
import io.metersphere.api.parse.PostmanAbstractParserParser;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.commons.constants.VariableTypeConstants;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class PostmanScenarioParser extends PostmanAbstractParserParser<ScenarioImport> {
@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<>();
parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario, request);
scenarioImport.setData(scenarioWithBLOBs);
return scenarioImport;
}
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
if (module != null) {
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
scenarioWithBLOBs.setModulePath("/" + module.getName());
}
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 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;
}
}

View File

@ -7,6 +7,6 @@ import java.util.List;
@Data
public class ScenarioImport {
private String projectid;
private String projectId;
private List<ApiScenarioWithBLOBs> data;
}

View File

@ -1,169 +0,0 @@
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);
}
}
}

View File

@ -1,9 +0,0 @@
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);
}

View File

@ -1,14 +1,15 @@
package io.metersphere.api.dto.automation.parse;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.commons.constants.ApiImportPlatform;
import org.apache.commons.lang3.StringUtils;
public class ScenarioImportParserFactory {
public static ScenarioImportParser getImportParser(String platform) {
public static ApiImportParser getImportParser(String platform) {
if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) {
return new MsScenarioParser();
} else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) {
return new MsPostmanParser();
return new PostmanScenarioParser();
} else if (StringUtils.equals(ApiImportPlatform.Jmeter.name(), platform)) {
return new MsJmeterParser();
}

View File

@ -12,6 +12,8 @@ import java.util.List;
public class ApiExportResult {
private String projectName;
private String protocol;
private String projectId;
private String version;
private List<ApiDefinitionWithBLOBs> data;
private List<ApiTestCaseWithBLOBs> cases;
}

View File

@ -14,10 +14,6 @@ public class ApiDefinitionImport {
private String protocol;
private List<ApiDefinitionWithBLOBs> data;
//导入场景
private MsScenario scenarioDefinition;
private List<ApiScenarioWithBLOBs> scenarioDefinitionData;
// 新版本带用例导出
private List<ApiTestCaseWithBLOBs> cases;
}

View File

@ -1,14 +1,15 @@
package io.metersphere.api.parse;
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.commons.constants.ApiImportPlatform;
import org.apache.commons.lang3.StringUtils;
public class ApiImportParserFactory {
public class ApiDefinitionImportParserFactory {
public static ApiImportParser getApiImportParser(String platform) {
if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) {
return new MsParser();
return new MsDefinitionParser();
} else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) {
return new PostmanParser();
return new PostmanDefinitionParser();
} else if (StringUtils.equals(ApiImportPlatform.Swagger2.name(), platform)) {
return new Swagger2Parser();
}

View File

@ -0,0 +1,52 @@
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
public class ApiDefinitionImportUtil {
public static ApiModule getSelectModule(String moduleId) {
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
ApiModule module = new ApiModule();
ApiModuleDTO moduleDTO = apiModuleService.getNode(moduleId);
if (moduleDTO != null) {
BeanUtils.copyBean(module, moduleDTO);
}
return module;
}
return null;
}
public static ApiModule buildModule(ApiModule parentModule, String name, String projectId) {
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
ApiModule module;
if (parentModule != null) {
module = apiModuleService.getNewModule(name, projectId, parentModule.getLevel() + 1);
module.setParentId(parentModule.getId());
} else {
module = apiModuleService.getNewModule(name, projectId, 1);
}
createModule(module);
return module;
}
public static void createModule(ApiModule module) {
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
module.setProtocol(RequestType.HTTP);
List<ApiModule> apiModules = apiModuleService.selectSameModule(module);
if (CollectionUtils.isEmpty(apiModules)) {
apiModuleService.addNode(module);
} else {
module.setId(apiModules.get(0).getId());
}
}
}

View File

@ -0,0 +1,99 @@
package io.metersphere.api.dto.definition.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.parse.MsAbstractParser;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.ApiImportPlatform;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.*;
public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
this.projectId = request.getProjectId();
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {
return parseMsFormat(testStr, request);
} else {
request.setPlatform(ApiImportPlatform.Plugin.name());
ApiDefinitionImport apiImport = new ApiDefinitionImport();
apiImport.setProtocol(RequestType.HTTP);
apiImport.setData(parsePluginFormat(testObject, request, true));
return apiImport;
}
}
protected List<ApiDefinitionWithBLOBs> parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest, Boolean isCreateModule) {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
testObject.keySet().forEach(tag -> {
String moduleId = null;
if (isCreateModule) {
moduleId = ApiDefinitionImportUtil.buildModule(ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()), tag, this.projectId).getId();
}
List<MsHTTPSamplerProxy> msHTTPSamplerProxies = parseMsHTTPSamplerProxy(testObject, tag);
for (MsHTTPSamplerProxy msHTTPSamplerProxy : msHTTPSamplerProxies) {
ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(msHTTPSamplerProxy.getId(), msHTTPSamplerProxy.getName(), msHTTPSamplerProxy.getPath(), msHTTPSamplerProxy.getMethod(), importRequest);
apiDefinition.setModuleId(moduleId);
apiDefinition.setProjectId(this.projectId);
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
apiDefinition.setName(apiDefinition.getPath() + " [" + apiDefinition.getMethod() + "]");
results.add(apiDefinition);
}
});
return results;
}
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
apiDefinitionImport.getData().forEach(apiDefinition -> {
parseApiDefinition(apiDefinition, importRequest);
});
return apiDefinitionImport;
}
private void parseApiDefinition(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest) {
String id = UUID.randomUUID().toString();
if (StringUtils.isBlank(apiDefinition.getModulePath())) {
apiDefinition.setModuleId(null);
}
parseModule(apiDefinition.getModulePath(), importRequest, apiDefinition);
apiDefinition.setId(id);
apiDefinition.setProjectId(this.projectId);
String request = apiDefinition.getRequest();
JSONObject requestObj = JSONObject.parseObject(request);
requestObj.put("id", id);
apiDefinition.setRequest(JSONObject.toJSONString(requestObj));
}
private void parseModule(String modulePath, ApiTestImportRequest importRequest, ApiDefinitionWithBLOBs apiDefinition) {
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("/"));
ApiModule parent = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
Iterator<String> iterator = modules.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
parent = ApiDefinitionImportUtil.buildModule(parent, item, this.projectId);
if (!iterator.hasNext()) {
apiDefinition.setModuleId(parent.getId());
}
}
}
}

View File

@ -0,0 +1,58 @@
package io.metersphere.api.dto.definition.parse;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.postman.PostmanCollection;
import io.metersphere.api.dto.parse.postman.PostmanItem;
import io.metersphere.api.dto.parse.postman.PostmanKeyValue;
import io.metersphere.api.parse.PostmanAbstractParserParser;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefinitionImport> {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
this.projectId = request.getProjectId();
PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class);
List<PostmanKeyValue> variables = postmanCollection.getVariable();
ApiDefinitionImport apiImport = new ApiDefinitionImport();
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
parseItem(postmanCollection.getItem(), variables, results,
ApiDefinitionImportUtil.buildModule(ApiDefinitionImportUtil.getSelectModule(request.getModuleId()), postmanCollection.getInfo().getName(), this.projectId), true);
apiImport.setData(results);
return apiImport;
}
protected void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results, ApiModule parentModule, Boolean isCreateModule) {
for (PostmanItem item : items) {
List<PostmanItem> childItems = item.getItem();
if (childItems != null) {
ApiModule module = null;
if (isCreateModule) {
module = ApiDefinitionImportUtil.buildModule(parentModule, item.getName(), this.projectId);
}
parseItem(childItems, variables, results, module, isCreateModule);
} else {
MsHTTPSamplerProxy msHTTPSamplerProxy = parsePostman(item);
ApiDefinitionWithBLOBs request = buildApiDefinition(msHTTPSamplerProxy.getId(), msHTTPSamplerProxy.getName(),
msHTTPSamplerProxy.getPath(), msHTTPSamplerProxy.getMethod(), new ApiTestImportRequest());
request.setPath(msHTTPSamplerProxy.getPath());
request.setRequest(JSON.toJSONString(msHTTPSamplerProxy));
if (request != null) {
results.add(request);
}
if (parentModule != null) {
request.setModuleId(parentModule.getId());
}
}
}
}
}

View File

@ -1,10 +1,9 @@
package io.metersphere.api.parse;
package io.metersphere.api.dto.definition.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.response.HttpResponse;
import io.metersphere.api.dto.scenario.Body;
@ -57,7 +56,7 @@ public class Swagger2Parser extends SwaggerAbstractParser {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
ApiModule parentNode = getSelectModule(importRequest.getModuleId());
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
for (String pathName : pathNames) {
Path path = paths.get(pathName);

View File

@ -1,10 +1,9 @@
package io.metersphere.api.parse;
package io.metersphere.api.dto.definition.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.response.HttpResponse;
import io.metersphere.api.dto.scenario.Body;
@ -78,7 +77,7 @@ public class Swagger3Parser extends SwaggerAbstractParser {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
ApiModule parentNode = getSelectModule(importRequest.getModuleId());
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
for (String pathName : pathNames) {
PathItem pathItem = paths.get(pathName);

View File

@ -1,16 +1,17 @@
package io.metersphere.api.parse;
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.parse.ApiImportAbstractParser;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import java.util.List;
public abstract class SwaggerAbstractParser extends ApiImportAbstractParser {
public abstract class SwaggerAbstractParser extends ApiImportAbstractParser<ApiDefinitionImport> {
protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List<String> tags) {
if (tags != null) {
tags.forEach(tag -> {
ApiModule module = buildModule(parentModule, tag);
ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId);
apiDefinition.setModuleId(module.getId());
});
}

View File

@ -66,9 +66,6 @@ public class MsScenario extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return;
} else if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
@ -77,16 +74,15 @@ public class MsScenario extends MsTestElement {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiScenarioWithBLOBs scenario = apiAutomationService.getApiScenario(this.getId());
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
hashTree = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
if (scenario != null && StringUtils.isNotEmpty(scenario.getScenarioDefinition())) {
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
hashTree = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
config.setStep(this.getName());
config.setStepType("SCENARIO");
config.setEnableCookieShare(enableCookieShare);
if (StringUtils.isNotEmpty(environmentId)) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
@ -103,6 +99,9 @@ public class MsScenario extends MsTestElement {
this.addCsvDataSet(tree, variables);
this.addCounter(tree, variables);
this.addRandom(tree, variables);
if (CollectionUtils.isNotEmpty(this.headers)) {
setHeader(tree, this.headers);
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
// 给所有孩子加一个父亲标志
@ -110,9 +109,6 @@ public class MsScenario extends MsTestElement {
el.toHashTree(tree, el.getHashTree(), config);
}
}
if (CollectionUtils.isNotEmpty(this.headers)) {
setHeader(tree, this.headers);
}
}
public void setOldVariables(List<KeyValue> oldVariables) {

View File

@ -164,9 +164,9 @@ public abstract class MsTestElement {
}
public Arguments addArguments(ParameterConfig config) {
Arguments arguments = new Arguments();
if (config != null && config.getConfig() != null && config.getConfig().getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().getCommonConfig().getVariables())) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name + "Variables");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
@ -174,8 +174,9 @@ public abstract class MsTestElement {
config.getConfig().getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
return arguments;
}
return arguments;
return null;
}
protected EnvironmentConfig getEnvironmentConfig(String environmentId) {
@ -255,14 +256,15 @@ public abstract class MsTestElement {
}
}
public MsTestElement getRootParent(MsTestElement element) {
public void getFullPath(MsTestElement element, StringBuilder path) {
if (element.getParent() == null) {
return element;
return;
}
if (MsTestElementConstants.LoopController.name().equals(element.getType())) {
return element;
return;
}
return getRootParent(element.getParent());
path.append(element.getResourceId()).append("/");
getFullPath(element.getParent(), path);
}
protected String getParentName(MsTestElement parent, ParameterConfig config) {
@ -279,13 +281,11 @@ public abstract class MsTestElement {
return "次数循环-" + "${LoopCounterConfigXXX}";
}
}
return parent.getName();
} else if (config != null && StringUtils.isNotEmpty(config.getStep())) {
if (MsTestElementConstants.SCENARIO.name().equals(config.getStepType())) {
return config.getStep();
} else {
return config.getStep() + "-" + "${LoopCounterConfigXXX}";
}
// 获取全路径以备后面使用
StringBuilder fullPath = new StringBuilder();
getFullPath(parent, fullPath);
return fullPath + "<->" + parent.getName();
}
return "";
}

View File

@ -45,11 +45,11 @@ public class MsThreadGroup extends MsTestElement {
loopController.setName("LoopController");
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
loopController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("LoopControlPanel"));
loopController.setEnabled(true);
loopController.setEnabled(this.isEnable());
loopController.setLoops(1);
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setEnabled(true);
threadGroup.setEnabled(this.isEnable());
threadGroup.setName(this.getName());
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ThreadGroupGui"));

View File

@ -8,15 +8,21 @@ import java.util.List;
@Data
public class ParameterConfig {
// 环境配置
/**
* 环境配置
*/
private EnvironmentConfig config;
// 公共场景参数
/**
* 公共场景参数
*/
private List<ScenarioVariable> variables;
// 公共Cookie
/**
* 公共Cookie
*/
private boolean enableCookieShare;
// 步骤
private String step;
private String stepType;
/**
* 是否是导入/导出操作
*/
private boolean isOperating;
}

View File

@ -27,9 +27,7 @@ public class MsAssertions extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (this.isEnable()) {
addAssertions(tree);
}
addAssertions(tree);
}
private void addAssertions(HashTree hashTree) {
@ -64,7 +62,7 @@ public class MsAssertions extends MsTestElement {
private ResponseAssertion responseAssertion(MsAssertionRegex assertionRegex) {
ResponseAssertion assertion = new ResponseAssertion();
assertion.setEnabled(true);
assertion.setEnabled(this.isEnable());
assertion.setName(assertionRegex.getDescription());
assertion.setProperty(TestElement.TEST_CLASS, ResponseAssertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("AssertionGui"));
@ -89,7 +87,7 @@ public class MsAssertions extends MsTestElement {
private JSONPathAssertion jsonPathAssertion(MsAssertionJsonPath assertionJsonPath) {
JSONPathAssertion assertion = new JSONPathAssertion();
assertion.setEnabled(true);
assertion.setEnabled(this.isEnable());
assertion.setName(StringUtils.isEmpty(assertionJsonPath.getDescription()) ? "JSONPathAssertion" : assertionJsonPath.getDescription());
assertion.setProperty(TestElement.TEST_CLASS, JSONPathAssertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("JSONPathAssertionGui"));
@ -104,7 +102,7 @@ public class MsAssertions extends MsTestElement {
private XPath2Assertion xPath2Assertion(MsAssertionXPath2 assertionXPath2) {
XPath2Assertion assertion = new XPath2Assertion();
assertion.setEnabled(true);
assertion.setEnabled(this.isEnable());
assertion.setName(StringUtils.isEmpty(assertionXPath2.getExpression()) ? "XPath2Assertion" : assertionXPath2.getExpression());
assertion.setProperty(TestElement.TEST_CLASS, XPath2Assertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("XPath2AssertionGui"));
@ -115,7 +113,7 @@ public class MsAssertions extends MsTestElement {
private DurationAssertion durationAssertion(MsAssertionDuration assertionDuration) {
DurationAssertion assertion = new DurationAssertion();
assertion.setEnabled(true);
assertion.setEnabled(this.isEnable());
assertion.setName("Response In Time: " + assertionDuration.getValue());
assertion.setProperty(TestElement.TEST_CLASS, DurationAssertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DurationAssertionGui"));
@ -125,7 +123,7 @@ public class MsAssertions extends MsTestElement {
private JSR223Assertion jsr223Assertion(MsAssertionJSR223 assertionJSR223) {
JSR223Assertion assertion = new JSR223Assertion();
assertion.setEnabled(true);
assertion.setEnabled(this.isEnable());
assertion.setName(StringUtils.isEmpty(assertionJSR223.getDesc()) ? "JSR223Assertion" : assertionJSR223.getDesc());
assertion.setProperty(TestElement.TEST_CLASS, JSR223Assertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));

View File

@ -27,11 +27,8 @@ public class MsHeaderManager extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setEnabled(this.isEnable());
headerManager.setName(this.getName() + "Headers");
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel"));

View File

@ -26,9 +26,6 @@ public class MsIfController extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(ifController());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
@ -41,7 +38,7 @@ public class MsIfController extends MsTestElement {
private IfController ifController() {
IfController ifController = new IfController();
ifController.setEnabled(true);
ifController.setEnabled(this.isEnable());
ifController.setName(StringUtils.isEmpty(this.getName()) ? "IfController" : this.getName());
ifController.setProperty(TestElement.TEST_CLASS, IfController.class.getName());
ifController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("IfControllerPanel"));

View File

@ -44,21 +44,6 @@ public class MsLoopController extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (StringUtils.equals(this.loopType, LoopConstants.WHILE.name()) && this.whileController != null) {
config.setStep("While 循环");
}
if (StringUtils.equals(this.loopType, LoopConstants.FOREACH.name()) && this.forEachController != null) {
config.setStep("ForEach 循环");
}
if (StringUtils.equals(this.loopType, LoopConstants.LOOP_COUNT.name()) && this.countController != null) {
config.setStep("次数循环");
}
config.setStepType("LOOP");
final HashTree groupTree = controller(tree);
if (CollectionUtils.isNotEmpty(config.getVariables())) {
this.addCsvDataSet(groupTree, config.getVariables());
@ -104,7 +89,7 @@ public class MsLoopController extends MsTestElement {
private LoopController initLoopController() {
LoopController loopController = new LoopController();
loopController.setEnabled(true);
loopController.setEnabled(this.isEnable());
loopController.setName("LoopController");
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
loopController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("LoopControlPanel"));
@ -142,7 +127,7 @@ public class MsLoopController extends MsTestElement {
return null;
}
WhileController controller = new WhileController();
controller.setEnabled(true);
controller.setEnabled(this.isEnable());
controller.setName("WhileController");
controller.setProperty(TestElement.TEST_CLASS, WhileController.class.getName());
controller.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("WhileControllerGui"));
@ -152,7 +137,7 @@ public class MsLoopController extends MsTestElement {
private ForeachController initForeachController() {
ForeachController controller = new ForeachController();
controller.setEnabled(true);
controller.setEnabled(this.isEnable());
controller.setName("ForeachController");
controller.setProperty(TestElement.TEST_CLASS, ForeachController.class.getName());
controller.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ForeachControlPanel"));
@ -188,7 +173,7 @@ public class MsLoopController extends MsTestElement {
private ConstantTimer getCnstantTimer() {
ConstantTimer constantTimer = new ConstantTimer();
constantTimer.setEnabled(true);
constantTimer.setEnabled(this.isEnable());
constantTimer.setProperty(TestElement.TEST_CLASS, ConstantTimer.class.getName());
constantTimer.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ConstantTimerGui"));
if (StringUtils.equals(this.loopType, LoopConstants.WHILE.name()) && this.whileController != null) {

View File

@ -30,9 +30,6 @@ public class MsExtract extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
addRequestExtractors(tree);
}
@ -68,7 +65,7 @@ public class MsExtract extends MsTestElement {
private RegexExtractor regexExtractor(MsExtractRegex extractRegex, StringJoiner extract) {
RegexExtractor extractor = new RegexExtractor();
extractor.setEnabled(true);
extractor.setEnabled(this.isEnable());
extractor.setName(extractRegex.getVariable() + " RegexExtractor");
extractor.setProperty(TestElement.TEST_CLASS, RegexExtractor.class.getName());
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("RegexExtractorGui"));
@ -86,7 +83,7 @@ public class MsExtract extends MsTestElement {
private XPath2Extractor xPath2Extractor(MsExtractXPath extractXPath, StringJoiner extract) {
XPath2Extractor extractor = new XPath2Extractor();
extractor.setEnabled(true);
extractor.setEnabled(this.isEnable());
extractor.setName(extractXPath.getVariable() + " XPath2Extractor");
extractor.setProperty(TestElement.TEST_CLASS, XPath2Extractor.class.getName());
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("XPath2ExtractorGui"));
@ -101,7 +98,7 @@ public class MsExtract extends MsTestElement {
private JSONPostProcessor jsonPostProcessor(MsExtractJSONPath extractJSONPath, StringJoiner extract) {
JSONPostProcessor extractor = new JSONPostProcessor();
extractor.setEnabled(true);
extractor.setEnabled(this.isEnable());
extractor.setName(extractJSONPath.getVariable() + " JSONExtractor");
extractor.setProperty(TestElement.TEST_CLASS, JSONPostProcessor.class.getName());
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("JSONPostProcessorGui"));

View File

@ -29,18 +29,15 @@ public class MsJSR223Processor extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
JSR223Sampler processor = new JSR223Sampler();
processor.setEnabled(true);
processor.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(this.getName())) {
processor.setName(this.getName());
} else {
processor.setName("JSR223Processor");
}
String name = this.getParentName(this.getParent(), config);
if (StringUtils.isNotEmpty(name)) {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
processor.setName(this.getName() + "<->" + name);
}
processor.setProperty(TestElement.TEST_CLASS, JSR223Sampler.class.getName());

View File

@ -29,11 +29,8 @@ public class MsJSR223PostProcessor extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
JSR223PostProcessor processor = new JSR223PostProcessor();
processor.setEnabled(true);
processor.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(this.getName())) {
processor.setName(this.getName());
} else {

View File

@ -29,9 +29,6 @@ public class MsJSR223PreProcessor extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
final HashTree jsr223PreTree = tree.add(getJSR223PreProcessor());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
@ -42,7 +39,7 @@ public class MsJSR223PreProcessor extends MsTestElement {
public JSR223PreProcessor getJSR223PreProcessor() {
JSR223PreProcessor processor = new JSR223PreProcessor();
processor.setEnabled(true);
processor.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(this.getName())) {
processor.setName(this.getName());
} else {

View File

@ -33,7 +33,7 @@ public class MsDubboSampler extends MsTestElement {
private String type = "DubboSampler";
@JSONField(ordinal = 52)
private String protocol = "DUBBO";
private final String protocol = "dubbo://";
@JsonProperty(value = "interface")
@JSONField(ordinal = 53, name = "interface")
private String _interface;
@ -52,14 +52,11 @@ public class MsDubboSampler extends MsTestElement {
@JSONField(ordinal = 59)
private List<KeyValue> attachmentArgs;
@JSONField(ordinal = 60)
private Object requestResult;
// @JSONField(ordinal = 60)
// private Object requestResult;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && "Deleted".equals(this.getReferenced())) {
return;
}
@ -77,9 +74,10 @@ public class MsDubboSampler extends MsTestElement {
private DubboSample dubboSample(ParameterConfig config) {
DubboSample sampler = new DubboSample();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
if (StringUtils.isNotEmpty(name)) {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}
sampler.setProperty(TestElement.TEST_CLASS, DubboSample.class.getName());

View File

@ -85,25 +85,23 @@ public class MsHTTPSamplerProxy extends MsTestElement {
@JSONField(ordinal = 34)
private List<KeyValue> arguments;
@JSONField(ordinal = 35)
private Object requestResult;
// @JSONField(ordinal = 35)
// private Object requestResult;
@JSONField(ordinal = 36)
private MsAuthManager authManager;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this);
}
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setEnabled(true);
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
if (StringUtils.isNotEmpty(name)) {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
@ -124,7 +122,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
// 添加环境中的公共变量
Arguments arguments = this.addArguments(config);
if (arguments != null) {
tree.add(this.addArguments(config));
tree.add(arguments);
}
try {
if (config != null && config.getConfig() != null) {

View File

@ -46,8 +46,8 @@ public class MsJDBCSampler extends MsTestElement {
private List<KeyValue> variables;
@JSONField(ordinal = 26)
private String environmentId;
@JSONField(ordinal = 27)
private Object requestResult;
// @JSONField(ordinal = 27)
// private Object requestResult;
@JSONField(ordinal = 28)
private String dataSourceId;
@JSONField(ordinal = 29)
@ -55,9 +55,6 @@ public class MsJDBCSampler extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this);
}
@ -70,7 +67,10 @@ public class MsJDBCSampler extends MsTestElement {
}
final HashTree samplerHashTree = tree.add(jdbcSampler(config));
tree.add(jdbcDataSource());
tree.add(arguments(this.getName() + " Variables", this.getVariables()));
Arguments arguments = arguments(this.getName() + " Variables", this.getVariables());
if (arguments != null) {
tree.add(arguments);
}
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(samplerHashTree, el.getHashTree(), config);
@ -95,24 +95,26 @@ public class MsJDBCSampler extends MsTestElement {
}
private Arguments arguments(String name, List<KeyValue> variables) {
Arguments arguments = new Arguments();
if (CollectionUtils.isNotEmpty(variables)) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name);
arguments.setName(name + "JDBC_Argument");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
return arguments;
}
return arguments;
return null;
}
private JDBCSampler jdbcSampler(ParameterConfig config) {
JDBCSampler sampler = new JDBCSampler();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
if (StringUtils.isNotEmpty(name)) {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + "<->" + name);
}
sampler.setProperty(TestElement.TEST_CLASS, JDBCSampler.class.getName());

View File

@ -59,8 +59,8 @@ public class MsTCPSampler extends MsTestElement {
private String password = "";
@JSONField(ordinal = 33)
private String request;
@JSONField(ordinal = 34)
private Object requestResult;
// @JSONField(ordinal = 34)
// private Object requestResult;
@JSONField(ordinal = 35)
private List<KeyValue> parameters;
@JSONField(ordinal = 36)
@ -72,9 +72,6 @@ public class MsTCPSampler extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) {
this.getRefElement(this);
}
@ -84,7 +81,7 @@ public class MsTCPSampler extends MsTestElement {
// 添加环境中的公共变量
Arguments arguments = this.addArguments(config);
if (arguments != null) {
tree.add(this.addArguments(config));
tree.add(arguments);
}
final HashTree samplerHashTree = new ListedHashTree();
@ -110,9 +107,10 @@ public class MsTCPSampler extends MsTestElement {
private TCPSampler tcpSampler(ParameterConfig config) {
TCPSampler tcpSampler = new TCPSampler();
tcpSampler.setEnabled(this.isEnable());
tcpSampler.setName(this.getName());
String name = this.getParentName(this.getParent(), config);
if (StringUtils.isNotEmpty(name)) {
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
tcpSampler.setName(this.getName() + "<->" + name);
}

View File

@ -26,9 +26,7 @@ public class MsConstantTimer extends MsTestElement {
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (!this.isEnable()) {
return;
}
final HashTree groupTree = tree.add(constantTimer());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
@ -39,7 +37,7 @@ public class MsConstantTimer extends MsTestElement {
private ConstantTimer constantTimer() {
ConstantTimer constantTimer = new ConstantTimer();
constantTimer.setEnabled(true);
constantTimer.setEnabled(this.isEnable());
constantTimer.setName(this.getDelay() + " ms");
constantTimer.setProperty(TestElement.TEST_CLASS, ConstantTimer.class.getName());
constantTimer.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ConstantTimerGui"));

View File

@ -29,17 +29,17 @@ public class MsJmeterElement extends MsTestElement {
@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)) {
if (config.isOperating()) {
elementTree = tree.add(scriptWrapper);
} else 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);

View File

@ -40,6 +40,10 @@ public class ScenarioVariable {
private String minNumber;
private String maxNumber;
public ScenarioVariable() {
}
public ScenarioVariable(String key, String value, String description, String type) {
this.name = key;
this.value = value;

View File

@ -48,8 +48,8 @@ public class TestResult {
result.getRequestResults().forEach(item -> {
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
String array[] = item.getName().split(SEPARATOR);
String scenarioName = array[array.length - 1];
item.setName(item.getName().replace(SEPARATOR + scenarioName, ""));
String scenarioName = item.getName().replace(array[0] + SEPARATOR, "");
item.setName(array[0]);
if (requestResultMap.containsKey(scenarioName)) {
requestResultMap.get(scenarioName).add(item);
} else {
@ -80,6 +80,9 @@ public class TestResult {
ScenarioResult scenarioResult = new ScenarioResult();
BeanUtils.copyBean(scenarioResult, result);
scenarioResult.setName(k);
if (k.indexOf(SEPARATOR) != -1) {
scenarioResult.setName(k.split(SEPARATOR)[1]);
}
scenarioResult.setRequestResults(v);
scenarios.add(scenarioResult);
});

View File

@ -1,18 +1,16 @@
package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.api.dto.definition.request.MsScenario;
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.Scenario;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
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 io.metersphere.commons.utils.SessionUtils;
import org.apache.commons.collections.CollectionUtils;
@ -29,10 +27,9 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
public abstract class ApiImportAbstractParser implements ApiImportParser {
public abstract class ApiImportAbstractParser<T> implements ApiImportParser<T> {
protected String projectId;
protected ApiModuleService apiModuleService;
protected String getApiTestStr(InputStream source) {
StringBuilder testStr = null;
@ -47,7 +44,9 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
LogUtil.error(e.getMessage(), e);
} finally {
try {
source.close();
if (source != null) {
source.close();
}
} catch (IOException e) {
MSException.throwException(e.getMessage());
LogUtil.error(e.getMessage(), e);
@ -62,42 +61,6 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
}
}
protected ApiModule getSelectModule(String moduleId) {
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
ApiModule module = new ApiModule();
ApiModuleDTO moduleDTO = apiModuleService.getNode(moduleId);
if (moduleDTO != null) {
BeanUtils.copyBean(module, moduleDTO);
}
return module;
}
return null;
}
protected ApiModule buildModule(ApiModule parentModule, String name) {
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
ApiModule 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(ApiModule module) {
module.setProtocol(RequestType.HTTP);
List<ApiModule> apiModules = apiModuleService.selectSameModule(module);
if (CollectionUtils.isEmpty(apiModules)) {
apiModuleService.addNode(module);
} else {
module.setId(apiModules.get(0).getId());
}
}
protected String getBodyType(String contentType) {
String bodyType = "";
switch (contentType) {
@ -233,4 +196,22 @@ public abstract class ApiImportAbstractParser implements ApiImportParser {
headers.add(new KeyValue(key, value, description, contentType, required));
}
}
protected ApiScenarioWithBLOBs parseScenario(MsScenario msScenario) {
// ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
scenarioWithBLOBs.setName(msScenario.getName());
scenarioWithBLOBs.setProjectId(this.projectId);
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));
return scenarioWithBLOBs;
// scenarioWithBLOBsList.add(scenarioWithBLOBs);
}
}

View File

@ -1,10 +1,9 @@
package io.metersphere.api.parse;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import java.io.InputStream;
public interface ApiImportParser {
ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request);
public interface ApiImportParser<T> {
T parse(InputStream source, ApiTestImportRequest request);
}

View File

@ -0,0 +1,99 @@
package io.metersphere.api.parse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.commons.utils.LogUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
public abstract class MsAbstractParser<T> extends ApiImportAbstractParser<T> {
protected List<MsHTTPSamplerProxy> parseMsHTTPSamplerProxy(JSONObject testObject, String tag) {
JSONObject requests = testObject.getJSONObject(tag);
List<MsHTTPSamplerProxy> msHTTPSamplerProxies = new ArrayList<>();
requests.keySet().forEach(requestName -> {
JSONObject requestObject = requests.getJSONObject(requestName);
String path = requestObject.getString("url");
String method = requestObject.getString("method");
MsHTTPSamplerProxy request = buildRequest(requestName, path, method);
parseBody(requestObject, request.getBody());
parseHeader(requestObject, request.getHeaders());
parsePath(request);
msHTTPSamplerProxies.add(request);
});
return msHTTPSamplerProxies;
}
private void parsePath(MsHTTPSamplerProxy request) {
if (StringUtils.isNotBlank(request.getPath())) {
String[] split = request.getPath().split("\\?");
String path = split[0];
parseQueryParameters(split, request.getArguments());
request.setPath(path);
} else {
request.setPath("/");
}
}
private void parseQueryParameters(String[] split, List<KeyValue> arguments) {
if (split.length > 1) {
try {
String queryParams = split[1];
queryParams = URLDecoder.decode(queryParams, "UTF-8");
String[] params = queryParams.split("&");
for (String param : params) {
String[] kv = param.split("=");
arguments.add(new KeyValue(kv[0], kv.length < 2 ? null : kv[1]));
}
} catch (UnsupportedEncodingException e) {
LogUtil.info(e.getMessage(), e);
return;
}
}
}
private void parseHeader(JSONObject requestObject, List<KeyValue> msHeaders) {
JSONArray headers = requestObject.getJSONArray("headers");
if (CollectionUtils.isNotEmpty(headers)) {
for (int i = 0; i < headers.size(); i++) {
JSONObject header = headers.getJSONObject(i);
msHeaders.add(new KeyValue(header.getString("name"), header.getString("value")));
}
}
}
private void parseBody(JSONObject requestObject, Body msBody) {
if (requestObject.containsKey("body")) {
Object body = requestObject.get("body");
if (body instanceof JSONArray) {
JSONArray bodies = requestObject.getJSONArray("body");
if (bodies != null) {
StringBuilder bodyStr = new StringBuilder();
for (int i = 0; i < bodies.size(); i++) {
String tmp = bodies.getString(i);
bodyStr.append(tmp);
}
msBody.setType(Body.RAW);
msBody.setRaw(bodyStr.toString());
}
} else if (body instanceof JSONObject) {
JSONObject bodyObj = requestObject.getJSONObject("body");
if (bodyObj != null) {
ArrayList<KeyValue> kvs = new ArrayList<>();
bodyObj.keySet().forEach(key -> {
kvs.add(new KeyValue(key, bodyObj.getString(key)));
});
msBody.setKvs(kvs);
msBody.setType(Body.WWW_FROM);
}
}
}
}
}

View File

@ -1,192 +0,0 @@
package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
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.parse.ApiDefinitionImport;
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.ApiModuleService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.commons.constants.ApiImportPlatform;
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.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.function.Consumer;
public class MsParser extends ApiImportAbstractParser {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
this.projectId = request.getProjectId();
if (testObject.get("projectName") != null) {
return parseMsFormat(testStr, request);
} else {
request.setPlatform(ApiImportPlatform.Plugin.name());
return parsePluginFormat(testObject, request, true);
}
}
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
apiDefinitionImport.getData().forEach(apiDefinition -> {
parseApiDefinition(apiDefinition, importRequest);
});
return apiDefinitionImport;
}
private void parseApiDefinition(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest) {
String id = UUID.randomUUID().toString();
if (StringUtils.isBlank(apiDefinition.getModulePath())) {
apiDefinition.setModuleId(null);
}
parseModule(apiDefinition.getModulePath(), importRequest, apiDefinition::setModuleId);
apiDefinition.setId(id);
apiDefinition.setProjectId(this.projectId);
String request = apiDefinition.getRequest();
JSONObject requestObj = JSONObject.parseObject(request);
requestObj.put("id", id);
apiDefinition.setRequest(JSONObject.toJSONString(requestObj));
}
protected ApiDefinitionImport parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest, Boolean isCreateModule) {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
ApiDefinitionImport apiImport = new ApiDefinitionImport();
apiImport.setProtocol(RequestType.HTTP);
apiImport.setData(results);
testObject.keySet().forEach(tag -> {
String moduleId = "";
if (isCreateModule) {
moduleId = buildModule(getSelectModule(importRequest.getModuleId()), tag).getId();
}
JSONObject requests = testObject.getJSONObject(tag);
String finalModuleId = moduleId;
requests.keySet().forEach(requestName -> {
JSONObject requestObject = requests.getJSONObject(requestName);
String path = requestObject.getString("url");
String method = requestObject.getString("method");
MsHTTPSamplerProxy request = buildRequest(requestName, path, method);
ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(request.getId(), requestName, path, method,importRequest);
apiDefinition.setModuleId(finalModuleId);
apiDefinition.setProjectId(this.projectId);
parseBody(requestObject, request.getBody());
parseHeader(requestObject, request.getHeaders());
parsePath(request, apiDefinition);
apiDefinition.setRequest(JSONObject.toJSONString(request));
results.add(apiDefinition);
});
});
return apiImport;
}
private void parsePath(MsHTTPSamplerProxy request, ApiDefinitionWithBLOBs apiDefinition) {
if (StringUtils.isNotBlank(request.getPath())) {
String[] split = request.getPath().split("\\?");
String path = split[0];
parseQueryParameters(split, request.getArguments());
request.setPath(path);
apiDefinition.setPath(path);
} else {
request.setPath("/");
apiDefinition.setPath("/");
}
apiDefinition.setName(apiDefinition.getPath() + " [" + apiDefinition.getMethod() + "]");
}
private void parseQueryParameters(String[] split, List<KeyValue> arguments) {
if (split.length > 1) {
try {
String queryParams = split[1];
queryParams = URLDecoder.decode(queryParams, "UTF-8");
String[] params = queryParams.split("&");
for (String param : params) {
String[] kv = param.split("=");
arguments.add(new KeyValue(kv[0], kv[1]));
}
} catch (UnsupportedEncodingException e) {
LogUtil.info(e.getMessage(), e);
return;
}
}
}
private void parseHeader(JSONObject requestObject, List<KeyValue> msHeaders) {
JSONArray headers = requestObject.getJSONArray("headers");
if (CollectionUtils.isNotEmpty(headers)) {
for (int i = 0; i < headers.size(); i++) {
JSONObject header = headers.getJSONObject(i);
msHeaders.add(new KeyValue(header.getString("name"), header.getString("value")));
}
}
}
private void parseBody(JSONObject requestObject, Body msBody) {
if (requestObject.containsKey("body")) {
Object body = requestObject.get("body");
if (body instanceof JSONArray) {
JSONArray bodies = requestObject.getJSONArray("body");
if (bodies != null) {
StringBuilder bodyStr = new StringBuilder();
for (int i = 0; i < bodies.size(); i++) {
String tmp = bodies.getString(i);
bodyStr.append(tmp);
}
msBody.setType(Body.RAW);
msBody.setRaw(bodyStr.toString());
}
} else if (body instanceof JSONObject) {
JSONObject bodyObj = requestObject.getJSONObject("body");
if (bodyObj != null) {
ArrayList<KeyValue> kvs = new ArrayList<>();
bodyObj.keySet().forEach(key -> {
kvs.add(new KeyValue(key, bodyObj.getString(key)));
});
msBody.setKvs(kvs);
msBody.setType(Body.WWW_FROM);
}
}
}
}
protected void parseModule(String modulePath, ApiTestImportRequest importRequest, Consumer<String> consumer) {
if (StringUtils.isBlank(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("/"));
ApiModule parent = getSelectModule(importRequest.getModuleId());
Iterator<String> iterator = modules.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
parent = buildModule(parent, item);
if (!iterator.hasNext()) {
consumer.accept(parent.getId());
}
}
}
}

View File

@ -2,64 +2,25 @@ 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.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.parse.postman.*;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.MsRequestBodyType;
import io.metersphere.commons.constants.PostmanRequestBodyMode;
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.stream.Collectors;
public class PostmanParser extends ApiImportAbstractParser {
public abstract class PostmanAbstractParserParser<T> extends ApiImportAbstractParser<T> {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
this.projectId = request.getProjectId();
PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class);
List<PostmanKeyValue> variables = postmanCollection.getVariable();
ApiDefinitionImport apiImport = new ApiDefinitionImport();
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
parseItem(postmanCollection.getItem(), variables, results, buildModule(getSelectModule(request.getModuleId()), postmanCollection.getInfo().getName()), true);
apiImport.setData(results);
return apiImport;
}
protected void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results, ApiModule parentModule, Boolean isCreateModule) {
for (PostmanItem item : items) {
List<PostmanItem> childItems = item.getItem();
if (childItems != null) {
ApiModule module = null;
if (isCreateModule) {
module = buildModule(parentModule, item.getName());
}
parseItem(childItems, variables, results, module, isCreateModule);
} else {
ApiDefinitionWithBLOBs request = parsePostman(item);
if (request != null) {
results.add(request);
}
if (parentModule != null) {
request.setModuleId(parentModule.getId());
}
}
}
}
private ApiDefinitionWithBLOBs parsePostman(PostmanItem requestItem) {
protected MsHTTPSamplerProxy parsePostman(PostmanItem requestItem) {
PostmanRequest requestDesc = requestItem.getRequest();
if (requestDesc == null) {
return null;
@ -67,44 +28,45 @@ public class PostmanParser extends ApiImportAbstractParser {
requestDesc.getAuth(); // todo 认证方式等待优化
PostmanUrl url = requestDesc.getUrl();
MsHTTPSamplerProxy request = buildRequest(requestItem.getName(), url.getRaw(), requestDesc.getMethod());
ApiDefinitionWithBLOBs apiDefinition =
buildApiDefinition(request.getId(), requestItem.getName(), url.getRaw(), requestDesc.getMethod(),new ApiTestImportRequest());
if (StringUtils.isNotBlank(request.getPath())) {
String path = request.getPath().split("\\?")[0];
path = path.replace("{{", "${");
path = path.replace("}}", "}");
request.setPath(path);
apiDefinition.setPath(path);
} else {
request.setPath("/");
apiDefinition.setPath("/");
}
parseBody(request.getBody(), requestDesc);
request.setArguments(parseKeyValue(url.getQuery()));
request.setHeaders(parseKeyValue(requestDesc.getHeader()));
addBodyHeader(request);
addPreScript(request, requestItem.getEvent());
apiDefinition.setRequest(JSON.toJSONString(request));
return apiDefinition;
return request;
}
private void addPreScript(MsHTTPSamplerProxy request, List<PostmanEvent> event) {
if (CollectionUtils.isNotEmpty(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();
List<String> exec = script.getExec();
if (CollectionUtils.isNotEmpty(exec)) {
exec.forEach(col -> {
scriptStr.append(col + "/n");
});
if (script != null && item.getListen().contains("prerequest")) {
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<>();
@ -129,6 +91,9 @@ public class PostmanParser extends ApiImportAbstractParser {
return;
}
String bodyMode = postmanBody.getString("mode");
if (StringUtils.isBlank(bodyMode)) {
return;
}
if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) {
parseRawBody(body, postmanBody, bodyMode);
} else if (StringUtils.equalsAny(bodyMode, PostmanRequestBodyMode.FORM_DATA.value(), PostmanRequestBodyMode.URLENCODED.value())) {

View File

@ -1,71 +0,0 @@
package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenrioExportResult;
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.service.ApiModuleService;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.commons.constants.ApiImportPlatform;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.UUID;
public class ScenarioMsParser extends MsParser {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
this.projectId = request.getProjectId();
if (testObject.get("projectId") != null) {
return parseMsFormat(testStr, request);
} else {
request.setPlatform(ApiImportPlatform.Plugin.name());
ApiDefinitionImport apiDefinitionImport = parsePluginFormat(testObject, request, false);
MsScenario msScenario = new MsScenario();
LinkedList<MsTestElement> msHTTPSamplerProxies = new LinkedList<>();
apiDefinitionImport.getData().forEach(res -> {
msHTTPSamplerProxies.add(JSONObject.parseObject(res.getRequest(), MsHTTPSamplerProxy.class));
});
msScenario.setHashTree(msHTTPSamplerProxies);
msScenario.setType("scenario");
apiDefinitionImport.setScenarioDefinition(msScenario);
return apiDefinitionImport;
}
}
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiScenrioExportResult apiScenrioExportResult = JSON.parseObject(testStr, ApiScenrioExportResult.class);
apiScenrioExportResult.getData().forEach(scenario -> {
parseApiDefinition(scenario, importRequest);
});
ApiDefinitionImport apiDefinitionImport = new ApiDefinitionImport();
apiDefinitionImport.setScenarioDefinitionData(apiScenrioExportResult.getData());
return apiDefinitionImport;
}
private void parseApiDefinition(ApiScenarioWithBLOBs scenario, ApiTestImportRequest importRequest) {
String id = UUID.randomUUID().toString();
if (StringUtils.isBlank(scenario.getModulePath())) {
scenario.setApiScenarioModuleId(null);
}
// 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));
}
}

View File

@ -35,6 +35,7 @@ import org.aspectj.util.FileUtil;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -461,55 +462,55 @@ public class APITestService {
});
}
public String updateJmxString(String jmxString,String testName,boolean updateHTTPSamplerProxyName) {
/**
* 更新jmx数据处理jmx里的各种参数
* <p>
* 与1.7分支合并时如果该方法产生冲突请以master为准
*
* @param jmxString 原JMX文件
* @param testNameParam 某些节点要替换的testName
* @param isFromScenario 是否来源于场景 来源于场景的话testName要进行处理
* @return
* @author song tianyang
*/
public String updateJmxString(String jmxString, String testNameParam, boolean isFromScenario) {
// 与1.7分支合并时如果该方法产生冲突请以master为准
String attribute_testName = "testname";
String[] requestElementNameArr = new String[]{"HTTPSamplerProxy", "TCPSampler", "JDBCSampler", "DubboSample"};
try {
//将ThreadGroup的testname改为接口名称
Document doc = DocumentHelper.parseText(jmxString);// 获取可续保保单列表报文模板
Element root = doc.getRootElement();
Element rootHashTreeElement = root.element("hashTree");
Element innerHashTreeElement = rootHashTreeElement.elements("hashTree").get(0);
Element theadGroupElement = innerHashTreeElement.elements("ThreadGroup").get(0);
theadGroupElement.attribute("testname").setText(testName);
List<Element> thirdHashTreeElementList = innerHashTreeElement.elements("hashTree");
for (Element element : thirdHashTreeElementList) {
if(updateHTTPSamplerProxyName){
List<Element> sampleProxyElementList = element.elements("HTTPSamplerProxy");
for (Element itemElement : sampleProxyElementList) {
itemElement.attribute("testname").setText(testName);
List<Element> innerHashTreeElementList = rootHashTreeElement.elements("hashTree");
for (Element innerHashTreeElement : innerHashTreeElementList) {
//转换DubboDefaultConfigGui
List<Element> configTestElementList = innerHashTreeElement.elements("ConfigTestElement");
for (Element configTestElement : configTestElementList) {
this.updateDubboDefaultConfigGuiElement(configTestElement);
}
List<Element> theadGroupElementList = innerHashTreeElement.elements("ThreadGroup");
for (Element theadGroupElement : theadGroupElementList) {
if (StringUtils.isNotEmpty(testNameParam)) {
theadGroupElement.attribute(attribute_testName).setText(testNameParam);
}
}
//检查有没有自定义参数
List<Element> scriptHashTreeElementList = element.elements("hashTree");
for (Element scriptHashTreeElement : scriptHashTreeElementList) {
boolean isRemove = false;
List<Element> removeElement = new ArrayList<>();
List<Element> scriptElementItemList = scriptHashTreeElement.elements();
for (Element hashTreeItemElement : scriptElementItemList) {
String className = hashTreeItemElement.attributeValue("testclass");
String qname = hashTreeItemElement.getQName().getName();
List<Element> thirdHashTreeElementList = innerHashTreeElement.elements("hashTree");
for (Element element : thirdHashTreeElementList) {
String testName = testNameParam;
if (isRemove) {
if (org.apache.commons.lang3.StringUtils.equals("hashTree", qname)) {
removeElement.add(hashTreeItemElement);
}
}
isRemove = false;
if (org.apache.commons.lang3.StringUtils.equals(className, "JSR223PostProcessor")) {
List<Element> scriptElements = hashTreeItemElement.elements("stringProp");
for (Element scriptElement : scriptElements) {
String scriptName = scriptElement.attributeValue("name");
String contentValue = scriptElement.getStringValue();
//更新请求类节点的部份属性
this.updateRequestElementInfo(element, testNameParam, requestElementNameArr, isFromScenario);
//检查有无jmeter不是别的自定义参数
this.checkPrivateFunctionNode(element);
if ("script".equals(scriptName) && contentValue.startsWith("io.metersphere.api.jmeter.JMeterVars.addVars")) {
isRemove = true;
removeElement.add(hashTreeItemElement);
}
}
}
}
for (Element itemElement : removeElement) {
scriptHashTreeElement.remove(itemElement);
//转换DubboDefaultConfigGui
List<Element> hashTreeConfigTestElementList = element.elements("ConfigTestElement");
for (Element configTestElement : hashTreeConfigTestElementList) {
this.updateDubboDefaultConfigGuiElement(configTestElement);
}
}
}
@ -517,6 +518,86 @@ public class APITestService {
} catch (Exception e) {
e.printStackTrace();
}
if (!jmxString.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")) {
jmxString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + jmxString;
}
return jmxString;
}
private void updateDubboDefaultConfigGuiElement(Element configTestElement) {
String dubboDefaultConfigGuiClassName = "io.github.ningyu.jmeter.plugin.dubbo.gui.DubboDefaultConfigGui";
if (configTestElement == null) {
return;
}
String guiClassValue = configTestElement.attributeValue("guiclass");
if (StringUtils.equals(guiClassValue, "DubboDefaultConfigGui")) {
configTestElement.attribute("guiclass").setText(dubboDefaultConfigGuiClassName);
}
}
private void checkPrivateFunctionNode(Element element) {
List<Element> scriptHashTreeElementList = element.elements("hashTree");
for (Element scriptHashTreeElement : scriptHashTreeElementList) {
boolean isRemove = false;
List<Element> removeElement = new ArrayList<>();
List<Element> scriptElementItemList = scriptHashTreeElement.elements();
for (Element hashTreeItemElement : scriptElementItemList) {
String className = hashTreeItemElement.attributeValue("testclass");
String qname = hashTreeItemElement.getQName().getName();
if (isRemove) {
if (org.apache.commons.lang3.StringUtils.equals("hashTree", qname)) {
removeElement.add(hashTreeItemElement);
}
}
isRemove = false;
if (org.apache.commons.lang3.StringUtils.equals(className, "JSR223PostProcessor")) {
List<Element> scriptElements = hashTreeItemElement.elements("stringProp");
for (Element scriptElement : scriptElements) {
String scriptName = scriptElement.attributeValue("name");
String contentValue = scriptElement.getStringValue();
if ("script".equals(scriptName) && contentValue.startsWith("io.metersphere.api.jmeter.JMeterVars.addVars")) {
isRemove = true;
removeElement.add(hashTreeItemElement);
}
}
}
}
for (Element itemElement : removeElement) {
scriptHashTreeElement.remove(itemElement);
}
}
}
private void updateRequestElementInfo(Element element, String testNameParam, String[] requestElementNameArr, boolean isFromScenario) {
String attribute_testName = "testname";
String scenarioCaseNameSplit = "<->";
String testName = testNameParam;
for (String requestElementName : requestElementNameArr) {
List<Element> sampleProxyElementList = element.elements(requestElementName);
for (Element itemElement : sampleProxyElementList) {
if (isFromScenario) {
testName = itemElement.attributeValue(attribute_testName);
String[] testNameArr = testName.split(scenarioCaseNameSplit);
if (testNameArr.length > 0) {
testName = testNameArr[0];
}
}
itemElement.attribute(attribute_testName).setText(testName);
//double的话有额外处理方式
if (StringUtils.equals(requestElementName, "DubboSample")) {
//dubbo节点要更新 标签guiClass testClass
itemElement.setName("io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample");
itemElement.attribute("testclass").setText("io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample");
itemElement.attribute("guiclass").setText("io.github.ningyu.jmeter.plugin.dubbo.gui.DubboSampleGui");
}
}
}
}
}

View File

@ -10,14 +10,15 @@ 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.*;
import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
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.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
@ -435,6 +436,56 @@ public class ApiAutomationService {
return jmeterHashTree;
}
private String generateJmx(ApiScenarioWithBLOBs apiScenario) {
HashTree jmeterHashTree = new ListedHashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setName(apiScenario.getName());
testPlan.setHashTree(new LinkedList<>());
ParameterConfig config = new ParameterConfig();
config.setOperating(true);
try {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(apiScenario.getScenarioDefinition());
MsScenario scenario = JSONObject.parseObject(apiScenario.getScenarioDefinition(), MsScenario.class);
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
scenario.setHashTree(elements);
}
if (StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<ScenarioVariable>>() {
});
scenario.setVariables(variables);
}
// 针对导入的jmx 处理
if (CollectionUtils.isNotEmpty(scenario.getHashTree()) && (scenario.getHashTree().get(0) instanceof MsJmeterElement)) {
scenario.toHashTree(jmeterHashTree, scenario.getHashTree(), config);
return scenario.getJmx(jmeterHashTree);
} else {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(apiScenario.getName());
group.setName(apiScenario.getName());
group.setEnableCookieShare(scenario.isEnableCookieShare());
group.setHashTree(new LinkedList<MsTestElement>() {{
this.add(scenario);
}});
testPlan.getHashTree().add(group);
}
} catch (Exception ex) {
ex.printStackTrace();
MSException.throwException(ex.getMessage());
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
return testPlan.getJmx(jmeterHashTree);
}
/**
* 场景测试执行
*
@ -515,7 +566,6 @@ 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());
@ -668,7 +718,7 @@ public class ApiAutomationService {
HashTree jmeterHashTree = generateHashTree(apiScenarios, request, null);
String jmx = testPlan.getJmx(jmeterHashTree);
jmx = apiTestService.updateJmxString(jmx,testName,false);
jmx = apiTestService.updateJmxString(jmx, testName, true);
//将ThreadGroup的testname改为接口名称
// Document doc = DocumentHelper.parseText(jmx);// 获取可续保保单列表报文模板
@ -720,16 +770,6 @@ public class ApiAutomationService {
}
}
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());
@ -801,10 +841,12 @@ public class ApiAutomationService {
}
public ScenarioImport scenarioImport(MultipartFile file, ApiTestImportRequest request) {
ScenarioImportParser apiImportParser = ScenarioImportParserFactory.getImportParser(request.getPlatform());
ApiImportParser apiImportParser = ScenarioImportParserFactory.getImportParser(request.getPlatform());
ScenarioImport apiImport = null;
Optional.ofNullable(file)
.ifPresent(item -> request.setFileName(file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."))));
try {
apiImport = Objects.requireNonNull(apiImportParser).parse(file == null ? null : file.getInputStream(), request);
apiImport = (ScenarioImport) 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"));
@ -815,16 +857,33 @@ public class ApiAutomationService {
return apiImport;
}
public ApiScenrioExportResult export(ApiScenarioBatchRequest request) {
private List<ApiScenarioWithBLOBs> getExportResult(ApiScenarioBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query));
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(request.getIds());
List<ApiScenarioWithBLOBs> apiScenarioWithBLOBs = apiScenarioMapper.selectByExampleWithBLOBs(example);
ApiScenrioExportResult result = new ApiScenrioExportResult();
result.setData(apiScenarioWithBLOBs);
return apiScenarioWithBLOBs;
}
public ApiScenrioExportResult export(ApiScenarioBatchRequest request) {
ApiScenrioExportResult result = new ApiScenrioExportResult();
result.setData(getExportResult(request));
result.setProjectId(request.getProjectId());
result.setVersion(System.getenv("MS_VERSION"));
return result;
}
public List<ApiScenrioExportJmx> exportJmx(ApiScenarioBatchRequest request) {
List<ApiScenarioWithBLOBs> apiScenarioWithBLOBs = getExportResult(request);
// 生成jmx
List<ApiScenrioExportJmx> resList = new ArrayList<>();
apiScenarioWithBLOBs.forEach(item -> {
String jmx = generateJmx(item);
ApiScenrioExportJmx scenrioExportJmx = new ApiScenrioExportJmx(item.getName(), apiTestService.updateJmxString(jmx, null, true));
resList.add(scenrioExportJmx);
});
return resList;
}
}

View File

@ -18,7 +18,7 @@ import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.RequestResult;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.api.parse.ApiImportParserFactory;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImportParserFactory;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
@ -130,6 +130,9 @@ public class ApiDefinitionService {
public void create(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
if (StringUtils.equals(request.getProtocol(), "DUBBO")) {
request.setMethod("dubbo://");
}
createTest(request);
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
}
@ -140,6 +143,9 @@ public class ApiDefinitionService {
}
List<String> bodyUploadIds = request.getBodyUploadIds();
request.setBodyUploadIds(null);
if (StringUtils.equals(request.getProtocol(), "DUBBO")) {
request.setMethod("dubbo://");
}
updateTest(request);
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
}
@ -382,6 +388,9 @@ public class ApiDefinitionService {
apiTestCase.setUpdateUserId(SessionUtils.getUserId());
apiTestCase.setNum(getNextNum(apiTestCase.getApiDefinitionId()));
apiTestCase.setPriority("P0");
if (apiTestCase.getName().length() > 255) {
apiTestCase.setName(apiTestCase.getName().substring(0, 255));
}
if (!isInsert) {
apiTestCase.setName(apiTestCase.getName() + "_" + apiTestCase.getId().substring(0, 5));
}
@ -490,10 +499,10 @@ public class ApiDefinitionService {
public ApiDefinitionImport apiTestImport(MultipartFile file, ApiTestImportRequest request) {
ApiImportParser apiImportParser = ApiImportParserFactory.getApiImportParser(request.getPlatform());
ApiImportParser apiImportParser = ApiDefinitionImportParserFactory.getApiImportParser(request.getPlatform());
ApiDefinitionImport apiImport = null;
try {
apiImport = Objects.requireNonNull(apiImportParser).parse(file == null ? null : file.getInputStream(), request);
apiImport = (ApiDefinitionImport) 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"));
@ -615,7 +624,7 @@ public class ApiDefinitionService {
return example;
}
private List<String> getAllApiIdsByFontedSelect(Map<String, List<String>> filters, String name, List<String> moduleIds, String projectId, List<String> unSelectIds,String protocol) {
private List<String> getAllApiIdsByFontedSelect(Map<String, List<String>> filters, String name, List<String> moduleIds, String projectId, List<String> unSelectIds, String protocol) {
ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setFilters(filters);
request.setName(name);
@ -744,6 +753,8 @@ public class ApiDefinitionService {
apiExportResult.setCases(apiTestCaseService.selectCasesBydApiIds(request.getIds()));
apiExportResult.setProjectName(request.getProjectId());
apiExportResult.setProtocol(request.getProtocol());
apiExportResult.setProjectId(request.getProjectId());
apiExportResult.setVersion(System.getenv("MS_VERSION"));
return apiExportResult;
}
}

View File

@ -5,13 +5,13 @@
SELECT api.id,api.name FROM Api_definition api
<where>
<if test="request.projectId != null">
api.project_Id = #{request.projectId}
AND api.project_Id = #{request.projectId}
</if>
<if test="request.name != null">
api.project_Id like CONCAT('%', #{request.name},'%')
<if test="request.name != null and request.name != '' ">
AND api.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.type != null">
api.method = #{request.type}
<if test="request.type != null and request.type != '' and request.type != 'ALL' ">
AND api.method = #{request.type}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">

View File

@ -4,7 +4,6 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ -26,13 +25,14 @@ public class ServiceUtils {
}
/**
* 获取前端全选的id列表
* 获取前端全选的id列表
*
* @param queryRequest 查询条件
* @param func 查询id列表的数据库查询
* @param func 查询id列表的数据库查询
* @return
*/
public static<T> void getSelectAllIds( T batchRequest, BaseQueryRequest queryRequest, Function<BaseQueryRequest, List<String>> func) {
if (queryRequest.isSelectAll()) {
public static <T> void getSelectAllIds(T batchRequest, BaseQueryRequest queryRequest, Function<BaseQueryRequest, List<String>> func) {
if (queryRequest != null && queryRequest.isSelectAll()) {
List<String> ids = func.apply(queryRequest);
if (!ids.isEmpty()) {
ids = ids.stream()

@ -1 +1 @@
Subproject commit 5e0b365f1080197e84055e80071165787e2e79c5
Subproject commit b9042074b780205e275c674f64417799110519fd

View File

@ -9,6 +9,7 @@
@setNodeTree="setNodeTree"
@enableTrash="enableTrash"
@exportAPI="exportAPI"
@exportJmx="exportJmx"
@refreshAll="refreshAll"
:type="'edit'"
ref="nodeTree"/>
@ -69,7 +70,6 @@
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",
@ -131,25 +131,10 @@
},
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));
});
this.$refs.apiScenarioList.exportApi();
},
buildApiPath(apis) {
apis.forEach((api) => {
this.moduleOptions.forEach(item => {
if (api.moduleId === item.id) {
api.modulePath = item.path;
}
});
});
exportJmx(){
this.$refs.apiScenarioList.exportJmx();
},
checkRedirectEditPage(redirectParam) {
if (redirectParam != null) {

View File

@ -167,50 +167,50 @@
</template>
<script>
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../common/components/MsTag";
import {downloadFile, getCurrentProjectID, getCurrentUser, getUUID} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsTableMoreBtn from "./TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "./testplan/TestPlanList";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/search/search-components";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import PriorityTableItem from "../../../track/common/tableItems/planview/PriorityTableItem";
import PlanStatusTableItem from "../../../track/common/tableItems/plan/PlanStatusTableItem";
import BatchEdit from "../../../track/case/components/BatchEdit";
import {API_SCENARIO_LIST, TEST_CASE_LIST, TEST_PLAN_LIST, WORKSPACE_ID} from "../../../../../common/js/constants";
import {PROJECT_NAME} from "../../../../../common/js/constants";
import EnvironmentSelect from "../../definition/components/environment/EnvironmentSelect";
import BatchMove from "../../../track/case/components/BatchMove";
import {_sort} from "@/common/js/tableUtils";
import {Api_Scenario_List, Track_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {
_filter,
_handleSelect,
_handleSelectAll,
getSelectDataCounts,
setUnSelectIds, toggleAllSelection
} from "@/common/js/tableUtils";
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../common/components/MsTag";
import {downloadFile, getCurrentProjectID, getCurrentUser, getUUID} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsTableMoreBtn from "./TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "./testplan/TestPlanList";
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/search/search-components";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import PriorityTableItem from "../../../track/common/tableItems/planview/PriorityTableItem";
import PlanStatusTableItem from "../../../track/common/tableItems/plan/PlanStatusTableItem";
import BatchEdit from "../../../track/case/components/BatchEdit";
import {API_SCENARIO_LIST, TEST_CASE_LIST, TEST_PLAN_LIST, WORKSPACE_ID} from "../../../../../common/js/constants";
import {PROJECT_NAME} from "../../../../../common/js/constants";
import EnvironmentSelect from "../../definition/components/environment/EnvironmentSelect";
import BatchMove from "../../../track/case/components/BatchMove";
import {_sort} from "@/common/js/tableUtils";
import {Api_Scenario_List} from "@/business/components/common/model/JsonData";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {
_filter,
_handleSelect,
_handleSelectAll,
getSelectDataCounts,
setUnSelectIds, toggleAllSelection
} from "@/common/js/tableUtils";
export default {
name: "MsApiScenarioList",
components: {
HeaderCustom,
BatchMove,
EnvironmentSelect,
BatchEdit,
PlanStatusTableItem,
PriorityTableItem,
MsTableHeaderSelectPopover,
MsTablePagination,
MsTableMoreBtn,
ShowMoreBtn,
MsTableHeader,
export default {
name: "MsApiScenarioList",
components: {
HeaderCustom,
BatchMove,
EnvironmentSelect,
BatchEdit,
PlanStatusTableItem,
PriorityTableItem,
MsTableHeaderSelectPopover,
MsTablePagination,
MsTableMoreBtn,
ShowMoreBtn,
MsTableHeader,
MsTag,
MsApiReportDetail,
MsScenarioExtendButtons,
@ -554,12 +554,15 @@ export default {
_handleSelectAll(this, selection, this.tableData, this.selectRows);
setUnSelectIds(this.tableData, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
this.$emit('selection', selection);
},
handleSelect(selection, row) {
_handleSelect(this, selection, row, this.selectRows);
setUnSelectIds(this.tableData, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
this.$emit('selection', selection);
},
isSelectDataAll(data) {
this.condition.selectAll = data;
setUnSelectIds(this.tableData, this.condition, this.selectRows);
@ -587,7 +590,7 @@ export default {
scenarioIds.push(row.id);
run.id = getUUID();
run.projectId = getCurrentProjectID();
run.scenarioIds = scenarioIds;
run.ids = scenarioIds;
this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
@ -672,6 +675,24 @@ export default {
downloadFile("Metersphere_Scenario_" + localStorage.getItem(PROJECT_NAME) + ".json", JSON.stringify(obj));
});
},
exportJmx() {
let param = {};
this.buildBatchParam(param);
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/jmx", param, response => {
this.loading = false;
let obj = response.data;
if (obj && obj.length > 0) {
obj.forEach(item => {
downloadFile(item.name + ".jmx", item.jmx);
})
}
});
},
buildApiPath(scenarios) {
scenarios.forEach((scenario) => {
this.moduleOptions.forEach(item => {

View File

@ -25,7 +25,8 @@
<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-item command="export">{{ $t('report.export') }}MS</el-dropdown-item>
<el-dropdown-item command="exportJmx">{{ $t('report.export') }}JMX</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
@ -33,14 +34,14 @@
<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"/>-->
<!--: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>
@ -56,27 +57,26 @@
</template>
<script>
import SelectMenu from "../../../track/common/SelectMenu";
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
import {getCurrentProjectID} from "@/common/js/utils";
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";
import SelectMenu from "../../../track/common/SelectMenu";
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
import {getCurrentProjectID} from "@/common/js/utils";
import MsNodeTree from "../../../track/common/NodeTree";
import {buildNodePath} from "../../definition/model/NodeTree";
import ModuleTrashButton from "../../definition/components/module/ModuleTrashButton";
import ApiImport from "./common/ScenarioImport";
export default {
name: 'MsApiScenarioModule',
components: {
ApiImport,
ModuleTrashButton,
MsNodeTree,
MsAddBasisScenario,
SelectMenu,
},
props: {
isReadOnly: {
type: Boolean,
export default {
name: 'MsApiScenarioModule',
components: {
ApiImport,
ModuleTrashButton,
MsNodeTree,
MsAddBasisScenario,
SelectMenu,
},
props: {
isReadOnly: {
type: Boolean,
default() {
return false
}
@ -145,6 +145,9 @@ export default {
case "export":
this.$emit('exportAPI');
break;
case "exportJmx":
this.$emit('exportJmx');
break;
}
},
list() {

View File

@ -204,44 +204,44 @@
</template>
<script>
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController
} from "../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsInputTag from "./MsInputTag";
import MsRun from "./DebugRun";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsVariableList from "./variable/VariableList";
import ApiImport from "../../definition/components/import/ApiImport";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController
} from "../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsInputTag from "./MsInputTag";
import MsRun from "./DebugRun";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsVariableList from "./variable/VariableList";
import ApiImport from "../../definition/components/import/ApiImport";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
export default {
name: "EditApiScenario",
props: {
moduleOptions: Array,
currentScenario: {},
},
components: {
MsVariableList,
ScenarioRelevance,
ScenarioApiRelevance,
ApiEnvironmentConfig,
export default {
name: "EditApiScenario",
props: {
moduleOptions: Array,
currentScenario: {},
},
components: {
MsVariableList,
ScenarioRelevance,
ScenarioApiRelevance,
ApiEnvironmentConfig,
MsApiReportDetail,
MsInputTag, MsRun,
MsApiCustomize,
@ -596,6 +596,9 @@ export default {
if (item.protocol) {
request.protocol = item.protocol;
}
if (request.protocol === "DUBBO") {
request.protocol = "dubbo://";
}
request.id = item.id;
request.name = item.name;
request.refType = refType;

View File

@ -2,13 +2,13 @@
<relevance-dialog :title="$t('api_test.automation.scenario_import')" ref="relevanceDialog">
<template v-slot:aside>
<ms-api-scenario-module
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
@enableTrash="false"
:is-read-only="true"
ref="nodeTree"/>
<ms-api-scenario-module
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
@enableTrash="false"
:is-read-only="true"
ref="nodeTree"/>
</template>
<ms-api-scenario-list
@ -27,94 +27,98 @@
</template>
<script>
import ScenarioRelevanceCaseList from "./RelevanceCaseList";
import MsApiModule from "../../../definition/components/module/ApiModule";
import MsContainer from "../../../../common/components/MsContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import MsApiScenarioModule from "../ApiScenarioModule";
import MsApiScenarioList from "../ApiScenarioList";
import {getUUID} from "../../../../../../common/js/utils";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
export default {
name: "ScenarioRelevance",
components: {
RelevanceDialog,
MsApiScenarioList,
MsApiScenarioModule,
MsMainContainer, MsAsideContainer, MsContainer},
data() {
return {
result: {},
currentProtocol: null,
selectNodeIds: [],
moduleOptions: {},
isApiListEnable: true,
currentScenario: [],
currentScenarioIds: [],
}
import ScenarioRelevanceCaseList from "./RelevanceCaseList";
import MsApiModule from "../../../definition/components/module/ApiModule";
import MsContainer from "../../../../common/components/MsContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import MsApiScenarioModule from "../ApiScenarioModule";
import MsApiScenarioList from "../ApiScenarioList";
import {getUUID} from "../../../../../../common/js/utils";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
export default {
name: "ScenarioRelevance",
components: {
RelevanceDialog,
MsApiScenarioList,
MsApiScenarioModule,
MsMainContainer, MsAsideContainer, MsContainer
},
data() {
return {
result: {},
currentProtocol: null,
selectNodeIds: [],
moduleOptions: {},
isApiListEnable: true,
currentScenario: [],
currentScenarioIds: [],
}
},
methods: {
reference() {
let scenarios = [];
if (!this.currentScenario || this.currentScenario.length < 1) {
this.$emit('请选择场景');
return;
}
this.currentScenario.forEach(item => {
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'REF', resourceId: getUUID()};
scenarios.push(obj);
});
this.$emit('save', scenarios);
this.close();
},
methods: {
reference() {
let scenarios = [];
if (!this.currentScenario || this.currentScenario.length < 1) {
this.$emit('请选择场景');
return;
}
this.currentScenario.forEach(item => {
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'REF', resourceId: getUUID()};
scenarios.push(obj);
});
this.$emit('save', scenarios);
this.close();
},
copy() {
let scenarios = [];
if (!this.currentScenarioIds || this.currentScenarioIds.length < 1) {
this.$emit('请选择场景');
return;
}
this.result = this.$post("/api/automation/getApiScenarios/", this.currentScenarioIds, response => {
if (response.data) {
response.data.forEach(item => {
let scenarioDefinition = JSON.parse(item.scenarioDefinition);
copy() {
let scenarios = [];
if (!this.currentScenarioIds || this.currentScenarioIds.length < 1) {
this.$warning('请选择场景');
return;
}
this.result = this.$post("/api/automation/getApiScenarios/", this.currentScenarioIds, response => {
if (response.data) {
response.data.forEach(item => {
let scenarioDefinition = JSON.parse(item.scenarioDefinition);
if (scenarioDefinition && scenarioDefinition.hashTree) {
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree};
scenarios.push(obj);
});
this.$emit('save', scenarios);
this.close();
}
})
},
close() {
this.refresh();
this.$refs.relevanceDialog.close();
},
open() {
this.$refs.relevanceDialog.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
});
this.$emit('save', scenarios);
this.close();
}
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
refresh() {
this.$refs.apiScenarioList.search();
},
setData(data) {
this.currentScenario = Array.from(data).map(row => row);
this.currentScenarioIds = Array.from(data).map(row => row.id);
},
}
})
},
close() {
this.refresh();
this.$refs.relevanceDialog.close();
},
open() {
this.$refs.relevanceDialog.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
refresh() {
this.$refs.apiScenarioList.search();
},
setData(data) {
this.currentScenario = Array.from(data).map(row => row);
this.currentScenarioIds = Array.from(data).map(row => row.id);
},
}
}
</script>
<style scoped>

View File

@ -1,5 +1,5 @@
<template>
<el-dialog :close-on-click-modal="false" :title="$t('api_test.api_import.title')" width="30%"
<el-dialog :close-on-click-modal="false" :title="$t('api_test.automation.scenario_import')" width="30%"
:visible.sync="visible" class="api-import" v-loading="result.loading" @close="close">
<div class="header-bar">

View File

@ -22,23 +22,23 @@
</template>
<script>
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import ApiBaseComponent from "../common/ApiBaseComponent";
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import ApiBaseComponent from "../common/ApiBaseComponent";
export default {
name: "ApiScenarioComponent",
props: {
scenario: {},
node: {},
draggable: {
type: Boolean,
default: false,
export default {
name: "ApiScenarioComponent",
props: {
scenario: {},
node: {},
draggable: {
type: Boolean,
default: false,
},
},
},
watch: {},
watch: {},
created() {
if (this.scenario.id && this.scenario.referenced === 'REF' && !this.scenario.loaded) {
this.result = this.$get("/api/automation/getApiScenario/" + this.scenario.id, response => {
@ -79,8 +79,10 @@ export default {
this.$emit('remove', this.scenario, this.node);
},
active(item) {
item.active = !item.active;
this.reload();
if (item && item.active) {
item.active = !item.active;
this.reload();
}
},
copyRow() {
this.$emit('copyRow', this.scenario, this.node);

View File

@ -81,7 +81,7 @@
</el-link>
</el-row>
<div style="min-height: 400px">
<ms-api-key-value :items="headers"/>
<ms-api-key-value :items="headers" :suggestions="headerSuggestions"/>
<batch-add-parameter @batchSave="batchSave" ref="batchAddParameter"/>
</div>
</el-tab-pane>
@ -95,33 +95,34 @@
</template>
<script>
import MsEditConstant from "./EditConstant";
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsEditCounter from "./EditCounter";
import MsEditRandom from "./EditRandom";
import MsEditListValue from "./EditListValue";
import MsEditCsv from "./EditCsv";
import {getUUID} from "@/common/js/utils";
import MsApiKeyValue from "../../../definition/components/ApiKeyValue";
import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter";
import {KeyValue} from "../../../definition/model/ApiTestModel";
import MsEditConstant from "./EditConstant";
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsEditCounter from "./EditCounter";
import MsEditRandom from "./EditRandom";
import MsEditListValue from "./EditListValue";
import MsEditCsv from "./EditCsv";
import {getUUID} from "@/common/js/utils";
import MsApiKeyValue from "../../../definition/components/ApiKeyValue";
import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter";
import {KeyValue} from "../../../definition/model/ApiTestModel";
import {REQUEST_HEADERS} from "@/common/js/constants";
export default {
name: "MsVariableList",
components: {
MsEditConstant,
MsDialogFooter,
MsTableHeader,
MsTablePagination,
MsEditCounter,
MsEditRandom,
MsEditListValue,
MsEditCsv,
MsApiKeyValue,
BatchAddParameter
},
export default {
name: "MsVariableList",
components: {
MsEditConstant,
MsDialogFooter,
MsTableHeader,
MsTablePagination,
MsEditCounter,
MsEditRandom,
MsEditListValue,
MsEditCsv,
MsApiKeyValue,
BatchAddParameter
},
data() {
return {
variables: [],
@ -144,6 +145,7 @@ export default {
editData: {},
pageSize: 10,
total: 0,
headerSuggestions: REQUEST_HEADERS,
}
},
methods: {
@ -285,19 +287,19 @@ export default {
</script>
<style>
.ms-variable-hidden-row {
display: none;
}
.ms-variable-hidden-row {
display: none;
}
.ms-variable-header {
background: #783887;
color: white;
height: 18px;
border-radius: 42%;
}
.ms-variable-header {
background: #783887;
color: white;
height: 18px;
border-radius: 42%;
}
.ms-variable-link {
float: right;
margin-right: 45px;
}
.ms-variable-link {
float: right;
margin-right: 45px;
}
</style>

View File

@ -384,6 +384,7 @@ export default {
}
let simpleInfoUrl = "/api/document/selectApiSimpleInfo";
this.apiSimpleInfoArray = [];
this.$post(simpleInfoUrl, simpleRequest, response => {
this.apiSimpleInfoArray = response.data;
this.apiStepIndex = 0;

View File

@ -699,6 +699,10 @@ export default {
exportApi() {
let param = this.buildBatchParam();
param.protocol = this.currentProtocol;
if (param.ids === undefined || param.ids.length < 1) {
this.$warning(this.$t("api_test.definition.check_select"));
return;
}
this.result = this.$post("/api/definition/export", param, response => {
let obj = response.data;
obj.protocol = this.currentProtocol;

View File

@ -1,83 +1,86 @@
<template>
<el-form :model="config" :rules="rules" ref="config" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="config.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-row>
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
</el-row>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="config.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-row>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="config.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="config.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Namespace" prop="namespace" class="dubbo-form-item">
<el-input v-model="config.namespace" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="config.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="config.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Namespace" prop="namespace" class="dubbo-form-item">
<el-input v-model="config.namespace" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="config.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="config.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="config.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="config.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="config.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="config.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-row>
</el-form>
</template>
<script>
import './dubbo.css'
import {ConfigCenter} from "@/business/components/api/definition/model/ApiTestModel";
import './dubbo.css'
import {ConfigCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboConfigCenter",
props: {
description: String,
config: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: ConfigCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
namespace: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 100, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
export default {
name: "MsDubboConfigCenter",
props: {
description: String,
config: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: ConfigCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
namespace: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 100, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
}
</script>

View File

@ -1,82 +1,86 @@
<template>
<el-form :model="consumer" :rules="rules" ref="consumer" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="consumer.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-row>
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
</el-row>
<el-row>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="consumer.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Version" prop="version" class="dubbo-form-item">
<el-input v-model="consumer.version" maxlength="30" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Version" prop="version" class="dubbo-form-item">
<el-input v-model="consumer.version" maxlength="30" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Retries" prop="retries" class="dubbo-form-item">
<el-input type="number" v-model="consumer.retries" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Retries" prop="retries" class="dubbo-form-item">
<el-input type="number" v-model="consumer.retries" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Cluster" prop="cluster" class="dubbo-form-item">
<el-input v-model="consumer.cluster" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="consumer.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Cluster" prop="cluster" class="dubbo-form-item">
<el-input v-model="consumer.cluster" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Connections" prop="connections" class="dubbo-form-item">
<el-input type="number" v-model="consumer.connections" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="consumer.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Async" prop="async" class="dubbo-form-item">
<el-select v-model="consumer.async" class="select-100" clearable>
<el-option v-for="option in asyncOptions" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
<el-form-item label="Connections" prop="connections" class="dubbo-form-item">
<el-input type="number" v-model="consumer.connections" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Async" prop="async" class="dubbo-form-item">
<el-select v-model="consumer.async" class="select-100" clearable>
<el-option v-for="option in asyncOptions" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
<el-form-item label="LoadBalance" prop="loadBalance" class="dubbo-form-item">
<el-select v-model="consumer.loadBalance" class="select-100" clearable>
<el-option v-for="option in loadBalances" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
<el-form-item label="LoadBalance" prop="loadBalance" class="dubbo-form-item">
<el-select v-model="consumer.loadBalance" class="select-100" clearable>
<el-option v-for="option in loadBalances" :key="option" :label="option" :value="option"/>
</el-select>
</el-form-item>
</el-row>
</el-form>
</template>
<script>
import './dubbo.css'
import {ConsumerAndService, RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
import './dubbo.css'
import {ConsumerAndService, RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboConsumerService",
props: {
description: String,
consumer: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
asyncOptions: ConsumerAndService.ASYNC_OPTIONS,
loadBalances: ConsumerAndService.LOAD_BALANCE_OPTIONS,
methods: [],
rules: {
version: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
cluster: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
export default {
name: "MsDubboConsumerService",
props: {
description: String,
consumer: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
asyncOptions: ConsumerAndService.ASYNC_OPTIONS,
loadBalances: ConsumerAndService.LOAD_BALANCE_OPTIONS,
methods: [],
rules: {
version: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
cluster: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
}
</script>

View File

@ -117,7 +117,7 @@
<style scoped>
.get-provider {
margin-bottom: 22px;
margin: 5px 5px 10px;
}
.select-100 {

View File

@ -1,73 +1,78 @@
<template>
<el-form :model="registry" :rules="rules" ref="registry" label-width="100px" size="small" :disabled="isReadOnly">
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="registry.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-row>
<div class="dubbo-form-description" v-if="description">
{{ description }}
</div>
</el-row>
<el-row>
<el-form-item label="Protocol" prop="protocol" class="dubbo-form-item">
<el-select v-model="registry.protocol" class="select-100" clearable>
<el-option v-for="p in protocols" :key="p" :label="p" :value="p"/>
</el-select>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="registry.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Group" prop="group" class="dubbo-form-item">
<el-input v-model="registry.group" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="registry.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="UserName" prop="username" class="dubbo-form-item">
<el-input v-model="registry.username" maxlength="100" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="registry.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Password" prop="password" class="dubbo-form-item">
<el-input v-model="registry.password" maxlength="30" show-word-limit show-password autocomplete="new-password"
:placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="registry.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Address" prop="address" class="dubbo-form-item-long">
<el-input v-model="registry.address" maxlength="300" show-word-limit
:placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="registry.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
<el-form-item label="Timeout" prop="timeout" class="dubbo-form-item">
<el-input type="number" v-model="registry.timeout" :placeholder="$t('commons.input_content')"/>
</el-form-item>
</el-row>
</el-form>
</template>
<script>
import './dubbo.css'
import {RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
import './dubbo.css'
import {RegistryCenter} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "MsDubboRegistryCenter",
props: {
description: String,
registry: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: RegistryCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
export default {
name: "MsDubboRegistryCenter",
props: {
description: String,
registry: {},
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
protocols: RegistryCenter.PROTOCOLS,
methods: [],
rules: {
group: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
username: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
],
password: [
{max: 30, message: this.$t('commons.input_limit', [0, 30]), trigger: 'blur'}
],
address: [
{max: 300, message: this.$t('commons.input_limit', [0, 300]), trigger: 'blur'}
]
}
}
}
}
}
</script>

View File

@ -8,18 +8,21 @@
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.response_header')" name="headers" class="pane">
<div style="width: 400px">
<pre>{{ response.responseResult.headers }}</pre>
</div>
<!--<div style="width: 400px">-->
<!--<pre>{{ response.responseResult.headers }}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.headers"/>
</el-tab-pane>
<!--<el-tab-pane label="Cookie" name="cookie" class="pane cookie">-->
<!--<pre>{{response.cookies}}</pre>-->
<!--</el-tab-pane>-->
<el-tab-pane :label="$t('api_test.definition.request.console')" name="console" class="pane">
<div style="width: 400px">
<pre>{{response.responseResult.console}}</pre>
</div>
<!--<div style="width: 400px">-->
<!--<pre>{{response.responseResult.console}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.console"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.assertions')" name="assertions" class="pane assertions">
@ -27,29 +30,30 @@
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="label" class="pane">
<div style="width: 400px">
<pre>{{response.responseResult.vars}}</pre>
</div>
<!--<div style="width: 400px">-->
<!--<pre>{{response.responseResult.vars}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="response.responseResult.vars"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.request_body')" name="request_body" class="pane">
<div class="ms-div">
{{$t('api_test.request.address')}} :
<pre>{{ response.url }}</pre>
</div>
<div class="ms-div">
{{$t('api_test.scenario.headers')}} :
<pre>{{ response.headers }}</pre>
</div>
<div class="ms-div">
Cookies :
<pre>{{response.cookies}}</pre>
</div>
<div class="ms-div">
Body :
<pre>{{response.body ? response.body:""}}</pre>
</div>
<!--<div class="ms-div">-->
<!--{{$t('api_test.request.address')}} :-->
<!--<pre>{{ response.url }}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--{{$t('api_test.scenario.headers')}} :-->
<!--<pre>{{ response.headers }}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--Cookies :-->
<!--<pre>{{response.cookies}}</pre>-->
<!--</div>-->
<!--<div class="ms-div">-->
<!--Body :-->
<!--<pre>{{response.body ? response.body:""}}</pre>-->
<!--</div>-->
<ms-code-edit :mode="'text'" :read-only="true" :data.sync="reqMessages"/>
</el-tab-pane>
<el-tab-pane v-if="activeName == 'body'" :disabled="true" name="mode" class="pane cookie">
@ -63,23 +67,23 @@
</template>
<script>
import MsAssertionResults from "./AssertionResults";
import MsCodeEdit from "../MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import {BODY_FORMAT} from "../../model/ApiTestModel";
import MsSqlResultTable from "./SqlResultTable";
import MsAssertionResults from "./AssertionResults";
import MsCodeEdit from "../MsCodeEdit";
import MsDropdown from "../../../../common/components/MsDropdown";
import {BODY_FORMAT} from "../../model/ApiTestModel";
import MsSqlResultTable from "./SqlResultTable";
export default {
name: "MsResponseResult",
export default {
name: "MsResponseResult",
components: {
MsDropdown,
MsCodeEdit,
MsAssertionResults,
MsSqlResultTable
},
components: {
MsDropdown,
MsCodeEdit,
MsAssertionResults,
MsSqlResultTable
},
props: {
props: {
response: Object,
currentProtocol: String,
},
@ -91,12 +95,14 @@ export default {
modes: ['text', 'json', 'xml', 'html'],
sqlModes: ['text', 'table'],
mode: BODY_FORMAT.TEXT,
isMsCodeEditShow: true
isMsCodeEditShow: true,
reqMessages: "",
}
},
watch: {
response() {
this.setBodyType();
this.setReqMessage();
}
},
methods: {
@ -126,9 +132,29 @@ export default {
this.isMsCodeEditShow = true;
});
},
setReqMessage() {
if (this.response) {
if (!this.response.url) {
this.response.url = "";
}
if (!this.response.headers) {
this.response.headers = "";
}
if (!this.response.cookies) {
this.response.cookies = "";
}
if (!this.response.body) {
this.response.body = "";
}
this.reqMessages = this.$t('api_test.request.address') + ":\n" + this.response.url + "\n" +
this.$t('api_test.scenario.headers') + ":\n" + this.response.headers + "\n" + "Cookies :\n" +
this.response.cookies + "\n" + "Bpdy:" + "\n" + this.response.body;
}
},
},
mounted() {
this.setBodyType();
this.setReqMessage();
},
computed: {
isSqlType() {

View File

@ -254,8 +254,12 @@ export default {
let resultValidate = {validate: true, msg: this.$t('test_resource_pool.fill_the_data')};
this.infoList.forEach(info => {
for (let key in info) {
//
if (key === 'nodeSelector') {
continue;
}
if (info[key] != '0' && !info[key]) {
resultValidate.validate = false
resultValidate.validate = false;
return false;
}
}

View File

@ -533,6 +533,7 @@ export default {
api_case_passing_rate: "Use case pass rate",
create_tip: "Note: Detailed interface information can be filled out on the edit page",
api_import: "Api Import",
check_select: "Please check the API",
select_comp: {
no_data: "No Data",
add_data: "Add Data"

View File

@ -533,6 +533,7 @@ export default {
api_case_passing_rate: "用例通过率",
create_tip: "注: 详细的接口信息可以在编辑页面填写",
api_import: "接口导入",
check_select: "请勾选接口",
select_comp: {
no_data: "无数据",
add_data: "去添加"

View File

@ -532,6 +532,7 @@ export default {
api_case_passing_rate: "用例通過率",
create_tip: "註: 詳細的接口信息可以在編輯頁面填寫",
api_import: "接口導入",
check_select: "請勾選接口",
select_comp: {
no_data: "無數據",
add_data: "去添加"