feat(接口定义): 请求数据格式按照jmeter 数据格式重构完成
This commit is contained in:
parent
8fd084db51
commit
bdaff53eaf
|
@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.api.dto.APIReportResult;
|
import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
|
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
|
||||||
import io.metersphere.api.dto.definition.ApiDefinitionResult;
|
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.dto.definition.SaveApiDefinitionRequest;
|
||||||
import io.metersphere.api.service.ApiDefinitionService;
|
import io.metersphere.api.service.ApiDefinitionService;
|
||||||
import io.metersphere.base.domain.ApiDefinition;
|
import io.metersphere.base.domain.ApiDefinition;
|
||||||
|
@ -61,12 +62,12 @@ public class ApiDefinitionController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
|
@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);
|
return apiDefinitionService.run(request, bodyFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/run", consumes = {"multipart/form-data"})
|
@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);
|
return apiDefinitionService.run(request, bodyFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,13 @@ public class ApiTestCaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
|
@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) {
|
public void create(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||||
apiTestCaseService.create(request, file, bodyFiles);
|
apiTestCaseService.create(request, bodyFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
|
@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) {
|
public void update(@RequestPart("request") SaveApiTestCaseRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||||
apiTestCaseService.update(request, file, bodyFiles);
|
apiTestCaseService.update(request, bodyFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/delete/{id}")
|
@GetMapping("/delete/{id}")
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.api.dto.definition;
|
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.definition.response.Response;
|
||||||
import io.metersphere.api.dto.scenario.Scenario;
|
|
||||||
import io.metersphere.base.domain.Schedule;
|
import io.metersphere.base.domain.Schedule;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
@ -32,9 +32,7 @@ public class SaveApiDefinitionRequest {
|
||||||
|
|
||||||
private String method;
|
private String method;
|
||||||
|
|
||||||
private Scenario scenario;
|
private MsTestElement request;
|
||||||
|
|
||||||
private Object request;
|
|
||||||
|
|
||||||
private Response response;
|
private Response response;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.metersphere.api.dto.definition;
|
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.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ public class SaveApiTestCaseRequest {
|
||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Request request;
|
private MsTestElement request;
|
||||||
|
|
||||||
private String response;
|
private String response;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ public class Body {
|
||||||
private String type;
|
private String type;
|
||||||
private String raw;
|
private String raw;
|
||||||
private String format;
|
private String format;
|
||||||
|
private List<KeyValue> fromUrlencoded;
|
||||||
private List<KeyValue> kvs;
|
private List<KeyValue> kvs;
|
||||||
private List<KeyValue> binary;
|
private List<KeyValue> binary;
|
||||||
private Object json;
|
private Object json;
|
||||||
|
|
|
@ -27,6 +27,8 @@ import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
|
||||||
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
|
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupTest(BackendListenerContext context) throws Exception {
|
public void setupTest(BackendListenerContext context) throws Exception {
|
||||||
|
setConsole();
|
||||||
setParam(context);
|
setParam(context);
|
||||||
apiTestService = CommonBeanFactory.getBean(APITestService.class);
|
apiTestService = CommonBeanFactory.getBean(APITestService.class);
|
||||||
if (apiTestService == null) {
|
if (apiTestService == null) {
|
||||||
|
@ -109,6 +112,18 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
super.setupTest(context);
|
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
|
@Override
|
||||||
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
|
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
|
||||||
|
@ -120,8 +135,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
TestResult testResult = new TestResult();
|
TestResult testResult = new TestResult();
|
||||||
testResult.setTestId(testId);
|
testResult.setTestId(testId);
|
||||||
testResult.setTotal(queue.size());
|
testResult.setTotal(queue.size());
|
||||||
|
// 一个脚本里可能包含多个场景(MsThreadGroup),所以要区分开,key: 场景Id
|
||||||
// 一个脚本里可能包含多个场景(ThreadGroup),所以要区分开,key: 场景Id
|
|
||||||
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
||||||
queue.forEach(result -> {
|
queue.forEach(result -> {
|
||||||
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
||||||
|
@ -276,7 +290,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
responseResult.setResponseSize(result.getResponseData().length);
|
responseResult.setResponseSize(result.getResponseData().length);
|
||||||
responseResult.setResponseTime(result.getTime());
|
responseResult.setResponseTime(result.getTime());
|
||||||
responseResult.setResponseMessage(result.getResponseMessage());
|
responseResult.setResponseMessage(result.getResponseMessage());
|
||||||
|
responseResult.setConsole(getConsole());
|
||||||
if (JMeterVars.get(result.hashCode()) != null) {
|
if (JMeterVars.get(result.hashCode()) != null) {
|
||||||
List<String> vars = new LinkedList<>();
|
List<String> vars = new LinkedList<>();
|
||||||
JMeterVars.get(result.hashCode()).entrySet().parallelStream().reduce(vars, (first, second) -> {
|
JMeterVars.get(result.hashCode()).entrySet().parallelStream().reduce(vars, (first, second) -> {
|
||||||
|
|
|
@ -42,12 +42,12 @@ public class JMeterService {
|
||||||
return jmxGenerator.parse(testId, testName, scenarios);
|
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 {
|
try {
|
||||||
init();
|
init();
|
||||||
HashTree testPlan = getHashTree(testId, testName, scenarios);
|
HashTree testPlan = getHashTree(testId, testName, scenarios);
|
||||||
JMeterVars.addJSR223PostProcessor(testPlan);
|
JMeterVars.addJSR223PostProcessor(testPlan);
|
||||||
addBackendListener(testId, debugReportId,runMode, testPlan);
|
addBackendListener(testId, debugReportId, runMode, testPlan);
|
||||||
LocalRunner runner = new LocalRunner(testPlan);
|
LocalRunner runner = new LocalRunner(testPlan);
|
||||||
runner.run();
|
runner.run();
|
||||||
} catch (Exception e) {
|
} 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 backendListener = new BackendListener();
|
||||||
backendListener.setName(testId);
|
backendListener.setName(testId);
|
||||||
Arguments arguments = new Arguments();
|
Arguments arguments = new Arguments();
|
||||||
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
|
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
|
||||||
if(StringUtils.isNotBlank(runMode)){
|
if (StringUtils.isNotBlank(runMode)) {
|
||||||
arguments.addArgument("runMode", runMode);
|
arguments.addArgument("runMode", runMode);
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(debugReportId)) {
|
if (StringUtils.isNotBlank(debugReportId)) {
|
||||||
|
@ -97,4 +97,17 @@ public class JMeterService {
|
||||||
backendListener.setClassname(APIBackendListenerClient.class.getCanonicalName());
|
backendListener.setClassname(APIBackendListenerClient.class.getCanonicalName());
|
||||||
testPlan.add(testPlan.getArray()[0], backendListener);
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ public class ResponseResult {
|
||||||
|
|
||||||
private String vars;
|
private String vars;
|
||||||
|
|
||||||
|
private String console;
|
||||||
|
|
||||||
private final List<ResponseAssertionResult> assertions = new ArrayList<>();
|
private final List<ResponseAssertionResult> assertions = new ArrayList<>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class JmeterDocumentParser {
|
||||||
private final static String STRING_PROP = "stringProp";
|
private final static String STRING_PROP = "stringProp";
|
||||||
private final static String ARGUMENTS = "Arguments";
|
private final static String ARGUMENTS = "Arguments";
|
||||||
private final static String COLLECTION_PROP = "collectionProp";
|
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";
|
private final static String ELEMENT_PROP = "elementProp";
|
||||||
|
|
||||||
public static byte[] parse(byte[] source) {
|
public static byte[] parse(byte[] source) {
|
||||||
|
|
|
@ -3,11 +3,7 @@ package io.metersphere.api.service;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.APIReportResult;
|
import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.definition.ApiComputeResult;
|
import io.metersphere.api.dto.definition.*;
|
||||||
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.jmeter.JMeterService;
|
import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.api.jmeter.TestResult;
|
import io.metersphere.api.jmeter.TestResult;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
|
@ -24,6 +20,7 @@ import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.service.FileService;
|
import io.metersphere.service.FileService;
|
||||||
import io.metersphere.service.QuotaService;
|
import io.metersphere.service.QuotaService;
|
||||||
|
import org.apache.jorphan.collections.HashTree;
|
||||||
import org.aspectj.util.FileUtil;
|
import org.aspectj.util.FileUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
@ -101,7 +98,6 @@ public class ApiDefinitionService {
|
||||||
|
|
||||||
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
public void update(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
||||||
deleteFileByTestId(request.getId());
|
deleteFileByTestId(request.getId());
|
||||||
|
|
||||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||||
request.setBodyUploadIds(null);
|
request.setBodyUploadIds(null);
|
||||||
ApiDefinition test = updateTest(request);
|
ApiDefinition test = updateTest(request);
|
||||||
|
@ -210,14 +206,6 @@ public class ApiDefinitionService {
|
||||||
return test;
|
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) {
|
private void deleteFileByTestId(String apiId) {
|
||||||
ApiTestFileExample apiTestFileExample = new ApiTestFileExample();
|
ApiTestFileExample apiTestFileExample = new ApiTestFileExample();
|
||||||
apiTestFileExample.createCriteria().andTestIdEqualTo(apiId);
|
apiTestFileExample.createCriteria().andTestIdEqualTo(apiId);
|
||||||
|
@ -237,13 +225,13 @@ public class ApiDefinitionService {
|
||||||
* @param bodyFiles
|
* @param bodyFiles
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String run(SaveApiDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
||||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||||
createBodyFiles(request.getId(), bodyUploadIds, bodyFiles);
|
createBodyFiles(request.getId(), bodyUploadIds, bodyFiles);
|
||||||
|
|
||||||
List<Scenario> scenarios = new ArrayList<>();
|
HashTree hashTree = request.getTestElement().get();
|
||||||
scenarios.add(request.getScenario());
|
// 调用执行方法
|
||||||
jMeterService.run(request.getId(), request.getName(), scenarios, request.getReportId(), ApiRunMode.DELIMIT.name());
|
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.DELIMIT.name());
|
||||||
return request.getId();
|
return request.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +269,9 @@ public class ApiDefinitionService {
|
||||||
*/
|
*/
|
||||||
public APIReportResult getDbResult(String testId) {
|
public APIReportResult getDbResult(String testId) {
|
||||||
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByResourceId(testId);
|
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByResourceId(testId);
|
||||||
|
if (result == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
APIReportResult reportResult = new APIReportResult();
|
APIReportResult reportResult = new APIReportResult();
|
||||||
reportResult.setContent(result.getContent());
|
reportResult.setContent(result.getContent());
|
||||||
return reportResult;
|
return reportResult;
|
||||||
|
|
|
@ -53,21 +53,10 @@ public class ApiTestCaseService {
|
||||||
return apiTestCaseMapper.selectByPrimaryKey(id);
|
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());
|
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);
|
ApiTestCase test = createTest(request);
|
||||||
saveFile(test.getId(), file);
|
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||||
return test;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkQuota() {
|
private void checkQuota() {
|
||||||
|
@ -77,17 +66,14 @@ public class ApiTestCaseService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(SaveApiTestCaseRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
public void update(SaveApiTestCaseRequest request, List<MultipartFile> bodyFiles) {
|
||||||
if (file == null) {
|
|
||||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
|
||||||
}
|
|
||||||
deleteFileByTestId(request.getId());
|
deleteFileByTestId(request.getId());
|
||||||
|
|
||||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||||
request.setBodyUploadIds(null);
|
request.setBodyUploadIds(null);
|
||||||
ApiTestCase test = updateTest(request);
|
ApiTestCase test = updateTest(request);
|
||||||
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||||
saveFile(test.getId(), file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createBodyFiles(ApiTestCase test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
|
private void createBodyFiles(ApiTestCase test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
|
||||||
|
|
|
@ -491,9 +491,9 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
setupElement.setAttribute("testclass", "SetupThreadGroup");
|
setupElement.setAttribute("testclass", "SetupThreadGroup");
|
||||||
setupElement.setAttribute("testname", "setUp Thread Group");
|
setupElement.setAttribute("testname", "setUp Thread Group");
|
||||||
setupElement.setAttribute("enabled", "true");
|
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");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "LoopController");
|
elementProp.setAttribute("elementType", "LoopController");
|
||||||
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
||||||
elementProp.setAttribute("testclass", "LoopController");
|
elementProp.setAttribute("testclass", "LoopController");
|
||||||
|
@ -502,12 +502,12 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
|
elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false));
|
||||||
elementProp.appendChild(createIntProp(document, "LoopController.loops", 1));
|
elementProp.appendChild(createIntProp(document, "LoopController.loops", 1));
|
||||||
setupElement.appendChild(elementProp);
|
setupElement.appendChild(elementProp);
|
||||||
setupElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
|
setupElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
|
||||||
setupElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
|
setupElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
|
||||||
setupElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
|
setupElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
|
||||||
setupElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
|
setupElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
|
||||||
setupElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
|
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
|
||||||
setupElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
|
setupElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
|
||||||
hashTree.appendChild(setupElement);
|
hashTree.appendChild(setupElement);
|
||||||
|
|
||||||
Element setupHashTree = document.createElement(HASH_TREE_ELEMENT);
|
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">
|
<PostThreadGroup guiclass="PostThreadGroupGui" testclass="PostThreadGroup" testname="tearDown Thread Group" enabled="true">
|
||||||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
|
||||||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
<elementProp name="MsThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
<stringProp name="LoopController.loops">1</stringProp>
|
<stringProp name="LoopController.loops">1</stringProp>
|
||||||
</elementProp>
|
</elementProp>
|
||||||
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
<stringProp name="MsThreadGroup.num_threads">1</stringProp>
|
||||||
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
<stringProp name="MsThreadGroup.ramp_time">1</stringProp>
|
||||||
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
<boolProp name="MsThreadGroup.scheduler">false</boolProp>
|
||||||
<stringProp name="ThreadGroup.duration"></stringProp>
|
<stringProp name="MsThreadGroup.duration"></stringProp>
|
||||||
<stringProp name="ThreadGroup.delay"></stringProp>
|
<stringProp name="MsThreadGroup.delay"></stringProp>
|
||||||
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
|
<boolProp name="MsThreadGroup.same_user_on_next_iteration">true</boolProp>
|
||||||
</PostThreadGroup>
|
</PostThreadGroup>
|
||||||
*/
|
*/
|
||||||
Element tearDownElement = document.createElement("PostThreadGroup");
|
Element tearDownElement = document.createElement("PostThreadGroup");
|
||||||
|
@ -586,15 +586,15 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
tearDownElement.setAttribute("testclass", "PostThreadGroup");
|
tearDownElement.setAttribute("testclass", "PostThreadGroup");
|
||||||
tearDownElement.setAttribute("testname", "tearDown Thread Group");
|
tearDownElement.setAttribute("testname", "tearDown Thread Group");
|
||||||
tearDownElement.setAttribute("enabled", "true");
|
tearDownElement.setAttribute("enabled", "true");
|
||||||
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
|
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.on_sample_error", "continue"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1"));
|
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.num_threads", "1"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1"));
|
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.ramp_time", "1"));
|
||||||
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.duration", ""));
|
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.duration", ""));
|
||||||
tearDownElement.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
|
tearDownElement.appendChild(createStringProp(document, "MsThreadGroup.delay", ""));
|
||||||
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false));
|
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.scheduler", false));
|
||||||
tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
|
tearDownElement.appendChild(createBoolProp(document, "MsThreadGroup.same_user_on_next_iteration", true));
|
||||||
Element elementProp = document.createElement("elementProp");
|
Element elementProp = document.createElement("elementProp");
|
||||||
elementProp.setAttribute("name", "ThreadGroup.main_controller");
|
elementProp.setAttribute("name", "MsThreadGroup.main_controller");
|
||||||
elementProp.setAttribute("elementType", "LoopController");
|
elementProp.setAttribute("elementType", "LoopController");
|
||||||
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
elementProp.setAttribute("guiclass", "LoopControlPanel");
|
||||||
elementProp.setAttribute("testclass", "LoopController");
|
elementProp.setAttribute("testclass", "LoopController");
|
||||||
|
@ -760,8 +760,8 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui");
|
threadGroup.setAttribute("guiclass", CONCURRENCY_THREAD_GROUP + "Gui");
|
||||||
threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP);
|
threadGroup.setAttribute("testclass", CONCURRENCY_THREAD_GROUP);
|
||||||
/*
|
/*
|
||||||
<elementProp name="ThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
|
<elementProp name="MsThreadGroup.main_controller" elementType="com.blazemeter.jmeter.control.VirtualUserController"/>
|
||||||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
<stringProp name="MsThreadGroup.on_sample_error">continue</stringProp>
|
||||||
<stringProp name="TargetLevel">2</stringProp>
|
<stringProp name="TargetLevel">2</stringProp>
|
||||||
<stringProp name="RampUp">12</stringProp>
|
<stringProp name="RampUp">12</stringProp>
|
||||||
<stringProp name="Steps">2</stringProp>
|
<stringProp name="Steps">2</stringProp>
|
||||||
|
@ -773,11 +773,11 @@ public class JmeterDocumentParser implements DocumentParser {
|
||||||
removeChildren(threadGroup);
|
removeChildren(threadGroup);
|
||||||
// elementProp
|
// elementProp
|
||||||
Element elementProp = document.createElement("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");
|
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
||||||
threadGroup.appendChild(elementProp);
|
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, "TargetLevel", "2"));
|
||||||
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
|
threadGroup.appendChild(createStringProp(document, "RampUp", "12"));
|
||||||
threadGroup.appendChild(createStringProp(document, "Steps", "2"));
|
threadGroup.appendChild(createStringProp(document, "Steps", "2"));
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
<el-col :span="1">
|
<el-col :span="1">
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<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')"/>
|
: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')"/>
|
: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')"/>
|
:content="$t('test_track.plan.plan_status_completed')"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -61,13 +61,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="2">
|
<el-col :span="2">
|
||||||
<!--<div class="ms-api-header-select">-->
|
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="addCase"
|
||||||
<!--<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"
|
|
||||||
@command="handleCommand">
|
@command="handleCommand">
|
||||||
+{{$t('api_test.definition.request.case')}}
|
+{{$t('api_test.definition.request.case')}}
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
@ -77,7 +71,7 @@
|
||||||
|
|
||||||
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="2">
|
<el-col :span="1">
|
||||||
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
|
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
|
||||||
class="el-dialog__close el-icon el-icon-close"></i></button>
|
class="el-dialog__close el-icon el-icon-close"></i></button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -124,7 +118,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<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/>
|
style="background-color: #409EFF;color: white" size="mini" circle/>
|
||||||
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
|
<ms-tip-button @click="copyCase(item)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
|
||||||
size="mini" circle/>
|
size="mini" circle/>
|
||||||
|
@ -146,12 +140,11 @@
|
||||||
<div v-if="item.active">
|
<div v-if="item.active">
|
||||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
<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>
|
<!-- <p class="tip">{{$t('api_test.definition.request.assertions_rule')}} </p>-->
|
||||||
|
<!--<ms-api-assertions :request="item.request" :is-read-only="isReadOnly"-->
|
||||||
<ms-api-assertions :request="item.test.request" :is-read-only="isReadOnly"
|
<!--:assertions="item.request.assertions"/>-->
|
||||||
:assertions="item.test.request.assertions"/>
|
|
||||||
|
|
||||||
<!-- 保存操作 -->
|
<!-- 保存操作 -->
|
||||||
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
|
<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 MsTag from "../../../common/components/MsTag";
|
||||||
import MsTipButton from "../../../common/components/MsTipButton";
|
import MsTipButton from "../../../common/components/MsTipButton";
|
||||||
import MsApiRequestForm from "./request/ApiRequestForm";
|
import MsApiRequestForm from "./request/ApiRequestForm";
|
||||||
import {Test, RequestFactory} from "../model/ApiTestModel";
|
|
||||||
import {downloadFile, getUUID} from "@/common/js/utils";
|
import {downloadFile, getUUID} from "@/common/js/utils";
|
||||||
import {parseEnvironment} from "../model/EnvironmentModel";
|
import {parseEnvironment} from "../model/EnvironmentModel";
|
||||||
import ApiEnvironmentConfig from "../../test/components/ApiEnvironmentConfig";
|
import ApiEnvironmentConfig from "../../test/components/ApiEnvironmentConfig";
|
||||||
|
@ -241,7 +233,7 @@
|
||||||
},
|
},
|
||||||
handleCommand(e) {
|
handleCommand(e) {
|
||||||
if (e === "run") {
|
if (e === "run") {
|
||||||
this.runCase();
|
this.batchRun();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showInput(row) {
|
showInput(row) {
|
||||||
|
@ -253,35 +245,39 @@
|
||||||
this.apiCaseList = [];
|
this.apiCaseList = [];
|
||||||
this.$emit('apiCaseClose');
|
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) {
|
if (!this.environment) {
|
||||||
this.$warning(this.$t('api_test.environment.select_environment'));
|
this.$warning(this.$t('api_test.environment.select_environment'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.runData = [];
|
this.runData = [];
|
||||||
if (row) {
|
this.loading = true;
|
||||||
row.test.request.url = this.api.url;
|
row.request.name = row.id;
|
||||||
row.test.request.method = this.api.method;
|
row.request.useEnvironment = this.environment.id;
|
||||||
row.test.request.name = row.id;
|
this.runData.push(row.request);
|
||||||
this.loading = true;
|
/*触发执行操作*/
|
||||||
this.runData.push(row.test.request);
|
this.reportId = getUUID().substring(0, 8);
|
||||||
/*触发执行操作*/
|
|
||||||
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("没有可执行的用例!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
runRefresh(data) {
|
runRefresh(data) {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
@ -293,42 +289,33 @@
|
||||||
this.$get('/api/testcase/delete/' + row.id, () => {
|
this.$get('/api/testcase/delete/' + row.id, () => {
|
||||||
this.$success(this.$t('commons.delete_success'));
|
this.$success(this.$t('commons.delete_success'));
|
||||||
this.apiCaseList.splice(index, 1);
|
this.apiCaseList.splice(index, 1);
|
||||||
|
this.$emit('refresh');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
copyCase(data) {
|
copyCase(data) {
|
||||||
let obj = {
|
let obj = {name: data.name, priority: data.priority, type: 'create', active: false, request: data.request};
|
||||||
name: data.name,
|
|
||||||
priority: data.priority,
|
|
||||||
type: 'create',
|
|
||||||
active: false,
|
|
||||||
test: data.test,
|
|
||||||
};
|
|
||||||
this.apiCaseList.unshift(obj);
|
this.apiCaseList.unshift(obj);
|
||||||
},
|
},
|
||||||
createCase(row) {
|
addCase() {
|
||||||
let obj = {
|
// 初始化对象
|
||||||
name: '',
|
|
||||||
priority: 'P0',
|
|
||||||
type: 'create',
|
|
||||||
active: false,
|
|
||||||
};
|
|
||||||
let request = {};
|
let request = {};
|
||||||
if (row) {
|
if (this.api.request instanceof Object) {
|
||||||
request = row.request;
|
request = this.api.request;
|
||||||
obj.apiDefinitionId = row.apiDefinitionId;
|
|
||||||
} else {
|
} 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);
|
this.apiCaseList.unshift(obj);
|
||||||
},
|
},
|
||||||
|
|
||||||
active(item) {
|
active(item) {
|
||||||
item.active = !item.active;
|
item.active = !item.active;
|
||||||
},
|
},
|
||||||
getBodyUploadFiles(row) {
|
getBodyUploadFiles(row) {
|
||||||
let bodyUploadFiles = [];
|
let bodyUploadFiles = [];
|
||||||
row.bodyUploadIds = [];
|
row.bodyUploadIds = [];
|
||||||
let request = row.test.request;
|
let request = row.request;
|
||||||
if (request.body) {
|
if (request.body) {
|
||||||
request.body.kvs.forEach(param => {
|
request.body.kvs.forEach(param => {
|
||||||
if (param.files) {
|
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;
|
return bodyUploadFiles;
|
||||||
},
|
},
|
||||||
|
@ -355,7 +355,7 @@
|
||||||
this.$post("/api/testcase/list", condition, response => {
|
this.$post("/api/testcase/list", condition, response => {
|
||||||
for (let index in response.data) {
|
for (let index in response.data) {
|
||||||
let test = response.data[index];
|
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;
|
this.apiCaseList = response.data;
|
||||||
});
|
});
|
||||||
|
@ -371,21 +371,16 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let bodyFiles = this.getBodyUploadFiles(row);
|
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.projectId = this.api.projectId;
|
||||||
row.apiDefinitionId = row.apiDefinitionId || this.api.id;
|
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";
|
let url = "/api/testcase/create";
|
||||||
if (row.id) {
|
if (row.id) {
|
||||||
url = "/api/testcase/update";
|
url = "/api/testcase/update";
|
||||||
}
|
}
|
||||||
this.$fileUpload(url, file, bodyFiles, row, () => {
|
this.$fileUpload(url, null, bodyFiles, row, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.getApiTest();
|
this.getApiTest();
|
||||||
|
this.$emit('refresh');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getEnvironments() {
|
getEnvironments() {
|
||||||
|
|
|
@ -10,10 +10,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi";
|
import MsAddCompleteHttpApi from "./complete/AddCompleteHttpApi";
|
||||||
import {RequestFactory, ResponseFactory, Test, Body} from "../model/ApiTestModel";
|
import {ResponseFactory, 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 {getUUID} from "@/common/js/utils";
|
import {getUUID} from "@/common/js/utils";
|
||||||
import {createComponent, Request} from "./jmeter/components";
|
import {createComponent, Request} from "./jmeter/components";
|
||||||
import Sampler from "./jmeter/components/sampler/sampler";
|
import Sampler from "./jmeter/components/sampler/sampler";
|
||||||
|
@ -24,10 +21,8 @@
|
||||||
components: {MsAddCompleteHttpApi},
|
components: {MsAddCompleteHttpApi},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
reqType: RequestFactory.TYPES.HTTP,
|
reqType: Request.TYPES.HTTP,
|
||||||
reqUrl: "",
|
reqUrl: "",
|
||||||
test: new Test(),
|
|
||||||
jmx: new JMX(),
|
|
||||||
request: Sampler,
|
request: Sampler,
|
||||||
response: {},
|
response: {},
|
||||||
headers: [],
|
headers: [],
|
||||||
|
@ -40,20 +35,9 @@
|
||||||
protocol: String,
|
protocol: String,
|
||||||
},
|
},
|
||||||
created() {
|
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) {
|
switch (this.protocol) {
|
||||||
case Request.TYPES.SQL:
|
case Request.TYPES.SQL:
|
||||||
this.request = createComponent("OT");
|
this.request = createComponent("SQL");
|
||||||
break;
|
break;
|
||||||
case Request.TYPES.DUBBO:
|
case Request.TYPES.DUBBO:
|
||||||
this.request = createComponent("JDBCSampler");
|
this.request = createComponent("JDBCSampler");
|
||||||
|
@ -65,15 +49,11 @@
|
||||||
this.createHttp();
|
this.createHttp();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (this.currentApi.response != null && this.currentApi.response != 'null' && this.currentApi.response != undefined) {
|
||||||
threadGroup.hashTree = [this.request];
|
this.response = new ResponseFactory(JSON.parse(this.currentApi.response));
|
||||||
this.response = this.currentApi.response != null ? new ResponseFactory(JSON.parse(this.currentApi.response)) : {
|
} else {
|
||||||
headers: [],
|
this.response = {headers: [], body: new Body(), statusCode: [], type: "HTTP"};
|
||||||
body: new Body(),
|
}
|
||||||
statusCode: [],
|
|
||||||
type: "HTTP"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.currentApi != null && this.currentApi.id != null) {
|
if (this.currentApi != null && this.currentApi.id != null) {
|
||||||
this.reqUrl = "/api/definition/update";
|
this.reqUrl = "/api/definition/update";
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,8 +64,9 @@
|
||||||
methods: {
|
methods: {
|
||||||
runTest(data) {
|
runTest(data) {
|
||||||
data.projectId = this.currentProject.id;
|
data.projectId = this.currentProject.id;
|
||||||
data.request = data.test.request;
|
this.request.hashTree[0].headers = this.headers;
|
||||||
data.response = data.test.response;
|
data.request = this.request;
|
||||||
|
data.response = this.response;
|
||||||
let bodyFiles = this.getBodyUploadFiles(data);
|
let bodyFiles = this.getBodyUploadFiles(data);
|
||||||
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
|
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
@ -94,13 +75,15 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createHttp() {
|
createHttp() {
|
||||||
if (this.currentApi.request != null) {
|
if (this.currentApi.request != undefined && this.currentApi.request != null) {
|
||||||
this.request = JSON.parse(this.currentApi.request);
|
this.request = JSON.parse(this.currentApi.request);
|
||||||
|
this.currentApi.request = this.request;
|
||||||
this.headers = this.request.hashTree[0].headers;
|
this.headers = this.request.hashTree[0].headers;
|
||||||
} else {
|
} else {
|
||||||
let header = createComponent("HeaderManager");
|
let header = createComponent("HeaderManager");
|
||||||
this.request = createComponent("HTTPSamplerProxy");
|
this.request = createComponent("HTTPSamplerProxy");
|
||||||
this.request.hashTree = [header];
|
this.request.hashTree = [header];
|
||||||
|
this.currentApi.request = this.request;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveApi(data) {
|
saveApi(data) {
|
||||||
|
@ -108,7 +91,6 @@
|
||||||
this.request.hashTree[0].headers = this.headers;
|
this.request.hashTree[0].headers = this.headers;
|
||||||
data.request = this.request;
|
data.request = this.request;
|
||||||
data.response = this.response;
|
data.response = this.response;
|
||||||
console.log(data)
|
|
||||||
let bodyFiles = this.getBodyUploadFiles(data);
|
let bodyFiles = this.getBodyUploadFiles(data);
|
||||||
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
|
this.$fileUpload(this.reqUrl, null, bodyFiles, data, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
<div></div>
|
<div></div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import {Scenario} from "../model/ApiTestModel";
|
|
||||||
import {getUUID} from "@/common/js/utils";
|
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 {
|
export default {
|
||||||
name: 'MsRun',
|
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;
|
return bodyUploadFiles;
|
||||||
},
|
},
|
||||||
run() {
|
run() {
|
||||||
let reqObj = {};
|
let testPlan = new TestPlan();
|
||||||
let scenario = new Scenario({requests: this.runData});
|
let threadGroup = new ThreadGroup();
|
||||||
let url = "";
|
threadGroup.hashTree = [];
|
||||||
let reportId = getUUID().substring(0, 8);
|
testPlan.hashTree = [threadGroup];
|
||||||
|
|
||||||
|
this.runData.forEach(item => {
|
||||||
|
threadGroup.hashTree.push(item);
|
||||||
|
})
|
||||||
|
let reqObj = {id: this.reportId, testElement: testPlan};
|
||||||
let bodyFiles = this.getBodyUploadFiles(reqObj);
|
let bodyFiles = this.getBodyUploadFiles(reqObj);
|
||||||
scenario.requests.forEach(item => {
|
let url = "";
|
||||||
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;
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
url = "/api/definition/run/debug";
|
url = "/api/definition/run/debug";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
:autosize="{ minRows: 2, maxRows: 10}"
|
:autosize="{ minRows: 2, maxRows: 10}"
|
||||||
:rows="2" size="small"/>
|
:rows="2" size="small"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
|
@ -48,9 +47,10 @@
|
||||||
<script>
|
<script>
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||||
import {Test} from "../../model/ApiTestModel"
|
|
||||||
import {REQ_METHOD} from "../../model/JsonData";
|
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 {
|
export default {
|
||||||
name: "MsAddBasisHttpApi",
|
name: "MsAddBasisHttpApi",
|
||||||
|
@ -81,22 +81,18 @@
|
||||||
if (valid) {
|
if (valid) {
|
||||||
let bodyFiles = [];
|
let bodyFiles = [];
|
||||||
let url = "/api/definition/create";
|
let url = "/api/definition/create";
|
||||||
let test = new Test();
|
|
||||||
this.httpForm.bodyUploadIds = [];
|
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.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) {
|
if (this.currentModule != null) {
|
||||||
this.httpForm.modulePath = this.currentModule.method != undefined ? this.currentModule.method : null;
|
this.httpForm.modulePath = this.currentModule.method != undefined ? this.currentModule.method : null;
|
||||||
this.httpForm.moduleId = this.currentModule.id;
|
this.httpForm.moduleId = this.currentModule.id;
|
||||||
}
|
}
|
||||||
let jmx = test.toJMX();
|
this.result = this.$fileUpload(url, null, bodyFiles, this.httpForm, () => {
|
||||||
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.httpVisible = false;
|
this.httpVisible = false;
|
||||||
this.$parent.refresh(this.currentModule);
|
this.$parent.refresh(this.currentModule);
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('api_report.request')" prop="url">
|
<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">
|
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-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
@ -127,6 +127,7 @@
|
||||||
},
|
},
|
||||||
setParameter() {
|
setParameter() {
|
||||||
this.httpForm.modulePath = this.getPath(this.httpForm.moduleId);
|
this.httpForm.modulePath = this.getPath(this.httpForm.moduleId);
|
||||||
|
this.httpForm.url = this.httpForm.request.path.value;
|
||||||
},
|
},
|
||||||
saveApi() {
|
saveApi() {
|
||||||
if (this.currentProject === null) {
|
if (this.currentProject === null) {
|
||||||
|
@ -163,7 +164,7 @@
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.ms-http-input {
|
.ms-http-input {
|
||||||
width: 500px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
|
@ -175,7 +176,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ms-http-textarea {
|
.ms-http-textarea {
|
||||||
width: 500px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ms-left-cell {
|
.ms-left-cell {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
||||||
<!-- HTTP 请求参数 -->
|
<!-- HTTP 请求参数 -->
|
||||||
<ms-api-request-form :request="test.request"/>
|
<ms-api-request-form :headers="headers" :request="request"/>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<!-- HTTP 请求返回数据 -->
|
<!-- HTTP 请求返回数据 -->
|
||||||
|
@ -41,14 +41,13 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsApiRequestForm from "../request/ApiRequestForm";
|
import MsApiRequestForm from "../request/ApiRequestForm";
|
||||||
import {Test} from "../../model/ApiTestModel";
|
|
||||||
import MsResponseResult from "../response/ResponseResult";
|
import MsResponseResult from "../response/ResponseResult";
|
||||||
import MsRequestMetric from "../response/RequestMetric";
|
import MsRequestMetric from "../response/RequestMetric";
|
||||||
import {getUUID, getCurrentUser} from "@/common/js/utils";
|
import {getUUID, getCurrentUser} from "@/common/js/utils";
|
||||||
import MsResponseText from "../response/ResponseText";
|
import MsResponseText from "../response/ResponseText";
|
||||||
import MsRun from "../Run";
|
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 {REQ_METHOD} from "../../model/JsonData";
|
||||||
import MsRequestResultTail from "../response/RequestResultTail";
|
import MsRequestResultTail from "../response/RequestResultTail";
|
||||||
|
|
||||||
|
@ -66,10 +65,27 @@
|
||||||
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
|
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
|
||||||
loading: false,
|
loading: false,
|
||||||
debugResultId: "",
|
debugResultId: "",
|
||||||
test: new Test(),
|
|
||||||
runData: [],
|
runData: [],
|
||||||
|
headers: [],
|
||||||
reportId: "",
|
reportId: "",
|
||||||
reqOptions: REQ_METHOD,
|
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: {
|
watch: {
|
||||||
|
@ -85,15 +101,21 @@
|
||||||
this.runDebug();
|
this.runDebug();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
createHttp() {
|
||||||
|
let header = createComponent("HeaderManager");
|
||||||
|
this.request = createComponent("HTTPSamplerProxy");
|
||||||
|
this.request.hashTree = [header];
|
||||||
|
},
|
||||||
runDebug() {
|
runDebug() {
|
||||||
this.$refs['debugForm'].validate((valid) => {
|
this.$refs['debugForm'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.test.request.url = this.debugForm.url;
|
this.request.url = this.debugForm.url;
|
||||||
this.test.request.method = this.debugForm.method;
|
this.request.method.value = this.debugForm.method;
|
||||||
this.test.request.name = getUUID().substring(0, 8);
|
this.request.hashTree[0].headers = this.headers;
|
||||||
|
this.request.name = getUUID().substring(0, 8);
|
||||||
this.runData = [];
|
this.runData = [];
|
||||||
this.runData.push(this.test.request);
|
this.runData.push(this.request);
|
||||||
/*触发执行操作*/
|
/*触发执行操作*/
|
||||||
this.reportId = getUUID().substring(0, 8);
|
this.reportId = getUUID().substring(0, 8);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +129,7 @@
|
||||||
saveAs() {
|
saveAs() {
|
||||||
this.$refs['debugForm'].validate((valid) => {
|
this.$refs['debugForm'].validate((valid) => {
|
||||||
if (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.userId = getCurrentUser().id;
|
||||||
this.debugForm.status = "Underway";
|
this.debugForm.status = "Underway";
|
||||||
this.$emit('saveAs', this.debugForm);
|
this.$emit('saveAs', this.debugForm);
|
||||||
|
|
|
@ -15,7 +15,7 @@ const DEFAULT_OPTIONS = {
|
||||||
export default class HeaderManager extends Configuration {
|
export default class HeaderManager extends Configuration {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
|
this.type = "HeaderManager";
|
||||||
this.headers = [];
|
this.headers = [];
|
||||||
let collectionProp = this.initCollectionProp('HeaderManager.headers');
|
let collectionProp = this.initCollectionProp('HeaderManager.headers');
|
||||||
collectionProp.forEach(elementProp => {
|
collectionProp.forEach(elementProp => {
|
||||||
|
|
|
@ -14,7 +14,8 @@ const DEFAULT_OPTIONS = {
|
||||||
export default class JSR223PostProcessor extends PostProcessor {
|
export default class JSR223PostProcessor extends PostProcessor {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.scriptLanguage = this.initStringProp("scriptLanguage", "groovy")
|
this.type = "JSR223PostProcessor";
|
||||||
|
this.scriptLanguage = this.initStringProp("scriptLanguage", "java")
|
||||||
this.parameters = this.initStringProp("parameters")
|
this.parameters = this.initStringProp("parameters")
|
||||||
this.filename = this.initStringProp("filename")
|
this.filename = this.initStringProp("filename")
|
||||||
this.cacheKey = this.initStringProp("cacheKey", true)
|
this.cacheKey = this.initStringProp("cacheKey", true)
|
||||||
|
|
|
@ -14,7 +14,8 @@ const DEFAULT_OPTIONS = {
|
||||||
export default class JSR223PreProcessor extends PostProcessor {
|
export default class JSR223PreProcessor extends PostProcessor {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.scriptLanguage = this.initStringProp("scriptLanguage", "groovy")
|
this.type = "JSR223PreProcessor";
|
||||||
|
this.scriptLanguage = this.initStringProp("scriptLanguage", "java")
|
||||||
this.parameters = this.initStringProp("parameters")
|
this.parameters = this.initStringProp("parameters")
|
||||||
this.filename = this.initStringProp("filename")
|
this.filename = this.initStringProp("filename")
|
||||||
this.cacheKey = this.initStringProp("cacheKey", true)
|
this.cacheKey = this.initStringProp("cacheKey", true)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {boolProp, elementProp, stringProp} from "../../../props";
|
import {boolProp, elementProp, stringProp} from "../../../props";
|
||||||
import Sampler from "../sampler";
|
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 = {
|
const DEFAULT_OPTIONS = {
|
||||||
options: {
|
options: {
|
||||||
|
@ -18,7 +18,7 @@ export default class HTTPSamplerProxy extends Sampler {
|
||||||
this.protocol = this.initStringProp('HTTPSampler.protocol', "https");
|
this.protocol = this.initStringProp('HTTPSampler.protocol', "https");
|
||||||
this.domain = this.initStringProp('HTTPSampler.domain');
|
this.domain = this.initStringProp('HTTPSampler.domain');
|
||||||
this.port = this.initStringProp('HTTPSampler.port');
|
this.port = this.initStringProp('HTTPSampler.port');
|
||||||
|
this.type = "HTTPSamplerProxy";
|
||||||
this.method = this.initStringProp('HTTPSampler.method', "GET");
|
this.method = this.initStringProp('HTTPSampler.method', "GET");
|
||||||
this.path = this.initStringProp('HTTPSampler.path');
|
this.path = this.initStringProp('HTTPSampler.path');
|
||||||
this.contentEncoding = this.initStringProp('HTTPSampler.contentEncoding', "UTF-8");
|
this.contentEncoding = this.initStringProp('HTTPSampler.contentEncoding', "UTF-8");
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class TestPlan extends HashTreeElement {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.$type = TYPE;
|
this.$type = TYPE;
|
||||||
|
this.type = TYPE;
|
||||||
this.functionalMode = this.initBoolProp('TestPlan.functional_mode', false);
|
this.functionalMode = this.initBoolProp('TestPlan.functional_mode', false);
|
||||||
this.serializeThreadGroups = this.initBoolProp('TestPlan.serialize_threadgroups', false);
|
this.serializeThreadGroups = this.initBoolProp('TestPlan.serialize_threadgroups', false);
|
||||||
this.tearDownOnShutdown = this.initBoolProp('TestPlan.tearDown_on_shutdown', true);
|
this.tearDownOnShutdown = this.initBoolProp('TestPlan.tearDown_on_shutdown', true);
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default class ThreadGroup extends HashTreeElement {
|
||||||
constructor(options = DEFAULT_OPTIONS) {
|
constructor(options = DEFAULT_OPTIONS) {
|
||||||
super(options);
|
super(options);
|
||||||
this.$type = TYPE;
|
this.$type = TYPE;
|
||||||
|
this.type = TYPE;
|
||||||
this.onSampleError = this.initStringProp('ThreadGroup.on_sample_error', 'continue');
|
this.onSampleError = this.initStringProp('ThreadGroup.on_sample_error', 'continue');
|
||||||
this.numThreads = this.initStringProp('ThreadGroup.num_threads', 1);
|
this.numThreads = this.initStringProp('ThreadGroup.num_threads', 1);
|
||||||
this.rampTime = this.initStringProp('ThreadGroup.ramp_time', 1);
|
this.rampTime = this.initStringProp('ThreadGroup.ramp_time', 1);
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,11 +3,9 @@
|
||||||
<el-row>
|
<el-row>
|
||||||
<div>
|
<div>
|
||||||
<el-button class="ms-left-buttion" size="small" :type="styleType" plain>{{title}}</el-button>
|
<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"
|
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive" style="margin-left: 20px"/>
|
||||||
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>
|
||||||
<el-input size="small" v-model="jsr223ProcessorData.name"
|
|
||||||
class="ms-api-header-select" style="width: 380px"/>
|
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-collapse-transition>
|
<el-collapse-transition>
|
||||||
|
@ -24,7 +22,7 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20" class="script-content">
|
<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"
|
:read-only="isReadOnly"
|
||||||
:data.sync="jsr223ProcessorData.script.value" theme="eclipse" :modes="['java','python']"
|
:data.sync="jsr223ProcessorData.script.value" theme="eclipse" :modes="['java','python']"
|
||||||
ref="codeEdit"/>
|
ref="codeEdit"/>
|
||||||
|
@ -90,7 +88,7 @@
|
||||||
],
|
],
|
||||||
isCodeEditAlive: true,
|
isCodeEditAlive: true,
|
||||||
languages: [
|
languages: [
|
||||||
'beanshell', "python"
|
'java', "python"
|
||||||
],
|
],
|
||||||
codeEditModeMap: {
|
codeEditModeMap: {
|
||||||
beanshell: 'java',
|
beanshell: 'java',
|
||||||
|
@ -102,16 +100,6 @@
|
||||||
this.jsr223ProcessorData = this.jsr223Processor;
|
this.jsr223ProcessorData = this.jsr223Processor;
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default:
|
|
||||||
"create",
|
|
||||||
}
|
|
||||||
,
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
}
|
|
||||||
,
|
|
||||||
isReadOnly: {
|
isReadOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default:
|
default:
|
||||||
|
@ -149,21 +137,20 @@
|
||||||
this.jsr223ProcessorData.script += ';';
|
this.jsr223ProcessorData.script += ';';
|
||||||
}
|
}
|
||||||
this.reload();
|
this.reload();
|
||||||
}
|
},
|
||||||
,
|
remove(){
|
||||||
|
this.$emit('remove', this.jsr223ProcessorData);
|
||||||
|
},
|
||||||
reload() {
|
reload() {
|
||||||
this.isCodeEditAlive = false;
|
this.isCodeEditAlive = false;
|
||||||
this.$nextTick(() => (this.isCodeEditAlive = true));
|
this.$nextTick(() => (this.isCodeEditAlive = true));
|
||||||
}
|
},
|
||||||
,
|
|
||||||
languageChange(language) {
|
languageChange(language) {
|
||||||
this.jsr223ProcessorData.language = language;
|
this.jsr223ProcessorData.language = language;
|
||||||
}
|
},
|
||||||
,
|
|
||||||
changeActive() {
|
changeActive() {
|
||||||
this.active = !this.active;
|
this.active = !this.active;
|
||||||
}
|
},
|
||||||
,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
|
|
||||||
<!--query 参数-->
|
<!--query 参数-->
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.query_param')" name="parameters">
|
<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>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!--REST 参数-->
|
<!--REST 参数-->
|
||||||
<el-tab-pane :label="$t('api_test.definition.request.rest_param')" name="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>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!--请求体-->
|
<!--请求体-->
|
||||||
|
@ -32,10 +32,10 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData">
|
<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"/>
|
: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"/>
|
:jsr223-processor="row"/>
|
||||||
|
|
||||||
<!--<ms-api-assertions v-if="row.label.indexOf('Assertion')>0" :is-read-only="isReadOnly" :request="request"/>-->
|
<!--<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.request.hashTree.push(jsonPostProcessor);
|
||||||
this.reload();
|
this.reload();
|
||||||
},
|
},
|
||||||
|
remove(row) {
|
||||||
|
let index = this.request.hashTree.indexOf(row);
|
||||||
|
this.request.hashTree.splice(index, 1);
|
||||||
|
this.reload();
|
||||||
|
},
|
||||||
reload() {
|
reload() {
|
||||||
this.isReloadData = true
|
this.isReloadData = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
|
<p class="tip">{{$t('test_track.plan_view.base_info')}} </p>
|
||||||
<!-- 请求方法 -->
|
<!-- 请求方法 -->
|
||||||
<el-form-item :label="$t('api_report.request')" prop="method">
|
<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-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 执行环境 -->
|
<!-- 执行环境 -->
|
||||||
<el-form-item prop="environmentId">
|
<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')"
|
:placeholder="$t('api_test.definition.request.run_env')"
|
||||||
@change="environmentChange" clearable>
|
@change="environmentChange" clearable>
|
||||||
<el-option v-for="(environment, index) in environments" :key="index"
|
<el-option v-for="(environment, index) in environments" :key="index"
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<!-- 请求地址 -->
|
<!-- 请求地址 -->
|
||||||
<el-form-item prop="url">
|
<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"/>
|
size="small" :disabled="false"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
||||||
<!-- HTTP 请求参数 -->
|
<!-- HTTP 请求参数 -->
|
||||||
<ms-api-request-form :request="api.request"/>
|
<ms-api-request-form :headers="api.request.hashTree[0].headers" :request="api.request"/>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
<!--返回结果-->
|
<!--返回结果-->
|
||||||
|
@ -149,11 +149,9 @@
|
||||||
this.$refs['apiData'].validate((valid) => {
|
this.$refs['apiData'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.api.test.request.url = this.api.url;
|
this.api.request.name = this.api.id;
|
||||||
this.api.test.request.method = this.api.method;
|
|
||||||
this.api.test.request.name = this.api.id;
|
|
||||||
this.runData = [];
|
this.runData = [];
|
||||||
this.runData.push(this.api.test.request);
|
this.runData.push(this.api.request);
|
||||||
/*触发执行操作*/
|
/*触发执行操作*/
|
||||||
this.reportId = getUUID().substring(0, 8);
|
this.reportId = getUUID().substring(0, 8);
|
||||||
}
|
}
|
||||||
|
@ -197,11 +195,7 @@
|
||||||
saveAsCase() {
|
saveAsCase() {
|
||||||
this.isHide = false;
|
this.isHide = false;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
let testCase = {};
|
this.$refs.caseList.addCase();
|
||||||
testCase.request = this.api.request;
|
|
||||||
testCase.apiDefinitionId = this.api.id;
|
|
||||||
testCase.priority = "P0";
|
|
||||||
this.$refs.caseList.createCase(testCase);
|
|
||||||
},
|
},
|
||||||
saveAsApi() {
|
saveAsApi() {
|
||||||
let data = {};
|
let data = {};
|
||||||
|
@ -216,17 +210,14 @@
|
||||||
updateApi() {
|
updateApi() {
|
||||||
let url = "/api/definition/update";
|
let url = "/api/definition/update";
|
||||||
let bodyFiles = this.getBodyUploadFiles();
|
let bodyFiles = this.getBodyUploadFiles();
|
||||||
let jmx = this.api.test.toJMX();
|
this.$fileUpload(url, null, bodyFiles, this.api, () => {
|
||||||
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.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.$emit('saveApi', this.api);
|
this.$emit('saveApi', this.api);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
selectTestCase(item) {
|
selectTestCase(item) {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
this.api.request = new RequestFactory(JSON.parse(item.request));
|
this.api.request = item.request;
|
||||||
} else {
|
} else {
|
||||||
this.api.request = this.currentRequest;
|
this.api.request = this.currentRequest;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +257,7 @@
|
||||||
environmentChange(value) {
|
environmentChange(value) {
|
||||||
for (let i in this.environments) {
|
for (let i in this.environments) {
|
||||||
if (this.environments[i].id === value) {
|
if (this.environments[i].id === value) {
|
||||||
this.api.environment = this.environments[i];
|
this.api.request.useEnvironment = this.environments[i].id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,6 +277,7 @@
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.api = this.apiData;
|
this.api = this.apiData;
|
||||||
|
this.currentRequest = this.api.request;
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
this.getResult();
|
this.getResult();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue