refactor(接口测试): 后台转换JMX
This commit is contained in:
parent
bd577770a4
commit
5a3310a837
|
@ -19,7 +19,7 @@
|
|||
<java.version>1.8</java.version>
|
||||
<jmeter.version>5.2.1</jmeter.version>
|
||||
<nacos.version>1.1.3</nacos.version>
|
||||
<dubbo.version>2.7.7</dubbo.version>
|
||||
<dubbo.version>2.7.8</dubbo.version>
|
||||
<graalvm.version>20.1.0</graalvm.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import static io.metersphere.commons.utils.JsonPathUtils.getListJson;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.*;
|
||||
|
@ -14,18 +16,15 @@ import io.metersphere.commons.utils.SessionUtils;
|
|||
import io.metersphere.controller.request.QueryScheduleRequest;
|
||||
import io.metersphere.dto.ScheduleDao;
|
||||
import io.metersphere.service.CheckOwnerService;
|
||||
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import static io.metersphere.commons.utils.JsonPathUtils.getListJson;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@RestController
|
||||
|
@ -76,18 +75,19 @@ public class APITestController {
|
|||
}
|
||||
|
||||
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
|
||||
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiTestService.create(request, file, bodyFiles);
|
||||
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiTestService.create(request, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/create/merge", consumes = {"multipart/form-data"})
|
||||
public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "selectIds") List<String> selectIds) {
|
||||
apiTestService.mergeCreate(request, file, selectIds);
|
||||
public void mergeCreate(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "selectIds") List<String> selectIds) {
|
||||
apiTestService.mergeCreate(request, selectIds);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
|
||||
public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
public void update(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
checkownerService.checkApiTestOwner(request.getId());
|
||||
apiTestService.update(request, file, bodyFiles);
|
||||
apiTestService.update(request, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/copy")
|
||||
|
@ -101,7 +101,6 @@ public class APITestController {
|
|||
return apiTestService.get(testId);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteAPITestRequest request) {
|
||||
String testId = request.getId();
|
||||
|
@ -109,14 +108,19 @@ public class APITestController {
|
|||
apiTestService.delete(testId);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/jmx")
|
||||
public String getJMX(@RequestBody SaveAPITestRequest request) {
|
||||
return apiTestService.getJMX(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
public String run(@RequestBody SaveAPITestRequest request) {
|
||||
return apiTestService.run(request);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
|
||||
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
return apiTestService.runDebug(request, file, bodyFiles);
|
||||
public String runDebug(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
return apiTestService.runDebug(request, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/checkName")
|
||||
|
@ -137,7 +141,7 @@ public class APITestController {
|
|||
|
||||
@PostMapping("/list/schedule/{goPage}/{pageSize}")
|
||||
public List<ScheduleDao> listSchedule(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryScheduleRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
PageHelper.startPage(goPage, pageSize, true);
|
||||
return apiTestService.listSchedule(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -10,4 +11,20 @@ public class Body {
|
|||
private String raw;
|
||||
private String format;
|
||||
private List<KeyValue> kvs;
|
||||
|
||||
private final static String KV = "KeyValue";
|
||||
private final static String FORM_DATA = "Form Data";
|
||||
private final static String RAW = "Raw";
|
||||
|
||||
public boolean isValid() {
|
||||
if (this.isKV()) {
|
||||
return kvs.stream().anyMatch(KeyValue::isValid);
|
||||
} else {
|
||||
return StringUtils.isNotBlank(raw);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isKV() {
|
||||
return StringUtils.equals(type, KV);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class HttpConfig {
|
||||
private String socket;
|
||||
private String domain;
|
||||
private String protocol = "https";
|
||||
private int port;
|
||||
private List<KeyValue> headers;
|
||||
}
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario;
|
|||
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -14,6 +15,7 @@ public class KeyValue {
|
|||
private String description;
|
||||
private String contentType;
|
||||
private boolean enable;
|
||||
private boolean encode = true;
|
||||
|
||||
public KeyValue() {
|
||||
this.enable = true;
|
||||
|
@ -31,4 +33,12 @@ public class KeyValue {
|
|||
this.enable = true;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return (StringUtils.isNotBlank(name) || StringUtils.isNotBlank(value)) && !StringUtils.equalsIgnoreCase(type, "file");
|
||||
}
|
||||
|
||||
public boolean isFile() {
|
||||
return (StringUtils.isNotBlank(name) || StringUtils.isNotBlank(value)) && StringUtils.equalsIgnoreCase(type, "file");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ public class Scenario {
|
|||
private String name;
|
||||
private String url;
|
||||
private String environmentId;
|
||||
private Boolean enableCookieShare;
|
||||
private boolean enableCookieShare;
|
||||
private List<KeyValue> variables;
|
||||
private List<KeyValue> headers;
|
||||
private List<Request> requests;
|
||||
private DubboConfig dubboConfig;
|
||||
private TCPConfig tcpConfig;
|
||||
private List<DatabaseConfig> databaseConfigs;
|
||||
private Boolean enable;
|
||||
private boolean enable = true;
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import lombok.Data;
|
|||
public class TCPConfig {
|
||||
private String classname;
|
||||
private String server;
|
||||
private Integer port;
|
||||
private Integer ctimeout;
|
||||
private Integer timeout;
|
||||
private Boolean reUseConnection;
|
||||
private Boolean nodelay;
|
||||
private Boolean closeConnection;
|
||||
private String port;
|
||||
private String ctimeout;
|
||||
private String timeout;
|
||||
private boolean reUseConnection;
|
||||
private boolean nodelay;
|
||||
private boolean closeConnection;
|
||||
private String soLinger;
|
||||
private String eolByte;
|
||||
private String username;
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.assertions;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
|
@ -11,4 +12,8 @@ public class AssertionDuration extends AssertionType {
|
|||
public AssertionDuration() {
|
||||
setType(AssertionType.DURATION);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return value > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.assertions;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
|
@ -17,4 +18,8 @@ public class AssertionJSR223 extends AssertionType {
|
|||
public AssertionJSR223() {
|
||||
setType(AssertionType.JSR223);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(script) && StringUtils.isNotBlank(language);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.assertions;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
|
@ -13,4 +14,8 @@ public class AssertionJsonPath extends AssertionType {
|
|||
public AssertionJsonPath() {
|
||||
setType(AssertionType.JSON_PATH);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.assertions;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
|
@ -9,9 +10,13 @@ public class AssertionRegex extends AssertionType {
|
|||
private String subject;
|
||||
private String expression;
|
||||
private String description;
|
||||
private Boolean assumeSuccess;
|
||||
private boolean assumeSuccess;
|
||||
|
||||
public AssertionRegex() {
|
||||
setType(AssertionType.REGEX);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(subject) && StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,56 @@
|
|||
package io.metersphere.api.dto.scenario.controller;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@Data
|
||||
public class IfController {
|
||||
private String type;
|
||||
private String id;
|
||||
private Boolean enable;
|
||||
private boolean enable = true;
|
||||
private String variable;
|
||||
private String operator;
|
||||
private String value;
|
||||
|
||||
public boolean isValid() {
|
||||
if (StringUtils.contains(operator, "empty")) {
|
||||
return StringUtils.isNotBlank(variable);
|
||||
}
|
||||
return StringUtils.isNotBlank(variable) && StringUtils.isNotBlank(operator) && StringUtils.isNotBlank(value);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
if (isValid()) {
|
||||
String label = variable + " " + operator;
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
label += " " + this.value;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
String variable = "\"" + this.variable + "\"";
|
||||
String operator = this.operator;
|
||||
String value = "\"" + this.value + "\"";
|
||||
|
||||
if (StringUtils.contains(operator, "~")) {
|
||||
value = "\".*" + this.value + ".*\"";
|
||||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is empty")) {
|
||||
variable = "empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is not empty")) {
|
||||
variable = "!empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
||||
return "${__jexl3(" + variable + operator + value + ")}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.api.dto.scenario.environment;
|
||||
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CommonConfig {
|
||||
private List<KeyValue> variables;
|
||||
private boolean enableHost;
|
||||
private List<Host> hosts;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package io.metersphere.api.dto.scenario.environment;
|
||||
|
||||
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||
import io.metersphere.api.dto.scenario.HttpConfig;
|
||||
import io.metersphere.api.dto.scenario.TCPConfig;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class EnvironmentConfig {
|
||||
private CommonConfig commonConfig;
|
||||
private HttpConfig httpConfig;
|
||||
private List<DatabaseConfig> databaseConfigs;
|
||||
private TCPConfig tcpConfig;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.api.dto.scenario.environment;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Host {
|
||||
private String ip;
|
||||
private String domain;
|
||||
private String status;
|
||||
private String annotation;
|
||||
private String uuid;
|
||||
}
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario.extract;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
|
@ -10,5 +11,9 @@ public class ExtractCommon extends ExtractType {
|
|||
private String value; // value: ${variable}
|
||||
private String expression;
|
||||
private String description;
|
||||
private Boolean multipleMatching;
|
||||
private boolean multipleMatching;
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(variable) && StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,23 +18,23 @@ import java.util.List;
|
|||
public class DubboRequest extends Request {
|
||||
// type 必须放最前面,以便能够转换正确的类
|
||||
private String type = RequestType.DUBBO;
|
||||
@JSONField(ordinal = 2)
|
||||
@JSONField(ordinal = 52)
|
||||
private String protocol;
|
||||
@JsonProperty(value = "interface")
|
||||
@JSONField(ordinal = 3, name = "interface")
|
||||
@JSONField(ordinal = 53, name = "interface")
|
||||
private String _interface;
|
||||
@JSONField(ordinal = 4)
|
||||
@JSONField(ordinal = 54)
|
||||
private String method;
|
||||
|
||||
@JSONField(ordinal = 5)
|
||||
@JSONField(ordinal = 55)
|
||||
private ConfigCenter configCenter;
|
||||
@JSONField(ordinal = 6)
|
||||
@JSONField(ordinal = 56)
|
||||
private RegistryCenter registryCenter;
|
||||
@JSONField(ordinal = 7)
|
||||
@JSONField(ordinal = 57)
|
||||
private ConsumerAndService consumerAndService;
|
||||
|
||||
@JSONField(ordinal = 8)
|
||||
@JSONField(ordinal = 58)
|
||||
private List<KeyValue> args;
|
||||
@JSONField(ordinal = 9)
|
||||
@JSONField(ordinal = 59)
|
||||
private List<KeyValue> attachmentArgs;
|
||||
}
|
||||
|
|
|
@ -15,26 +15,24 @@ import java.util.List;
|
|||
public class HttpRequest extends Request {
|
||||
// type 必须放最前面,以便能够转换正确的类
|
||||
private String type = RequestType.HTTP;
|
||||
@JSONField(ordinal = 2)
|
||||
@JSONField(ordinal = 50)
|
||||
private String url;
|
||||
@JSONField(ordinal = 3)
|
||||
@JSONField(ordinal = 51)
|
||||
private String method;
|
||||
@JSONField(ordinal = 4)
|
||||
@JSONField(ordinal = 52)
|
||||
private String path;
|
||||
@JSONField(ordinal = 5)
|
||||
private Boolean useEnvironment;
|
||||
@JSONField(ordinal = 6)
|
||||
@JSONField(ordinal = 53)
|
||||
private List<KeyValue> parameters;
|
||||
@JSONField(ordinal = 7)
|
||||
@JSONField(ordinal = 54)
|
||||
private List<KeyValue> headers;
|
||||
@JSONField(ordinal = 8)
|
||||
@JSONField(ordinal = 55)
|
||||
private Body body;
|
||||
@JSONField(ordinal = 14)
|
||||
private Long connectTimeout;
|
||||
@JSONField(ordinal = 15)
|
||||
private Long responseTimeout;
|
||||
@JSONField(ordinal = 16)
|
||||
private Boolean followRedirects;
|
||||
@JSONField(ordinal = 17)
|
||||
private Boolean doMultipartPost;
|
||||
@JSONField(ordinal = 56)
|
||||
private String connectTimeout;
|
||||
@JSONField(ordinal = 57)
|
||||
private String responseTimeout;
|
||||
@JSONField(ordinal = 58)
|
||||
private boolean followRedirects;
|
||||
@JSONField(ordinal = 59)
|
||||
private boolean doMultipartPost;
|
||||
}
|
||||
|
|
|
@ -22,22 +22,25 @@ import lombok.Data;
|
|||
@JSONType(seeAlso = {HttpRequest.class, DubboRequest.class, SqlRequest.class, TCPRequest.class}, typeKey = "type")
|
||||
@Data
|
||||
public abstract class Request {
|
||||
private String type;
|
||||
@JSONField(ordinal = 1)
|
||||
private String id;
|
||||
@JSONField(ordinal = 2)
|
||||
private String name;
|
||||
@JSONField(ordinal = 3)
|
||||
private Boolean enable;
|
||||
private boolean enable = true;
|
||||
@JSONField(ordinal = 4)
|
||||
private Assertions assertions;
|
||||
private boolean useEnvironment;
|
||||
@JSONField(ordinal = 5)
|
||||
private Extract extract;
|
||||
private Assertions assertions;
|
||||
@JSONField(ordinal = 6)
|
||||
private JSR223PreProcessor jsr223PreProcessor;
|
||||
private Extract extract;
|
||||
@JSONField(ordinal = 7)
|
||||
private JSR223PostProcessor jsr223PostProcessor;
|
||||
private JSR223PreProcessor jsr223PreProcessor;
|
||||
@JSONField(ordinal = 8)
|
||||
private IfController controller;
|
||||
private JSR223PostProcessor jsr223PostProcessor;
|
||||
@JSONField(ordinal = 9)
|
||||
private IfController controller;
|
||||
@JSONField(ordinal = 10)
|
||||
private ConstantTimer timer;
|
||||
}
|
||||
|
|
|
@ -14,20 +14,16 @@ import java.util.List;
|
|||
public class SqlRequest extends Request {
|
||||
// type 必须放最前面,以便能够转换正确的类
|
||||
private String type = RequestType.SQL;
|
||||
@JSONField(ordinal = 3)
|
||||
@JSONField(ordinal = 50)
|
||||
private String dataSource;
|
||||
@JSONField(ordinal = 4)
|
||||
@JSONField(ordinal = 51)
|
||||
private String query;
|
||||
@JSONField(ordinal = 5)
|
||||
@JSONField(ordinal = 52)
|
||||
private long queryTimeout;
|
||||
@JSONField(ordinal = 6)
|
||||
private Boolean useEnvironment;
|
||||
@JSONField(ordinal = 7)
|
||||
private Boolean followRedirects;
|
||||
@JSONField(ordinal = 13)
|
||||
@JSONField(ordinal = 53)
|
||||
private String resultVariable;
|
||||
@JSONField(ordinal = 14)
|
||||
@JSONField(ordinal = 54)
|
||||
private String variableNames;
|
||||
@JSONField(ordinal = 15)
|
||||
@JSONField(ordinal = 55)
|
||||
private List<KeyValue> variables;
|
||||
}
|
||||
|
|
|
@ -11,24 +11,22 @@ import lombok.EqualsAndHashCode;
|
|||
public class TCPRequest extends Request {
|
||||
// type 必须放最前面,以便能够转换正确的类
|
||||
private String type = RequestType.TCP;
|
||||
@JSONField(ordinal = 50)
|
||||
private Boolean useEnvironment;
|
||||
@JSONField(ordinal = 51)
|
||||
private String classname;
|
||||
@JSONField(ordinal = 52)
|
||||
private String server;
|
||||
@JSONField(ordinal = 53)
|
||||
private Integer port;
|
||||
private String port;
|
||||
@JSONField(ordinal = 54)
|
||||
private Integer ctimeout;
|
||||
private String ctimeout;
|
||||
@JSONField(ordinal = 55)
|
||||
private Integer timeout;
|
||||
private String timeout;
|
||||
@JSONField(ordinal = 56)
|
||||
private Boolean reUseConnection;
|
||||
private boolean reUseConnection;
|
||||
@JSONField(ordinal = 57)
|
||||
private Boolean nodelay;
|
||||
private boolean nodelay;
|
||||
@JSONField(ordinal = 58)
|
||||
private Boolean closeConnection;
|
||||
private boolean closeConnection;
|
||||
@JSONField(ordinal = 59)
|
||||
private String soLinger;
|
||||
@JSONField(ordinal = 60)
|
||||
|
|
|
@ -6,6 +6,6 @@ import lombok.Data;
|
|||
public class ConstantTimer {
|
||||
private String type;
|
||||
private String id;
|
||||
private Boolean enable;
|
||||
private boolean enable = true;
|
||||
private String delay;
|
||||
}
|
||||
|
|
|
@ -42,14 +42,13 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
private final List<SampleResult> queue = new ArrayList<>();
|
||||
|
||||
private APITestService apiTestService;
|
||||
|
||||
private APIReportService apiReportService;
|
||||
|
||||
private TestPlanTestCaseService testPlanTestCaseService;
|
||||
|
||||
private NoticeService noticeService;
|
||||
|
||||
private MailService mailService;
|
||||
private DingTaskService dingTaskService;
|
||||
private WxChatTaskService wxChatTaskService;
|
||||
private SystemParameterService systemParameterService;
|
||||
|
||||
public String runMode = ApiRunMode.RUN.name();
|
||||
|
||||
|
@ -82,6 +81,18 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
if (mailService == null) {
|
||||
LogUtil.error("mailService is required");
|
||||
}
|
||||
dingTaskService = CommonBeanFactory.getBean(DingTaskService.class);
|
||||
if (dingTaskService == null) {
|
||||
LogUtil.error("dingTaskService is required");
|
||||
}
|
||||
wxChatTaskService = CommonBeanFactory.getBean(WxChatTaskService.class);
|
||||
if (wxChatTaskService == null) {
|
||||
LogUtil.error("wxChatTaskService is required");
|
||||
}
|
||||
systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
if (systemParameterService == null) {
|
||||
LogUtil.error("systemParameterService is required");
|
||||
}
|
||||
super.setupTest(context);
|
||||
}
|
||||
|
||||
|
@ -146,7 +157,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
queue.clear();
|
||||
super.teardownTest(context);
|
||||
|
||||
TestPlanTestCaseService testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
||||
List<String> ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
|
||||
if (ids.size() > 0) {
|
||||
try {
|
||||
|
@ -167,12 +177,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
|
||||
}
|
||||
|
||||
private static void sendTask(ApiTestReport report, TestResult testResult) {
|
||||
NoticeService noticeService = CommonBeanFactory.getBean(NoticeService.class);
|
||||
MailService mailService = CommonBeanFactory.getBean(MailService.class);
|
||||
DingTaskService dingTaskService = CommonBeanFactory.getBean(DingTaskService.class);
|
||||
WxChatTaskService wxChatTaskService = CommonBeanFactory.getBean(WxChatTaskService.class);
|
||||
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
private void sendTask(ApiTestReport report, TestResult testResult) {
|
||||
if (StringUtils.equals(NoticeConstants.API, report.getTriggerMode()) || StringUtils.equals(NoticeConstants.SCHEDULE, report.getTriggerMode())) {
|
||||
List<String> userIds = new ArrayList<>();
|
||||
List<MessageDetail> taskList = new ArrayList<>();
|
||||
|
|
|
@ -0,0 +1,730 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.gui.DubboSampleGui;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
|
||||
import io.github.ningyu.jmeter.plugin.util.Constants;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.dto.scenario.assertions.*;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.dto.scenario.environment.Host;
|
||||
import io.metersphere.api.dto.scenario.extract.*;
|
||||
import io.metersphere.api.dto.scenario.request.*;
|
||||
import io.metersphere.api.service.ApiTestEnvironmentService;
|
||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.apache.jmeter.assertions.DurationAssertion;
|
||||
import org.apache.jmeter.assertions.JSONPathAssertion;
|
||||
import org.apache.jmeter.assertions.JSR223Assertion;
|
||||
import org.apache.jmeter.assertions.ResponseAssertion;
|
||||
import org.apache.jmeter.config.Arguments;
|
||||
import org.apache.jmeter.config.ConfigTestElement;
|
||||
import org.apache.jmeter.control.IfController;
|
||||
import org.apache.jmeter.control.LoopController;
|
||||
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
||||
import org.apache.jmeter.extractor.RegexExtractor;
|
||||
import org.apache.jmeter.extractor.XPath2Extractor;
|
||||
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
|
||||
import org.apache.jmeter.modifiers.JSR223PreProcessor;
|
||||
import org.apache.jmeter.protocol.http.control.CookieManager;
|
||||
import org.apache.jmeter.protocol.http.control.DNSCacheManager;
|
||||
import org.apache.jmeter.protocol.http.control.Header;
|
||||
import org.apache.jmeter.protocol.http.control.HeaderManager;
|
||||
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.protocol.jdbc.config.DataSourceElement;
|
||||
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
|
||||
import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jmeter.testelement.TestPlan;
|
||||
import org.apache.jmeter.threads.ThreadGroup;
|
||||
import org.apache.jmeter.timers.ConstantTimer;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.apache.jorphan.collections.ListedHashTree;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Component
|
||||
public class JMXGenerator {
|
||||
|
||||
@Resource
|
||||
private ApiTestEnvironmentService environmentService;
|
||||
|
||||
public HashTree parse(String testId, String testName, List<Scenario> scenarios) {
|
||||
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
||||
final HashTree testPlanHashTree = jmeterTestPlanHashTree.add(testPlan(testName));
|
||||
|
||||
scenarios.stream().filter(Scenario::isEnable).forEach(scenario -> {
|
||||
final HashTree threadGroupHashTree = testPlanHashTree.add(threadGroup(scenario.getName()));
|
||||
|
||||
EnvironmentConfig config = getEnvironmentConfig(scenario.getEnvironmentId());
|
||||
|
||||
// 场景变量
|
||||
if (CollectionUtils.isNotEmpty(scenario.getVariables())) {
|
||||
threadGroupHashTree.add(arguments(scenario.getName() + " Variables", scenario.getVariables()));
|
||||
}
|
||||
// 场景请求头
|
||||
if (CollectionUtils.isNotEmpty(scenario.getHeaders())) {
|
||||
threadGroupHashTree.add(headerManager(scenario.getName() + " Headers", scenario.getHeaders()));
|
||||
}
|
||||
// 共享Cookie
|
||||
if (scenario.isEnableCookieShare()) {
|
||||
threadGroupHashTree.add(cookieManager(scenario));
|
||||
}
|
||||
// 场景JDBCDataSource
|
||||
final Map<String, String> databaseConfigMap = new HashMap<>();
|
||||
if (CollectionUtils.isNotEmpty(scenario.getDatabaseConfigs())) {
|
||||
scenario.getDatabaseConfigs().forEach(databaseConfig -> {
|
||||
threadGroupHashTree.add(jdbcDataSource(databaseConfig));
|
||||
databaseConfigMap.put(databaseConfig.getId(), databaseConfig.getName());
|
||||
});
|
||||
}
|
||||
// 场景TCP Config
|
||||
threadGroupHashTree.add(tcpConfig(scenario.getName() + "TCP Config", scenario.getTcpConfig()));
|
||||
|
||||
// 请求
|
||||
scenario.getRequests().stream().filter(Request::isEnable).forEach(request -> {
|
||||
final HashTree samplerHashTree = new ListedHashTree();
|
||||
Object sampler;
|
||||
switch (request.getType()) {
|
||||
case RequestType.TCP:
|
||||
sampler = tcpSampler((TCPRequest) request);
|
||||
// 引用环境的TCP Config
|
||||
if (request.isUseEnvironment() && config != null) {
|
||||
samplerHashTree.add(tcpConfig(request.getName() + "TCP Config", config.getTcpConfig()));
|
||||
}
|
||||
break;
|
||||
case RequestType.DUBBO:
|
||||
sampler = dubboSample((DubboRequest) request);
|
||||
break;
|
||||
case RequestType.SQL:
|
||||
SqlRequest sqlRequest = (SqlRequest) request;
|
||||
// 引用环境的JDBCDataSource
|
||||
if (request.isUseEnvironment() && config != null) {
|
||||
config.getDatabaseConfigs().forEach(databaseConfig -> {
|
||||
if (!databaseConfigMap.containsValue(databaseConfig.getName())) {
|
||||
samplerHashTree.add(jdbcDataSource(databaseConfig));
|
||||
databaseConfigMap.put(databaseConfig.getId(), databaseConfig.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
samplerHashTree.add(arguments(sqlRequest.getName() + " Variables", sqlRequest.getVariables()));
|
||||
sampler = jdbcSampler(sqlRequest, databaseConfigMap);
|
||||
break;
|
||||
default:
|
||||
HttpRequest httpRequest = (HttpRequest) request;
|
||||
sampler = httpSamplerProxy(httpRequest, config, testId);
|
||||
// 请求头(包括引用环境里设置的请求头)
|
||||
List<KeyValue> headers = httpRequest.getHeaders();
|
||||
if (request.isUseEnvironment() && config != null) {
|
||||
headers = merge(headers, config.getHttpConfig().getHeaders());
|
||||
}
|
||||
// 根据请求内容给请求头添加Content-Type
|
||||
addContentType(headers, httpRequest.getBody());
|
||||
samplerHashTree.add(headerManager(request.getName() + " Headers", headers));
|
||||
break;
|
||||
}
|
||||
|
||||
if (request.getController() != null && request.getController().isEnable() && request.getController().isValid()) {
|
||||
threadGroupHashTree.add(ifController(request)).set(sampler, samplerHashTree);
|
||||
} else {
|
||||
threadGroupHashTree.set(sampler, samplerHashTree);
|
||||
}
|
||||
|
||||
if (request.isUseEnvironment() && config != null && config.getCommonConfig() != null) {
|
||||
addEnvironmentVariables(samplerHashTree, request, config);
|
||||
addEnvironmentDNS(samplerHashTree, request, config);
|
||||
}
|
||||
|
||||
addRequestAssertions(samplerHashTree, request);
|
||||
addRequestExtractors(samplerHashTree, request);
|
||||
addJSR223Processors(samplerHashTree, request);
|
||||
|
||||
if (request.getTimer() != null && request.getTimer().isEnable()) {
|
||||
if (StringUtils.isNotBlank(request.getTimer().getDelay())) {
|
||||
samplerHashTree.add(constantTimer(request));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return jmeterTestPlanHashTree;
|
||||
}
|
||||
|
||||
private void addContentType(List<KeyValue> headers, Body body) {
|
||||
if (!body.isKV() && StringUtils.isNotBlank(body.getFormat())) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("json", "application/json");
|
||||
map.put("html", "text/html");
|
||||
map.put("xml", "text/xml");
|
||||
String contentType = map.get(body.getFormat());
|
||||
boolean hasContentType = headers.stream().filter(KeyValue::isEnable).anyMatch(keyValue -> keyValue.getName().equals(HTTP.CONTENT_TYPE));
|
||||
if (contentType != null && !hasContentType) {
|
||||
headers.add(new KeyValue(HTTP.CONTENT_TYPE, contentType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addEnvironmentVariables(HashTree samplerHashTree, Request request, EnvironmentConfig config) {
|
||||
String name = request.getName() + "Environment Variables";
|
||||
samplerHashTree.add(arguments(name, config.getCommonConfig().getVariables()));
|
||||
}
|
||||
|
||||
private void addEnvironmentDNS(HashTree samplerHashTree, Request request, 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(request.getName() + " DNSCacheManager", hosts));
|
||||
}
|
||||
}
|
||||
|
||||
private void addRequestAssertions(HashTree samplerHashTree, Request request) {
|
||||
Assertions assertions = request.getAssertions();
|
||||
if (CollectionUtils.isNotEmpty(assertions.getRegex())) {
|
||||
assertions.getRegex().stream().filter(AssertionRegex::isValid).forEach(assertion ->
|
||||
samplerHashTree.add(responseAssertion(assertion))
|
||||
);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(assertions.getJsonPath())) {
|
||||
assertions.getJsonPath().stream().filter(AssertionJsonPath::isValid).forEach(assertion ->
|
||||
samplerHashTree.add(jsonPathAssertion(assertion))
|
||||
);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(assertions.getJsr223())) {
|
||||
assertions.getJsr223().stream().filter(AssertionJSR223::isValid).forEach(assertion ->
|
||||
samplerHashTree.add(jsr223Assertion(assertion))
|
||||
);
|
||||
}
|
||||
|
||||
if (assertions.getDuration().isValid()) {
|
||||
samplerHashTree.add(durationAssertion(assertions.getDuration()));
|
||||
}
|
||||
}
|
||||
|
||||
private void addRequestExtractors(HashTree samplerHashTree, Request request) {
|
||||
Extract extract = request.getExtract();
|
||||
if (CollectionUtils.isNotEmpty(extract.getRegex())) {
|
||||
extract.getRegex().stream().filter(ExtractCommon::isValid).forEach(extractRegex ->
|
||||
samplerHashTree.add(regexExtractor(extractRegex))
|
||||
);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(extract.getXpath())) {
|
||||
extract.getXpath().stream().filter(ExtractCommon::isValid).forEach(extractXPath ->
|
||||
samplerHashTree.add(xPath2Extractor(extractXPath))
|
||||
);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(extract.getJson())) {
|
||||
extract.getJson().stream().filter(ExtractCommon::isValid).forEach(extractJSONPath ->
|
||||
samplerHashTree.add(jsonPostProcessor(extractJSONPath))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void addJSR223Processors(HashTree samplerHashTree, Request request) {
|
||||
if (request.getJsr223PreProcessor() != null) {
|
||||
if (StringUtils.isNotBlank(request.getJsr223PreProcessor().getScript())) {
|
||||
samplerHashTree.add(jsr223PreProcessor(request));
|
||||
}
|
||||
}
|
||||
if (request.getJsr223PostProcessor() != null) {
|
||||
if (StringUtils.isNotBlank(request.getJsr223PostProcessor().getScript())) {
|
||||
samplerHashTree.add(jsr223PostProcessor(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EnvironmentConfig getEnvironmentConfig(String id) {
|
||||
if (StringUtils.isBlank(id)) return null;
|
||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(id);
|
||||
if (environment != null) {
|
||||
return JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private TestPlan testPlan(String testName) {
|
||||
TestPlan testPlan = new TestPlan(testName);
|
||||
testPlan.setProperty(TestElement.TEST_CLASS, "TestPlan");
|
||||
testPlan.setProperty(TestElement.GUI_CLASS, "TestPlanGui");
|
||||
testPlan.setEnabled(true);
|
||||
testPlan.setFunctionalMode(false);
|
||||
testPlan.setSerialized(true);
|
||||
testPlan.setTearDownOnShutdown(true);
|
||||
testPlan.setUserDefinedVariables(new Arguments());
|
||||
return testPlan;
|
||||
}
|
||||
|
||||
private ThreadGroup threadGroup(String name) {
|
||||
LoopController loopController = new LoopController();
|
||||
loopController.setName("LoopController");
|
||||
loopController.setProperty(TestElement.TEST_CLASS, "LoopController");
|
||||
loopController.setProperty(TestElement.GUI_CLASS, "LoopControlPanel");
|
||||
loopController.setEnabled(true);
|
||||
loopController.setLoops(1);
|
||||
|
||||
ThreadGroup threadGroup = new ThreadGroup();
|
||||
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.setName(name);
|
||||
threadGroup.setProperty(TestElement.TEST_CLASS, "ThreadGroup");
|
||||
threadGroup.setProperty(TestElement.GUI_CLASS, "ThreadGroupGui");
|
||||
threadGroup.setEnabled(true);
|
||||
threadGroup.setSamplerController(loopController);
|
||||
|
||||
return threadGroup;
|
||||
}
|
||||
|
||||
private Arguments arguments(String name, List<KeyValue> variables) {
|
||||
Arguments arguments = new Arguments();
|
||||
arguments.setEnabled(true);
|
||||
arguments.setName(name);
|
||||
arguments.setProperty(TestElement.TEST_CLASS, "Arguments");
|
||||
arguments.setProperty(TestElement.GUI_CLASS, "ArgumentsPanel");
|
||||
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
||||
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||
);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private HeaderManager headerManager(String name, List<KeyValue> headers) {
|
||||
HeaderManager headerManager = new HeaderManager();
|
||||
headerManager.setEnabled(true);
|
||||
headerManager.setName(name);
|
||||
headerManager.setProperty(TestElement.TEST_CLASS, "HeaderManager");
|
||||
headerManager.setProperty(TestElement.GUI_CLASS, "HeaderPanel");
|
||||
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
||||
headerManager.add(new Header(keyValue.getName(), keyValue.getValue()))
|
||||
);
|
||||
return headerManager;
|
||||
}
|
||||
|
||||
private CookieManager cookieManager(Scenario scenario) {
|
||||
CookieManager cookieManager = new CookieManager();
|
||||
cookieManager.setEnabled(true);
|
||||
cookieManager.setName(scenario.getName() + " Cookie");
|
||||
cookieManager.setProperty(TestElement.TEST_CLASS, "CookieManager");
|
||||
cookieManager.setProperty(TestElement.GUI_CLASS, "CookiePanel");
|
||||
cookieManager.setClearEachIteration(false);
|
||||
cookieManager.setControlledByThread(false);
|
||||
return cookieManager;
|
||||
}
|
||||
|
||||
private DataSourceElement jdbcDataSource(DatabaseConfig databaseConfig) {
|
||||
DataSourceElement dataSourceElement = new DataSourceElement();
|
||||
dataSourceElement.setEnabled(true);
|
||||
dataSourceElement.setName(databaseConfig.getName() + " JDBCDataSource");
|
||||
dataSourceElement.setProperty(TestElement.TEST_CLASS, "JDBCDataSource");
|
||||
dataSourceElement.setProperty(TestElement.GUI_CLASS, "TestBeanGUI");
|
||||
dataSourceElement.setAutocommit(true);
|
||||
dataSourceElement.setKeepAlive(true);
|
||||
dataSourceElement.setPreinit(true);
|
||||
dataSourceElement.setDataSource(databaseConfig.getName());
|
||||
dataSourceElement.setDbUrl(databaseConfig.getDbUrl());
|
||||
dataSourceElement.setDriver(databaseConfig.getDriver());
|
||||
dataSourceElement.setUsername(databaseConfig.getUsername());
|
||||
dataSourceElement.setPassword(databaseConfig.getPassword());
|
||||
dataSourceElement.setPoolMax(String.valueOf(databaseConfig.getPoolMax()));
|
||||
dataSourceElement.setTimeout(String.valueOf(databaseConfig.getTimeout()));
|
||||
dataSourceElement.setConnectionAge("5000");
|
||||
dataSourceElement.setTrimInterval("60000");
|
||||
dataSourceElement.setTransactionIsolation("DEFAULT");
|
||||
return dataSourceElement;
|
||||
}
|
||||
|
||||
private ConfigTestElement tcpConfig(String name, TCPConfig tcpConfig) {
|
||||
ConfigTestElement configTestElement = new ConfigTestElement();
|
||||
configTestElement.setEnabled(true);
|
||||
configTestElement.setName(name);
|
||||
configTestElement.setProperty(TestElement.TEST_CLASS, "ConfigTestElement");
|
||||
configTestElement.setProperty(TestElement.GUI_CLASS, "TCPConfigGui");
|
||||
configTestElement.setProperty(TCPSampler.CLASSNAME, tcpConfig.getClassname());
|
||||
configTestElement.setProperty(TCPSampler.SERVER, tcpConfig.getServer());
|
||||
configTestElement.setProperty(TCPSampler.PORT, tcpConfig.getPort());
|
||||
configTestElement.setProperty(TCPSampler.TIMEOUT_CONNECT, tcpConfig.getCtimeout());
|
||||
configTestElement.setProperty(TCPSampler.RE_USE_CONNECTION, tcpConfig.isReUseConnection());
|
||||
configTestElement.setProperty(TCPSampler.NODELAY, tcpConfig.isNodelay());
|
||||
configTestElement.setProperty(TCPSampler.CLOSE_CONNECTION, tcpConfig.isCloseConnection());
|
||||
configTestElement.setProperty(TCPSampler.SO_LINGER, tcpConfig.getSoLinger());
|
||||
configTestElement.setProperty(TCPSampler.EOL_BYTE, tcpConfig.getEolByte());
|
||||
configTestElement.setProperty(TCPSampler.SO_LINGER, tcpConfig.getSoLinger());
|
||||
configTestElement.setProperty(ConfigTestElement.USERNAME, tcpConfig.getUsername());
|
||||
configTestElement.setProperty(ConfigTestElement.PASSWORD, tcpConfig.getPassword());
|
||||
return configTestElement;
|
||||
}
|
||||
|
||||
private HTTPSamplerProxy httpSamplerProxy(HttpRequest request, EnvironmentConfig config, String testId) {
|
||||
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
|
||||
sampler.setEnabled(true);
|
||||
sampler.setName(request.getName());
|
||||
sampler.setProperty(TestElement.TEST_CLASS, "HTTPSamplerProxy");
|
||||
sampler.setProperty(TestElement.GUI_CLASS, "HttpTestSampleGui");
|
||||
sampler.setMethod(request.getMethod());
|
||||
|
||||
try {
|
||||
if (request.isUseEnvironment()) {
|
||||
sampler.setDomain(config.getHttpConfig().getDomain());
|
||||
sampler.setPort(config.getHttpConfig().getPort());
|
||||
sampler.setProtocol(config.getHttpConfig().getProtocol());
|
||||
String url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
|
||||
URL urlObject = new URL(url);
|
||||
sampler.setDomain(config.getHttpConfig().getDomain());
|
||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
||||
if (StringUtils.isNotBlank(request.getPath())) {
|
||||
envPath += request.getPath();
|
||||
}
|
||||
sampler.setPath(getPostQueryParameters(request, URLDecoder.decode(envPath, "UTF-8")));
|
||||
} else {
|
||||
String url = request.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(request, URLDecoder.decode(urlObject.getPath(), "UTF-8")));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
|
||||
sampler.setConnectTimeout(request.getConnectTimeout());
|
||||
sampler.setResponseTimeout(request.getResponseTimeout());
|
||||
sampler.setFollowRedirects(request.isFollowRedirects());
|
||||
sampler.setDoBrowserCompatibleMultipart(request.isDoMultipartPost());
|
||||
// 请求参数
|
||||
sampler.setArguments(httpArguments(request.getParameters()));
|
||||
// 请求体
|
||||
if (!StringUtils.equals(request.getMethod(), "GET")) {
|
||||
List<KeyValue> body = new ArrayList<>();
|
||||
if (request.getBody().isKV()) {
|
||||
body = request.getBody().getKvs().stream().filter(KeyValue::isValid).collect(Collectors.toList());
|
||||
sampler.setHTTPFiles(httpFileArgs(request, testId));
|
||||
} else {
|
||||
KeyValue keyValue = new KeyValue("", request.getBody().getRaw());
|
||||
keyValue.setEnable(true);
|
||||
keyValue.setEncode(false);
|
||||
body.add(keyValue);
|
||||
}
|
||||
sampler.setPostBodyRaw(true);
|
||||
sampler.setArguments(httpArguments(body));
|
||||
}
|
||||
return sampler;
|
||||
}
|
||||
|
||||
private String getPostQueryParameters(HttpRequest request, String path) {
|
||||
if (!StringUtils.equals(request.getMethod(), "GET")) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append(path);
|
||||
stringBuffer.append("?");
|
||||
request.getParameters().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 "";
|
||||
}
|
||||
|
||||
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());
|
||||
httpArgument.setUseEquals(true);
|
||||
httpArgument.setContentType(keyValue.getContentType());
|
||||
arguments.addArgument(httpArgument);
|
||||
}
|
||||
);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private HTTPFileArg[] httpFileArgs(HttpRequest request, String testId) {
|
||||
final String BODY_FILE_DIR = "/opt/metersphere/data/body";
|
||||
List<HTTPFileArg> list = new ArrayList<>();
|
||||
request.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 + '/' + testId + '/' + file.getId() + '_' + file.getName();
|
||||
String mimetype = keyValue.getContentType();
|
||||
list.add(new HTTPFileArg(path, paramName, mimetype));
|
||||
});
|
||||
}
|
||||
});
|
||||
return list.toArray(new HTTPFileArg[0]);
|
||||
}
|
||||
|
||||
private List<KeyValue> merge(List<KeyValue> list1, List<KeyValue> list2) {
|
||||
Set<String> names = list1.stream().map(KeyValue::getName).collect(Collectors.toSet());
|
||||
List<KeyValue> list = new ArrayList<>(list1);
|
||||
list2.stream().filter(keyValue -> !names.contains(keyValue.getName())).forEach(list::add);
|
||||
return list;
|
||||
}
|
||||
|
||||
private TCPSampler tcpSampler(TCPRequest request) {
|
||||
TCPSampler tcpSampler = new TCPSampler();
|
||||
tcpSampler.setName(request.getName());
|
||||
tcpSampler.setProperty(TestElement.TEST_CLASS, "TCPSampler");
|
||||
tcpSampler.setProperty(TestElement.GUI_CLASS, "TCPSamplerGui");
|
||||
tcpSampler.setClassname(request.getClassname());
|
||||
tcpSampler.setServer(request.getServer());
|
||||
tcpSampler.setPort(request.getPort());
|
||||
tcpSampler.setConnectTimeout(request.getCtimeout());
|
||||
tcpSampler.setProperty(TCPSampler.RE_USE_CONNECTION, request.isReUseConnection());
|
||||
tcpSampler.setProperty(TCPSampler.NODELAY, request.isNodelay());
|
||||
tcpSampler.setCloseConnection(String.valueOf(request.isCloseConnection()));
|
||||
tcpSampler.setSoLinger(request.getSoLinger());
|
||||
tcpSampler.setEolByte(request.getEolByte());
|
||||
tcpSampler.setRequestData(request.getRequest());
|
||||
tcpSampler.setProperty(ConfigTestElement.USERNAME, request.getUsername());
|
||||
tcpSampler.setProperty(ConfigTestElement.PASSWORD, request.getPassword());
|
||||
|
||||
return tcpSampler;
|
||||
}
|
||||
|
||||
private JDBCSampler jdbcSampler(SqlRequest request, Map<String, String> databaseConfigMap) {
|
||||
JDBCSampler sampler = new JDBCSampler();
|
||||
sampler.setName(request.getName());
|
||||
sampler.setProperty(TestElement.TEST_CLASS, "JDBCSampler");
|
||||
sampler.setProperty(TestElement.GUI_CLASS, "TestBeanGUI");
|
||||
// request.getDataSource() 是ID,需要转换为Name
|
||||
sampler.setDataSource(databaseConfigMap.get(request.getDataSource()));
|
||||
sampler.setQuery(request.getQuery());
|
||||
sampler.setQueryTimeout(String.valueOf(request.getQueryTimeout()));
|
||||
sampler.setResultVariable(request.getResultVariable());
|
||||
sampler.setVariableNames(request.getVariableNames());
|
||||
sampler.setResultSetHandler("Store as String");
|
||||
sampler.setQueryType("Callable Statement");
|
||||
return sampler;
|
||||
}
|
||||
|
||||
private DubboSample dubboSample(DubboRequest request) {
|
||||
DubboSample sampler = new DubboSample();
|
||||
sampler.setName(request.getName());
|
||||
sampler.setProperty(TestElement.TEST_CLASS, DubboSample.class.getName());
|
||||
sampler.setProperty(TestElement.GUI_CLASS, DubboSampleGui.class.getName());
|
||||
|
||||
Constants.setConfigCenterProtocol(request.getConfigCenter().getProtocol(), sampler);
|
||||
Constants.setConfigCenterGroup(request.getConfigCenter().getGroup(), sampler);
|
||||
Constants.setConfigCenterNamespace(request.getConfigCenter().getNamespace(), sampler);
|
||||
Constants.setConfigCenterUserName(request.getConfigCenter().getUsername(), sampler);
|
||||
Constants.setConfigCenterPassword(request.getConfigCenter().getPassword(), sampler);
|
||||
Constants.setConfigCenterAddress(request.getConfigCenter().getAddress(), sampler);
|
||||
Constants.setConfigCenterTimeout(request.getConfigCenter().getTimeout(), sampler);
|
||||
|
||||
Constants.setRegistryProtocol(request.getRegistryCenter().getProtocol(), sampler);
|
||||
Constants.setRegistryGroup(request.getRegistryCenter().getGroup(), sampler);
|
||||
Constants.setRegistryUserName(request.getRegistryCenter().getUsername(), sampler);
|
||||
Constants.setRegistryPassword(request.getRegistryCenter().getPassword(), sampler);
|
||||
Constants.setRegistryTimeout(request.getRegistryCenter().getTimeout(), sampler);
|
||||
Constants.setAddress(request.getRegistryCenter().getAddress(), sampler);
|
||||
|
||||
Constants.setTimeout(request.getConsumerAndService().getTimeout(), sampler);
|
||||
Constants.setVersion(request.getConsumerAndService().getVersion(), sampler);
|
||||
Constants.setGroup(request.getConsumerAndService().getGroup(), sampler);
|
||||
Constants.setConnections(request.getConsumerAndService().getConnections(), sampler);
|
||||
Constants.setLoadbalance(request.getConsumerAndService().getLoadBalance(), sampler);
|
||||
Constants.setAsync(request.getConsumerAndService().getAsync(), sampler);
|
||||
Constants.setCluster(request.getConsumerAndService().getCluster(), sampler);
|
||||
|
||||
Constants.setRpcProtocol(request.getProtocol(), sampler);
|
||||
Constants.setInterfaceName(request.get_interface(), sampler);
|
||||
Constants.setMethod(request.getMethod(), sampler);
|
||||
|
||||
List<MethodArgument> methodArgs = request.getArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setMethodArgs(methodArgs, sampler);
|
||||
|
||||
List<MethodArgument> attachmentArgs = request.getAttachmentArgs().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable)
|
||||
.map(keyValue -> new MethodArgument(keyValue.getName(), keyValue.getValue())).collect(Collectors.toList());
|
||||
Constants.setAttachmentArgs(attachmentArgs, sampler);
|
||||
|
||||
return sampler;
|
||||
}
|
||||
|
||||
private DNSCacheManager dnsCacheManager(String name, List<Host> hosts) {
|
||||
DNSCacheManager dnsCacheManager = new DNSCacheManager();
|
||||
dnsCacheManager.setEnabled(true);
|
||||
dnsCacheManager.setName(name);
|
||||
dnsCacheManager.setProperty(TestElement.TEST_CLASS, "DNSCacheManager");
|
||||
dnsCacheManager.setProperty(TestElement.GUI_CLASS, "DNSCachePanel");
|
||||
dnsCacheManager.setCustomResolver(true);
|
||||
hosts.forEach(host -> dnsCacheManager.addHost(host.getDomain(), host.getIp()));
|
||||
|
||||
return dnsCacheManager;
|
||||
}
|
||||
|
||||
private ResponseAssertion responseAssertion(AssertionRegex assertionRegex) {
|
||||
ResponseAssertion assertion = new ResponseAssertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionRegex.getDescription());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, "ResponseAssertion");
|
||||
assertion.setProperty(TestElement.GUI_CLASS, "AssertionGui");
|
||||
assertion.setAssumeSuccess(assertionRegex.isAssumeSuccess());
|
||||
assertion.setToContainsType();
|
||||
switch (assertionRegex.getSubject()) {
|
||||
case "Response Code":
|
||||
assertion.setTestFieldResponseCode();
|
||||
break;
|
||||
case "Response Headers":
|
||||
assertion.setTestFieldResponseHeaders();
|
||||
break;
|
||||
case "Response Data":
|
||||
assertion.setTestFieldResponseData();
|
||||
break;
|
||||
}
|
||||
return assertion;
|
||||
}
|
||||
|
||||
private JSONPathAssertion jsonPathAssertion(AssertionJsonPath assertionJsonPath) {
|
||||
JSONPathAssertion assertion = new JSONPathAssertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionJsonPath.getDescription());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, "JSONPathAssertion");
|
||||
assertion.setProperty(TestElement.GUI_CLASS, "JSONPathAssertionGui");
|
||||
assertion.setJsonPath(assertionJsonPath.getExpression());
|
||||
assertion.setExpectedValue(assertionJsonPath.getExpect());
|
||||
assertion.setJsonValidationBool(true);
|
||||
assertion.setExpectNull(false);
|
||||
assertion.setInvert(false);
|
||||
assertion.setIsRegex(true);
|
||||
return assertion;
|
||||
}
|
||||
|
||||
private DurationAssertion durationAssertion(AssertionDuration assertionDuration) {
|
||||
DurationAssertion assertion = new DurationAssertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName("Response In Time: " + assertionDuration.getValue());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, "DurationAssertion");
|
||||
assertion.setProperty(TestElement.GUI_CLASS, "DurationAssertionGui");
|
||||
assertion.setAllowedDuration(assertionDuration.getValue());
|
||||
return assertion;
|
||||
}
|
||||
|
||||
private JSR223Assertion jsr223Assertion(AssertionJSR223 assertionJSR223) {
|
||||
JSR223Assertion assertion = new JSR223Assertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionJSR223.getDesc());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, "JSR223Assertion");
|
||||
assertion.setProperty(TestElement.GUI_CLASS, "TestBeanGUI");
|
||||
assertion.setProperty("cacheKey", "true");
|
||||
assertion.setProperty("scriptLanguage", assertionJSR223.getLanguage());
|
||||
assertion.setProperty("script", assertionJSR223.getScript());
|
||||
return assertion;
|
||||
}
|
||||
|
||||
private RegexExtractor regexExtractor(ExtractRegex extractRegex) {
|
||||
RegexExtractor extractor = new RegexExtractor();
|
||||
extractor.setEnabled(true);
|
||||
extractor.setName(extractRegex.getVariable() + " RegexExtractor");
|
||||
extractor.setProperty(TestElement.TEST_CLASS, "RegexExtractor");
|
||||
extractor.setProperty(TestElement.GUI_CLASS, "RegexExtractorGui");
|
||||
extractor.setRefName(extractRegex.getVariable());
|
||||
extractor.setRegex(extractRegex.getExpression());
|
||||
extractor.setUseField(extractRegex.getUseHeaders());
|
||||
if (extractRegex.isMultipleMatching()) {
|
||||
extractor.setMatchNumber(-1);
|
||||
}
|
||||
extractor.setTemplate("$1$");
|
||||
return extractor;
|
||||
}
|
||||
|
||||
private JSONPostProcessor jsonPostProcessor(ExtractJSONPath extractJSONPath) {
|
||||
JSONPostProcessor extractor = new JSONPostProcessor();
|
||||
extractor.setEnabled(true);
|
||||
extractor.setName(extractJSONPath.getVariable() + " JSONExtractor");
|
||||
extractor.setProperty(TestElement.TEST_CLASS, "JSONPostProcessor");
|
||||
extractor.setProperty(TestElement.GUI_CLASS, "JSONPostProcessorGui");
|
||||
extractor.setRefNames(extractJSONPath.getVariable());
|
||||
extractor.setJsonPathExpressions(extractJSONPath.getExpression());
|
||||
if (extractJSONPath.isMultipleMatching()) {
|
||||
extractor.setMatchNumbers("-1");
|
||||
}
|
||||
return extractor;
|
||||
}
|
||||
|
||||
private XPath2Extractor xPath2Extractor(ExtractXPath extractXPath) {
|
||||
XPath2Extractor extractor = new XPath2Extractor();
|
||||
extractor.setEnabled(true);
|
||||
extractor.setName(extractXPath.getVariable() + " XPath2Extractor");
|
||||
extractor.setProperty(TestElement.TEST_CLASS, "XPath2Extractor");
|
||||
extractor.setProperty(TestElement.GUI_CLASS, "XPath2ExtractorGui");
|
||||
extractor.setRefName(extractXPath.getVariable());
|
||||
extractor.setXPathQuery(extractXPath.getExpression());
|
||||
if (extractXPath.isMultipleMatching()) {
|
||||
extractor.setMatchNumber(-1);
|
||||
}
|
||||
return extractor;
|
||||
}
|
||||
|
||||
private JSR223PreProcessor jsr223PreProcessor(Request request) {
|
||||
JSR223PreProcessor processor = new JSR223PreProcessor();
|
||||
processor.setEnabled(true);
|
||||
processor.setName(request.getName());
|
||||
processor.setProperty(TestElement.TEST_CLASS, "JSR223PreProcessor");
|
||||
processor.setProperty(TestElement.GUI_CLASS, "TestBeanGUI");
|
||||
processor.setProperty("cacheKey", "true");
|
||||
processor.setProperty("scriptLanguage", request.getJsr223PreProcessor().getLanguage());
|
||||
processor.setProperty("script", request.getJsr223PreProcessor().getScript());
|
||||
return processor;
|
||||
}
|
||||
|
||||
private JSR223PostProcessor jsr223PostProcessor(Request request) {
|
||||
JSR223PostProcessor processor = new JSR223PostProcessor();
|
||||
processor.setEnabled(true);
|
||||
processor.setName(request.getName());
|
||||
processor.setProperty(TestElement.TEST_CLASS, "JSR223PostProcessor");
|
||||
processor.setProperty(TestElement.GUI_CLASS, "TestBeanGUI");
|
||||
processor.setProperty("cacheKey", "true");
|
||||
processor.setProperty("scriptLanguage", request.getJsr223PostProcessor().getLanguage());
|
||||
processor.setProperty("script", request.getJsr223PostProcessor().getScript());
|
||||
return processor;
|
||||
}
|
||||
|
||||
private ConstantTimer constantTimer(Request request) {
|
||||
ConstantTimer constantTimer = new ConstantTimer();
|
||||
constantTimer.setEnabled(true);
|
||||
constantTimer.setName(request.getTimer().getDelay() + " ms");
|
||||
constantTimer.setProperty(TestElement.TEST_CLASS, "ConstantTimer");
|
||||
constantTimer.setProperty(TestElement.GUI_CLASS, "ConstantTimerGui");
|
||||
constantTimer.setDelay(request.getTimer().getDelay());
|
||||
return constantTimer;
|
||||
}
|
||||
|
||||
private IfController ifController(Request request) {
|
||||
IfController ifController = new IfController();
|
||||
ifController.setEnabled(true);
|
||||
ifController.setName(request.getController().getLabel());
|
||||
ifController.setCondition(request.getController().getCondition());
|
||||
ifController.setProperty(TestElement.TEST_CLASS, "IfController");
|
||||
ifController.setProperty(TestElement.GUI_CLASS, "IfControllerPanel");
|
||||
ifController.setEvaluateAll(false);
|
||||
ifController.setUseExpression(true);
|
||||
return ifController;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import io.metersphere.api.dto.scenario.Scenario;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
|
@ -14,28 +15,38 @@ import org.apache.jorphan.collections.HashTree;
|
|||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class JMeterService {
|
||||
|
||||
@Resource
|
||||
private JmeterProperties jmeterProperties;
|
||||
@Resource
|
||||
private JMXGenerator jmxGenerator;
|
||||
|
||||
public void run(String testId, String debugReportId, InputStream is) {
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
String JMETER_HOME = getJmeterHome();
|
||||
|
||||
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
|
||||
JMeterUtils.loadJMeterProperties(JMETER_PROPERTIES);
|
||||
JMeterUtils.setJMeterHome(JMETER_HOME);
|
||||
JMeterUtils.setLocale(LocaleContextHolder.getLocale());
|
||||
}
|
||||
|
||||
public HashTree getHashTree(String testId, String testName, List<Scenario> scenarios) {
|
||||
return jmxGenerator.parse(testId, testName, scenarios);
|
||||
}
|
||||
|
||||
public void run(String testId, String testName, List<Scenario> scenarios, String debugReportId) {
|
||||
try {
|
||||
Object scriptWrapper = SaveService.loadElement(is);
|
||||
HashTree testPlan = getHashTree(scriptWrapper);
|
||||
HashTree testPlan = getHashTree(testId, testName, scenarios);
|
||||
JMeterVars.addJSR223PostProcessor(testPlan);
|
||||
addBackendListener(testId, debugReportId, testPlan);
|
||||
LocalRunner runner = new LocalRunner(testPlan);
|
||||
|
@ -46,6 +57,17 @@ public class JMeterService {
|
|||
}
|
||||
}
|
||||
|
||||
public String getJMX(HashTree hashTree) {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
SaveService.saveTree(hashTree, baos);
|
||||
LogUtil.debug(baos.toString());
|
||||
return baos.toString();
|
||||
} catch (Exception e) {
|
||||
LogUtil.warn("HashTree error, can't log jmx content");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getJmeterHome() {
|
||||
String home = getClass().getResource("/").getPath() + "jmeter";
|
||||
try {
|
||||
|
@ -60,12 +82,6 @@ public class JMeterService {
|
|||
}
|
||||
}
|
||||
|
||||
private HashTree getHashTree(Object scriptWrapper) throws Exception {
|
||||
Field field = scriptWrapper.getClass().getDeclaredField("testPlan");
|
||||
field.setAccessible(true);
|
||||
return (HashTree) field.get(scriptWrapper);
|
||||
}
|
||||
|
||||
private void addBackendListener(String testId, String debugReportId, HashTree testPlan) {
|
||||
BackendListener backendListener = new BackendListener();
|
||||
backendListener.setName(testId);
|
||||
|
|
|
@ -8,7 +8,6 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
|
|||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.api.parse.ApiImportParserFactory;
|
||||
import io.metersphere.api.parse.JmeterDocumentParser;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiTestFileMapper;
|
||||
import io.metersphere.base.mapper.ApiTestMapper;
|
||||
|
@ -23,9 +22,9 @@ import io.metersphere.controller.request.QueryScheduleRequest;
|
|||
import io.metersphere.dto.ScheduleDao;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.job.sechedule.ApiTestJob;
|
||||
import io.metersphere.notice.service.MailService;
|
||||
import io.metersphere.notice.service.NoticeService;
|
||||
import io.metersphere.service.*;
|
||||
import io.metersphere.service.FileService;
|
||||
import io.metersphere.service.QuotaService;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import io.metersphere.track.service.TestCaseService;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
|
@ -35,16 +34,15 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class APITestService {
|
||||
@Resource
|
||||
private UserService userService;
|
||||
@Resource
|
||||
private ApiTestMapper apiTestMapper;
|
||||
@Resource
|
||||
|
@ -61,10 +59,6 @@ public class APITestService {
|
|||
private ScheduleService scheduleService;
|
||||
@Resource
|
||||
private TestCaseService testCaseService;
|
||||
@Resource
|
||||
private MailService mailService;
|
||||
@Resource
|
||||
private NoticeService noticeService;
|
||||
|
||||
private static final String BODY_FILE_DIR = "/opt/metersphere/data/body";
|
||||
|
||||
|
@ -82,33 +76,19 @@ public class APITestService {
|
|||
return extApiTestMapper.listByIds(request.getIds());
|
||||
}
|
||||
|
||||
public void create(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
public void create(SaveAPITestRequest request, List<MultipartFile> bodyFiles) {
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
ApiTest test = createTest(request, file);
|
||||
ApiTest test = createTest(request);
|
||||
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||
}
|
||||
private ApiTest createTest(SaveAPITestRequest request, MultipartFile file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
checkQuota();
|
||||
request.setBodyUploadIds(null);
|
||||
ApiTest test = createTest(request);
|
||||
saveFile(test.getId(), file);
|
||||
return test;
|
||||
}
|
||||
|
||||
public void update(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
public void update(SaveAPITestRequest request, List<MultipartFile> bodyFiles) {
|
||||
deleteFileByTestId(request.getId());
|
||||
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
request.setBodyUploadIds(null);
|
||||
ApiTest test = updateTest(request);
|
||||
createBodyFiles(test, bodyUploadIds, bodyFiles);
|
||||
saveFile(test.getId(), file);
|
||||
}
|
||||
|
||||
private void createBodyFiles(ApiTest test, List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
|
||||
|
@ -151,14 +131,6 @@ public class APITestService {
|
|||
copy.setStatus(APITestStatus.Saved.name());
|
||||
copy.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
|
||||
apiTestMapper.insert(copy);
|
||||
// copy test file
|
||||
ApiTestFile apiTestFile = getFileByTestId(request.getId());
|
||||
if (apiTestFile != null) {
|
||||
FileMetadata fileMetadata = fileService.copyFile(apiTestFile.getFileId());
|
||||
apiTestFile.setTestId(copy.getId());
|
||||
apiTestFile.setFileId(fileMetadata.getId());
|
||||
apiTestFileMapper.insert(apiTestFile);
|
||||
}
|
||||
copyBodyFiles(copy.getId(), request.getId());
|
||||
}
|
||||
|
||||
|
@ -211,26 +183,13 @@ public class APITestService {
|
|||
}
|
||||
|
||||
public String run(SaveAPITestRequest request) {
|
||||
ApiTestFile file = getFileByTestId(request.getId());
|
||||
if (file == null) {
|
||||
MSException.throwException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
byte[] bytes = fileService.loadFileAsBytes(file.getFileId());
|
||||
// 解析 xml 处理 mock 数据
|
||||
bytes = JmeterDocumentParser.parse(bytes);
|
||||
InputStream is = new ByteArrayInputStream(bytes);
|
||||
|
||||
APITestResult apiTest = get(request.getId());
|
||||
if (SessionUtils.getUser() == null) {
|
||||
apiTest.setUserId(request.getUserId());
|
||||
}
|
||||
String reportId = apiReportService.create(apiTest, request.getTriggerMode());
|
||||
/*if (request.getTriggerMode().equals("SCHEDULE")) {
|
||||
List<Notice> notice = noticeService.queryNotice(request.getId());
|
||||
mailService.sendHtml(reportId,notice,"api");
|
||||
}*/
|
||||
changeStatus(request.getId(), APITestStatus.Running);
|
||||
jMeterService.run(request.getId(), null, is);
|
||||
jMeterService.run(request.getId(), request.getName(), request.getScenarioDefinition(), null);
|
||||
return reportId;
|
||||
}
|
||||
|
||||
|
@ -271,6 +230,8 @@ public class APITestService {
|
|||
}
|
||||
|
||||
private ApiTest createTest(SaveAPITestRequest request) {
|
||||
checkQuota();
|
||||
request.setBodyUploadIds(null);
|
||||
checkNameExist(request);
|
||||
final ApiTest test = new ApiTest();
|
||||
test.setId(request.getId());
|
||||
|
@ -285,14 +246,6 @@ public class APITestService {
|
|||
return test;
|
||||
}
|
||||
|
||||
private void saveFile(String testId, MultipartFile file) {
|
||||
final FileMetadata fileMetadata = fileService.saveFile(file);
|
||||
ApiTestFile apiTestFile = new ApiTestFile();
|
||||
apiTestFile.setTestId(testId);
|
||||
apiTestFile.setFileId(fileMetadata.getId());
|
||||
apiTestFileMapper.insert(apiTestFile);
|
||||
}
|
||||
|
||||
private void deleteFileByTestId(String testId) {
|
||||
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
|
||||
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
|
||||
|
@ -305,18 +258,6 @@ public class APITestService {
|
|||
}
|
||||
}
|
||||
|
||||
private ApiTestFile getFileByTestId(String testId) {
|
||||
ApiTestFileExample ApiTestFileExample = new ApiTestFileExample();
|
||||
ApiTestFileExample.createCriteria().andTestIdEqualTo(testId);
|
||||
final List<ApiTestFile> ApiTestFiles = apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
apiTestFileMapper.selectByExample(ApiTestFileExample);
|
||||
if (!CollectionUtils.isEmpty(ApiTestFiles)) {
|
||||
return ApiTestFiles.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSchedule(Schedule request) {
|
||||
scheduleService.editSchedule(request);
|
||||
addOrUpdateApiTestCronJob(request);
|
||||
|
@ -409,10 +350,7 @@ public class APITestService {
|
|||
return schedules;
|
||||
}
|
||||
|
||||
public String runDebug(SaveAPITestRequest request, MultipartFile file, List<MultipartFile> bodyFiles) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||
}
|
||||
public String runDebug(SaveAPITestRequest request, List<MultipartFile> bodyFiles) {
|
||||
updateTest(request);
|
||||
APITestResult apiTest = get(request.getId());
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
|
@ -423,17 +361,7 @@ public class APITestService {
|
|||
}
|
||||
String reportId = apiReportService.createDebugReport(apiTest);
|
||||
|
||||
InputStream is = null;
|
||||
try {
|
||||
byte[] bytes = file.getBytes();
|
||||
// 解析 xml 处理 mock 数据
|
||||
bytes = JmeterDocumentParser.parse(bytes);
|
||||
is = new ByteArrayInputStream(bytes);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
|
||||
jMeterService.run(request.getId(), reportId, is);
|
||||
jMeterService.run(request.getId(), request.getName(), request.getScenarioDefinition(), reportId);
|
||||
return reportId;
|
||||
}
|
||||
|
||||
|
@ -444,10 +372,12 @@ public class APITestService {
|
|||
}
|
||||
}
|
||||
|
||||
public void mergeCreate(SaveAPITestRequest request, MultipartFile file, List<String> selectIds) {
|
||||
ApiTest test = createTest(request, file);
|
||||
selectIds.forEach(sourceId -> {
|
||||
copyBodyFiles(test.getId(), sourceId);
|
||||
});
|
||||
public void mergeCreate(SaveAPITestRequest request, List<String> selectIds) {
|
||||
ApiTest test = createTest(request);
|
||||
selectIds.forEach(sourceId -> copyBodyFiles(test.getId(), sourceId));
|
||||
}
|
||||
|
||||
public String getJMX(SaveAPITestRequest request) {
|
||||
return jMeterService.getJMX(jMeterService.getHashTree(request.getId(), request.getName(), request.getScenarioDefinition()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
{{ $t('load_test.save_and_run') }}
|
||||
</el-button>
|
||||
|
||||
<!-- <el-button :disabled="isReadOnly" type="primary" plain v-if="isShowRun" @click="runTest">-->
|
||||
<!-- {{$t('api_test.run')}}-->
|
||||
<!-- </el-button>-->
|
||||
|
||||
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{ $t('commons.cancel') }}
|
||||
</el-button>
|
||||
|
||||
|
@ -76,353 +72,363 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import {Scenario, Test} from "./model/ScenarioModel"
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {checkoutTestManagerOrTestUser, downloadFile, getUUID} from "@/common/js/utils";
|
||||
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
|
||||
import ApiImport from "./components/import/ApiImport";
|
||||
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
|
||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsJarConfig from "./components/jar/JarConfig";
|
||||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import {Scenario, Test} from "./model/ScenarioModel"
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {checkoutTestManagerOrTestUser, downloadFile, getUUID} from "@/common/js/utils";
|
||||
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
|
||||
import ApiImport from "./components/import/ApiImport";
|
||||
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
|
||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsJarConfig from "./components/jar/JarConfig";
|
||||
|
||||
export default {
|
||||
name: "MsApiTestConfig",
|
||||
export default {
|
||||
name: "MsApiTestConfig",
|
||||
|
||||
components: {
|
||||
MsJarConfig,
|
||||
MsMainContainer,
|
||||
MsContainer, ApiImport, MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig
|
||||
},
|
||||
components: {
|
||||
MsJarConfig,
|
||||
MsMainContainer,
|
||||
MsContainer, ApiImport, MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig
|
||||
},
|
||||
|
||||
props: ["id"],
|
||||
props: ["id"],
|
||||
|
||||
data() {
|
||||
return {
|
||||
reportVisible: false,
|
||||
create: false,
|
||||
result: {},
|
||||
projects: [],
|
||||
change: false,
|
||||
test: new Test(),
|
||||
isReadOnly: false,
|
||||
debugReportId: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reportVisible: false,
|
||||
create: false,
|
||||
result: {},
|
||||
projects: [],
|
||||
change: false,
|
||||
test: new Test(),
|
||||
isReadOnly: false,
|
||||
debugReportId: ''
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route': 'init',
|
||||
test: {
|
||||
handler: function () {
|
||||
this.change = true;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
let projectId;
|
||||
|
||||
this.isReadOnly = !checkoutTestManagerOrTestUser();
|
||||
|
||||
if (this.id) {
|
||||
this.create = false;
|
||||
this.getTest(this.id);
|
||||
} else {
|
||||
this.create = true;
|
||||
this.test = new Test();
|
||||
if (this.$refs.config) {
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
// 仅创建时获取选择的项目
|
||||
projectId = this.$store.state.common.projectId;
|
||||
}
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
this.projects = response.data;
|
||||
// 等待项目列表加载完
|
||||
if (projectId) this.test.projectId = projectId;
|
||||
})
|
||||
watch: {
|
||||
'$route': 'init',
|
||||
test: {
|
||||
handler: function () {
|
||||
this.change = true;
|
||||
},
|
||||
updateReference() {
|
||||
let updateIds = [];
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
let projectId;
|
||||
|
||||
this.isReadOnly = !checkoutTestManagerOrTestUser();
|
||||
|
||||
if (this.id) {
|
||||
this.create = false;
|
||||
this.getTest(this.id);
|
||||
} else {
|
||||
this.create = true;
|
||||
this.test = new Test();
|
||||
if (this.$refs.config) {
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
// 仅创建时获取选择的项目
|
||||
projectId = this.$store.state.common.projectId;
|
||||
}
|
||||
this.result = this.$get("/project/listAll", response => {
|
||||
this.projects = response.data;
|
||||
// 等待项目列表加载完
|
||||
if (projectId) this.test.projectId = projectId;
|
||||
})
|
||||
},
|
||||
updateReference() {
|
||||
let updateIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
updateIds.push(scenario.id.split("#")[0]);
|
||||
}
|
||||
})
|
||||
|
||||
if (updateIds.length === 0) return;
|
||||
// 更新引用场景
|
||||
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
|
||||
let scenarioMap = {};
|
||||
if (response.data) {
|
||||
response.data.forEach(test => {
|
||||
JSON.parse(test.scenarioDefinition).forEach(options => {
|
||||
let referenceId = test.id + "#" + options.id;
|
||||
scenarioMap[referenceId] = new Scenario(options);
|
||||
scenarioMap[referenceId].id = referenceId;
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
let scenarios = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
updateIds.push(scenario.id.split("#")[0]);
|
||||
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
|
||||
} else {
|
||||
scenarios.push(scenario);
|
||||
}
|
||||
})
|
||||
this.test.scenarioDefinition = scenarios;
|
||||
})
|
||||
},
|
||||
getTest(id) {
|
||||
this.result = this.$get("/api/get/" + id, response => {
|
||||
if (response.data) {
|
||||
let item = response.data;
|
||||
|
||||
if (updateIds.length === 0) return;
|
||||
// 更新引用场景
|
||||
this.result = this.$post("/api/list/ids", {ids: updateIds}, response => {
|
||||
let scenarioMap = {};
|
||||
if (response.data) {
|
||||
response.data.forEach(test => {
|
||||
JSON.parse(test.scenarioDefinition).forEach(options => {
|
||||
let referenceId = test.id + "#" + options.id;
|
||||
scenarioMap[referenceId] = new Scenario(options);
|
||||
scenarioMap[referenceId].id = referenceId;
|
||||
})
|
||||
})
|
||||
}
|
||||
this.test = new Test({
|
||||
id: item.id,
|
||||
projectId: item.projectId,
|
||||
name: item.name,
|
||||
status: item.status,
|
||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||
schedule: item.schedule ? item.schedule : {},
|
||||
});
|
||||
this.updateReference();
|
||||
|
||||
let scenarios = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
if (scenario.isReference()) {
|
||||
if (scenarioMap[scenario.id]) scenarios.push(scenarioMap[scenario.id]);
|
||||
} else {
|
||||
scenarios.push(scenario);
|
||||
}
|
||||
})
|
||||
this.test.scenarioDefinition = scenarios;
|
||||
})
|
||||
},
|
||||
getTest(id) {
|
||||
this.result = this.$get("/api/get/" + id, response => {
|
||||
if (response.data) {
|
||||
let item = response.data;
|
||||
|
||||
this.test = new Test({
|
||||
id: item.id,
|
||||
projectId: item.projectId,
|
||||
name: item.name,
|
||||
status: item.status,
|
||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||
schedule: item.schedule ? item.schedule : {},
|
||||
});
|
||||
this.updateReference();
|
||||
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
});
|
||||
},
|
||||
save(callback) {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
this.$refs.config.reset();
|
||||
}
|
||||
this.change = false;
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
let url = this.create ? "/api/create" : "/api/update";
|
||||
let jmx = this.test.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
let file = new File([blob], jmx.name);
|
||||
this.result = this.$fileUpload(url, file, bodyFiles, this.test, () => {
|
||||
if (callback) callback();
|
||||
this.create = false;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
saveTest() {
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.create) {
|
||||
this.$router.push({
|
||||
path: '/api/test/edit?id=' + this.test.id
|
||||
})
|
||||
}
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
runTest() {
|
||||
this.result = this.$post("/api/run", {id: this.test.id, triggerMode: 'MANUAL'}, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
});
|
||||
},
|
||||
save(callback) {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
this.change = false;
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
let url = this.create ? "/api/create" : "/api/update";
|
||||
this.result = this.$fileUpload(url, null, bodyFiles, this.test, () => {
|
||||
if (callback) callback();
|
||||
this.create = false;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
saveTest() {
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
if (this.create) {
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
path: '/api/test/edit?id=' + this.test.id
|
||||
})
|
||||
});
|
||||
},
|
||||
saveRunTest() {
|
||||
this.change = false;
|
||||
if (!this.validateEnableTest()) {
|
||||
this.$warning(this.$t('api_test.enable_validate_tip'));
|
||||
return;
|
||||
}
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.runTest();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
runTest() {
|
||||
this.test.triggerMode = 'MANUAL';
|
||||
this.result = this.$post("/api/run", this.test, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
})
|
||||
},
|
||||
getBodyUploadFiles() {
|
||||
let bodyUploadFiles = [];
|
||||
this.test.bodyUploadIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.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;
|
||||
this.test.bodyUploadIds.push(fileId);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
validateEnableTest() {
|
||||
for (let scenario of this.test.scenarioDefinition) {
|
||||
if (scenario.enable) {
|
||||
for (let request of scenario.requests) {
|
||||
if (request.enable) {
|
||||
return true;
|
||||
});
|
||||
},
|
||||
saveRunTest() {
|
||||
this.change = false;
|
||||
if (!this.validateEnableTest()) {
|
||||
this.$warning(this.$t('api_test.enable_validate_tip'));
|
||||
return;
|
||||
}
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.runTest();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
})
|
||||
},
|
||||
getBodyUploadFiles() {
|
||||
let bodyUploadFiles = [];
|
||||
this.test.bodyUploadIds = [];
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.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;
|
||||
this.test.bodyUploadIds.push(fileId);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
validateEnableTest() {
|
||||
for (let scenario of this.test.scenarioDefinition) {
|
||||
if (scenario.enable) {
|
||||
for (let request of scenario.requests) {
|
||||
if (request.enable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resetBodyFile() {
|
||||
//下次保存不再上传已传文件
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
item.file = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
this.$router.push('/api/test/list/all');
|
||||
},
|
||||
createPerformance() {
|
||||
let validator = this.test.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
this.result = this.$post("/api/jmx", this.test, response => {
|
||||
let jmx = {
|
||||
name: this.test.name + '.jmx',
|
||||
xml: response.data
|
||||
};
|
||||
this.$store.commit('setTest', {
|
||||
projectId: this.test.projectId,
|
||||
name: this.test.name,
|
||||
jmx: jmx
|
||||
})
|
||||
this.$router.push({
|
||||
path: "/performance/test/create"
|
||||
})
|
||||
});
|
||||
},
|
||||
handleCommand(command) {
|
||||
|
||||
switch (command) {
|
||||
case "report":
|
||||
this.$refs.reportDialog.open();
|
||||
break;
|
||||
case "performance":
|
||||
this.createPerformance();
|
||||
break;
|
||||
case "export":
|
||||
downloadFile(this.test.name + ".json", this.test.export());
|
||||
break;
|
||||
case "jar":
|
||||
this.$refs.jarConfig.open();
|
||||
break;
|
||||
case "import":
|
||||
this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
saveCronExpression(cronExpression) {
|
||||
this.test.schedule.enable = true;
|
||||
this.test.schedule.value = cronExpression;
|
||||
this.saveSchedule();
|
||||
},
|
||||
saveSchedule() {
|
||||
this.checkScheduleEdit();
|
||||
let param = {};
|
||||
param = this.test.schedule;
|
||||
param.resourceId = this.test.id;
|
||||
let url = '/api/schedule/create';
|
||||
if (param.id) {
|
||||
url = '/api/schedule/update';
|
||||
}
|
||||
this.$post(url, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.getTest(this.test.id);
|
||||
});
|
||||
},
|
||||
checkScheduleEdit() {
|
||||
if (this.create) {
|
||||
this.$message(this.$t('api_test.environment.please_save_test'));
|
||||
return false;
|
||||
},
|
||||
resetBodyFile() {
|
||||
//下次保存不再上传已传文件
|
||||
this.test.scenarioDefinition.forEach(scenario => {
|
||||
scenario.requests.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
item.file = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
this.$router.push('/api/test/list/all');
|
||||
},
|
||||
handleCommand(command) {
|
||||
switch (command) {
|
||||
case "report":
|
||||
this.$refs.reportDialog.open();
|
||||
break;
|
||||
case "performance":
|
||||
this.$store.commit('setTest', {
|
||||
projectId: this.test.projectId,
|
||||
name: this.test.name,
|
||||
jmx: this.test.toJMX()
|
||||
})
|
||||
this.$router.push({
|
||||
path: "/performance/test/create"
|
||||
})
|
||||
break;
|
||||
case "export":
|
||||
downloadFile(this.test.name + ".json", this.test.export());
|
||||
break;
|
||||
case "jar":
|
||||
this.$refs.jarConfig.open();
|
||||
break;
|
||||
case "import":
|
||||
this.$refs.apiImport.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
saveCronExpression(cronExpression) {
|
||||
this.test.schedule.enable = true;
|
||||
this.test.schedule.value = cronExpression;
|
||||
this.saveSchedule();
|
||||
},
|
||||
saveSchedule() {
|
||||
this.checkScheduleEdit();
|
||||
let param = {};
|
||||
param = this.test.schedule;
|
||||
param.resourceId = this.test.id;
|
||||
let url = '/api/schedule/create';
|
||||
if (param.id) {
|
||||
url = '/api/schedule/update';
|
||||
}
|
||||
this.$post(url, param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.getTest(this.test.id);
|
||||
});
|
||||
},
|
||||
checkScheduleEdit() {
|
||||
if (this.create) {
|
||||
this.$message(this.$t('api_test.environment.please_save_test'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
runDebug(scenario) {
|
||||
if (this.create) {
|
||||
this.$warning(this.$t('api_test.environment.please_save_test'));
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "/api/run/debug";
|
||||
let runningTest = new Test();
|
||||
Object.assign(runningTest, this.test);
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
runningTest.scenarioDefinition = [];
|
||||
runningTest.scenarioDefinition.push(scenario);
|
||||
let validator = runningTest.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
|
||||
let jmx = runningTest.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
let file = new File([blob], jmx.name);
|
||||
this.$fileUpload(url, file, bodyFiles, this.test, response => {
|
||||
this.debugReportId = response.data;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
console.log('拦截到 ctrl + s');//ctrl+s
|
||||
this.saveTest();
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
return true;
|
||||
},
|
||||
runDebug(scenario) {
|
||||
if (this.create) {
|
||||
this.$warning(this.$t('api_test.environment.please_save_test'));
|
||||
return;
|
||||
}
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
//
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
let url = "/api/run/debug";
|
||||
let runningTest = new Test();
|
||||
Object.assign(runningTest, this.test);
|
||||
let bodyFiles = this.getBodyUploadFiles();
|
||||
runningTest.scenarioDefinition = [];
|
||||
runningTest.scenarioDefinition.push(scenario);
|
||||
let validator = runningTest.isValid();
|
||||
if (!validator.isValid) {
|
||||
this.$warning(this.$t(validator.info));
|
||||
return;
|
||||
}
|
||||
|
||||
this.$fileUpload(url, null, bodyFiles, this.test, response => {
|
||||
this.debugReportId = response.data;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
}
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
console.log('拦截到 ctrl + s');//ctrl+s
|
||||
this.saveTest();
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
//
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.test-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
}
|
||||
.test-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.test-name {
|
||||
width: 600px;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.test-name {
|
||||
width: 600px;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.test-project {
|
||||
min-width: 150px;
|
||||
}
|
||||
.test-project {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.test-container .more {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.test-container .more {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {parseEnvironment} from "./model/EnvironmentModel";
|
||||
|
||||
|
||||
|
@ -181,9 +180,6 @@
|
|||
type: "application/json"
|
||||
}));
|
||||
|
||||
let jmx = this.test.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
formData.append("file", new File([blob], jmx.name));
|
||||
return {
|
||||
method: 'POST',
|
||||
url: url,
|
||||
|
|
|
@ -201,12 +201,12 @@ export class Test extends BaseConfig {
|
|||
return {isValid: true};
|
||||
}
|
||||
|
||||
toJMX() {
|
||||
return {
|
||||
name: this.name + '.jmx',
|
||||
xml: new JMXGenerator(this).toXML()
|
||||
};
|
||||
}
|
||||
// toJMX() {
|
||||
// return {
|
||||
// name: this.name + '.jmx',
|
||||
// xml: new JMXGenerator(this).toXML()
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
||||
export class Scenario extends BaseConfig {
|
||||
|
@ -973,7 +973,7 @@ export class ConstantTimer extends Timer {
|
|||
}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------------ **/
|
||||
/** ------------------------------------------------------------------------
|
||||
const JMX_ASSERTION_CONDITION = {
|
||||
MATCH: 1,
|
||||
CONTAINS: 1 << 1,
|
||||
|
@ -1188,7 +1188,7 @@ class JMXGenerator {
|
|||
envArray = JSON.parse(environments);
|
||||
}
|
||||
envArray.forEach(item => {
|
||||
if (item.enable != false && item.name && !keys.has(item.name)) {
|
||||
if (item.enable !== false && item.name && !keys.has(item.name)) {
|
||||
target.push(new KeyValue({name: item.name, value: item.value}));
|
||||
}
|
||||
})
|
||||
|
@ -1373,8 +1373,7 @@ class JMXGenerator {
|
|||
let hasContentType = false;
|
||||
for (let index in request.headers) {
|
||||
if (request.headers.hasOwnProperty(index)) {
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable != false) {
|
||||
request.headers.splice(index, 1);
|
||||
if (request.headers[index].name === 'Content-Type' && request.headers[index].enable !== false) {
|
||||
hasContentType = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1462,7 +1461,7 @@ class JMXGenerator {
|
|||
|
||||
getResponseAssertion(regex) {
|
||||
let name = regex.description;
|
||||
let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match,自己写正则
|
||||
let type = JMX_ASSERTION_CONDITION.CONTAINS;
|
||||
let value = regex.expression;
|
||||
let assumeSuccess = regex.assumeSuccess;
|
||||
switch (regex.subject) {
|
||||
|
@ -1539,4 +1538,4 @@ class JMXGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
**/
|
||||
|
|
Loading…
Reference in New Issue