feat(接口定义): 请求数据格式按照jmeter 数据格式重构完成

This commit is contained in:
fit2-zhao 2020-11-19 19:14:06 +08:00
parent 8fd084db51
commit bdaff53eaf
41 changed files with 951 additions and 379 deletions

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.base.domain.ApiDefinition;
@ -61,12 +62,12 @@ public class ApiDefinitionController {
}
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
public String runDebug(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
public String runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
return apiDefinitionService.run(request, bodyFiles);
}
@PostMapping(value = "/run", consumes = {"multipart/form-data"})
public String run(@RequestPart("request") SaveApiDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
public String run(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
return apiDefinitionService.run(request, bodyFiles);
}

View File

@ -29,13 +29,13 @@ public class ApiTestCaseController {
}
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
public void create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.create(request, file, bodyFiles);
public void create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.create(request, bodyFiles);
}
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
public void update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.update(request, file, bodyFiles);
public void update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiTestCaseService.update(request, bodyFiles);
}
@GetMapping("/delete/{id}")

View File

@ -0,0 +1,23 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.response.Response;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
public class RunDefinitionRequest {
private String id;
private String reportId;
private MsTestElement testElement;
private Response response;
private List<String> bodyUploadIds;
}

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.response.Response;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.base.domain.Schedule;
import lombok.Getter;
import lombok.Setter;
@ -31,10 +31,8 @@ public class SaveApiDefinitionRequest {
private String modulePath;
private String method;
private Scenario scenario;
private Object request;
private MsTestElement request;
private Response response;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.scenario.request.Request;
import io.metersphere.api.dto.definition.request.MsTestElement;
import lombok.Getter;
import lombok.Setter;
@ -22,7 +22,7 @@ public class SaveApiTestCaseRequest {
private String description;
private Request request;
private MsTestElement request;
private String response;

View File

@ -1,17 +0,0 @@
package io.metersphere.api.dto.definition.request;
import org.apache.jorphan.collections.HashTree;
public class Element {
public String id;
public String type;
public String name;
public HashTree elementHashTree;
}

View File

@ -1,22 +0,0 @@
package io.metersphere.api.dto.definition.request;
public class HTTPSamplerProxy extends Element {
public String protocol;
public String domain;
public String port;
public String method;
public String path;
public String contentEncoding;
public boolean autoRedirects;
public boolean followRedirects;
public boolean useKeepalive;
public boolean postBodyRaw;
public boolean doMultipartPost;
public boolean browserCompatibleMultipart;
public String embeddedUrlRe;
public String connectTimeout;
public String responseTimeout;
public String arguments;
}

View File

@ -0,0 +1,79 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.commons.utils.LogUtil;
import lombok.Data;
import org.apache.jmeter.save.SaveService;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.io.ByteArrayOutputStream;
import java.util.LinkedList;
import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = MsHTTPSamplerProxy.class, name = "HTTPSamplerProxy"),
@JsonSubTypes.Type(value = MsHeaderManager.class, name = "HeaderManager"),
@JsonSubTypes.Type(value = MsJSR223PostProcessor.class, name = "JSR223PostProcessor"),
@JsonSubTypes.Type(value = MsJSR223PreProcessor.class, name = "JSR223PreProcessor"),
@JsonSubTypes.Type(value = MsTestPlan.class, name = "TestPlan"),
@JsonSubTypes.Type(value = MsThreadGroup.class, name = "ThreadGroup"),
})
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class, MsJSR223PreProcessor.class}, typeKey = "type")
@Data
public class MsTestElement {
private String type;
@JSONField(ordinal = 1)
private String id;
@JSONField(ordinal = 2)
private String name;
@JSONField(ordinal = 3)
private String label;
@JSONField(ordinal = 4)
private LinkedList<MsTestElement> hashTree;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree);
}
}
/**
* 转换JMX
*
* @param hashTree
* @return
*/
public String getJmx(HashTree hashTree) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
SaveService.saveTree(hashTree, baos);
System.out.print(baos.toString());
return baos.toString();
} catch (Exception e) {
e.printStackTrace();
LogUtil.warn("HashTree error, can't log jmx content");
}
return null;
}
public HashTree get() {
HashTree jmeterTestPlanHashTree = new ListedHashTree();
this.toHashTree(jmeterTestPlanHashTree, this.hashTree);
return jmeterTestPlanHashTree;
}
}

View File

@ -0,0 +1,42 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "TestPlan")
public class MsTestPlan extends MsTestElement {
private String type = "TestPlan";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
final HashTree testPlanTree = tree.add(getPlan());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(testPlanTree, el.getHashTree());
});
}
}
public TestPlan getPlan() {
TestPlan testPlan = new TestPlan(this.getName() + "TestPlan");
testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
testPlan.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestPlanGui"));
testPlan.setEnabled(true);
testPlan.setFunctionalMode(false);
testPlan.setSerialized(true);
testPlan.setTearDownOnShutdown(true);
testPlan.setUserDefinedVariables(new Arguments());
return testPlan;
}
}

View File

@ -0,0 +1,52 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "ThreadGroup")
public class MsThreadGroup extends MsTestElement {
private String type = "ThreadGroup";
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
final HashTree groupTree = tree.add(getThreadGroup());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(groupTree, el.getHashTree());
});
}
}
public ThreadGroup getThreadGroup() {
LoopController loopController = new LoopController();
loopController.setName("LoopController");
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
loopController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("LoopControlPanel"));
loopController.setEnabled(true);
loopController.setLoops(1);
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setEnabled(true);
threadGroup.setName(this.getName() + "ThreadGroup");
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ThreadGroupGui"));
threadGroup.setNumThreads(1);
threadGroup.setRampUp(1);
threadGroup.setDelay(0);
threadGroup.setDuration(0);
threadGroup.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
threadGroup.setScheduler(false);
threadGroup.setSamplerController(loopController);
return threadGroup;
}
}

View File

@ -0,0 +1,43 @@
package io.metersphere.api.dto.definition.request.configurations;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.KeyValue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "HeaderManager")
public class MsHeaderManager extends MsTestElement {
private String type = "HeaderManager";
@JSONField(ordinal = 10)
private List<KeyValue> headers;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setName(this.getName() + "Headers");
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel"));
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
headerManager.add(new Header(keyValue.getName(), keyValue.getValue()))
);
final HashTree headersTree = tree.add(headerManager);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(headersTree, el.getHashTree());
});
}
}
}

View File

@ -0,0 +1,78 @@
package io.metersphere.api.dto.definition.request.dns;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.Host;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.control.DNSCacheManager;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.ArrayList;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "DNSCacheManager")
public class MsDNSCacheManager extends MsTestElement {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.getHashTree());
}
}
public static void addEnvironmentVariables(HashTree samplerHashTree, String name, EnvironmentConfig config) {
name += "Environment Variables";
samplerHashTree.add(arguments(name, config.getCommonConfig().getVariables()));
}
public static void addEnvironmentDNS(HashTree samplerHashTree, String name, EnvironmentConfig config) {
if (config.getCommonConfig().isEnableHost() && CollectionUtils.isNotEmpty(config.getCommonConfig().getHosts())) {
String domain = config.getHttpConfig().getDomain().trim();
List<Host> hosts = new ArrayList<>();
config.getCommonConfig().getHosts().forEach(host -> {
if (StringUtils.isNotBlank(host.getDomain())) {
String hostDomain = host.getDomain().trim().replace("http://", "").replace("https://", "");
if (StringUtils.equals(hostDomain, domain)) {
host.setDomain(hostDomain); // 域名去掉协议
hosts.add(host);
}
}
});
samplerHashTree.add(dnsCacheManager(name + " DNSCacheManager", hosts));
}
}
private static Arguments arguments(String name, List<KeyValue> variables) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name);
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;
}
private static DNSCacheManager dnsCacheManager(String name, List<Host> hosts) {
DNSCacheManager dnsCacheManager = new DNSCacheManager();
dnsCacheManager.setEnabled(true);
dnsCacheManager.setName(name);
dnsCacheManager.setProperty(TestElement.TEST_CLASS, DNSCacheManager.class.getName());
dnsCacheManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DNSCachePanel"));
dnsCacheManager.setCustomResolver(true);
hosts.forEach(host -> dnsCacheManager.addHost(host.getDomain(), host.getIp()));
return dnsCacheManager;
}
}

View File

@ -0,0 +1,48 @@
package io.metersphere.api.dto.definition.request.processors.post;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.prop.StringProp;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.extractor.JSR223PostProcessor;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "JSR223PostProcessor")
public class MsJSR223PostProcessor extends MsTestElement {
private String type = "JSR223PostProcessor";
@JSONField(ordinal = 10)
private StringProp script;
@JSONField(ordinal = 11)
private StringProp scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
JSR223PostProcessor processor = new JSR223PostProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PostProcessor");
processor.setProperty(TestElement.TEST_CLASS, JSR223PostProcessor.class.getName());
processor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
processor.setProperty("cacheKey", "true");
processor.setProperty("scriptLanguage", this.getScriptLanguage().getValue());
processor.setProperty("script", this.getScript().getValue());
final HashTree jsr223PostTree = tree.add(processor);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(jsr223PostTree, el.getHashTree());
});
}
}
}

View File

@ -0,0 +1,47 @@
package io.metersphere.api.dto.definition.request.processors.pre;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.prop.StringProp;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.modifiers.JSR223PreProcessor;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "JSR223PreProcessor")
public class MsJSR223PreProcessor extends MsTestElement {
private String type = "JSR223PreProcessor";
@JSONField(ordinal = 10)
private StringProp script;
@JSONField(ordinal = 11)
private StringProp scriptLanguage;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
JSR223PreProcessor processor = new JSR223PreProcessor();
processor.setEnabled(true);
processor.setName(this.getName() + "JSR223PreProcessor");
processor.setProperty(TestElement.TEST_CLASS, JSR223PreProcessor.class.getName());
processor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
processor.setProperty("cacheKey", "true");
processor.setProperty("scriptLanguage", this.getScriptLanguage().getValue());
processor.setProperty("script", this.getScript().getValue());
final HashTree jsr223PreTree = tree.add(processor);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(jsr223PreTree, el.getHashTree());
});
}
}
}

View File

@ -0,0 +1,12 @@
package io.metersphere.api.dto.definition.request.prop;
import lombok.Data;
@Data
public class BoolProp {
private String id;
private String key;
private String name;
private String type;
private boolean value;
}

View File

@ -0,0 +1,12 @@
package io.metersphere.api.dto.definition.request.prop;
import lombok.Data;
@Data
public class StringProp {
private String id;
private String key;
private String name;
private String type;
private String value;
}

View File

@ -0,0 +1,231 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
import io.metersphere.api.dto.definition.request.prop.BoolProp;
import io.metersphere.api.dto.definition.request.prop.StringProp;
import io.metersphere.api.dto.scenario.AuthConfig;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.http.util.HTTPArgument;
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Data
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "HTTPSamplerProxy")
public class MsHTTPSamplerProxy extends MsTestElement {
private String type = "HTTPSamplerProxy";
@JSONField(ordinal = 10)
private StringProp protocol;
@JSONField(ordinal = 11)
private StringProp domain;
@JSONField(ordinal = 12)
private StringProp port;
@JSONField(ordinal = 13)
private StringProp method;
@JSONField(ordinal = 14)
private StringProp path;
@JSONField(ordinal = 15)
private StringProp connectTimeout;
@JSONField(ordinal = 16)
private StringProp responseTimeout;
@JSONField(ordinal = 17)
private List<KeyValue> arguments;
@JSONField(ordinal = 18)
private Body body;
@JSONField(ordinal = 19)
private List<KeyValue> rest;
@JSONField(ordinal = 20)
private AuthConfig authConfig;
@JSONField(ordinal = 21)
private BoolProp followRedirects;
@JSONField(ordinal = 22)
private BoolProp doMultipartPost;
@JSONField(ordinal = 23)
private String useEnvironment;
@JSONField(ordinal = 24)
private String url;
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setEnabled(true);
sampler.setName(this.getName());
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
sampler.setMethod(this.getMethod().getValue());
sampler.setContentEncoding("UTF-8");
sampler.setConnectTimeout(this.getConnectTimeout().getValue() == null ? "6000" : this.getConnectTimeout().getValue());
sampler.setResponseTimeout(this.getResponseTimeout().getValue() == null ? "6000" : this.getResponseTimeout().getValue());
sampler.setFollowRedirects(this.getFollowRedirects() != null ? this.getFollowRedirects().isValue() : true);
sampler.setUseKeepAlive(true);
sampler.setDoMultipart(this.getDoMultipartPost() != null ? this.getDoMultipartPost().isValue() : true);
EnvironmentConfig config = null;
if (useEnvironment != null) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment);
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
}
try {
if (config != null) {
String url = "";
sampler.setDomain(config.getHttpConfig().getDomain());
sampler.setPort(config.getHttpConfig().getPort());
sampler.setProtocol(config.getHttpConfig().getProtocol());
url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
URL urlObject = new URL(url);
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
if (StringUtils.isNotBlank(this.getPath().getValue())) {
envPath += this.getPath().getValue();
}
sampler.setPath(getPostQueryParameters(URLDecoder.decode(envPath, "UTF-8")));
} else {
String url = this.getUrl();
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
URL urlObject = new URL(url);
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
sampler.setPort(urlObject.getPort());
sampler.setProtocol(urlObject.getProtocol());
sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
}
} catch (Exception e) {
LogUtil.error(e);
}
// 请求参数
if (CollectionUtils.isNotEmpty(this.getArguments())) {
sampler.setArguments(httpArguments(this.getArguments()));
}
// rest参数处理
if (CollectionUtils.isNotEmpty(this.getRest())) {
sampler.setArguments(httpArguments(this.getRest()));
}
// 请求体
if (!StringUtils.equals(this.getMethod().getValue(), "GET")) {
List<KeyValue> body = new ArrayList<>();
if (this.getBody().isKV()) {
body = this.getBody().getKvs().stream().filter(KeyValue::isValid).collect(Collectors.toList());
sampler.setHTTPFiles(httpFileArgs());
} else if (this.getBody().isBinary()) {
// 上传二进制数据处理
} else if (this.getBody().isJson()) {
} else {
if (StringUtils.isNotBlank(this.getBody().getRaw())) {
sampler.setPostBodyRaw(true);
KeyValue keyValue = new KeyValue("", this.getBody().getRaw());
keyValue.setEnable(true);
keyValue.setEncode(false);
body.add(keyValue);
}
if (StringUtils.isNotBlank(this.getBody().getXml())) {
sampler.setPostBodyRaw(true);
KeyValue keyValue = new KeyValue("", this.getBody().getXml());
keyValue.setEnable(true);
keyValue.setEncode(false);
body.add(keyValue);
}
}
sampler.setArguments(httpArguments(body));
}
final HashTree httpSamplerTree = tree.add(sampler);
//判断是否要开启DNS
if (config != null && config.getCommonConfig() != null && config.getCommonConfig().isEnableHost()) {
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config);
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config);
}
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(httpSamplerTree, el.getHashTree());
});
}
}
private String getPostQueryParameters(String path) {
if (!StringUtils.equals(this.getMethod().getValue(), "GET")) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(path);
stringBuffer.append("?");
this.getArguments().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue ->
stringBuffer.append(keyValue.getName()).append("=").append(keyValue.getValue()).append("&")
);
return stringBuffer.substring(0, stringBuffer.length() - 1);
}
return path;
}
private Arguments httpArguments(List<KeyValue> list) {
Arguments arguments = new Arguments();
list.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> {
HTTPArgument httpArgument = new HTTPArgument(keyValue.getName(), keyValue.getValue());
httpArgument.setAlwaysEncoded(keyValue.isEncode());
if (StringUtils.isNotBlank(keyValue.getContentType())) {
httpArgument.setContentType(keyValue.getContentType());
}
arguments.addArgument(httpArgument);
}
);
return arguments;
}
private HTTPFileArg[] httpFileArgs() {
final String BODY_FILE_DIR = "/opt/metersphere/data/body";
List<HTTPFileArg> list = new ArrayList<>();
this.getBody().getKvs().stream().filter(KeyValue::isFile).filter(KeyValue::isEnable).forEach(keyValue -> {
if (keyValue.getFiles() != null) {
keyValue.getFiles().forEach(file -> {
String paramName = keyValue.getName();
String path = BODY_FILE_DIR + '/' + this.getId() + '/' + file.getId() + '_' + file.getName();
String mimetype = keyValue.getContentType();
list.add(new HTTPFileArg(path, paramName, mimetype));
});
}
});
return list.toArray(new HTTPFileArg[0]);
}
}

View File

@ -10,6 +10,7 @@ public class Body {
private String type;
private String raw;
private String format;
private List<KeyValue> fromUrlencoded;
private List<KeyValue> kvs;
private List<KeyValue> binary;
private Object json;

View File

@ -27,6 +27,8 @@ import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
import org.springframework.http.HttpMethod;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.*;
@ -63,6 +65,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
@Override
public void setupTest(BackendListenerContext context) throws Exception {
setConsole();
setParam(context);
apiTestService = CommonBeanFactory.getBean(APITestService.class);
if (apiTestService == null) {
@ -109,6 +112,18 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
super.setupTest(context);
}
//获得控制台内容
private PrintStream oldPrintStream = System.out;
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
private void setConsole() {
System.setOut(new PrintStream(bos)); //设置新的out
}
private String getConsole() {
System.setOut(oldPrintStream);
return bos.toString();
}
@Override
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
@ -120,8 +135,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
TestResult testResult = new TestResult();
testResult.setTestId(testId);
testResult.setTotal(queue.size());
// 一个脚本里可能包含多个场景(ThreadGroup)所以要区分开key: 场景Id
// 一个脚本里可能包含多个场景(MsThreadGroup)所以要区分开key: 场景Id
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
queue.forEach(result -> {
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如Scenario 2-1
@ -276,7 +290,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
responseResult.setResponseSize(result.getResponseData().length);
responseResult.setResponseTime(result.getTime());
responseResult.setResponseMessage(result.getResponseMessage());
responseResult.setConsole(getConsole());
if (JMeterVars.get(result.hashCode()) != null) {
List<String> vars = new LinkedList<>();
JMeterVars.get(result.hashCode()).entrySet().parallelStream().reduce(vars, (first, second) -> {

View File

@ -42,12 +42,12 @@ public class JMeterService {
return jmxGenerator.parse(testId, testName, scenarios);
}
public void run(String testId, String testName, List<Scenario> scenarios, String debugReportId,String runMode) {
public void run(String testId, String testName, List<Scenario> scenarios, String debugReportId, String runMode) {
try {
init();
HashTree testPlan = getHashTree(testId, testName, scenarios);
JMeterVars.addJSR223PostProcessor(testPlan);
addBackendListener(testId, debugReportId,runMode, testPlan);
addBackendListener(testId, debugReportId, runMode, testPlan);
LocalRunner runner = new LocalRunner(testPlan);
runner.run();
} catch (Exception e) {
@ -82,12 +82,12 @@ public class JMeterService {
}
}
private void addBackendListener(String testId, String debugReportId,String runMode, HashTree testPlan) {
private void addBackendListener(String testId, String debugReportId, String runMode, HashTree testPlan) {
BackendListener backendListener = new BackendListener();
backendListener.setName(testId);
Arguments arguments = new Arguments();
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
if(StringUtils.isNotBlank(runMode)){
if (StringUtils.isNotBlank(runMode)) {
arguments.addArgument("runMode", runMode);
}
if (StringUtils.isNotBlank(debugReportId)) {
@ -97,4 +97,17 @@ public class JMeterService {
backendListener.setClassname(APIBackendListenerClient.class.getCanonicalName());
testPlan.add(testPlan.getArray()[0], backendListener);
}
public void runDefinition(String testId, HashTree testPlan, String debugReportId, String runMode) {
try {
JMeterVars.addJSR223PostProcessor(testPlan);
addBackendListener(testId, debugReportId, runMode, testPlan);
LocalRunner runner = new LocalRunner(testPlan);
runner.run();
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("api_load_script_error"));
}
}
}

View File

@ -25,6 +25,8 @@ public class ResponseResult {
private String vars;
private String console;
private final List<ResponseAssertionResult> assertions = new ArrayList<>();
}

View File

@ -26,7 +26,7 @@ public class JmeterDocumentParser {
private final static String STRING_PROP = "stringProp";
private final static String ARGUMENTS = "Arguments";
private final static String COLLECTION_PROP = "collectionProp";
private final static String HTTP_SAMPLER_PROXY = "HTTPSamplerProxy";
private final static String HTTP_SAMPLER_PROXY = "MsHTTPSamplerProxy";
private final static String ELEMENT_PROP = "elementProp";
public static byte[] parse(byte[] source) {

View File

@ -3,11 +3,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.definition.ApiComputeResult;
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*;
@ -24,6 +20,7 @@ import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
import org.apache.jorphan.collections.HashTree;
import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -101,7 +98,6 @@ public class ApiDefinitionService {
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
deleteFileByTestId(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiDefinition test = updateTest(request);
@ -210,14 +206,6 @@ public class ApiDefinitionService {
return test;
}
private void saveFile(String apiId, MultipartFile file) {
final FileMetadata metadata = fileService.saveFile(file);
ApiTestFile apiTestFile = new ApiTestFile();
apiTestFile.setTestId(apiId);
apiTestFile.setFileId(metadata.getId());
apiTestFileMapper.insert(apiTestFile);
}
private void deleteFileByTestId(String apiId) {
ApiTestFileExample apiTestFileExample = new ApiTestFileExample();
apiTestFileExample.createCriteria().andTestIdEqualTo(apiId);
@ -237,13 +225,13 @@ public class ApiDefinitionService {
* @param bodyFiles
* @return
*/
public String run(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(request.getId(), bodyUploadIds, bodyFiles);
List<Scenario> scenarios = new ArrayList<>();
scenarios.add(request.getScenario());
jMeterService.run(request.getId(), request.getName(), scenarios, request.getReportId(), ApiRunMode.DELIMIT.name());
HashTree hashTree = request.getTestElement().get();
// 调用执行方法
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.DELIMIT.name());
return request.getId();
}
@ -281,6 +269,9 @@ public class ApiDefinitionService {
*/
public APIReportResult getDbResult(String testId) {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByResourceId(testId);
if (result == null) {
return null;
}
APIReportResult reportResult = new APIReportResult();
reportResult.setContent(result.getContent());
return reportResult;

View File

@ -53,21 +53,10 @@ public class ApiTestCaseService {
return apiTestCaseMapper.selectByPrimaryKey(id);
}
public void create(SaveApiTestCaseRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
public void create(SaveApiTestCaseRequest request, List<MultipartFile> bodyFiles) {
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
ApiTestCase test = createTest(request, file);
createBodyFiles(test, bodyUploadIds, bodyFiles);
}
private ApiTestCase createTest(SaveApiTestCaseRequest request, MultipartFile file) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
checkQuota();
request.setBodyUploadIds(null);
ApiTestCase test = createTest(request);
saveFile(test.getId(), file);
return test;
createBodyFiles(test, bodyUploadIds, bodyFiles);
}
private void checkQuota() {
@ -77,17 +66,14 @@ public class ApiTestCaseService {
}
}
public void update(SaveApiTestCaseRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
if (file == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
}
public void update(SaveApiTestCaseRequest request, List<MultipartFile> bodyFiles) {
deleteFileByTestId(request.getId());
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
request.setBodyUploadIds(null);
ApiTestCase test = updateTest(request);
createBodyFiles(test, bodyUploadIds, bodyFiles);
saveFile(test.getId(), file);
}
private void createBodyFiles(ApiTestCase test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {

View File

@ -491,9 +491,9 @@ public class JmeterDocumentParser implements DocumentParser {
setupElement.setAttribute("testclass", "SetupThreadGroup");
setupElement.setAttribute("testname", "setUp Thread Group");
setupElement.setAttribute("enabled", "true");
setupElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "stoptestnow"));
setupElement.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "stoptestnow"));
Element elementProp = document.createElement("elementProp");
elementProp.setAttribute("name", "ThreadGroup.main_controller");
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
elementProp.setAttribute("elementType", "LoopController");
elementProp.setAttribute("guiclass", "LoopControlPanel");
elementProp.setAttribute("testclass", "LoopController");
@ -502,12 +502,12 @@ public class JmeterDocumentParser implements DocumentParser {
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
elementProp.appendChild(createIntProp(document, "LoopController.loops", 1));
setupElement.appendChild(elementProp);
setupElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
setupElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
setupElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
setupElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
setupElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
setupElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
setupElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
setupElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
setupElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
setupElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
hashTree.appendChild(setupElement);
Element setupHashTree = document.createElement(HASH_TREE_ELEMENT);
@ -568,17 +568,17 @@ public class JmeterDocumentParser implements DocumentParser {
}
/*
<PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="MsThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">1</stringProp>
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
<stringProp name="MsThreadGroup.num_threads">1</stringProp>
<stringProp name="MsThreadGroup.ramp_time">1</stringProp>
<boolProp name="MsThreadGroup.scheduler">false</boolProp>
<stringProp name="MsThreadGroup.duration"></stringProp>
<stringProp name="MsThreadGroup.delay"></stringProp>
<boolProp name="MsThreadGroup.same_user_on_next_iteration">true</boolProp>
</PostThreadGroup>
*/
Element tearDownElement = document.createElement("PostThreadGroup");
@ -586,15 +586,15 @@ public class JmeterDocumentParser implements DocumentParser {
tearDownElement.setAttribute("testclass", "PostThreadGroup");
tearDownElement.setAttribute("testname", "tearDown Thread Group");
tearDownElement.setAttribute("enabled", "true");
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "continue"));
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
Element elementProp = document.createElement("elementProp");
elementProp.setAttribute("name", "ThreadGroup.main_controller");
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
elementProp.setAttribute("elementType", "LoopController");
elementProp.setAttribute("guiclass", "LoopControlPanel");
elementProp.setAttribute("testclass", "LoopController");
@ -760,8 +760,8 @@ public class JmeterDocumentParser implements DocumentParser {
threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui");
threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP);
/*
<elementProp name="ThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="MsThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
<stringProp name="TargetLevel">2</stringProp>
<stringProp name="RampUp">12</stringProp>
<stringProp name="Steps">2</stringProp>
@ -773,11 +773,11 @@ public class JmeterDocumentParser implements DocumentParser {
removeChildren(threadGroup);
// elementProp
Element elementProp = document.createElement("elementProp");
elementProp.setAttribute("name", "ThreadGroup.main_controller");
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
threadGroup.appendChild(elementProp);
threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
threadGroup.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "continue"));
threadGroup.appendChild(createStringProp(document, "TargetLevel", "2"));
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
threadGroup.appendChild(createStringProp(document, "Steps", "2"));

View File

@ -10,11 +10,11 @@
<el-col :span="1">
<template>
<div>
<ms-tag v-if="api.api_status == 'Prepare'" type="info"
<ms-tag v-if="api.status == 'Prepare'" type="info"
:content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="api.api_status == 'Underway'" type="primary"
<ms-tag v-if="api.status == 'Underway'" type="primary"
:content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="api.api_status == 'Completed'" type="success"
<ms-tag v-if="api.status == 'Completed'" type="success"
:content="$t('test_track.plan.plan_status_completed')"/>
</div>
</template>
@ -61,13 +61,7 @@
</div>
</el-col>
<el-col :span="2">
<!--<div class="ms-api-header-select">-->
<!--<el-button size="small" style="background-color: #783887;color: white" @click="createCase">-->
<!--+{{$t('api_test.definition.request.case')}}-->
<!--</el-button>-->
<!--</div>-->
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="createCase"
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="addCase"
@command="handleCommand">
+{{$t('api_test.definition.request.case')}}
<el-dropdown-menu slot="dropdown">
@ -77,7 +71,7 @@
</el-col>
<el-col :span="2">
<el-col :span="1">
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
class="el-dialog__close el-icon el-icon-close"></i></button>
</el-col>
@ -124,7 +118,7 @@
</div>
</el-col>
<el-col :span="4">
<ms-tip-button @click="runCase(item)" :tip="$t('api_test.run')" icon="el-icon-video-play"
<ms-tip-button @click="singleRun(item)" :tip="$t('api_test.run')" icon="el-icon-video-play"
style="background-color: #409EFF;color: white" size="mini" circle/>
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" circle/>
@ -146,12 +140,11 @@
<div v-if="item.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :request="item.test.request"/>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.hashTree[0].headers " :request="item.request"/>
<p class="tip">{{$t('api_test.definition.request.assertions_rule')}} </p>
<ms-api-assertions :request="item.test.request" :is-read-only="isReadOnly"
:assertions="item.test.request.assertions"/>
<!-- <p class="tip">{{$t('api_test.definition.request.assertions_rule')}} </p>-->
<!--<ms-api-assertions :request="item.request" :is-read-only="isReadOnly"-->
<!--:assertions="item.request.assertions"/>-->
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
@ -176,7 +169,6 @@
import MsTag from "../../../common/components/MsTag";
import MsTipButton from "../../../common/components/MsTipButton";
import MsApiRequestForm from "./request/ApiRequestForm";
import {Test, RequestFactory} from "../model/ApiTestModel";
import {downloadFile, getUUID} from "@/common/js/utils";
import {parseEnvironment} from "../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../test/components/ApiEnvironmentConfig";
@ -241,7 +233,7 @@
},
handleCommand(e) {
if (e === "run") {
this.runCase();
this.batchRun();
}
},
showInput(row) {
@ -253,35 +245,39 @@
this.apiCaseList = [];
this.$emit('apiCaseClose');
},
runCase(row) {
batchRun() {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.loading = true;
if (this.apiCaseList.length > 0) {
this.apiCaseList.forEach(item => {
if (item.type != "create") {
item.request.name = item.id;
item.request.useEnvironment = this.environment.id;
this.runData.push(item.request);
}
})
this.loading = true;
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
} else {
this.$warning("没有可执行的用例!");
}
},
singleRun(row) {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.runData = [];
if (row) {
row.test.request.url = this.api.url;
row.test.request.method = this.api.method;
row.test.request.name = row.id;
this.loading = true;
this.runData.push(row.test.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
} else {
if (this.apiCaseList.length > 0) {
this.apiCaseList.forEach(item => {
if (item.type != "create") {
item.test.request.name = item.id;
this.runData.push(item.test.request);
}
})
this.loading = true;
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
} else {
this.$warning("没有可执行的用例!");
}
}
this.loading = true;
row.request.name = row.id;
row.request.useEnvironment = this.environment.id;
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
runRefresh(data) {
this.loading = false;
@ -293,42 +289,33 @@
this.$get('/api/testcase/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.apiCaseList.splice(index, 1);
this.$emit('refresh');
});
},
copyCase(data) {
let obj = {
name: data.name,
priority: data.priority,
type: 'create',
active: false,
test: data.test,
};
let obj = {name: data.name, priority: data.priority, type: 'create', active: false, request: data.request};
this.apiCaseList.unshift(obj);
},
createCase(row) {
let obj = {
name: '',
priority: 'P0',
type: 'create',
active: false,
};
addCase() {
//
let request = {};
if (row) {
request = row.request;
obj.apiDefinitionId = row.apiDefinitionId;
if (this.api.request instanceof Object) {
request = this.api.request;
} else {
request: new RequestFactory(JSON.parse(this.api.request))
request = JSON.parse(this.api.request);
}
obj.test = new Test({request: request});
let obj = {apiDefinitionId: this.api.id, name: '', priority: 'P0', type: 'create', active: false};
obj.request = request;
this.apiCaseList.unshift(obj);
},
active(item) {
item.active = !item.active;
},
getBodyUploadFiles(row) {
let bodyUploadFiles = [];
row.bodyUploadIds = [];
let request = row.test.request;
let request = row.request;
if (request.body) {
request.body.kvs.forEach(param => {
if (param.files) {
@ -343,6 +330,19 @@
});
}
});
request.body.binary.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
row.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
@ -355,7 +355,7 @@
this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.test = new Test({request: new RequestFactory(JSON.parse(test.request))});
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
});
@ -371,21 +371,16 @@
return;
}
let bodyFiles = this.getBodyUploadFiles(row);
row.test.request.url = this.api.url;
row.test.request.method = this.api.method;
row.projectId = this.api.projectId;
row.apiDefinitionId = row.apiDefinitionId || this.api.id;
row.request = row.test.request;
let jmx = row.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
let url = "/api/testcase/create";
if (row.id) {
url = "/api/testcase/update";
}
this.$fileUpload(url, file, bodyFiles, row, () => {
this.$fileUpload(url, null, bodyFiles, row, () => {
this.$success(this.$t('commons.save_success'));
this.getApiTest();
this.$emit('refresh');
});
},
getEnvironments() {

View File

@ -10,10 +10,7 @@
<script>
import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi";
import {RequestFactory, ResponseFactory, Test, Body} from "../model/ApiTestModel";
import JMX from "./jmeter/jmx";
import JmeterTestPlan from "./jmeter/components/jmeter-test-plan";
import TestPlan from "./jmeter/components/test-plan";
import {ResponseFactory, Body} from "../model/ApiTestModel";
import {getUUID} from "@/common/js/utils";
import {createComponent, Request} from "./jmeter/components";
import Sampler from "./jmeter/components/sampler/sampler";
@ -24,10 +21,8 @@
components: {MsAddCompleteHttpApi},
data() {
return {
reqType: RequestFactory.TYPES.HTTP,
reqType: Request.TYPES.HTTP,
reqUrl: "",
test: new Test(),
jmx: new JMX(),
request: Sampler,
response: {},
headers: [],
@ -40,20 +35,9 @@
protocol: String,
},
created() {
let jmx = new JMX();
let rootTestPlan = new JmeterTestPlan();
//
let testPlan = new TestPlan();
rootTestPlan.hashTree = [testPlan];
jmx.elements = [rootTestPlan];
// 线
let threadGroup = createComponent("ThreadGroup");
testPlan.hashTree = [threadGroup];
this.jmx = jmx;
switch (this.protocol) {
case Request.TYPES.SQL:
this.request = createComponent("OT");
this.request = createComponent("SQL");
break;
case Request.TYPES.DUBBO:
this.request = createComponent("JDBCSampler");
@ -65,15 +49,11 @@
this.createHttp();
break;
}
threadGroup.hashTree = [this.request];
this.response = this.currentApi.response != null ? new ResponseFactory(JSON.parse(this.currentApi.response)) : {
headers: [],
body: new Body(),
statusCode: [],
type: "HTTP"
};
if (this.currentApi.response != null && this.currentApi.response != 'null' && this.currentApi.response != undefined) {
this.response = new ResponseFactory(JSON.parse(this.currentApi.response));
} else {
this.response = {headers: [], body: new Body(), statusCode: [], type: "HTTP"};
}
if (this.currentApi != null && this.currentApi.id != null) {
this.reqUrl = "/api/definition/update";
} else {
@ -84,8 +64,9 @@
methods: {
runTest(data) {
data.projectId = this.currentProject.id;
data.request = data.test.request;
data.response = data.test.response;
this.request.hashTree[0].headers = this.headers;
data.request = this.request;
data.response = this.response;
let bodyFiles = this.getBodyUploadFiles(data);
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
this.$success(this.$t('commons.save_success'));
@ -94,13 +75,15 @@
});
},
createHttp() {
if (this.currentApi.request != null) {
if (this.currentApi.request != undefined && this.currentApi.request != null) {
this.request = JSON.parse(this.currentApi.request);
this.currentApi.request = this.request;
this.headers = this.request.hashTree[0].headers;
} else {
let header = createComponent("HeaderManager");
this.request = createComponent("HTTPSamplerProxy");
this.request.hashTree = [header];
this.currentApi.request = this.request;
}
},
saveApi(data) {
@ -108,7 +91,6 @@
this.request.hashTree[0].headers = this.headers;
data.request = this.request;
data.response = this.response;
console.log(data)
let bodyFiles = this.getBodyUploadFiles(data);
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -2,8 +2,10 @@
<div></div>
</template>
<script>
import {Scenario} from "../model/ApiTestModel";
import {getUUID} from "@/common/js/utils";
import HeaderManager from "./jmeter/components/configurations/header-manager";
import ThreadGroup from "./jmeter/components/thread-group";
import TestPlan from "./jmeter/components/test-plan";
export default {
name: 'MsRun',
@ -65,29 +67,35 @@
});
}
});
request.body.binary.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
obj.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
});
return bodyUploadFiles;
},
run() {
let reqObj = {};
let scenario = new Scenario({requests: this.runData});
let url = "";
let reportId = getUUID().substring(0, 8);
let testPlan = new TestPlan();
let threadGroup = new ThreadGroup();
threadGroup.hashTree = [];
testPlan.hashTree = [threadGroup];
this.runData.forEach(item => {
threadGroup.hashTree.push(item);
})
let reqObj = {id: this.reportId, testElement: testPlan};
let bodyFiles = this.getBodyUploadFiles(reqObj);
scenario.requests.forEach(item => {
if (this.environment != null) {
item.useEnvironment = true;
scenario.environmentId = this.environment.id;
}
item.definition = true;
});
scenario.name = reportId;
scenario.dubboConfig = null;
scenario.tcpConfig = null;
reqObj.name = reportId;
reqObj.scenario = scenario;
reqObj.id = reportId;
let url = "";
if (this.debug) {
url = "/api/definition/run/debug";
} else {

View File

@ -34,7 +34,6 @@
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
</el-form>
<template v-slot:footer>
@ -48,9 +47,10 @@
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import {Test} from "../../model/ApiTestModel"
import {REQ_METHOD} from "../../model/JsonData";
import {getCurrentUser} from "../../../../../../common/js/utils";
import {getCurrentUser, getUUID} from "../../../../../../common/js/utils";
import {createComponent} from "../jmeter/components";
import HeaderManager from "../jmeter/components/configurations/header-manager";
export default {
name: "MsAddBasisHttpApi",
@ -81,22 +81,18 @@
if (valid) {
let bodyFiles = [];
let url = "/api/definition/create";
let test = new Test();
this.httpForm.bodyUploadIds = [];
this.httpForm.request = test.request;
this.httpForm.request.url = this.httpForm.url;
this.httpForm.request.method = this.httpForm.method;
this.httpForm.projectId = this.projectId;
this.httpForm.id = test.id;
this.httpForm.id = getUUID().substring(0, 8);
let header = createComponent("HeaderManager");
let request = createComponent("HTTPSamplerProxy");
request.hashTree = [header];
this.httpForm.request = request;
if (this.currentModule != null) {
this.httpForm.modulePath = this.currentModule.method != undefined ? this.currentModule.method : null;
this.httpForm.moduleId = this.currentModule.id;
}
let jmx = test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
this.result = this.$fileUpload(url, file, bodyFiles, this.httpForm, () => {
this.result = this.$fileUpload(url, null, bodyFiles, this.httpForm, () => {
this.httpVisible = false;
this.$parent.refresh(this.currentModule);
});

View File

@ -22,9 +22,9 @@
</el-form-item>
<el-form-item :label="$t('api_report.request')" prop="url">
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="httpForm.url"
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="httpForm.request.path.value"
class="ms-http-input" size="small" style="margin-top: 5px">
<el-select v-model="httpForm.method" slot="prepend" style="width: 100px" size="small">
<el-select v-model="httpForm.request.method.value" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-input>
@ -127,6 +127,7 @@
},
setParameter() {
this.httpForm.modulePath = this.getPath(this.httpForm.moduleId);
this.httpForm.url = this.httpForm.request.path.value;
},
saveApi() {
if (this.currentProject === null) {
@ -163,7 +164,7 @@
<style scoped>
.ms-http-input {
width: 500px;
width: 400px;
}
.tip {
@ -175,7 +176,7 @@
}
.ms-http-textarea {
width: 500px;
width: 400px;
}
.ms-left-cell {

View File

@ -26,7 +26,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- HTTP 请求参数 -->
<ms-api-request-form :request="test.request"/>
<ms-api-request-form :headers="headers" :request="request"/>
</el-form>
<!-- HTTP 请求返回数据 -->
@ -41,14 +41,13 @@
<script>
import MsApiRequestForm from "../request/ApiRequestForm";
import {Test} from "../../model/ApiTestModel";
import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText";
import MsRun from "../Run";
import {createComponent, Request} from "../jmeter/components";
import HeaderManager from "../jmeter/components/configurations/header-manager";
import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail";
@ -66,10 +65,27 @@
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
loading: false,
debugResultId: "",
test: new Test(),
runData: [],
headers: [],
reportId: "",
reqOptions: REQ_METHOD,
request: {},
}
},
created() {
switch (this.protocol) {
case Request.TYPES.SQL:
this.request = createComponent("SQL");
break;
case Request.TYPES.DUBBO:
this.request = createComponent("JDBCSampler");
break;
case Request.TYPES.TCP:
this.request = createComponent("TCPSampler");
break;
default:
this.createHttp();
break;
}
},
watch: {
@ -85,15 +101,21 @@
this.runDebug();
}
},
createHttp() {
let header = createComponent("HeaderManager");
this.request = createComponent("HTTPSamplerProxy");
this.request.hashTree = [header];
},
runDebug() {
this.$refs['debugForm'].validate((valid) => {
if (valid) {
this.loading = true;
this.test.request.url = this.debugForm.url;
this.test.request.method = this.debugForm.method;
this.test.request.name = getUUID().substring(0, 8);
this.request.url = this.debugForm.url;
this.request.method.value = this.debugForm.method;
this.request.hashTree[0].headers = this.headers;
this.request.name = getUUID().substring(0, 8);
this.runData = [];
this.runData.push(this.test.request);
this.runData.push(this.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
}
@ -107,7 +129,7 @@
saveAs() {
this.$refs['debugForm'].validate((valid) => {
if (valid) {
this.debugForm.request = JSON.stringify(this.test.request);
this.debugForm.request = JSON.stringify(this.request);
this.debugForm.userId = getCurrentUser().id;
this.debugForm.status = "Underway";
this.$emit('saveAs', this.debugForm);

View File

@ -15,7 +15,7 @@ const DEFAULT_OPTIONS = {
export default class HeaderManager extends Configuration {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.type = "HeaderManager";
this.headers = [];
let collectionProp = this.initCollectionProp('HeaderManager.headers');
collectionProp.forEach(elementProp => {

View File

@ -14,7 +14,8 @@ const DEFAULT_OPTIONS = {
export default class JSR223PostProcessor extends PostProcessor {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.scriptLanguage = this.initStringProp("scriptLanguage", "groovy")
this.type = "JSR223PostProcessor";
this.scriptLanguage = this.initStringProp("scriptLanguage", "java")
this.parameters = this.initStringProp("parameters")
this.filename = this.initStringProp("filename")
this.cacheKey = this.initStringProp("cacheKey", true)

View File

@ -14,7 +14,8 @@ const DEFAULT_OPTIONS = {
export default class JSR223PreProcessor extends PostProcessor {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.scriptLanguage = this.initStringProp("scriptLanguage", "groovy")
this.type = "JSR223PreProcessor";
this.scriptLanguage = this.initStringProp("scriptLanguage", "java")
this.parameters = this.initStringProp("parameters")
this.filename = this.initStringProp("filename")
this.cacheKey = this.initStringProp("cacheKey", true)

View File

@ -1,6 +1,6 @@
import {boolProp, elementProp, stringProp} from "../../../props";
import Sampler from "../sampler";
import {BaseConfig, BODY_TYPE, KeyValue,Body} from "../../../../../model/ApiTestModel";
import {BaseConfig, BODY_TYPE, KeyValue, Body} from "../../../../../model/ApiTestModel";
const DEFAULT_OPTIONS = {
options: {
@ -18,7 +18,7 @@ export default class HTTPSamplerProxy extends Sampler {
this.protocol = this.initStringProp('HTTPSampler.protocol', "https");
this.domain = this.initStringProp('HTTPSampler.domain');
this.port = this.initStringProp('HTTPSampler.port');
this.type = "HTTPSamplerProxy";
this.method = this.initStringProp('HTTPSampler.method', "GET");
this.path = this.initStringProp('HTTPSampler.path');
this.contentEncoding = this.initStringProp('HTTPSampler.contentEncoding', "UTF-8");

View File

@ -13,7 +13,7 @@ export default class TestPlan extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.$type = TYPE;
this.type = TYPE;
this.functionalMode = this.initBoolProp('TestPlan.functional_mode', false);
this.serializeThreadGroups = this.initBoolProp('TestPlan.serialize_threadgroups', false);
this.tearDownOnShutdown = this.initBoolProp('TestPlan.tearDown_on_shutdown', true);

View File

@ -12,7 +12,7 @@ export default class ThreadGroup extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.$type = TYPE;
this.type = TYPE;
this.onSampleError = this.initStringProp('ThreadGroup.on_sample_error', 'continue');
this.numThreads = this.initStringProp('ThreadGroup.num_threads', 1);
this.rampTime = this.initStringProp('ThreadGroup.ramp_time', 1);

View File

@ -1,52 +0,0 @@
import Element from "../element";
import {loadComponent} from "../components";
import JmeterTestPlan from "../components/jmeter-test-plan";
import TestPlan from "../components/test-plan";
import {js2xml, xml2js} from "xml-js";
const DEFAULT_OPTIONS = {
declaration: {attributes: {version: "1.0", encoding: "UTF-8"}}
}
export default class JMX extends Element {
constructor(options = DEFAULT_OPTIONS) {
super(options);
this.declaration = options.declaration;
if (options.elements) {
this.elements = [];
options.elements.forEach(e => {
this.elements.push(loadComponent(e));
})
}
}
toJson() {
let json = {
declaration: this.declaration
};
if (this.elements) {
json.elements = [];
this.elements.forEach(e => {
json.elements.push(e.toJson());
})
}
return json;
}
toXML() {
return js2xml(this.toJson(), {spaces: 2});
}
static create() {
let jmx = new JMX();
let jmeterTestPlan = new JmeterTestPlan();
let testPlan = new TestPlan();
jmeterTestPlan.hashTree = [testPlan];
jmx.elements = [jmeterTestPlan];
return jmx;
}
static fromJMX(xml) {
return new JMX(xml2js(xml));
}
}

View File

@ -3,11 +3,9 @@
<el-row>
<div>
<el-button class="ms-left-buttion" size="small" :type="styleType" plain>{{title}}</el-button>
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive"
style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name"
class="ms-api-header-select" style="width: 380px"/>
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive" style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<el-button size="small" style="float: right" @click="remove">移除</el-button>
</div>
</el-row>
<el-collapse-transition>
@ -24,7 +22,7 @@
</el-row>
<el-row>
<el-col :span="20" class="script-content">
<ms-code-edit v-if="isCodeEditAlive" :mode="codeEditModeMap[jsr223ProcessorData.language]=== null ?'java':'python'"
<ms-code-edit v-if="isCodeEditAlive" :mode="jsr223ProcessorData.scriptLanguage.value"
:read-only="isReadOnly"
:data.sync="jsr223ProcessorData.script.value" theme="eclipse" :modes="['java','python']"
ref="codeEdit"/>
@ -90,7 +88,7 @@
],
isCodeEditAlive: true,
languages: [
'beanshell', "python"
'java', "python"
],
codeEditModeMap: {
beanshell: 'java',
@ -102,16 +100,6 @@
this.jsr223ProcessorData = this.jsr223Processor;
},
props: {
type: {
type: String,
default:
"create",
}
,
name: {
type: String,
}
,
isReadOnly: {
type: Boolean,
default:
@ -149,21 +137,20 @@
this.jsr223ProcessorData.script += ';';
}
this.reload();
}
,
},
remove(){
this.$emit('remove', this.jsr223ProcessorData);
},
reload() {
this.isCodeEditAlive = false;
this.$nextTick(() => (this.isCodeEditAlive = true));
}
,
},
languageChange(language) {
this.jsr223ProcessorData.language = language;
}
,
},
changeActive() {
this.active = !this.active;
}
,
},
}
}
</script>

View File

@ -12,12 +12,12 @@
<!--query 参数-->
<el-tab-pane :label="$t('api_test.definition.request.query_param')" name="parameters">
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.arguments"/>
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.arguments"/>
</el-tab-pane>
<!--REST 参数-->
<el-tab-pane :label="$t('api_test.definition.request.rest_param')" name="rest">
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.rest"/>
<ms-api-variable :is-read-only="isReadOnly" :parameters="request.rest"/>
</el-tab-pane>
<!--请求体-->
@ -32,10 +32,10 @@
</el-tabs>
</div>
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData">
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" :is-read-only="false" title="前置脚本" style-type="warning"
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" title="前置脚本" style-type="warning"
:jsr223-processor="row"/>
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" :is-read-only="false" title="后置脚本" style-type="success"
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" title="后置脚本" style-type="success"
:jsr223-processor="row"/>
<!--<ms-api-assertions v-if="row.label.indexOf('Assertion')>0" :is-read-only="isReadOnly" :request="request"/>-->
@ -137,6 +137,11 @@
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {

View File

@ -8,14 +8,14 @@
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
<!-- 请求方法 -->
<el-form-item :label="$t('api_report.request')" prop="method">
<el-select v-model="api.method" style="width: 100px" size="small">
<el-select v-model="api.request.method.value" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
<!-- 执行环境 -->
<el-form-item prop="environmentId">
<el-select v-model="api.environmentId" size="small" class="ms-htt-width"
<el-select v-model="api.request.useEnvironment" size="small" class="ms-htt-width"
:placeholder="$t('api_test.definition.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
@ -36,7 +36,7 @@
<!-- 请求地址 -->
<el-form-item prop="url">
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="api.url" class="ms-htt-width"
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="api.request.path.value" class="ms-htt-width"
size="small" :disabled="false"/>
</el-form-item>
@ -59,7 +59,7 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- HTTP 请求参数 -->
<ms-api-request-form :request="api.request"/>
<ms-api-request-form :headers="api.request.hashTree[0].headers" :request="api.request"/>
</el-form>
<!--返回结果-->
@ -149,11 +149,9 @@
this.$refs['apiData'].validate((valid) => {
if (valid) {
this.loading = true;
this.api.test.request.url = this.api.url;
this.api.test.request.method = this.api.method;
this.api.test.request.name = this.api.id;
this.api.request.name = this.api.id;
this.runData = [];
this.runData.push(this.api.test.request);
this.runData.push(this.api.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
}
@ -197,11 +195,7 @@
saveAsCase() {
this.isHide = false;
this.loaded = false;
let testCase = {};
testCase.request = this.api.request;
testCase.apiDefinitionId = this.api.id;
testCase.priority = "P0";
this.$refs.caseList.createCase(testCase);
this.$refs.caseList.addCase();
},
saveAsApi() {
let data = {};
@ -216,17 +210,14 @@
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
let jmx = this.api.test.toJMX();
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
let file = new File([blob], jmx.name);
this.$fileUpload(url, file, bodyFiles, this.api, () => {
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('saveApi', this.api);
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = new RequestFactory(JSON.parse(item.request));
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
@ -266,7 +257,7 @@
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.api.environment = this.environments[i];
this.api.request.useEnvironment = this.environments[i].id;
break;
}
}
@ -286,6 +277,7 @@
},
created() {
this.api = this.apiData;
this.currentRequest = this.api.request;
this.getEnvironments();
this.getResult();
}