feat(接口自动化): 完成批量执行等
This commit is contained in:
parent
6ce41bdbde
commit
6a8a718ff2
|
@ -4,6 +4,8 @@ import io.metersphere.base.domain.ApiTestReport;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
public class APIReportResult extends ApiTestReport {
|
public class APIReportResult extends ApiTestReport {
|
||||||
|
@ -14,5 +16,7 @@ public class APIReportResult extends ApiTestReport {
|
||||||
|
|
||||||
private String userName;
|
private String userName;
|
||||||
|
|
||||||
|
private List<String> scenarioIds;
|
||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.jmeter.save.SaveService;
|
||||||
|
import org.apache.jmeter.testelement.TestElement;
|
||||||
import org.apache.jorphan.collections.HashTree;
|
import org.apache.jorphan.collections.HashTree;
|
||||||
|
import org.apache.jmeter.config.Arguments;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -40,11 +43,14 @@ public class MsScenario extends MsTestElement {
|
||||||
@JSONField(ordinal = 13)
|
@JSONField(ordinal = 13)
|
||||||
private List<KeyValue> variables;
|
private List<KeyValue> variables;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
if (environmentId != null) {
|
if (environmentId != null) {
|
||||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
|
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
|
||||||
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||||
|
config.setVariables(this.variables);
|
||||||
}
|
}
|
||||||
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
|
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
|
||||||
return;
|
return;
|
||||||
|
@ -66,10 +72,29 @@ public class MsScenario extends MsTestElement {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 场景变量
|
||||||
|
if (CollectionUtils.isNotEmpty(this.getVariables())) {
|
||||||
|
tree.add(arguments());
|
||||||
|
}
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
for (MsTestElement el : hashTree) {
|
for (MsTestElement el : hashTree) {
|
||||||
el.toHashTree(tree, el.getHashTree(), config);
|
el.toHashTree(tree, el.getHashTree(), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Arguments arguments() {
|
||||||
|
Arguments arguments = new Arguments();
|
||||||
|
arguments.setEnabled(true);
|
||||||
|
arguments.setName(name + "Variables");
|
||||||
|
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||||
|
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
|
||||||
|
variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
||||||
|
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
|
||||||
|
);
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
|
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
|
||||||
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
|
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.jmeter.protocol.http.control.AuthManager;
|
import org.apache.jmeter.protocol.http.control.AuthManager;
|
||||||
|
@ -71,7 +70,7 @@ public class MsTestElement {
|
||||||
private LinkedList<MsTestElement> hashTree;
|
private LinkedList<MsTestElement> hashTree;
|
||||||
|
|
||||||
// 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
|
// 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
for (MsTestElement el : hashTree) {
|
for (MsTestElement el : hashTree) {
|
||||||
el.toHashTree(tree, el.hashTree, config);
|
el.toHashTree(tree, el.hashTree, config);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +94,7 @@ public class MsTestElement {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashTree generateHashTree(EnvironmentConfig config) {
|
public HashTree generateHashTree(ParameterConfig config) {
|
||||||
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
||||||
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, config);
|
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, config);
|
||||||
return jmeterTestPlanHashTree;
|
return jmeterTestPlanHashTree;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.metersphere.api.dto.definition.request;
|
package io.metersphere.api.dto.definition.request;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -19,7 +18,7 @@ import java.util.List;
|
||||||
public class MsTestPlan extends MsTestElement {
|
public class MsTestPlan extends MsTestElement {
|
||||||
private String type = "TestPlan";
|
private String type = "TestPlan";
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree testPlanTree = tree.add(getPlan());
|
final HashTree testPlanTree = tree.add(getPlan());
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
hashTree.forEach(el -> {
|
hashTree.forEach(el -> {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package io.metersphere.api.dto.definition.request;
|
package io.metersphere.api.dto.definition.request;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -19,7 +18,7 @@ import java.util.List;
|
||||||
public class MsThreadGroup extends MsTestElement {
|
public class MsThreadGroup extends MsTestElement {
|
||||||
private String type = "ThreadGroup";
|
private String type = "ThreadGroup";
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree groupTree = tree.add(getThreadGroup());
|
final HashTree groupTree = tree.add(getThreadGroup());
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
hashTree.forEach(el -> {
|
hashTree.forEach(el -> {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package io.metersphere.api.dto.definition.request;
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ParameterConfig {
|
||||||
|
// 环境配置
|
||||||
|
private EnvironmentConfig config;
|
||||||
|
// 公共场景参数
|
||||||
|
private List<KeyValue> variables;
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.assertions;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -24,7 +24,7 @@ public class MsAssertions extends MsTestElement {
|
||||||
private MsAssertionDuration duration;
|
private MsAssertionDuration duration;
|
||||||
private String type = "Assertions";
|
private String type = "Assertions";
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
addAssertions(tree);
|
addAssertions(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.service.ApiTestEnvironmentService;
|
import io.metersphere.api.service.ApiTestEnvironmentService;
|
||||||
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
|
||||||
|
@ -50,7 +51,7 @@ public class MsAuthManager extends MsTestElement {
|
||||||
@JSONField(ordinal = 18)
|
@JSONField(ordinal = 18)
|
||||||
private String environment;
|
private String environment;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
AuthManager authManager = new AuthManager();
|
AuthManager authManager = new AuthManager();
|
||||||
authManager.setEnabled(true);
|
authManager.setEnabled(true);
|
||||||
authManager.setName(this.getUsername() + "AuthManager");
|
authManager.setName(this.getUsername() + "AuthManager");
|
||||||
|
@ -63,8 +64,8 @@ public class MsAuthManager extends MsTestElement {
|
||||||
if (environment != null) {
|
if (environment != null) {
|
||||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||||
ApiTestEnvironmentWithBLOBs environmentWithBLOBs = environmentService.get(environment);
|
ApiTestEnvironmentWithBLOBs environmentWithBLOBs = environmentService.get(environment);
|
||||||
config = JSONObject.parseObject(environmentWithBLOBs.getConfig(), EnvironmentConfig.class);
|
EnvironmentConfig envConfig = JSONObject.parseObject(environmentWithBLOBs.getConfig(), EnvironmentConfig.class);
|
||||||
this.url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
|
this.url = envConfig.getHttpConfig().getProtocol() + "://" + envConfig.getHttpConfig().getSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auth.setDomain(this.domain);
|
auth.setDomain(this.domain);
|
||||||
|
|
|
@ -3,8 +3,8 @@ package io.metersphere.api.dto.definition.request.configurations;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -25,7 +25,7 @@ public class MsHeaderManager extends MsTestElement {
|
||||||
@JSONField(ordinal = 10)
|
@JSONField(ordinal = 10)
|
||||||
private List<KeyValue> headers;
|
private List<KeyValue> headers;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
HeaderManager headerManager = new HeaderManager();
|
HeaderManager headerManager = new HeaderManager();
|
||||||
headerManager.setEnabled(true);
|
headerManager.setEnabled(true);
|
||||||
headerManager.setName(this.getName() + "Headers");
|
headerManager.setName(this.getName() + "Headers");
|
||||||
|
|
|
@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -25,7 +25,7 @@ public class MsIfController extends MsTestElement {
|
||||||
private String operator;
|
private String operator;
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree groupTree = tree.add(ifController());
|
final HashTree groupTree = tree.add(ifController());
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
hashTree.forEach(el -> {
|
hashTree.forEach(el -> {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.request.dns;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.dto.scenario.environment.Host;
|
import io.metersphere.api.dto.scenario.environment.Host;
|
||||||
|
@ -23,7 +24,7 @@ import java.util.List;
|
||||||
@JSONType(typeName = "DNSCacheManager")
|
@JSONType(typeName = "DNSCacheManager")
|
||||||
public class MsDNSCacheManager extends MsTestElement {
|
public class MsDNSCacheManager extends MsTestElement {
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
for (MsTestElement el : hashTree) {
|
for (MsTestElement el : hashTree) {
|
||||||
el.toHashTree(tree, el.getHashTree(), config);
|
el.toHashTree(tree, el.getHashTree(), config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition.request.extract;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -24,7 +24,7 @@ public class MsExtract extends MsTestElement {
|
||||||
private List<MsExtractXPath> xpath;
|
private List<MsExtractXPath> xpath;
|
||||||
private String type = "Extract";
|
private String type = "Extract";
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
addRequestExtractors(tree);
|
addRequestExtractors(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -26,7 +26,7 @@ public class MsJSR223Processor extends MsTestElement {
|
||||||
@JSONField(ordinal = 11)
|
@JSONField(ordinal = 11)
|
||||||
private String scriptLanguage;
|
private String scriptLanguage;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
JSR223Sampler processor = new JSR223Sampler();
|
JSR223Sampler processor = new JSR223Sampler();
|
||||||
processor.setEnabled(true);
|
processor.setEnabled(true);
|
||||||
processor.setName(this.getName() + "JSR223Processor");
|
processor.setName(this.getName() + "JSR223Processor");
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors.post;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -27,7 +27,7 @@ public class MsJSR223PostProcessor extends MsTestElement {
|
||||||
private String scriptLanguage;
|
private String scriptLanguage;
|
||||||
|
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
JSR223PostProcessor processor = new JSR223PostProcessor();
|
JSR223PostProcessor processor = new JSR223PostProcessor();
|
||||||
processor.setEnabled(true);
|
processor.setEnabled(true);
|
||||||
processor.setName(this.getName() + "JSR223PostProcessor");
|
processor.setName(this.getName() + "JSR223PostProcessor");
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.processors.pre;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -26,7 +26,7 @@ public class MsJSR223PreProcessor extends MsTestElement {
|
||||||
@JSONField(ordinal = 11)
|
@JSONField(ordinal = 11)
|
||||||
private String scriptLanguage;
|
private String scriptLanguage;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
JSR223PreProcessor processor = new JSR223PreProcessor();
|
JSR223PreProcessor processor = new JSR223PreProcessor();
|
||||||
processor.setEnabled(true);
|
processor.setEnabled(true);
|
||||||
processor.setName(this.getName() + "JSR223PreProcessor");
|
processor.setName(this.getName() + "JSR223PreProcessor");
|
||||||
|
|
|
@ -7,11 +7,11 @@ import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
|
||||||
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
|
import io.github.ningyu.jmeter.plugin.dubbo.sample.MethodArgument;
|
||||||
import io.github.ningyu.jmeter.plugin.util.Constants;
|
import io.github.ningyu.jmeter.plugin.util.Constants;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConfigCenter;
|
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConfigCenter;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConsumerAndService;
|
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsConsumerAndService;
|
||||||
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
|
import io.metersphere.api.dto.definition.request.sampler.dubbo.MsRegistryCenter;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -51,7 +51,7 @@ public class MsDubboSampler extends MsTestElement {
|
||||||
@JSONField(ordinal = 59)
|
@JSONField(ordinal = 59)
|
||||||
private List<KeyValue> attachmentArgs;
|
private List<KeyValue> attachmentArgs;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree testPlanTree = new ListedHashTree();
|
final HashTree testPlanTree = new ListedHashTree();
|
||||||
testPlanTree.add(dubboConfig());
|
testPlanTree.add(dubboConfig());
|
||||||
tree.set(dubboSample(), testPlanTree);
|
tree.set(dubboSample(), testPlanTree);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
|
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
|
||||||
import io.metersphere.api.dto.scenario.Body;
|
import io.metersphere.api.dto.scenario.Body;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
|
@ -80,7 +81,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
@JSONField(ordinal = 24)
|
@JSONField(ordinal = 24)
|
||||||
private List<KeyValue> arguments;
|
private List<KeyValue> arguments;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
|
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
|
||||||
sampler.setEnabled(true);
|
sampler.setEnabled(true);
|
||||||
sampler.setName(this.getName());
|
sampler.setName(this.getName());
|
||||||
|
@ -96,15 +97,15 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
if (useEnvironment != null) {
|
if (useEnvironment != null) {
|
||||||
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment);
|
ApiTestEnvironmentWithBLOBs environment = environmentService.get(useEnvironment);
|
||||||
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (config != null) {
|
if (config != null && config.getConfig() != null) {
|
||||||
String url = "";
|
String url = "";
|
||||||
sampler.setDomain(config.getHttpConfig().getDomain());
|
sampler.setDomain(config.getConfig().getHttpConfig().getDomain());
|
||||||
sampler.setPort(config.getHttpConfig().getPort());
|
sampler.setPort(config.getConfig().getHttpConfig().getPort());
|
||||||
sampler.setProtocol(config.getHttpConfig().getProtocol());
|
sampler.setProtocol(config.getConfig().getHttpConfig().getProtocol());
|
||||||
url = config.getHttpConfig().getProtocol() + "://" + config.getHttpConfig().getSocket();
|
url = config.getConfig().getHttpConfig().getProtocol() + "://" + config.getConfig().getHttpConfig().getSocket();
|
||||||
URL urlObject = new URL(url);
|
URL urlObject = new URL(url);
|
||||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
||||||
if (StringUtils.isNotBlank(this.getPath())) {
|
if (StringUtils.isNotBlank(this.getPath())) {
|
||||||
|
@ -125,8 +126,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
sampler.setPort(urlObject.getPort());
|
sampler.setPort(urlObject.getPort());
|
||||||
sampler.setProtocol(urlObject.getProtocol());
|
sampler.setProtocol(urlObject.getProtocol());
|
||||||
|
|
||||||
sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
|
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
||||||
sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
|
sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
|
||||||
|
} else {
|
||||||
|
sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
|
@ -148,9 +152,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
setHeader(httpSamplerTree);
|
setHeader(httpSamplerTree);
|
||||||
}
|
}
|
||||||
//判断是否要开启DNS
|
//判断是否要开启DNS
|
||||||
if (config != null && config.getCommonConfig() != null && config.getCommonConfig().isEnableHost()) {
|
if (config != null && config.getConfig() != null && config.getConfig().getCommonConfig() != null
|
||||||
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config);
|
&& config.getConfig().getCommonConfig().isEnableHost()) {
|
||||||
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config);
|
MsDNSCacheManager.addEnvironmentVariables(httpSamplerTree, this.getName(), config.getConfig());
|
||||||
|
MsDNSCacheManager.addEnvironmentDNS(httpSamplerTree, this.getName(), config.getConfig());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
for (MsTestElement el : hashTree) {
|
for (MsTestElement el : hashTree) {
|
||||||
|
|
|
@ -3,9 +3,9 @@ package io.metersphere.api.dto.definition.request.sampler;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
import io.metersphere.api.dto.scenario.DatabaseConfig;
|
||||||
import io.metersphere.api.dto.scenario.KeyValue;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -39,7 +39,7 @@ public class MsJDBCSampler extends MsTestElement {
|
||||||
@JSONField(ordinal = 16)
|
@JSONField(ordinal = 16)
|
||||||
private String environmentId;
|
private String environmentId;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree samplerHashTree = tree.add(jdbcSampler());
|
final HashTree samplerHashTree = tree.add(jdbcSampler());
|
||||||
tree.add(jdbcDataSource());
|
tree.add(jdbcDataSource());
|
||||||
tree.add(arguments(this.getName() + " Variables", this.getVariables()));
|
tree.add(arguments(this.getName() + " Variables", this.getVariables()));
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.sampler;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -49,7 +49,7 @@ public class MsTCPSampler extends MsTestElement {
|
||||||
@JSONField(ordinal = 23)
|
@JSONField(ordinal = 23)
|
||||||
private String request;
|
private String request;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree samplerHashTree = new ListedHashTree();
|
final HashTree samplerHashTree = new ListedHashTree();
|
||||||
samplerHashTree.add(tcpConfig());
|
samplerHashTree.add(tcpConfig());
|
||||||
tree.set(tcpSampler(), samplerHashTree);
|
tree.set(tcpSampler(), samplerHashTree);
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition.request.timer;
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
import com.alibaba.fastjson.annotation.JSONType;
|
import com.alibaba.fastjson.annotation.JSONType;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.definition.request.ParameterConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -26,7 +26,7 @@ public class MsConstantTimer extends MsTestElement {
|
||||||
@JSONField(ordinal = 12)
|
@JSONField(ordinal = 12)
|
||||||
private String delay;
|
private String delay;
|
||||||
|
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, EnvironmentConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
final HashTree groupTree = tree.add(constantTimer());
|
final HashTree groupTree = tree.add(constantTimer());
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
hashTree.forEach(el -> {
|
hashTree.forEach(el -> {
|
||||||
|
|
|
@ -9,9 +9,8 @@ import com.google.gson.Gson;
|
||||||
import io.metersphere.api.dto.APIReportResult;
|
import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.automation.*;
|
import io.metersphere.api.dto.automation.*;
|
||||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
import io.metersphere.api.dto.definition.request.*;
|
||||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
import io.metersphere.api.dto.scenario.KeyValue;
|
||||||
import io.metersphere.api.dto.definition.request.MsThreadGroup;
|
|
||||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||||
import io.metersphere.api.jmeter.JMeterService;
|
import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
|
@ -244,7 +243,6 @@ public class ApiAutomationService {
|
||||||
MsTestPlan testPlan = new MsTestPlan();
|
MsTestPlan testPlan = new MsTestPlan();
|
||||||
testPlan.setHashTree(new LinkedList<>());
|
testPlan.setHashTree(new LinkedList<>());
|
||||||
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
||||||
EnvironmentConfig config = null;
|
|
||||||
for (ApiScenario item : apiScenarios) {
|
for (ApiScenario item : apiScenarios) {
|
||||||
MsThreadGroup group = new MsThreadGroup();
|
MsThreadGroup group = new MsThreadGroup();
|
||||||
group.setLabel(item.getName());
|
group.setLabel(item.getName());
|
||||||
|
@ -253,22 +251,23 @@ public class ApiAutomationService {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
|
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
|
||||||
String environmentId = element.getString("environmentId");
|
MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class);
|
||||||
if (environmentId != null) {
|
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
|
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
|
||||||
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
new TypeReference<LinkedList<MsTestElement>>() {});
|
||||||
}
|
LinkedList<KeyValue> variables = mapper.readValue(element.getString("variables"),
|
||||||
|
new TypeReference<LinkedList<KeyValue>>() {});
|
||||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
|
scenario.setHashTree(elements);
|
||||||
});
|
scenario.setVariables(variables);
|
||||||
group.setHashTree(elements);
|
LinkedList<MsTestElement> scenarios = new LinkedList<>();
|
||||||
|
scenarios.add(scenario);
|
||||||
|
group.setHashTree(scenarios);
|
||||||
testPlan.getHashTree().add(group);
|
testPlan.getHashTree().add(group);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), config);
|
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), new ParameterConfig());
|
||||||
|
|
||||||
// 调用执行方法
|
// 调用执行方法
|
||||||
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
||||||
createAPIReportResult(request.getId());
|
createAPIReportResult(request.getId());
|
||||||
|
@ -286,11 +285,13 @@ public class ApiAutomationService {
|
||||||
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
|
||||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||||
createBodyFiles(bodyUploadIds, bodyFiles);
|
createBodyFiles(bodyUploadIds, bodyFiles);
|
||||||
EnvironmentConfig config = null;
|
EnvironmentConfig envConfig = null;
|
||||||
if (request.getEnvironmentId() != null) {
|
if (request.getEnvironmentId() != null) {
|
||||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId());
|
ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId());
|
||||||
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
envConfig = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
||||||
}
|
}
|
||||||
|
ParameterConfig config = new ParameterConfig();
|
||||||
|
config.setConfig(envConfig);
|
||||||
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
||||||
request.getTestElement().getJmx(hashTree);
|
request.getTestElement().getJmx(hashTree);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.api.service;
|
package io.metersphere.api.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.metersphere.api.dto.APIReportResult;
|
import io.metersphere.api.dto.APIReportResult;
|
||||||
import io.metersphere.api.dto.DeleteAPIReportRequest;
|
import io.metersphere.api.dto.DeleteAPIReportRequest;
|
||||||
|
@ -7,6 +8,7 @@ import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||||
import io.metersphere.api.jmeter.TestResult;
|
import io.metersphere.api.jmeter.TestResult;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
|
import io.metersphere.base.mapper.ApiScenarioMapper;
|
||||||
import io.metersphere.base.mapper.ApiScenarioReportDetailMapper;
|
import io.metersphere.base.mapper.ApiScenarioReportDetailMapper;
|
||||||
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
||||||
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
|
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
|
||||||
|
@ -21,6 +23,7 @@ import sun.security.util.Cache;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -35,6 +38,8 @@ public class ApiScenarioReportService {
|
||||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
|
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
|
||||||
|
@Resource
|
||||||
|
private ApiScenarioMapper apiScenarioMapper;
|
||||||
|
|
||||||
public void complete(TestResult result) {
|
public void complete(TestResult result) {
|
||||||
Object obj = cache.get(result.getTestId());
|
Object obj = cache.get(result.getTestId());
|
||||||
|
@ -139,6 +144,27 @@ public class ApiScenarioReportService {
|
||||||
public String add(APIScenarioReportResult test) {
|
public String add(APIScenarioReportResult test) {
|
||||||
ApiScenarioReport report = createReport(test);
|
ApiScenarioReport report = createReport(test);
|
||||||
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
|
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
|
||||||
|
TestResult result = JSON.parseObject(test.getContent(), TestResult.class);
|
||||||
|
// 更新场景
|
||||||
|
if (result != null) {
|
||||||
|
result.getScenarios().forEach(item -> {
|
||||||
|
ApiScenarioExample example = new ApiScenarioExample();
|
||||||
|
example.createCriteria().andNameEqualTo(item.getName()).andProjectIdEqualTo(test.getProjectId());
|
||||||
|
List<ApiScenario> list = apiScenarioMapper.selectByExample(example);
|
||||||
|
if (list.size() > 0) {
|
||||||
|
ApiScenario scenario = list.get(0);
|
||||||
|
if (item.getError() > 0) {
|
||||||
|
scenario.setLastResult("Fail");
|
||||||
|
} else {
|
||||||
|
scenario.setLastResult("Success");
|
||||||
|
}
|
||||||
|
String passRate = new DecimalFormat("0%").format((float) item.getSuccess() / (item.getSuccess() + item.getError()));
|
||||||
|
scenario.setPassRate(passRate);
|
||||||
|
scenario.setReportId(report.getId());
|
||||||
|
apiScenarioMapper.updateByPrimaryKey(scenario);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
|
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
|
||||||
detail.setReportId(report.getId());
|
detail.setReportId(report.getId());
|
||||||
detail.setProjectId(test.getProjectId());
|
detail.setProjectId(test.getProjectId());
|
||||||
|
|
|
@ -37,6 +37,12 @@ public class ApiScenario implements Serializable {
|
||||||
|
|
||||||
private Long updateTime;
|
private Long updateTime;
|
||||||
|
|
||||||
|
private String passRate;
|
||||||
|
|
||||||
|
private String lastResult;
|
||||||
|
|
||||||
|
private String reportId;
|
||||||
|
|
||||||
private String scenarioDefinition;
|
private String scenarioDefinition;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
|
@ -1193,6 +1193,216 @@ public class ApiScenarioExample {
|
||||||
addCriterion("update_time not between", value1, value2, "updateTime");
|
addCriterion("update_time not between", value1, value2, "updateTime");
|
||||||
return (Criteria) this;
|
return (Criteria) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateIsNull() {
|
||||||
|
addCriterion("pass_rate is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateIsNotNull() {
|
||||||
|
addCriterion("pass_rate is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateEqualTo(String value) {
|
||||||
|
addCriterion("pass_rate =", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateNotEqualTo(String value) {
|
||||||
|
addCriterion("pass_rate <>", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateGreaterThan(String value) {
|
||||||
|
addCriterion("pass_rate >", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("pass_rate >=", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateLessThan(String value) {
|
||||||
|
addCriterion("pass_rate <", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("pass_rate <=", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateLike(String value) {
|
||||||
|
addCriterion("pass_rate like", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateNotLike(String value) {
|
||||||
|
addCriterion("pass_rate not like", value, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateIn(List<String> values) {
|
||||||
|
addCriterion("pass_rate in", values, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateNotIn(List<String> values) {
|
||||||
|
addCriterion("pass_rate not in", values, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateBetween(String value1, String value2) {
|
||||||
|
addCriterion("pass_rate between", value1, value2, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andPassRateNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("pass_rate not between", value1, value2, "passRate");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultIsNull() {
|
||||||
|
addCriterion("last_result is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultIsNotNull() {
|
||||||
|
addCriterion("last_result is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultEqualTo(String value) {
|
||||||
|
addCriterion("last_result =", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultNotEqualTo(String value) {
|
||||||
|
addCriterion("last_result <>", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultGreaterThan(String value) {
|
||||||
|
addCriterion("last_result >", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("last_result >=", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultLessThan(String value) {
|
||||||
|
addCriterion("last_result <", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("last_result <=", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultLike(String value) {
|
||||||
|
addCriterion("last_result like", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultNotLike(String value) {
|
||||||
|
addCriterion("last_result not like", value, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultIn(List<String> values) {
|
||||||
|
addCriterion("last_result in", values, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultNotIn(List<String> values) {
|
||||||
|
addCriterion("last_result not in", values, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultBetween(String value1, String value2) {
|
||||||
|
addCriterion("last_result between", value1, value2, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andLastResultNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("last_result not between", value1, value2, "lastResult");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdIsNull() {
|
||||||
|
addCriterion("report_id is null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdIsNotNull() {
|
||||||
|
addCriterion("report_id is not null");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdEqualTo(String value) {
|
||||||
|
addCriterion("report_id =", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdNotEqualTo(String value) {
|
||||||
|
addCriterion("report_id <>", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdGreaterThan(String value) {
|
||||||
|
addCriterion("report_id >", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdGreaterThanOrEqualTo(String value) {
|
||||||
|
addCriterion("report_id >=", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdLessThan(String value) {
|
||||||
|
addCriterion("report_id <", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdLessThanOrEqualTo(String value) {
|
||||||
|
addCriterion("report_id <=", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdLike(String value) {
|
||||||
|
addCriterion("report_id like", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdNotLike(String value) {
|
||||||
|
addCriterion("report_id not like", value, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdIn(List<String> values) {
|
||||||
|
addCriterion("report_id in", values, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdNotIn(List<String> values) {
|
||||||
|
addCriterion("report_id not in", values, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdBetween(String value1, String value2) {
|
||||||
|
addCriterion("report_id between", value1, value2, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Criteria andReportIdNotBetween(String value1, String value2) {
|
||||||
|
addCriterion("report_id not between", value1, value2, "reportId");
|
||||||
|
return (Criteria) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Criteria extends GeneratedCriteria {
|
public static class Criteria extends GeneratedCriteria {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package io.metersphere.base.domain;
|
package io.metersphere.base.domain;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class ApiScenarioReport implements Serializable {
|
public class ApiScenarioReport implements Serializable {
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
<result column="description" jdbcType="VARCHAR" property="description" />
|
<result column="description" jdbcType="VARCHAR" property="description" />
|
||||||
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
||||||
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
||||||
|
<result column="pass_rate" jdbcType="VARCHAR" property="passRate" />
|
||||||
|
<result column="last_result" jdbcType="VARCHAR" property="lastResult" />
|
||||||
|
<result column="report_id" jdbcType="VARCHAR" property="reportId" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenario">
|
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenario">
|
||||||
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
|
<result column="scenario_definition" jdbcType="LONGVARCHAR" property="scenarioDefinition" />
|
||||||
|
@ -83,7 +86,7 @@
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, project_id, tag_id, user_id, api_scenario_module_id, module_path, `name`, `level`,
|
id, project_id, tag_id, user_id, api_scenario_module_id, module_path, `name`, `level`,
|
||||||
`status`, principal, step_total, follow_people, schedule, description, create_time,
|
`status`, principal, step_total, follow_people, schedule, description, create_time,
|
||||||
update_time
|
update_time, pass_rate, last_result, report_id
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="Blob_Column_List">
|
<sql id="Blob_Column_List">
|
||||||
scenario_definition
|
scenario_definition
|
||||||
|
@ -142,13 +145,15 @@
|
||||||
`name`, `level`, `status`,
|
`name`, `level`, `status`,
|
||||||
principal, step_total, follow_people,
|
principal, step_total, follow_people,
|
||||||
schedule, description, create_time,
|
schedule, description, create_time,
|
||||||
update_time, scenario_definition)
|
update_time, pass_rate, last_result,
|
||||||
|
report_id, scenario_definition)
|
||||||
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tagId,jdbcType=VARCHAR},
|
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{tagId,jdbcType=VARCHAR},
|
||||||
#{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR},
|
#{userId,jdbcType=VARCHAR}, #{apiScenarioModuleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR},
|
||||||
#{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
|
#{name,jdbcType=VARCHAR}, #{level,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
|
||||||
#{principal,jdbcType=VARCHAR}, #{stepTotal,jdbcType=INTEGER}, #{followPeople,jdbcType=VARCHAR},
|
#{principal,jdbcType=VARCHAR}, #{stepTotal,jdbcType=INTEGER}, #{followPeople,jdbcType=VARCHAR},
|
||||||
#{schedule,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
|
#{schedule,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
|
||||||
#{updateTime,jdbcType=BIGINT}, #{scenarioDefinition,jdbcType=LONGVARCHAR})
|
#{updateTime,jdbcType=BIGINT}, #{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR},
|
||||||
|
#{reportId,jdbcType=VARCHAR}, #{scenarioDefinition,jdbcType=LONGVARCHAR})
|
||||||
</insert>
|
</insert>
|
||||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenario">
|
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenario">
|
||||||
insert into api_scenario
|
insert into api_scenario
|
||||||
|
@ -201,6 +206,15 @@
|
||||||
<if test="updateTime != null">
|
<if test="updateTime != null">
|
||||||
update_time,
|
update_time,
|
||||||
</if>
|
</if>
|
||||||
|
<if test="passRate != null">
|
||||||
|
pass_rate,
|
||||||
|
</if>
|
||||||
|
<if test="lastResult != null">
|
||||||
|
last_result,
|
||||||
|
</if>
|
||||||
|
<if test="reportId != null">
|
||||||
|
report_id,
|
||||||
|
</if>
|
||||||
<if test="scenarioDefinition != null">
|
<if test="scenarioDefinition != null">
|
||||||
scenario_definition,
|
scenario_definition,
|
||||||
</if>
|
</if>
|
||||||
|
@ -254,6 +268,15 @@
|
||||||
<if test="updateTime != null">
|
<if test="updateTime != null">
|
||||||
#{updateTime,jdbcType=BIGINT},
|
#{updateTime,jdbcType=BIGINT},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="passRate != null">
|
||||||
|
#{passRate,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="lastResult != null">
|
||||||
|
#{lastResult,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="reportId != null">
|
||||||
|
#{reportId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="scenarioDefinition != null">
|
<if test="scenarioDefinition != null">
|
||||||
#{scenarioDefinition,jdbcType=LONGVARCHAR},
|
#{scenarioDefinition,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -316,6 +339,15 @@
|
||||||
<if test="record.updateTime != null">
|
<if test="record.updateTime != null">
|
||||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="record.passRate != null">
|
||||||
|
pass_rate = #{record.passRate,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="record.lastResult != null">
|
||||||
|
last_result = #{record.lastResult,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="record.reportId != null">
|
||||||
|
report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="record.scenarioDefinition != null">
|
<if test="record.scenarioDefinition != null">
|
||||||
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
|
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -342,6 +374,9 @@
|
||||||
description = #{record.description,jdbcType=VARCHAR},
|
description = #{record.description,jdbcType=VARCHAR},
|
||||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||||
|
pass_rate = #{record.passRate,jdbcType=VARCHAR},
|
||||||
|
last_result = #{record.lastResult,jdbcType=VARCHAR},
|
||||||
|
report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||||
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR}
|
scenario_definition = #{record.scenarioDefinition,jdbcType=LONGVARCHAR}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
|
@ -364,7 +399,10 @@
|
||||||
schedule = #{record.schedule,jdbcType=VARCHAR},
|
schedule = #{record.schedule,jdbcType=VARCHAR},
|
||||||
description = #{record.description,jdbcType=VARCHAR},
|
description = #{record.description,jdbcType=VARCHAR},
|
||||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||||
update_time = #{record.updateTime,jdbcType=BIGINT}
|
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||||
|
pass_rate = #{record.passRate,jdbcType=VARCHAR},
|
||||||
|
last_result = #{record.lastResult,jdbcType=VARCHAR},
|
||||||
|
report_id = #{record.reportId,jdbcType=VARCHAR}
|
||||||
<if test="_parameter != null">
|
<if test="_parameter != null">
|
||||||
<include refid="Update_By_Example_Where_Clause" />
|
<include refid="Update_By_Example_Where_Clause" />
|
||||||
</if>
|
</if>
|
||||||
|
@ -417,6 +455,15 @@
|
||||||
<if test="updateTime != null">
|
<if test="updateTime != null">
|
||||||
update_time = #{updateTime,jdbcType=BIGINT},
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
</if>
|
</if>
|
||||||
|
<if test="passRate != null">
|
||||||
|
pass_rate = #{passRate,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="lastResult != null">
|
||||||
|
last_result = #{lastResult,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="reportId != null">
|
||||||
|
report_id = #{reportId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
<if test="scenarioDefinition != null">
|
<if test="scenarioDefinition != null">
|
||||||
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
|
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR},
|
||||||
</if>
|
</if>
|
||||||
|
@ -440,6 +487,9 @@
|
||||||
description = #{description,jdbcType=VARCHAR},
|
description = #{description,jdbcType=VARCHAR},
|
||||||
create_time = #{createTime,jdbcType=BIGINT},
|
create_time = #{createTime,jdbcType=BIGINT},
|
||||||
update_time = #{updateTime,jdbcType=BIGINT},
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
|
pass_rate = #{passRate,jdbcType=VARCHAR},
|
||||||
|
last_result = #{lastResult,jdbcType=VARCHAR},
|
||||||
|
report_id = #{reportId,jdbcType=VARCHAR},
|
||||||
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR}
|
scenario_definition = #{scenarioDefinition,jdbcType=LONGVARCHAR}
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
|
@ -459,7 +509,10 @@
|
||||||
schedule = #{schedule,jdbcType=VARCHAR},
|
schedule = #{schedule,jdbcType=VARCHAR},
|
||||||
description = #{description,jdbcType=VARCHAR},
|
description = #{description,jdbcType=VARCHAR},
|
||||||
create_time = #{createTime,jdbcType=BIGINT},
|
create_time = #{createTime,jdbcType=BIGINT},
|
||||||
update_time = #{updateTime,jdbcType=BIGINT}
|
update_time = #{updateTime,jdbcType=BIGINT},
|
||||||
|
pass_rate = #{passRate,jdbcType=VARCHAR},
|
||||||
|
last_result = #{lastResult,jdbcType=VARCHAR},
|
||||||
|
report_id = #{reportId,jdbcType=VARCHAR}
|
||||||
where id = #{id,jdbcType=VARCHAR}
|
where id = #{id,jdbcType=VARCHAR}
|
||||||
</update>
|
</update>
|
||||||
</mapper>
|
</mapper>
|
|
@ -12,6 +12,7 @@
|
||||||
select api_scenario.id, api_scenario.project_id, api_scenario.tag_id, api_scenario.user_id,
|
select api_scenario.id, api_scenario.project_id, api_scenario.tag_id, api_scenario.user_id,
|
||||||
api_scenario.api_scenario_module_id,api_scenario.module_path, api_scenario.name, api_scenario.level,
|
api_scenario.api_scenario_module_id,api_scenario.module_path, api_scenario.name, api_scenario.level,
|
||||||
api_scenario.status, api_scenario.principal, api_scenario.step_total, api_scenario.follow_people,
|
api_scenario.status, api_scenario.principal, api_scenario.step_total, api_scenario.follow_people,
|
||||||
|
api_scenario.last_result,api_scenario.pass_rate,api_scenario.report_id,
|
||||||
api_scenario.schedule, api_scenario.description, api_scenario.create_time, api_scenario.update_time,
|
api_scenario.schedule, api_scenario.description, api_scenario.create_time, api_scenario.update_time,
|
||||||
project.name as project_name, user.name as user_name
|
project.name as project_name, user.name as user_name
|
||||||
from api_scenario
|
from api_scenario
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<el-card>
|
<el-card>
|
||||||
<section class="report-container" v-if="this.report.testId">
|
<section class="report-container" v-if="this.report.testId">
|
||||||
|
|
||||||
<ms-api-report-view-header :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
|
<ms-api-report-view-header :debug="debug" :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
|
||||||
|
|
||||||
<main v-if="this.isNotRunning">
|
<main v-if="this.isNotRunning">
|
||||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||||
|
@ -71,6 +71,7 @@
|
||||||
reportId: String,
|
reportId: String,
|
||||||
currentProjectId: String,
|
currentProjectId: String,
|
||||||
infoDb: Boolean,
|
infoDb: Boolean,
|
||||||
|
debug: Boolean,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
reportId() {
|
reportId() {
|
||||||
|
@ -178,6 +179,8 @@
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.$emit('refresh');
|
this.$emit('refresh');
|
||||||
|
}, error => {
|
||||||
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportReportReset() {
|
exportReportReset() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
{{$t('test_track.plan_view.export_report')}}
|
{{$t('test_track.plan_view.export_report')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
|
<el-button v-if="!debug" :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
|
||||||
{{$t('commons.save')}}
|
{{$t('commons.save')}}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
@ -23,7 +23,10 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiReportViewHeader",
|
name: "MsApiReportViewHeader",
|
||||||
props: ['report'],
|
props: {
|
||||||
|
report: {},
|
||||||
|
debug: Boolean,
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
path() {
|
path() {
|
||||||
return "/api/test/edit?id=" + this.report.testId;
|
return "/api/test/edit?id=" + this.report.testId;
|
||||||
|
|
|
@ -21,6 +21,13 @@
|
||||||
<!-- 请求参数-->
|
<!-- 请求参数-->
|
||||||
<el-collapse-transition>
|
<el-collapse-transition>
|
||||||
<div v-if="request.active">
|
<div v-if="request.active">
|
||||||
|
<div v-if="request.protocol === 'HTTP'">
|
||||||
|
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-model="request.url" style="width: 85%;margin-top: 10px" size="small">
|
||||||
|
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
|
||||||
|
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||||
|
</el-select>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
||||||
<ms-api-request-form :headers="request.headers " :request="request" v-if="request.protocol==='HTTP'"/>
|
<ms-api-request-form :headers="request.headers " :request="request" v-if="request.protocol==='HTTP'"/>
|
||||||
<ms-tcp-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
|
<ms-tcp-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
|
||||||
|
@ -41,6 +48,7 @@
|
||||||
import MsTcpBasisParameters from "../../definition/components/request/tcp/BasisParameters";
|
import MsTcpBasisParameters from "../../definition/components/request/tcp/BasisParameters";
|
||||||
import MsDubboBasisParameters from "../../definition/components/request/dubbo/BasisParameters";
|
import MsDubboBasisParameters from "../../definition/components/request/dubbo/BasisParameters";
|
||||||
import MsApiRequestForm from "../../definition/components/request/http/ApiRequestForm";
|
import MsApiRequestForm from "../../definition/components/request/http/ApiRequestForm";
|
||||||
|
import {REQ_METHOD} from "../../definition/model/JsonData";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiComponent",
|
name: "MsApiComponent",
|
||||||
|
@ -51,7 +59,18 @@
|
||||||
},
|
},
|
||||||
components: {MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm},
|
components: {MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm},
|
||||||
data() {
|
data() {
|
||||||
return {loading: false,}
|
return {loading: false, reqOptions: REQ_METHOD,}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.request.protocol === 'HTTP') {
|
||||||
|
let urlObject = new URL(this.request.url);
|
||||||
|
let url = urlObject.protocol + "//" + urlObject.host + "/";
|
||||||
|
let path = this.request.url.substr(url.length);
|
||||||
|
if (!path.startsWith('/')) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
this.request.path = path;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
remove() {
|
remove() {
|
||||||
|
@ -94,4 +113,12 @@
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 4px solid #783887;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -58,6 +58,10 @@
|
||||||
let name = this.request.name;
|
let name = this.request.name;
|
||||||
Object.assign(this.request, row.request);
|
Object.assign(this.request, row.request);
|
||||||
this.request.name = name;
|
this.request.name = name;
|
||||||
|
if (this.request.protocol === 'HTTP') {
|
||||||
|
this.request.url = row.url;
|
||||||
|
this.request.method = row.method;
|
||||||
|
}
|
||||||
this.request.resourceId = getUUID();
|
this.request.resourceId = getUUID();
|
||||||
this.$emit('addCustomizeApi', this.request);
|
this.$emit('addCustomizeApi', this.request);
|
||||||
},
|
},
|
||||||
|
@ -72,5 +76,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.tip {
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 4px solid #783887;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -37,14 +37,13 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
|
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
|
||||||
<el-table-column prop="status" :label="$t('api_test.automation.last_result')">
|
<el-table-column prop="lastResult" :label="$t('api_test.automation.last_result')">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
<el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
|
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
|
||||||
<el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
|
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
|
||||||
<el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')"
|
<el-table-column prop="passRate" :label="$t('api_test.automation.passing_rate')"
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
<el-table-column :label="$t('commons.operating')" width="180">
|
<el-table-column :label="$t('commons.operating')" width="180">
|
||||||
<template v-slot:default="{row}">
|
<template v-slot:default="{row}">
|
||||||
|
@ -59,9 +58,9 @@
|
||||||
:total="total"/>
|
:total="total"/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<!-- 调试结果 -->
|
<!-- 执行结果 -->
|
||||||
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
||||||
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject!=undefined ? currentProject.id:''"/>
|
<ms-api-report-detail @refresh="search" :infoDb="infoDb" :report-id="reportId" :currentProjectId="currentProject!=undefined ? currentProject.id:''"/>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
@ -95,6 +94,7 @@
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
reportId: "",
|
reportId: "",
|
||||||
|
infoDb: false,
|
||||||
runVisible: false,
|
runVisible: false,
|
||||||
runData: [],
|
runData: [],
|
||||||
buttons: [
|
buttons: [
|
||||||
|
@ -154,6 +154,7 @@
|
||||||
|
|
||||||
},
|
},
|
||||||
handleBatchExecute() {
|
handleBatchExecute() {
|
||||||
|
this.infoDb = false;
|
||||||
let url = "/api/automation/run";
|
let url = "/api/automation/run";
|
||||||
let run = {};
|
let run = {};
|
||||||
let scenarioIds = this.selection;
|
let scenarioIds = this.selection;
|
||||||
|
@ -179,6 +180,7 @@
|
||||||
this.$emit('edit', row);
|
this.$emit('edit', row);
|
||||||
},
|
},
|
||||||
execute(row) {
|
execute(row) {
|
||||||
|
this.infoDb = false;
|
||||||
let url = "/api/automation/run";
|
let url = "/api/automation/run";
|
||||||
let run = {};
|
let run = {};
|
||||||
let scenarioIds = [];
|
let scenarioIds = [];
|
||||||
|
@ -195,6 +197,11 @@
|
||||||
row.id = getUUID();
|
row.id = getUUID();
|
||||||
this.$emit('edit', row);
|
this.$emit('edit', row);
|
||||||
},
|
},
|
||||||
|
showReport(row) {
|
||||||
|
this.runVisible = true;
|
||||||
|
this.infoDb = true;
|
||||||
|
this.reportId = row.reportId;
|
||||||
|
},
|
||||||
remove(row) {
|
remove(row) {
|
||||||
if (this.currentModule !== undefined && this.currentModule != null && this.currentModule.id === "gc") {
|
if (this.currentModule !== undefined && this.currentModule != null && this.currentModule.id === "gc") {
|
||||||
this.$get('/api/automation/delete/' + row.id, () => {
|
this.$get('/api/automation/delete/' + row.id, () => {
|
||||||
|
|
|
@ -263,7 +263,7 @@
|
||||||
@runRefresh="runRefresh" ref="runTest"/>
|
@runRefresh="runRefresh" ref="runTest"/>
|
||||||
<!-- 调试结果 -->
|
<!-- 调试结果 -->
|
||||||
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
||||||
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject.id"/>
|
<ms-api-report-detail :report-id="reportId" :debug="true" :currentProjectId="currentProject.id"/>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
||||||
<!--场景公共参数-->
|
<!--场景公共参数-->
|
||||||
|
@ -553,7 +553,11 @@
|
||||||
this.$error(this.$t('api_test.environment.select_environment'));
|
this.$error(this.$t('api_test.environment.select_environment'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.debugData = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
|
this.debugData = {
|
||||||
|
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
|
||||||
|
variables: this.currentScenario.variables, referenced: 'Created',
|
||||||
|
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
|
||||||
|
};
|
||||||
this.reportId = getUUID().substring(0, 8);
|
this.reportId = getUUID().substring(0, 8);
|
||||||
},
|
},
|
||||||
getEnvironments() {
|
getEnvironments() {
|
||||||
|
@ -681,6 +685,7 @@
|
||||||
if (response.data.scenarioDefinition != null) {
|
if (response.data.scenarioDefinition != null) {
|
||||||
let obj = JSON.parse(response.data.scenarioDefinition);
|
let obj = JSON.parse(response.data.scenarioDefinition);
|
||||||
this.currentEnvironmentId = obj.environmentId;
|
this.currentEnvironmentId = obj.environmentId;
|
||||||
|
this.currentScenario.variables = obj.variables;
|
||||||
this.scenarioDefinition = obj.hashTree;
|
this.scenarioDefinition = obj.hashTree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -695,7 +700,10 @@
|
||||||
this.currentScenario.stepTotal = this.scenarioDefinition.length;
|
this.currentScenario.stepTotal = this.scenarioDefinition.length;
|
||||||
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
|
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
|
||||||
// 构建一个场景对象 方便引用处理
|
// 构建一个场景对象 方便引用处理
|
||||||
let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
|
let scenario = {
|
||||||
|
id: this.currentScenario.id, name: this.currentScenario.name, variables: this.currentScenario.variables,
|
||||||
|
type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition
|
||||||
|
};
|
||||||
this.currentScenario.scenarioDefinition = scenario;
|
this.currentScenario.scenarioDefinition = scenario;
|
||||||
this.currentScenario.tagId = JSON.stringify(this.currentScenario.tagId);
|
this.currentScenario.tagId = JSON.stringify(this.currentScenario.tagId);
|
||||||
if (this.currentModule != null) {
|
if (this.currentModule != null) {
|
||||||
|
|
|
@ -50,8 +50,7 @@
|
||||||
import {getUUID, getCurrentUser} from "@/common/js/utils";
|
import {getUUID, getCurrentUser} from "@/common/js/utils";
|
||||||
import MsResponseText from "../response/ResponseText";
|
import MsResponseText from "../response/ResponseText";
|
||||||
import MsRun from "../Run";
|
import MsRun from "../Run";
|
||||||
import {createComponent, Request} from "../jmeter/components";
|
import {createComponent} from "../jmeter/components";
|
||||||
import HeaderManager from "../jmeter/components/configurations/header-manager";
|
|
||||||
import {REQ_METHOD} from "../../model/JsonData";
|
import {REQ_METHOD} from "../../model/JsonData";
|
||||||
import MsRequestResultTail from "../response/RequestResultTail";
|
import MsRequestResultTail from "../response/RequestResultTail";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue