feat (接口自动化): 合并插件需求代码 (#5911)

* feat (接口自动化): 动态插件初步完整版 (#5467)

* feat (接口自动化): 合并插件需求代码

Co-authored-by: fit2-zhao <yong.zhao@fit2cloud.com>
Co-authored-by: fit2-zhao <70558837+fit2-zhao@users.noreply.github.com>
This commit is contained in:
metersphere-bot 2021-09-02 16:31:30 +08:00 committed by GitHub
parent d72412ddeb
commit 94f9383db7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 3309 additions and 543 deletions

View File

@ -440,6 +440,13 @@
<artifactId>xmindjbehaveplugin</artifactId>
<version>0.8</version>
</dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-plugin-core</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.automation;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Getter;
import lombok.Setter;

View File

@ -5,7 +5,7 @@ import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.har.HarUtils;
import io.metersphere.api.dto.definition.parse.har.model.*;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.jmeter.RequestResult;

View File

@ -8,7 +8,7 @@ import io.github.ningyu.jmeter.plugin.util.Constants;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ImportPoolsDTO;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.assertions.*;
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
import io.metersphere.api.dto.definition.request.controller.MsTransactionController;

View File

@ -7,7 +7,7 @@ import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.parse.MsAbstractParser;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestCaseService;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.automation.parse;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.parse.postman.PostmanCollection;

View File

@ -1,8 +1,8 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.response.Response;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Getter;
import lombok.Setter;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.response.Response;
import io.metersphere.base.domain.Schedule;
import lombok.Getter;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.base.domain.ApiTestCase;
import lombok.Getter;
import lombok.Setter;

View File

@ -9,7 +9,6 @@ import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ImportPoolsDTO;
import io.metersphere.api.dto.automation.parse.MsJmeterParser;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.assertions.*;
import io.metersphere.api.dto.definition.request.extract.MsExtract;
import io.metersphere.api.dto.definition.request.extract.MsExtractJSONPath;
@ -17,6 +16,7 @@ import io.metersphere.api.dto.definition.request.extract.MsExtractRegex;
import io.metersphere.api.dto.definition.request.extract.MsExtractXPath;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;

View File

@ -1,28 +1,9 @@
package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.controller.MsIfController;
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
import io.metersphere.api.dto.definition.request.controller.MsTransactionController;
import io.metersphere.api.dto.definition.request.extract.MsExtract;
import io.metersphere.api.dto.definition.request.processors.MsJSR223Processor;
import io.metersphere.api.dto.definition.request.processors.post.MsJDBCPostProcessor;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJDBCPreProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
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.MsTCPSampler;
import io.metersphere.api.dto.definition.request.timer.MsConstantTimer;
import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.mockconfig.MockConfigStaticData;
import io.metersphere.api.dto.scenario.KeyValue;
@ -35,8 +16,7 @@ import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import lombok.Data;
import io.metersphere.plugin.core.MsTestElement;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
@ -46,120 +26,25 @@ import org.apache.jmeter.modifiers.CounterConfig;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = MsHTTPSamplerProxy.class, name = "HTTPSamplerProxy"),
@JsonSubTypes.Type(value = MsHeaderManager.class, name = "HeaderManager"),
@JsonSubTypes.Type(value = MsJSR223Processor.class, name = "JSR223Processor"),
@JsonSubTypes.Type(value = MsJSR223PostProcessor.class, name = "JSR223PostProcessor"),
@JsonSubTypes.Type(value = MsJSR223PreProcessor.class, name = "JSR223PreProcessor"),
@JsonSubTypes.Type(value = MsJDBCPreProcessor.class, name = "JDBCPreProcessor"),
@JsonSubTypes.Type(value = MsJDBCPostProcessor.class, name = "JDBCPostProcessor"),
@JsonSubTypes.Type(value = MsTestPlan.class, name = "TestPlan"),
@JsonSubTypes.Type(value = MsThreadGroup.class, name = "ThreadGroup"),
@JsonSubTypes.Type(value = MsAuthManager.class, name = "AuthManager"),
@JsonSubTypes.Type(value = MsAssertions.class, name = "Assertions"),
@JsonSubTypes.Type(value = MsExtract.class, name = "Extract"),
@JsonSubTypes.Type(value = MsTCPSampler.class, name = "TCPSampler"),
@JsonSubTypes.Type(value = MsDubboSampler.class, name = "DubboSampler"),
@JsonSubTypes.Type(value = MsJDBCSampler.class, name = "JDBCSampler"),
@JsonSubTypes.Type(value = MsConstantTimer.class, name = "ConstantTimer"),
@JsonSubTypes.Type(value = MsIfController.class, name = "IfController"),
@JsonSubTypes.Type(value = MsTransactionController.class, name = "TransactionController"),
@JsonSubTypes.Type(value = MsScenario.class, name = "scenario"),
@JsonSubTypes.Type(value = MsLoopController.class, name = "LoopController"),
@JsonSubTypes.Type(value = MsJmeterElement.class, name = "JmeterElement"),
})
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223Processor.class, MsJSR223PostProcessor.class, MsJDBCPreProcessor.class, MsJDBCPostProcessor.class,
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, MsAuthManager.class, MsAssertions.class,
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsTransactionController.class, MsScenario.class, MsLoopController.class, MsJmeterElement.class}, typeKey = "type")
@Data
public abstract class MsTestElement {
private String type;
@JSONField(ordinal = 1)
private String id;
@JSONField(ordinal = 2)
private String name;
@JSONField(ordinal = 3)
private String label;
@JSONField(ordinal = 4)
private String resourceId;
@JSONField(ordinal = 5)
private String referenced;
@JSONField(ordinal = 6)
private boolean active;
@JSONField(ordinal = 7)
private String index;
@JSONField(ordinal = 8)
private boolean enable = true;
@JSONField(ordinal = 9)
private String refType;
@JSONField(ordinal = 10)
private LinkedList<MsTestElement> hashTree;
@JSONField(ordinal = 11)
private boolean customizeReq;
@JSONField(ordinal = 12)
private String projectId;
@JSONField(ordinal = 13)
private boolean isMockEnvironment;
@JSONField(ordinal = 14)
private String environmentId;
private MsTestElement parent;
public class ElementUtil {
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
/**
* todo 公共环境逐层传递如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境
*/
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree, config);
}
}
}
/**
* 转换JMX
*
* @param hashTree
* @return
*/
public String getJmx(HashTree hashTree) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
SaveService.saveTree(hashTree, baos);
return baos.toString();
} catch (Exception e) {
e.printStackTrace();
LogUtil.warn("HashTree error, can't log jmx scenarioDefinition");
}
return null;
}
public HashTree generateHashTree(ParameterConfig config) {
HashTree jmeterTestPlanHashTree = new ListedHashTree();
this.toHashTree(jmeterTestPlanHashTree, this.hashTree, config);
return jmeterTestPlanHashTree;
}
public Arguments addArguments(ParameterConfig config) {
if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) {
public static Arguments addArguments(ParameterConfig config, String projectId, String name) {
if (config.isEffective(projectId) && config.getConfig().get(projectId).getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().get(projectId).getCommonConfig().getVariables())) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(StringUtils.isNoneBlank(this.getName()) ? this.getName() : "Arguments");
arguments.setName(StringUtils.isNoneBlank(name) ? name : "Arguments");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel"));
config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
if (arguments.getArguments().size() > 0) {
@ -169,7 +54,7 @@ public abstract class MsTestElement {
return null;
}
protected Map<String, EnvironmentConfig> getEnvironmentConfig(String environmentId) {
public static Map<String, EnvironmentConfig> getEnvironmentConfig(String environmentId, String projectId, boolean isMockEnvironment) {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
if (environment != null && environment.getConfig() != null) {
@ -178,7 +63,7 @@ public abstract class MsTestElement {
}
// 单独接口执行
Map<String, EnvironmentConfig> map = new HashMap<>();
map.put(this.getProjectId(), JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
map.put(projectId, JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class));
return map;
}
@ -186,7 +71,7 @@ public abstract class MsTestElement {
return null;
}
protected void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables, ParameterConfig config, String shareMode) {
public static void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables, ParameterConfig config, String shareMode) {
if (CollectionUtils.isNotEmpty(variables)) {
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
@ -215,7 +100,7 @@ public abstract class MsTestElement {
}
}
protected void addCounter(HashTree tree, List<ScenarioVariable> variables) {
public static void addCounter(HashTree tree, List<ScenarioVariable> variables) {
if (CollectionUtils.isNotEmpty(variables)) {
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCounterValid).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
@ -237,7 +122,7 @@ public abstract class MsTestElement {
}
}
protected void addRandom(HashTree tree, List<ScenarioVariable> variables) {
public static void addRandom(HashTree tree, List<ScenarioVariable> variables) {
if (CollectionUtils.isNotEmpty(variables)) {
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isRandom).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
@ -258,7 +143,7 @@ public abstract class MsTestElement {
}
}
public String getFullPath(MsTestElement element, String path) {
public static String getFullPath(MsTestElement element, String path) {
if (element.getParent() == null) {
return path;
}
@ -279,7 +164,7 @@ public abstract class MsTestElement {
return getFullPath(element.getParent(), path);
}
public void getScenarioSet(MsTestElement element, List<String> id_names) {
public static void getScenarioSet(MsTestElement element, List<String> id_names) {
if (StringUtils.equals(element.getType(), "scenario")) {
id_names.add(element.getResourceId() + "_" + element.getName());
}
@ -289,7 +174,7 @@ public abstract class MsTestElement {
getScenarioSet(element.getParent(), id_names);
}
protected String getParentName(MsTestElement parent) {
public static String getParentName(MsTestElement parent) {
if (parent != null) {
// if (MsTestElementConstants.TransactionController.name().equals(parent.getType())) {
// MsTransactionController transactionController = (MsTransactionController) parent;
@ -308,7 +193,7 @@ public abstract class MsTestElement {
return "";
}
public String getFullIndexPath(MsTestElement element, String path) {
public static String getFullIndexPath(MsTestElement element, String path) {
if (element == null || element.getParent() == null) {
return path;
}
@ -316,7 +201,7 @@ public abstract class MsTestElement {
return getFullIndexPath(element.getParent(), path);
}
public boolean isURL(String str) {
public static boolean isURL(String str) {
try {
if (StringUtils.isEmpty(str)) {
return false;
@ -350,9 +235,55 @@ public abstract class MsTestElement {
}
return requests;
}
public final static HashMap<String, String> clazzMap = new HashMap<String, String>() {
{
put("scenario", "io.metersphere.api.dto.definition.request.MsScenario");
put("HTTPSamplerProxy", "io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy");
put("DubboSampler", "io.metersphere.api.dto.definition.request.sampler.MsDubboSampler");
put("JDBCSampler", "io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler");
put("TCPSampler", "io.metersphere.api.dto.definition.request.sampler.MsTCPSampler");
put("IfController", "io.metersphere.api.dto.definition.request.controller.MsIfController");
put("TransactionController", "io.metersphere.api.dto.definition.request.controller.MsTransactionController");
put("LoopController", "io.metersphere.api.dto.definition.request.controller.MsLoopController");
put("ConstantTimer", "io.metersphere.api.dto.definition.request.timer.MsConstantTimer");
put("JSR223Processor", "io.metersphere.api.dto.definition.request.processors.MsJSR223Processor");
put("JSR223PreProcessor", "io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor");
put("JSR223PostProcessor", "io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor");
put("JDBCPreProcessor", "io.metersphere.api.dto.definition.request.processors.pre.MsJDBCPreProcessor");
put("JDBCPostProcessor", "io.metersphere.api.dto.definition.request.processors.post.MsJDBCPostProcessor");
put("Assertions", "io.metersphere.api.dto.definition.request.assertions.MsAssertions");
put("Extract", "io.metersphere.api.dto.definition.request.extract.MsExtract");
put("JmeterElement", "io.metersphere.api.dto.definition.request.unknown.MsJmeterElement");
put("TestPlan", "io.metersphere.api.dto.definition.request.MsTestPlan");
put("ThreadGroup", "io.metersphere.api.dto.definition.request.MsThreadGroup");
put("DNSCacheManager", "io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager");
put("DebugSampler", "io.metersphere.api.dto.definition.request.sampler.MsDebugSampler");
}
};
public static void dataFormatting(JSONArray hashTree) {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray);
}
}
}
public static void dataFormatting(JSONObject element) {
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (element != null && element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray);
}
}
}

View File

@ -19,6 +19,8 @@ import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -42,6 +44,7 @@ import java.util.stream.Collectors;
public class MsScenario extends MsTestElement {
private String type = "scenario";
private String clazzName = "io.metersphere.api.dto.definition.request.MsScenario";
@JSONField(ordinal = 21)
private String referenced;
@ -77,7 +80,8 @@ public class MsScenario extends MsTestElement {
}
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -92,6 +96,8 @@ public class MsScenario extends MsTestElement {
ApiScenarioWithBLOBs scenario = apiAutomationService.getApiScenario(this.getId());
if (scenario != null && StringUtils.isNotEmpty(scenario.getScenarioDefinition())) {
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
// 历史数据处理
ElementUtil.dataFormatting(element.getJSONArray("hashTree"));
this.setName(scenario.getName());
this.setProjectId(scenario.getProjectId());
hashTree = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
@ -161,9 +167,9 @@ public class MsScenario extends MsTestElement {
if (arguments != null) {
tree.add(ParameterConfig.valueSupposeMock(arguments));
}
this.addCsvDataSet(tree, variables, config, "shareMode.group");
this.addCounter(tree, variables);
this.addRandom(tree, variables);
ElementUtil.addCsvDataSet(tree, variables, config, "shareMode.group");
ElementUtil.addCounter(tree, variables);
ElementUtil.addRandom(tree, variables);
if (CollectionUtils.isNotEmpty(this.headers)) {
//setHeader(tree, this.headers);
config.setHeaders(this.headers);

View File

@ -2,6 +2,8 @@ package io.metersphere.api.dto.definition.request;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -18,10 +20,13 @@ import java.util.List;
@JSONType(typeName = "TestPlan")
public class MsTestPlan extends MsTestElement {
private String type = "TestPlan";
private String clazzName = "io.metersphere.api.dto.definition.request.MsTestPlan";
private boolean serializeThreadgroups = false;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
final HashTree testPlanTree = tree.add(getPlan());
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {

View File

@ -3,6 +3,8 @@ package io.metersphere.api.dto.definition.request;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.dto.definition.request.sampler.MsDebugSampler;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -20,11 +22,14 @@ import java.util.List;
@JSONType(typeName = "ThreadGroup")
public class MsThreadGroup extends MsTestElement {
private String type = "ThreadGroup";
private String clazzName = "io.metersphere.api.dto.definition.request.MsThreadGroup";
private boolean enableCookieShare;
private Boolean onSampleError;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
final HashTree groupTree = tree.add(getThreadGroup());
if ((config != null && config.isEnableCookieShare()) || enableCookieShare) {
CookieManager cookieManager = new CookieManager();

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.request;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.plugin.core.MsTestElement;
import org.apache.commons.lang3.StringUtils;
import java.util.List;

View File

@ -5,6 +5,7 @@ import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.ssl.MsKeyStore;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.plugin.core.MsParameter;
import lombok.Data;
import org.apache.jmeter.config.Arguments;
@ -14,7 +15,7 @@ import java.util.List;
import java.util.Map;
@Data
public class ParameterConfig {
public class ParameterConfig extends MsParameter {
/**
* 环境配置
*/

View File

@ -1,8 +1,9 @@
package io.metersphere.api.dto.definition.request.assertions;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -18,6 +19,8 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "Assertions")
public class MsAssertions extends MsTestElement {
private String clazzName = "io.metersphere.api.dto.definition.request.assertions.MsAssertions";
private List<MsAssertionRegex> regex;
private List<MsAssertionJsonPath> jsonPath;
private List<MsAssertionJSR223> jsr223;
@ -26,7 +29,8 @@ public class MsAssertions extends MsTestElement {
private String type = "Assertions";
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -2,8 +2,9 @@ package io.metersphere.api.dto.definition.request.auth;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@ -21,6 +22,8 @@ import java.util.List;
@JSONType(typeName = "AuthManager")
public class MsAuthManager extends MsTestElement {
private String type = "AuthManager";
private String clazzName = "io.metersphere.api.dto.definition.request.auth.MsAuthManager";
@JSONField(ordinal = 20)
private String username;
@ -49,10 +52,11 @@ public class MsAuthManager extends MsTestElement {
private String environment;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
if (!this.isEnable()) {
return;
}
ParameterConfig config = (ParameterConfig) msParameter;
AuthManager authManager = new AuthManager();
authManager.setEnabled(true);
authManager.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "AuthManager");

View File

@ -2,9 +2,10 @@ package io.metersphere.api.dto.definition.request.configurations;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -23,11 +24,14 @@ import java.util.List;
public class MsHeaderManager extends MsTestElement {
private String type = "HeaderManager";
private String clazzName = "io.metersphere.api.dto.definition.request.configurations.MsHeaderManager";
@JSONField(ordinal = 20)
private List<KeyValue> headers;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(this.isEnable());
headerManager.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() + "HeaderManager" : "HeaderManager");

View File

@ -1,8 +1,9 @@
package io.metersphere.api.dto.definition.request.controller;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -21,6 +22,8 @@ import java.util.regex.Pattern;
@JSONType(typeName = "IfController")
public class MsIfController extends MsTestElement {
private String type = "IfController";
private String clazzName = "io.metersphere.api.dto.definition.request.controller.MsIfController";
private String id;
private String variable;
private String operator;
@ -28,7 +31,8 @@ public class MsIfController extends MsTestElement {
private String remark;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -2,12 +2,14 @@ package io.metersphere.api.dto.definition.request.controller;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.controller.loop.CountController;
import io.metersphere.api.dto.definition.request.controller.loop.MsForEachController;
import io.metersphere.api.dto.definition.request.controller.loop.MsWhileController;
import io.metersphere.commons.constants.LoopConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -30,6 +32,8 @@ import java.util.UUID;
@JSONType(typeName = "LoopController")
public class MsLoopController extends MsTestElement {
private String type = "LoopController";
private String clazzName = "io.metersphere.api.dto.definition.request.controller.MsLoopController";
@JSONField(ordinal = 20)
private String loopType;
@ -46,16 +50,18 @@ public class MsLoopController extends MsTestElement {
private String ms_current_timer = UUID.randomUUID().toString();
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
final HashTree groupTree = controller(tree);
if (CollectionUtils.isNotEmpty(config.getVariables())) {
this.addCsvDataSet(groupTree, config.getVariables(), config, "shareMode.thread");
this.addCounter(groupTree, config.getVariables());
this.addRandom(groupTree, config.getVariables());
ElementUtil.addCsvDataSet(groupTree, config.getVariables(), config, "shareMode.thread");
ElementUtil.addCounter(groupTree, config.getVariables());
ElementUtil.addRandom(groupTree, config.getVariables());
}
// 循环下都增加一个计数器用于结果统计

View File

@ -1,14 +1,15 @@
package io.metersphere.api.dto.definition.request.controller;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.control.IfController;
import org.apache.jmeter.control.TransactionController;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
@ -21,19 +22,22 @@ import java.util.List;
@JSONType(typeName = "TransactionController")
public class MsTransactionController extends MsTestElement {
private String type = "TransactionController";
private String clazzName = "io.metersphere.api.dto.definition.request.controller.MsTransactionController";
private String name;
private boolean generateParentSample;
private boolean includeTimers;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
}
TransactionController transactionController = transactionController();
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
transactionController.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}

View File

@ -1,12 +1,13 @@
package io.metersphere.api.dto.definition.request.dns;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.HttpConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.Host;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -24,9 +25,11 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "DNSCacheManager")
public class MsDNSCacheManager extends MsTestElement {
private String clazzName = "io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager";
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -1,8 +1,9 @@
package io.metersphere.api.dto.definition.request.extract;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -23,13 +24,16 @@ import java.util.StringJoiner;
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "Extract")
public class MsExtract extends MsTestElement {
private String clazzName = "io.metersphere.api.dto.definition.request.extract.MsExtract";
private List<MsExtractRegex> regex;
private List<MsExtractJSONPath> json;
private List<MsExtractXPath> xpath;
private String type = "Extract";
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -4,10 +4,12 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -26,6 +28,7 @@ import java.util.List;
@JSONType(typeName = "JSR223Processor")
public class MsJSR223Processor extends MsTestElement {
private String type = "JSR223Processor";
private String clazzName = "io.metersphere.api.dto.definition.request.processors.MsJSR223Processor";
@JSONField(ordinal = 20)
private String script;
@ -34,7 +37,8 @@ public class MsJSR223Processor extends MsTestElement {
private String scriptLanguage;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
//替换Metersphere环境变量
if(StringUtils.isEmpty(this.getEnvironmentId())){
if(config.getConfig() != null){
@ -67,14 +71,14 @@ public class MsJSR223Processor extends MsTestElement {
} else {
processor.setName("JSR223Processor");
}
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
processor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
processor.setProperty("MS-ID", this.getId());
processor.setProperty("MS-RESOURCE-ID", this.getResourceId()+ "_" + this.getIndex());
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
processor.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
processor.setProperty(TestElement.TEST_CLASS, JSR223Sampler.class.getName());

View File

@ -7,7 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
@ -24,6 +24,8 @@ import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -50,6 +52,8 @@ import java.util.stream.Collectors;
public class MsJDBCPostProcessor extends MsTestElement {
// type 必须放最前面以便能够转换正确的类
private String type = "JDBCPostProcessor";
private String clazzName = "io.metersphere.api.dto.definition.request.processors.post.MsJDBCPostProcessor";
@JSONField(ordinal = 20)
private DatabaseConfig dataSource;
@JSONField(ordinal = 21)
@ -73,7 +77,8 @@ public class MsJDBCPostProcessor extends MsTestElement {
private String useEnvironment;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -84,7 +89,7 @@ public class MsJDBCPostProcessor extends MsTestElement {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId));
config.setConfig(ElementUtil.getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId, this.getProjectId(), this.isMockEnvironment()));
}
// 数据兼容处理
@ -108,7 +113,7 @@ public class MsJDBCPostProcessor extends MsTestElement {
}
}
//如果当前数据源为null则获取已选环境的数据源
if(this.dataSource == null){
if (this.dataSource == null) {
// 自选了数据源
if (config.isEffective(this.getProjectId()) && CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getDatabaseConfigs())
&& isDataSource(config.getConfig().get(this.getProjectId()).getDatabaseConfigs())) {
@ -174,7 +179,9 @@ public class MsJDBCPostProcessor extends MsTestElement {
if (bloBs != null) {
this.setName(bloBs.getName());
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsJDBCPostProcessor>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsJDBCPostProcessor>() {
});
}
} else {
@ -237,7 +244,7 @@ public class MsJDBCPostProcessor extends MsTestElement {
JDBCPostProcessor jdbcPostProcessor = new JDBCPostProcessor();
jdbcPostProcessor.setEnabled(this.isEnable());
jdbcPostProcessor.setName(this.getName() == null? "JDBCPostProcessor" : this.getName());
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
jdbcPostProcessor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
@ -245,9 +252,9 @@ public class MsJDBCPostProcessor extends MsTestElement {
jdbcPostProcessor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
jdbcPostProcessor.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
jdbcPostProcessor.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
jdbcPostProcessor.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
jdbcPostProcessor.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
// request.getDataSource() 是ID需要转换为Name

View File

@ -3,9 +3,10 @@ package io.metersphere.api.dto.definition.request.processors.post;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.RunningParamKeys;
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.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -23,6 +24,7 @@ import java.util.List;
@JSONType(typeName = "JSR223PostProcessor")
public class MsJSR223PostProcessor extends MsTestElement {
private String type = "JSR223PostProcessor";
private String clazzName = "io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor";
@JSONField(ordinal = 20)
private String script;
@ -31,7 +33,8 @@ public class MsJSR223PostProcessor extends MsTestElement {
private String scriptLanguage;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
if(StringUtils.isEmpty(this.getEnvironmentId())){
if(config.getConfig() != null){
if(config.getProjectId() != null){

View File

@ -7,7 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
@ -24,6 +24,8 @@ import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -50,6 +52,8 @@ import java.util.stream.Collectors;
public class MsJDBCPreProcessor extends MsTestElement {
// type 必须放最前面以便能够转换正确的类
private String type = "JDBCPreProcessor";
private String clazzName = "io.metersphere.api.dto.definition.request.processors.pre.MsJDBCPreProcessor";
@JSONField(ordinal = 20)
private DatabaseConfig dataSource;
@JSONField(ordinal = 21)
@ -73,7 +77,8 @@ public class MsJDBCPreProcessor extends MsTestElement {
private String useEnvironment;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -84,7 +89,7 @@ public class MsJDBCPreProcessor extends MsTestElement {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId));
config.setConfig(ElementUtil.getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId, this.getProjectId(), isMockEnvironment()));
}
// 数据兼容处理
@ -108,7 +113,7 @@ public class MsJDBCPreProcessor extends MsTestElement {
}
}
//如果当前数据源为null则获取已选环境的数据源
if(this.dataSource == null){
if (this.dataSource == null) {
// 自选了数据源
if (config.isEffective(this.getProjectId()) && CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getDatabaseConfigs())
&& isDataSource(config.getConfig().get(this.getProjectId()).getDatabaseConfigs())) {
@ -174,7 +179,9 @@ public class MsJDBCPreProcessor extends MsTestElement {
if (bloBs != null) {
this.setName(bloBs.getName());
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsJDBCPreProcessor>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsJDBCPreProcessor>() {
});
}
} else {
@ -237,7 +244,7 @@ public class MsJDBCPreProcessor extends MsTestElement {
JDBCPreProcessor jdbcPreProcessor = new JDBCPreProcessor();
jdbcPreProcessor.setEnabled(this.isEnable());
jdbcPreProcessor.setName(this.getName() == null? "JDBCPreProcessor" : this.getName());
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
jdbcPreProcessor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
@ -245,9 +252,9 @@ public class MsJDBCPreProcessor extends MsTestElement {
jdbcPreProcessor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
jdbcPreProcessor.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
jdbcPreProcessor.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
jdbcPreProcessor.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
jdbcPreProcessor.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
// request.getDataSource() 是ID需要转换为Name

View File

@ -3,9 +3,10 @@ package io.metersphere.api.dto.definition.request.processors.pre;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.RunningParamKeys;
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.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -23,6 +24,7 @@ import java.util.List;
@JSONType(typeName = "JSR223PreProcessor")
public class MsJSR223PreProcessor extends MsTestElement {
private String type = "JSR223PreProcessor";
private String clazzName = "io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor";
@JSONField(ordinal = 20)
private String script;
@ -31,7 +33,8 @@ public class MsJSR223PreProcessor extends MsTestElement {
private String scriptLanguage;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
if(StringUtils.isEmpty(this.getEnvironmentId())){
if(config.getConfig() != null){
if(config.getProjectId() != null){

View File

@ -2,8 +2,9 @@ package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -19,6 +20,8 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "DebugSampler")
public class MsDebugSampler extends MsTestElement {
private String clazzName = "io.metersphere.api.dto.definition.request.sampler.MsDebugSampler";
@JSONField(ordinal = 40)
private String type = "DebugSampler";
@JSONField(ordinal = 41)
@ -29,7 +32,8 @@ public class MsDebugSampler extends MsTestElement {
private boolean displaySystemProperties = false;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.annotation.JsonProperty;
@ -10,7 +11,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
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.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
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.MsConsumerAndService;
@ -24,6 +25,8 @@ import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -41,6 +44,8 @@ import java.util.stream.Collectors;
@EqualsAndHashCode(callSuper = true)
@JSONType(typeName = "DubboSampler")
public class MsDubboSampler extends MsTestElement {
private String clazzName = "io.metersphere.api.dto.definition.request.sampler.MsDubboSampler";
/**
* type 必须放最前面以便能够转换正确的类
*/
@ -69,8 +74,13 @@ public class MsDubboSampler extends MsTestElement {
@JSONField(ordinal = 60)
private String useEnvironment;
@JSONField(ordinal = 61)
private boolean customizeReq;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -101,7 +111,9 @@ public class MsDubboSampler extends MsTestElement {
ApiTestCaseWithBLOBs bloBs = apiTestCaseService.get(this.getId());
if (bloBs != null) {
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsDubboSampler>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsDubboSampler>() {
});
this.setName(bloBs.getName());
}
@ -134,7 +146,7 @@ public class MsDubboSampler extends MsTestElement {
DubboSample sampler = new DubboSample();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
@ -142,9 +154,9 @@ public class MsDubboSampler extends MsTestElement {
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DubboSampleGui"));
sampler.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
sampler.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
sampler.addTestElement(configCenter(this.getConfigCenter()));

View File

@ -7,7 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
@ -38,6 +38,8 @@ import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.track.service.TestPlanApiCaseService;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -68,6 +70,7 @@ import java.util.stream.Collectors;
@JSONType(typeName = "HTTPSamplerProxy")
public class MsHTTPSamplerProxy extends MsTestElement {
private String type = "HTTPSamplerProxy";
private String clazzName = "io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy";
@JSONField(ordinal = 20)
private String protocol;
@ -122,10 +125,13 @@ public class MsHTTPSamplerProxy extends MsTestElement {
@JSONField(ordinal = 38)
private String alias;
@JSONField(ordinal = 39)
private boolean customizeReq;
private MsJSR223PreProcessor preProcessor;
private MsJSR223PostProcessor postProcessor;
private void setRefElement() {
try {
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
@ -137,7 +143,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
ApiTestCaseWithBLOBs bloBs = apiTestCaseService.get(this.getId());
if (bloBs != null) {
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsHTTPSamplerProxy>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsHTTPSamplerProxy>() {
});
this.setName(bloBs.getName());
}
@ -165,7 +173,8 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
if (StringUtils.isEmpty(this.getEnvironmentId())) {
this.setEnvironmentId(this.useEnvironment);
}
@ -183,7 +192,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (StringUtils.isEmpty(this.getName())) {
sampler.setName("HTTPSamplerProxy");
}
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
@ -191,9 +200,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
sampler.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
sampler.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
sampler.setMethod(this.getMethod());
@ -204,7 +213,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(useEnvironment));
config.setConfig(ElementUtil.getEnvironmentConfig(this.useEnvironment, this.getProjectId(), this.isMockEnvironment()));
}
compatible(config);
@ -355,7 +364,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
private void setSamplerPath(ParameterConfig config, HttpConfig httpConfig, HTTPSamplerProxy sampler) {
try {
if (config.isEffective(this.getProjectId())) {
if (httpConfig == null && !isURL(this.getUrl())) {
if (httpConfig == null && !ElementUtil.isURL(this.getUrl())) {
MSException.throwException("未匹配到环境,请检查环境配置");
}
if (StringUtils.isEmpty(httpConfig.getProtocol())) {
@ -367,7 +376,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
String url = httpConfig.getProtocol() + "://" + httpConfig.getSocket();
// 补充如果是完整URL 则用自身URL
if (StringUtils.isNotEmpty(this.getUrl()) && isURL(this.getUrl())) {
if (StringUtils.isNotEmpty(this.getUrl()) && ElementUtil.isURL(this.getUrl())) {
url = this.getUrl();
}
@ -588,7 +597,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
return true;
}
if (StringUtils.isNotEmpty(this.getUrl()) && isURL(this.getUrl())) {
if (StringUtils.isNotEmpty(this.getUrl()) && ElementUtil.isURL(this.getUrl())) {
return true;
}
return false;
@ -817,7 +826,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
public static List<MsHTTPSamplerProxy> findHttpSampleFromHashTree(MsTestElement hashTree) {
return findFromHashTreeByType(hashTree, MsHTTPSamplerProxy.class, null);
return ElementUtil.findFromHashTreeByType(hashTree, MsHTTPSamplerProxy.class, null);
}
}

View File

@ -7,7 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
@ -26,6 +26,8 @@ import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -48,6 +50,8 @@ import java.util.stream.Collectors;
public class MsJDBCSampler extends MsTestElement {
// type 必须放最前面以便能够转换正确的类
private String type = "JDBCSampler";
private String clazzName = "io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler";
@JSONField(ordinal = 20)
private DatabaseConfig dataSource;
@JSONField(ordinal = 21)
@ -70,11 +74,15 @@ public class MsJDBCSampler extends MsTestElement {
@JSONField(ordinal = 30)
private String useEnvironment;
@JSONField(ordinal = 31)
private boolean customizeReq;
private MsJSR223PreProcessor preProcessor;
private MsJSR223PostProcessor postProcessor;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -85,7 +93,7 @@ public class MsJDBCSampler extends MsTestElement {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId));
config.setConfig(ElementUtil.getEnvironmentConfig(StringUtils.isNotEmpty(useEnvironment) ? useEnvironment : environmentId, this.getProjectId(), this.isMockEnvironment()));
}
// 数据兼容处理
@ -205,7 +213,9 @@ public class MsJDBCSampler extends MsTestElement {
if (bloBs != null) {
this.setName(bloBs.getName());
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsJDBCSampler>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsJDBCSampler>() {
});
}
} else {
@ -272,7 +282,7 @@ public class MsJDBCSampler extends MsTestElement {
JDBCSampler sampler = new JDBCSampler();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
@ -280,9 +290,9 @@ public class MsJDBCSampler extends MsTestElement {
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
sampler.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
sampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
sampler.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
// request.getDataSource() 是ID需要转换为Name

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
@ -8,7 +9,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
@ -23,6 +24,8 @@ import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -52,6 +55,8 @@ import java.util.regex.Pattern;
public class MsTCPSampler extends MsTestElement {
@JSONField(ordinal = 20)
private String type = "TCPSampler";
private String clazzName = "io.metersphere.api.dto.definition.request.sampler.MsTCPSampler";
@JSONField(ordinal = 21)
private String classname = "";
@JSONField(ordinal = 22)
@ -99,6 +104,9 @@ public class MsTCPSampler extends MsTestElement {
@JSONField(ordinal = 44)
private String rawDataStruct;
@JSONField(ordinal = 45)
private boolean customizeReq;
private MsJSR223PreProcessor preProcessor;
private MsJSR223PostProcessor postProcessor;
@ -109,7 +117,8 @@ public class MsTCPSampler extends MsTestElement {
private List<EsbDataStruct> backEsbDataStruct;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;
@ -120,14 +129,14 @@ public class MsTCPSampler extends MsTestElement {
if (config.getConfig() == null) {
// 单独接口执行
this.setProjectId(config.getProjectId());
config.setConfig(getEnvironmentConfig(useEnvironment));
config.setConfig(ElementUtil.getEnvironmentConfig(useEnvironment, this.getProjectId(), this.isMockEnvironment()));
}
if (config.getConfig() != null) {
parseEnvironment(config.getConfig().get(this.projectId));
}
// 添加环境中的公共变量
Arguments arguments = this.addArguments(config);
Arguments arguments = ElementUtil.addArguments(config, this.getProjectId(), this.getName());
if (arguments != null) {
tree.add(arguments);
}
@ -180,7 +189,9 @@ public class MsTCPSampler extends MsTestElement {
if (bloBs != null) {
this.setName(bloBs.getName());
this.setProjectId(bloBs.getProjectId());
proxy = mapper.readValue(bloBs.getRequest(), new TypeReference<MsTCPSampler>() {
JSONObject element = JSON.parseObject(bloBs.getRequest());
ElementUtil.dataFormatting(element);
proxy = mapper.readValue(element.toJSONString(), new TypeReference<MsTCPSampler>() {
});
}
} else {
@ -229,15 +240,15 @@ public class MsTCPSampler extends MsTestElement {
TCPSampler tcpSampler = new TCPSampler();
tcpSampler.setEnabled(this.isEnable());
tcpSampler.setName(this.getName());
String name = this.getParentName(this.getParent());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
tcpSampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
tcpSampler.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
tcpSampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + this.getFullIndexPath(this.getParent(), indexPath));
tcpSampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));
List<String> id_names = new LinkedList<>();
this.getScenarioSet(this, id_names);
ElementUtil.getScenarioSet(this, id_names);
tcpSampler.setProperty("MS-SCENARIO", JSON.toJSONString(id_names));
tcpSampler.setProperty(TestElement.TEST_CLASS, TCPSampler.class.getName());

View File

@ -2,8 +2,9 @@ package io.metersphere.api.dto.definition.request.timer;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -19,13 +20,16 @@ import java.util.List;
@JSONType(typeName = "ConstantTimer")
public class MsConstantTimer extends MsTestElement {
private String type = "ConstantTimer";
private String clazzName = "io.metersphere.api.dto.definition.request.timer.MsConstantTimer";
@JSONField(ordinal = 20)
private String id;
@JSONField(ordinal = 21)
private String delay;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -1,13 +1,14 @@
package io.metersphere.api.dto.definition.request.unknown;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
@ -33,12 +34,15 @@ import java.util.stream.Collectors;
@JSONType(typeName = "JmeterElement")
public class MsJmeterElement extends MsTestElement {
private String type = "JmeterElement";
private String clazzName = "io.metersphere.api.dto.definition.request.unknown.MsJmeterElement";
private String elementType;
private String jmeterElement;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, MsParameter msParameter) {
try {
ParameterConfig config = (ParameterConfig) msParameter;
// 非导出操作且不是启用状态则跳过执行
if (!config.isOperating() && !this.isEnable()) {
return;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.definition.parse.har.model.*;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.postman.PostmanEvent;

View File

@ -2,7 +2,7 @@ package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.postman.*;

View File

@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.ApiImport;

View File

@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.parse.ApiImport;

View File

@ -42,6 +42,7 @@ import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.api.AutomationReference;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.dto.TestPlanDTO;
@ -601,6 +602,7 @@ public class ApiAutomationService {
JSONObject element = JSON.parseObject(definition);
try {
if (element != null) {
ElementUtil.dataFormatting(element);
return objectMapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
}
@ -611,9 +613,7 @@ public class ApiAutomationService {
}
public ScenarioEnv getApiScenarioEnv(String definition) {
ObjectMapper mapper = new ObjectMapper();
ScenarioEnv env = new ScenarioEnv();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<MsTestElement> hashTree = getScenarioHashTree(definition);
for (int i = 0; i < hashTree.size(); i++) {
MsTestElement tr = hashTree.get(i);
@ -727,6 +727,7 @@ public class ApiAutomationService {
env.getProjectIds().add(apiScenario.getProjectId());
String scenarioDefinition = apiScenario.getScenarioDefinition();
JSONObject element1 = JSON.parseObject(scenarioDefinition);
ElementUtil.dataFormatting(element1);
LinkedList<MsTestElement> hashTree1 = mapper.readValue(element1.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
tr.setHashTree(hashTree1);
@ -738,7 +739,7 @@ public class ApiAutomationService {
// 校验是否是全路径
MsHTTPSamplerProxy httpSamplerProxy = (MsHTTPSamplerProxy) tr;
if (httpSamplerProxy.isEnable()) {
if (StringUtils.isBlank(httpSamplerProxy.getUrl()) || !tr.isURL(httpSamplerProxy.getUrl())) {
if (StringUtils.isBlank(httpSamplerProxy.getUrl()) || !ElementUtil.isURL(httpSamplerProxy.getUrl())) {
env.setFullUrl(false);
env.getProjectIds().add(httpSamplerProxy.getProjectId());
}
@ -826,6 +827,8 @@ public class ApiAutomationService {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
JSONObject element = JSON.parseObject(scenarioDefinition);
ElementUtil.dataFormatting(element);
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
@ -1207,7 +1210,7 @@ public class ApiAutomationService {
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
for (ApiScenarioWithBLOBs item : apiScenarios) {
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
// 只有一个场景且没有测试步骤则提示
// 只有 一个场景且没有测试步骤则提示
if (apiScenarios.size() == 1) {
MSException.throwException((item.getName() + "" + Translator.get("automation_exec_info")));
}
@ -1227,6 +1230,9 @@ public class ApiAutomationService {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
// 历史数据处理
ElementUtil.dataFormatting(element.getJSONArray("hashTree"));
MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class);
group.setOnSampleError(scenario.getOnSampleError());
this.preduceMsScenario(scenario);
@ -1307,8 +1313,6 @@ public class ApiAutomationService {
}
private boolean checkScenarioEnv(ApiScenarioWithBLOBs apiScenarioWithBLOBs, TestPlanApiScenario testPlanApiScenarios) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String definition = apiScenarioWithBLOBs.getScenarioDefinition();
MsScenario scenario = JSONObject.parseObject(definition, MsScenario.class);
boolean isEnv = true;

View File

@ -10,7 +10,7 @@ import io.metersphere.api.dto.DeleteCheckResult;
import io.metersphere.api.dto.JmxInfoDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
@ -29,6 +29,7 @@ import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.api.DefinitionReference;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
import io.metersphere.service.UserService;
@ -551,8 +552,6 @@ public class ApiTestCaseService {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiTestCaseMapper batchMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
bloBs.forEach(apiTestCase -> {
JSONObject req = JSON.parseObject(apiTestCase.getRequest());
req.put("useEnvironment", request.getEnvId());
@ -578,6 +577,8 @@ public class ApiTestCaseService {
MsHTTPSamplerProxy req = JSON.parseObject(apiTestCase.getRequest(), MsHTTPSamplerProxy.class);
try {
JSONObject element = JSON.parseObject(apiTestCase.getRequest());
ElementUtil.dataFormatting(element);
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
@ -717,7 +718,10 @@ public class ApiTestCaseService {
public HashTree generateHashTree(RunCaseRequest request, ApiTestCaseWithBLOBs testCaseWithBLOBs) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MsTestElement element = mapper.readValue(testCaseWithBLOBs.getRequest(), new TypeReference<MsTestElement>() {
JSONObject elementObj = JSON.parseObject(testCaseWithBLOBs.getRequest());
ElementUtil.dataFormatting(elementObj);
MsTestElement element = mapper.readValue(elementObj.toJSONString(), new TypeReference<MsTestElement>() {
});
element.setProjectId(testCaseWithBLOBs.getProjectId());
if (StringUtils.isBlank(request.getEnvironmentId())) {

View File

@ -6,7 +6,7 @@ import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.automation.parse.EsbDataParser;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.scenario.KeyValue;

View File

@ -8,7 +8,7 @@ import io.metersphere.api.dto.SaveHistoricalDataUpgrade;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.dto.datacount.ApiMethodUrlDTO;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.assertions.MsAssertionDuration;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.definition.request.controller.MsIfController;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.service;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

View File

@ -0,0 +1,30 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class Plugin implements Serializable {
private String id;
private String name;
private String pluginId;
private String clazzName;
private String sourcePath;
private String sourceName;
private String execEntry;
private Long createTime;
private Long updateTime;
private String createUserId;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,880 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class PluginExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public PluginExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andNameIsNull() {
addCriterion("`name` is null");
return (Criteria) this;
}
public Criteria andNameIsNotNull() {
addCriterion("`name` is not null");
return (Criteria) this;
}
public Criteria andNameEqualTo(String value) {
addCriterion("`name` =", value, "name");
return (Criteria) this;
}
public Criteria andNameNotEqualTo(String value) {
addCriterion("`name` <>", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThan(String value) {
addCriterion("`name` >", value, "name");
return (Criteria) this;
}
public Criteria andNameGreaterThanOrEqualTo(String value) {
addCriterion("`name` >=", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThan(String value) {
addCriterion("`name` <", value, "name");
return (Criteria) this;
}
public Criteria andNameLessThanOrEqualTo(String value) {
addCriterion("`name` <=", value, "name");
return (Criteria) this;
}
public Criteria andNameLike(String value) {
addCriterion("`name` like", value, "name");
return (Criteria) this;
}
public Criteria andNameNotLike(String value) {
addCriterion("`name` not like", value, "name");
return (Criteria) this;
}
public Criteria andNameIn(List<String> values) {
addCriterion("`name` in", values, "name");
return (Criteria) this;
}
public Criteria andNameNotIn(List<String> values) {
addCriterion("`name` not in", values, "name");
return (Criteria) this;
}
public Criteria andNameBetween(String value1, String value2) {
addCriterion("`name` between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andNameNotBetween(String value1, String value2) {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andPluginIdIsNull() {
addCriterion("plugin_id is null");
return (Criteria) this;
}
public Criteria andPluginIdIsNotNull() {
addCriterion("plugin_id is not null");
return (Criteria) this;
}
public Criteria andPluginIdEqualTo(String value) {
addCriterion("plugin_id =", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdNotEqualTo(String value) {
addCriterion("plugin_id <>", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdGreaterThan(String value) {
addCriterion("plugin_id >", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdGreaterThanOrEqualTo(String value) {
addCriterion("plugin_id >=", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdLessThan(String value) {
addCriterion("plugin_id <", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdLessThanOrEqualTo(String value) {
addCriterion("plugin_id <=", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdLike(String value) {
addCriterion("plugin_id like", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdNotLike(String value) {
addCriterion("plugin_id not like", value, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdIn(List<String> values) {
addCriterion("plugin_id in", values, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdNotIn(List<String> values) {
addCriterion("plugin_id not in", values, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdBetween(String value1, String value2) {
addCriterion("plugin_id between", value1, value2, "pluginId");
return (Criteria) this;
}
public Criteria andPluginIdNotBetween(String value1, String value2) {
addCriterion("plugin_id not between", value1, value2, "pluginId");
return (Criteria) this;
}
public Criteria andClazzNameIsNull() {
addCriterion("clazz_name is null");
return (Criteria) this;
}
public Criteria andClazzNameIsNotNull() {
addCriterion("clazz_name is not null");
return (Criteria) this;
}
public Criteria andClazzNameEqualTo(String value) {
addCriterion("clazz_name =", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameNotEqualTo(String value) {
addCriterion("clazz_name <>", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameGreaterThan(String value) {
addCriterion("clazz_name >", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameGreaterThanOrEqualTo(String value) {
addCriterion("clazz_name >=", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameLessThan(String value) {
addCriterion("clazz_name <", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameLessThanOrEqualTo(String value) {
addCriterion("clazz_name <=", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameLike(String value) {
addCriterion("clazz_name like", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameNotLike(String value) {
addCriterion("clazz_name not like", value, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameIn(List<String> values) {
addCriterion("clazz_name in", values, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameNotIn(List<String> values) {
addCriterion("clazz_name not in", values, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameBetween(String value1, String value2) {
addCriterion("clazz_name between", value1, value2, "clazzName");
return (Criteria) this;
}
public Criteria andClazzNameNotBetween(String value1, String value2) {
addCriterion("clazz_name not between", value1, value2, "clazzName");
return (Criteria) this;
}
public Criteria andSourcePathIsNull() {
addCriterion("source_path is null");
return (Criteria) this;
}
public Criteria andSourcePathIsNotNull() {
addCriterion("source_path is not null");
return (Criteria) this;
}
public Criteria andSourcePathEqualTo(String value) {
addCriterion("source_path =", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathNotEqualTo(String value) {
addCriterion("source_path <>", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathGreaterThan(String value) {
addCriterion("source_path >", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathGreaterThanOrEqualTo(String value) {
addCriterion("source_path >=", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathLessThan(String value) {
addCriterion("source_path <", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathLessThanOrEqualTo(String value) {
addCriterion("source_path <=", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathLike(String value) {
addCriterion("source_path like", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathNotLike(String value) {
addCriterion("source_path not like", value, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathIn(List<String> values) {
addCriterion("source_path in", values, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathNotIn(List<String> values) {
addCriterion("source_path not in", values, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathBetween(String value1, String value2) {
addCriterion("source_path between", value1, value2, "sourcePath");
return (Criteria) this;
}
public Criteria andSourcePathNotBetween(String value1, String value2) {
addCriterion("source_path not between", value1, value2, "sourcePath");
return (Criteria) this;
}
public Criteria andSourceNameIsNull() {
addCriterion("source_name is null");
return (Criteria) this;
}
public Criteria andSourceNameIsNotNull() {
addCriterion("source_name is not null");
return (Criteria) this;
}
public Criteria andSourceNameEqualTo(String value) {
addCriterion("source_name =", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameNotEqualTo(String value) {
addCriterion("source_name <>", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameGreaterThan(String value) {
addCriterion("source_name >", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameGreaterThanOrEqualTo(String value) {
addCriterion("source_name >=", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameLessThan(String value) {
addCriterion("source_name <", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameLessThanOrEqualTo(String value) {
addCriterion("source_name <=", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameLike(String value) {
addCriterion("source_name like", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameNotLike(String value) {
addCriterion("source_name not like", value, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameIn(List<String> values) {
addCriterion("source_name in", values, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameNotIn(List<String> values) {
addCriterion("source_name not in", values, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameBetween(String value1, String value2) {
addCriterion("source_name between", value1, value2, "sourceName");
return (Criteria) this;
}
public Criteria andSourceNameNotBetween(String value1, String value2) {
addCriterion("source_name not between", value1, value2, "sourceName");
return (Criteria) this;
}
public Criteria andExecEntryIsNull() {
addCriterion("exec_entry is null");
return (Criteria) this;
}
public Criteria andExecEntryIsNotNull() {
addCriterion("exec_entry is not null");
return (Criteria) this;
}
public Criteria andExecEntryEqualTo(String value) {
addCriterion("exec_entry =", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryNotEqualTo(String value) {
addCriterion("exec_entry <>", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryGreaterThan(String value) {
addCriterion("exec_entry >", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryGreaterThanOrEqualTo(String value) {
addCriterion("exec_entry >=", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryLessThan(String value) {
addCriterion("exec_entry <", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryLessThanOrEqualTo(String value) {
addCriterion("exec_entry <=", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryLike(String value) {
addCriterion("exec_entry like", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryNotLike(String value) {
addCriterion("exec_entry not like", value, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryIn(List<String> values) {
addCriterion("exec_entry in", values, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryNotIn(List<String> values) {
addCriterion("exec_entry not in", values, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryBetween(String value1, String value2) {
addCriterion("exec_entry between", value1, value2, "execEntry");
return (Criteria) this;
}
public Criteria andExecEntryNotBetween(String value1, String value2) {
addCriterion("exec_entry not between", value1, value2, "execEntry");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andCreateUserIdIsNull() {
addCriterion("create_user_id is null");
return (Criteria) this;
}
public Criteria andCreateUserIdIsNotNull() {
addCriterion("create_user_id is not null");
return (Criteria) this;
}
public Criteria andCreateUserIdEqualTo(String value) {
addCriterion("create_user_id =", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdNotEqualTo(String value) {
addCriterion("create_user_id <>", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdGreaterThan(String value) {
addCriterion("create_user_id >", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdGreaterThanOrEqualTo(String value) {
addCriterion("create_user_id >=", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdLessThan(String value) {
addCriterion("create_user_id <", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdLessThanOrEqualTo(String value) {
addCriterion("create_user_id <=", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdLike(String value) {
addCriterion("create_user_id like", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdNotLike(String value) {
addCriterion("create_user_id not like", value, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdIn(List<String> values) {
addCriterion("create_user_id in", values, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdNotIn(List<String> values) {
addCriterion("create_user_id not in", values, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdBetween(String value1, String value2) {
addCriterion("create_user_id between", value1, value2, "createUserId");
return (Criteria) this;
}
public Criteria andCreateUserIdNotBetween(String value1, String value2) {
addCriterion("create_user_id not between", value1, value2, "createUserId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,18 @@
package io.metersphere.base.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PluginWithBLOBs extends Plugin implements Serializable {
private String formOption;
private String formScript;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,37 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface PluginMapper {
long countByExample(PluginExample example);
int deleteByExample(PluginExample example);
int deleteByPrimaryKey(String id);
int insert(PluginWithBLOBs record);
int insertSelective(PluginWithBLOBs record);
List<PluginWithBLOBs> selectByExampleWithBLOBs(PluginExample example);
List<Plugin> selectByExample(PluginExample example);
PluginWithBLOBs selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") PluginWithBLOBs record, @Param("example") PluginExample example);
int updateByExampleWithBLOBs(@Param("record") PluginWithBLOBs record, @Param("example") PluginExample example);
int updateByExample(@Param("record") Plugin record, @Param("example") PluginExample example);
int updateByPrimaryKeySelective(PluginWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(PluginWithBLOBs record);
int updateByPrimaryKey(Plugin record);
}

View File

@ -0,0 +1,375 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.PluginMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.Plugin">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="plugin_id" jdbcType="VARCHAR" property="pluginId" />
<result column="clazz_name" jdbcType="VARCHAR" property="clazzName" />
<result column="source_path" jdbcType="VARCHAR" property="sourcePath" />
<result column="source_name" jdbcType="VARCHAR" property="sourceName" />
<result column="exec_entry" jdbcType="VARCHAR" property="execEntry" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user_id" jdbcType="VARCHAR" property="createUserId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.PluginWithBLOBs">
<result column="form_option" jdbcType="LONGVARCHAR" property="formOption" />
<result column="form_script" jdbcType="LONGVARCHAR" property="formScript" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, plugin_id, clazz_name, source_path, source_name, exec_entry, create_time,
update_time, create_user_id
</sql>
<sql id="Blob_Column_List">
form_option, form_script
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.PluginExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.PluginExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from plugin
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from plugin
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.PluginExample">
delete from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin (id, `name`, plugin_id,
clazz_name, source_path, source_name,
exec_entry, create_time, update_time,
create_user_id, form_option, form_script
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR},
#{clazzName,jdbcType=VARCHAR}, #{sourcePath,jdbcType=VARCHAR}, #{sourceName,jdbcType=VARCHAR},
#{execEntry,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{createUserId,jdbcType=VARCHAR}, #{formOption,jdbcType=LONGVARCHAR}, #{formScript,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
`name`,
</if>
<if test="pluginId != null">
plugin_id,
</if>
<if test="clazzName != null">
clazz_name,
</if>
<if test="sourcePath != null">
source_path,
</if>
<if test="sourceName != null">
source_name,
</if>
<if test="execEntry != null">
exec_entry,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="createUserId != null">
create_user_id,
</if>
<if test="formOption != null">
form_option,
</if>
<if test="formScript != null">
form_script,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="pluginId != null">
#{pluginId,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
#{clazzName,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null">
#{sourcePath,jdbcType=VARCHAR},
</if>
<if test="sourceName != null">
#{sourceName,jdbcType=VARCHAR},
</if>
<if test="execEntry != null">
#{execEntry,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="createUserId != null">
#{createUserId,jdbcType=VARCHAR},
</if>
<if test="formOption != null">
#{formOption,jdbcType=LONGVARCHAR},
</if>
<if test="formScript != null">
#{formScript,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.PluginExample" resultType="java.lang.Long">
select count(*) from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update plugin
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.pluginId != null">
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
</if>
<if test="record.clazzName != null">
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
</if>
<if test="record.sourcePath != null">
source_path = #{record.sourcePath,jdbcType=VARCHAR},
</if>
<if test="record.sourceName != null">
source_name = #{record.sourceName,jdbcType=VARCHAR},
</if>
<if test="record.execEntry != null">
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.createUserId != null">
create_user_id = #{record.createUserId,jdbcType=VARCHAR},
</if>
<if test="record.formOption != null">
form_option = #{record.formOption,jdbcType=LONGVARCHAR},
</if>
<if test="record.formScript != null">
form_script = #{record.formScript,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update plugin
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR},
form_option = #{record.formOption,jdbcType=LONGVARCHAR},
form_script = #{record.formScript,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update plugin
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
update plugin
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="pluginId != null">
plugin_id = #{pluginId,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
clazz_name = #{clazzName,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null">
source_path = #{sourcePath,jdbcType=VARCHAR},
</if>
<if test="sourceName != null">
source_name = #{sourceName,jdbcType=VARCHAR},
</if>
<if test="execEntry != null">
exec_entry = #{execEntry,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="createUserId != null">
create_user_id = #{createUserId,jdbcType=VARCHAR},
</if>
<if test="formOption != null">
form_option = #{formOption,jdbcType=LONGVARCHAR},
</if>
<if test="formScript != null">
form_script = #{formScript,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
update plugin
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR},
form_option = #{formOption,jdbcType=LONGVARCHAR},
form_script = #{formScript,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.Plugin">
update plugin
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -54,6 +54,30 @@ public class FileUtils {
}
}
public static String create(String id, MultipartFile item) {
String filePath = BODY_FILE_DIR + "/plugin";
if (item != null) {
File testDir = new File(filePath);
if (!testDir.exists()) {
testDir.mkdirs();
}
File file = new File(filePath + "/" + id + "_" + item.getOriginalFilename());
try (InputStream in = item.getInputStream(); OutputStream out = new FileOutputStream(file)) {
file.createNewFile();
final int MAX = 4096;
byte[] buf = new byte[MAX];
for (int bytesRead = in.read(buf, 0, MAX); bytesRead != -1; bytesRead = in.read(buf, 0, MAX)) {
out.write(buf, 0, bytesRead);
}
} catch (IOException e) {
LogUtil.error(e);
MSException.throwException(Translator.get("upload_fail"));
}
return file.getPath();
}
return null;
}
public static void createBodyFiles(String requestId, List<MultipartFile> bodyFiles) {
if (CollectionUtils.isNotEmpty(bodyFiles) && StringUtils.isNotBlank(requestId)) {
String path = BODY_FILE_DIR + "/" + requestId;
@ -158,7 +182,6 @@ public class FileUtils {
}
/**
* 获取当前jmx 涉及到的文件
*

View File

@ -55,6 +55,7 @@ public class LogUtil {
Logger logger = LogUtil.getLogger();
if (logger != null && logger.isInfoEnabled()) {
logger.info(LogUtil.getMsg(msg));
System.out.println(msg);
}
}

View File

@ -69,6 +69,8 @@ public class ShiroUtils {
filterChainDefinitionMap.put("/mock/**", "anon");
filterChainDefinitionMap.put("/ws/**", "anon");
filterChainDefinitionMap.put("/plugin/**", "anon");
}
public static void ignoreCsrfFilter(Map<String, String> filterChainDefinitionMap) {

View File

@ -0,0 +1,48 @@
package io.metersphere.controller;
import io.metersphere.base.domain.Plugin;
import io.metersphere.commons.exception.MSException;
import io.metersphere.controller.request.PluginRequest;
import io.metersphere.service.PluginService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping(value = "/plugin")
public class PluginController {
@Resource
private PluginService pluginService;
@PostMapping("/add")
public String create(@RequestPart(value = "file", required = false) MultipartFile file) {
if (file == null) {
MSException.throwException("上传文件/执行入口为空");
}
return pluginService.editPlugin(file);
}
@GetMapping("/list")
public List<Plugin> list() {
return pluginService.list();
}
@GetMapping("/get/{id}")
public Plugin get(@PathVariable String id) {
return pluginService.get(id);
}
@GetMapping("/delete/{id}")
public String delete(@PathVariable String id) {
return pluginService.delete(id);
}
@PostMapping(value = "/customMethod")
public Object customMethod(@RequestBody PluginRequest request) {
return pluginService.customMethod(request);
}
}

View File

@ -0,0 +1,9 @@
package io.metersphere.controller.request;
import lombok.Data;
@Data
public class PluginRequest {
private String entry;
private String request;
}

View File

@ -0,0 +1,9 @@
package io.metersphere.controller.request;
import io.metersphere.plugin.core.ui.PluginResource;
import lombok.Data;
@Data
public class PluginResourceDTO extends PluginResource {
private String entry;
}

View File

@ -9,6 +9,7 @@ import io.metersphere.commons.utils.RunInterface;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.service.JarConfigService;
import io.metersphere.service.ProjectService;
import io.metersphere.service.PluginService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.service.IssuesService;
@ -42,6 +43,9 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
private ProjectService projectService;
@Resource
private PerformanceTestService performanceTestService;
@Resource
private PluginService pluginService;
@Value("${jmeter.home}")
private String jmeterHome;
@ -70,7 +74,7 @@ public class AppStartListener implements ApplicationListener<ApplicationReadyEve
initOperate(issuesService::syncThirdPartyIssues, "init.issue");
initOperate(issuesService::issuesCount, "init.issueCount");
initOperate(performanceTestService::initScenarioLoadTest, "init.scenario.load.test");
pluginService.loadPlugins();
try {
Thread.sleep(1 * 60 * 1000);
} catch (InterruptedException e) {

View File

@ -0,0 +1,197 @@
package io.metersphere.service;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.base.mapper.PluginMapper;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.PluginRequest;
import io.metersphere.controller.request.PluginResourceDTO;
import io.metersphere.plugin.core.ui.PluginResource;
import io.metersphere.service.utils.CommonUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class PluginService {
@Resource
private PluginMapper pluginMapper;
public String editPlugin(MultipartFile file) {
String id = UUID.randomUUID().toString();
String path = FileUtils.create(id, file);
if (StringUtils.isNotEmpty(path)) {
List<PluginResourceDTO> resources = this.getMethod(path, file.getOriginalFilename());
if (CollectionUtils.isNotEmpty(resources)) {
for (PluginResourceDTO resource : resources) {
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(resource.getPluginId());
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
String delPath = plugins.get(0).getSourcePath();
// this.closeJar(delPath);
FileUtils.deleteFile(delPath);
pluginMapper.deleteByExample(example);
}
this.create(resource, path, file.getOriginalFilename());
}
}
}
return null;
}
private void create(PluginResourceDTO resource, String path, String name) {
resource.getUiScripts().forEach(item -> {
PluginWithBLOBs plugin = new PluginWithBLOBs();
plugin.setId(UUID.randomUUID().toString());
plugin.setCreateTime(System.currentTimeMillis());
plugin.setUpdateTime(System.currentTimeMillis());
plugin.setName(item.getName());
plugin.setPluginId(resource.getPluginId());
plugin.setSourcePath(path);
plugin.setFormOption(item.getFormOption());
plugin.setFormScript(item.getFormScript());
plugin.setClazzName(item.getClazzName());
plugin.setSourceName(name);
plugin.setExecEntry(resource.getEntry());
plugin.setCreateUserId(SessionUtils.getUserId());
pluginMapper.insert(plugin);
});
}
private List<PluginResourceDTO> getMethod(String path, String fileName) {
List<PluginResourceDTO> resources = new LinkedList<>();
try {
this.loadJar(path);
List<Class<?>> classes = CommonUtil.getSubClass(fileName);
for (Class<?> aClass : classes) {
Object instance = aClass.newInstance();
Object pluginObj = aClass.getDeclaredMethod("init").invoke(instance);
if (pluginObj != null) {
PluginResourceDTO pluginResourceDTO = new PluginResourceDTO();
BeanUtils.copyBean(pluginResourceDTO, (PluginResource) pluginObj);
pluginResourceDTO.setEntry(aClass.getName());
resources.add(pluginResourceDTO);
}
}
} catch (Exception e) {
LogUtil.error("初始化脚本异常:" + e.getMessage());
}
return resources;
}
private void closeJar(String jarPath) {
File jarFile = new File(jarPath);
Method method = null;
try {
method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
} catch (NoSuchMethodException | SecurityException e1) {
e1.printStackTrace();
}
// 获取方法的访问权限以便写回
try {
method.setAccessible(true);
// 获取系统类加载器
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
URL url = jarFile.toURI().toURL();
method.invoke(classLoader, url);
classLoader.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
private void loadJar(String jarPath) {
File jarFile = new File(jarPath);
// 从URLClassLoader类中获取类所在文件夹的方法jar也可以认为是一个文件夹
Method method = null;
try {
method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
} catch (NoSuchMethodException | SecurityException e1) {
e1.printStackTrace();
}
// 获取方法的访问权限以便写回
try {
method.setAccessible(true);
// 获取系统类加载器
URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
URL url = jarFile.toURI().toURL();
method.invoke(classLoader, url);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
public void loadPlugins() {
PluginExample example = new PluginExample();
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
plugins.forEach(item -> {
this.loadJar(item.getSourcePath());
});
}
}
public List<Plugin> list() {
PluginExample example = new PluginExample();
List<Plugin> plugins = pluginMapper.selectByExample(example);
return plugins;
}
public Plugin get(String pluginId) {
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(pluginId);
List<PluginWithBLOBs> plugins = pluginMapper.selectByExampleWithBLOBs(example);
if (CollectionUtils.isNotEmpty(plugins)) {
return plugins.get(0);
}
return null;
}
public String delete(String id) {
Plugin plugin = pluginMapper.selectByPrimaryKey(id);
if (plugin != null) {
//通过pluginId判断是否还有其他脚本无则清理加载的jar包
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(plugin.getPluginId());
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (plugins.size() == 1) {
// this.closeJar(plugin.getSourcePath());
FileUtils.deleteFile(plugin.getSourcePath());
}
pluginMapper.deleteByPrimaryKey(id);
return "success";
}
return "error";
}
public Object customMethod(PluginRequest request) {
try {
Class<?> clazz = Class.forName(request.getEntry());
Object instance = clazz.newInstance();
Object pluginObj = clazz.getDeclaredMethod("customMethod", String.class).invoke(instance, request.getRequest());
return pluginObj;
} catch (Exception ex) {
LogUtil.error("加载自定义方法失败:" + ex.getMessage());
}
return null;
}
}

View File

@ -0,0 +1,93 @@
package io.metersphere.service.utils;
import com.github.pagehelper.util.StringUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.api.UiScriptApi;
import org.reflections8.Reflections;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.ClassPathResource;
import java.io.File;
import java.net.URL;
import java.util.*;
public class CommonUtil {
//获取某个类的实现类
public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws Exception {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> c : getClasses(cls)) {
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
classes.add(c);
}
}
return classes;
}
public static List<Class<?>> getClasses(Class<?> cls) throws Exception {
String pk = cls.getPackage().getName();
String path = pk.replace('.', '/');
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL url = classloader.getResource(path);
return getClasses(new File(url.getFile()), pk);
}
//根据路径获取
public static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
if (!dir.exists()) {
return classes;
}
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
classes.addAll(getClasses(f, pk + "." + f.getName()));
}
String name = f.getName();
if (name.endsWith(".class")) {
classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
}
}
return classes;
}
public static List<Class<?>> getSubClass(String fileName) throws Exception {
List<Class<?>> classes = new LinkedList<>();
ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
if (StringUtil.isNotEmpty(fileName) && fileName.endsWith(".jar")) {
fileName = fileName.substring(0, fileName.length() - 4);
}
LogUtil.info("获取到文件路径:" + fileName);
Resource resource = new ClassPathResource(fileName);
Properties inPro = PropertiesLoaderUtils.loadProperties(resource);
if (inPro != null) {
LogUtil.info("开始读取文件内容进行反射处理");
Set<String> entryObj = inPro.stringPropertyNames();
if (entryObj != null) {
for (String entry : entryObj) {
try {
Class<?> clazz = Class.forName(entry);
classes.add(clazz);
} catch (Exception e) {
LogUtil.error("反射类【" + entry + " 】失败:" + e.getMessage());
e.printStackTrace();
}
}
}
}
return classes;
}
public static List<Class<?>> getSubClazz(String pac) {
List<Class<?>> classes = new LinkedList<>();
try {
Reflections reflections = new Reflections(pac);
Set<Class<? extends UiScriptApi>> subTypes = reflections.getSubTypesOf(UiScriptApi.class);
subTypes.forEach(x -> classes.add(x));
} catch (Exception ex) {
LogUtil.error(ex.getMessage());
ex.printStackTrace();
}
return classes;
}
}

View File

@ -14,7 +14,7 @@ import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
@ -41,6 +41,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.dto.PlanReportCaseDTO;
import io.metersphere.track.dto.TestCaseReportStatusResultDTO;
@ -291,6 +292,8 @@ public class TestPlanApiCaseService {
try {
String api = caseWithBLOBs.getRequest();
JSONObject element = JSON.parseObject(api);
ElementUtil.dataFormatting(element);
LinkedList<MsTestElement> list = new LinkedList<>();
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),

View File

@ -45,6 +45,7 @@ import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.performance.service.MetricQueryService;
import io.metersphere.performance.service.PerformanceReportService;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.IssueTemplateService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
@ -970,6 +971,8 @@ public class TestPlanService {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
ElementUtil.dataFormatting(element);
MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class);
group.setOnSampleError(scenario.getOnSampleError());
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取

View File

@ -0,0 +1,17 @@
CREATE TABLE `plugin` (
`id` varchar(50) NOT NULL COMMENT 'ID',
`name` varchar(300) DEFAULT NULL COMMENT 'plugin name',
`plugin_id` varchar(300) NOT NULL COMMENT 'Plugin id',
`clazz_name` varchar(500) NOT NULL COMMENT 'Plugin clazzName',
`source_path` varchar(300) NOT NULL COMMENT 'Plugin jar path',
`source_name` varchar(300) NOT NULL COMMENT 'Plugin jar name',
`form_option` longtext COMMENT 'plugin form option',
`form_script` longtext COMMENT 'plugin form script',
`exec_entry` varchar(300) DEFAULT NULL COMMENT 'plugin init entry class',
`create_time` bigint(13) DEFAULT NULL,
`update_time` bigint(13) DEFAULT NULL,
`create_user_id` varchar(64) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE utf8mb4_general_ci;

View File

@ -11,6 +11,7 @@
"dependencies": {
"@ckeditor/ckeditor5-build-classic": "^18.0.0",
"@ckeditor/ckeditor5-vue": "^1.0.1",
"@form-create/element-ui": "^2.5.8",
"@fortawesome/fontawesome-svg-core": "^1.2.26",
"@fortawesome/free-brands-svg-icons": "^5.13.0",
"@fortawesome/free-regular-svg-icons": "^5.12.0",
@ -44,6 +45,7 @@
"md5": "^2.3.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"pdfjs-dist": "2.5.207",
"sha.js": "^2.4.11",
"vue": "2.6.14",
"vue-calendar-heatmap": "^0.8.4",
@ -56,12 +58,11 @@
"vue-papa-parse": "^2.0.0",
"vue-pdf": "^4.2.0",
"vue-router": "^3.1.3",
"vue2-ace-editor": "0.0.15",
"vuedraggable": "^2.24.3",
"vuex": "^3.1.2",
"xml-js": "^1.6.11",
"yan-progress": "^1.0.3",
"vue2-ace-editor": "0.0.15",
"pdfjs-dist": "2.5.207"
"yan-progress": "^1.0.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.0",

View File

@ -69,8 +69,16 @@ function getScenarioFiles(obj) {
return scenarioFiles;
}
export function saveScenario(url, scenario, scenarioDefinition, success) {
export function saveScenario(url, scenario, scenarioDefinition, _this,success) {
let bodyFiles = getBodyUploadFiles(scenario, scenarioDefinition);
if (_this.$store.state.pluginFiles && _this.$store.state.pluginFiles.length > 0) {
_this.$store.state.pluginFiles.forEach(fileItem => {
if (fileItem.file) {
scenario.bodyFileRequestIds.push(fileItem.file.id);
bodyFiles.push(fileItem.file);
}
});
}
let scenarioFiles = getScenarioFiles(scenario);
let formData = new FormData();
if (bodyFiles) {

View File

@ -3,53 +3,59 @@
</template>
<script>
import {getCurrentProjectID, strMapToObj} from "@/common/js/utils";
import {createComponent} from "../../definition/components/jmeter/components";
import {createComponent} from "../../definition/components/jmeter/components";
import {saveScenario} from "@/business/components/api/automation/api-automation";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
export default {
name: 'MsDebugRun',
components: {},
props: {
environment: Map,
debug: Boolean,
reportId: String,
runData: Object,
saved: Boolean,
},
data() {
return {
result: {},
loading: false,
runId: "",
reqNumber: 0,
}
},
watch: {
//
reportId() {
this.run()
}
},
methods: {
run() {
let testPlan = createComponent('TestPlan');
let threadGroup = createComponent('ThreadGroup');
threadGroup.hashTree = [];
threadGroup.name = this.reportId;
threadGroup.enableCookieShare = this.runData.enableCookieShare;
threadGroup.onSampleError = this.runData.onSampleError;
let map = this.environment;
this.runData.projectId = getCurrentProjectID();
threadGroup.hashTree.push(this.runData);
testPlan.hashTree.push(threadGroup);
let reqObj = {id: this.reportId, reportId: this.reportId, scenarioName: this.runData.name,saved:this.saved,
scenarioId: this.runData.id, testElement: testPlan, projectId: getCurrentProjectID(), environmentMap: strMapToObj(map)};
saveScenario('/api/automation/run/debug', reqObj, this.runData.hashTree, (response) => {
this.runId = response.data;
this.$emit('runRefresh', {});
});
},
export default {
name: 'MsDebugRun',
components: {},
props: {
environment: Map,
debug: Boolean,
reportId: String,
runData: Object,
saved: Boolean,
},
data() {
return {
result: {},
loading: false,
runId: "",
reqNumber: 0,
}
},
watch: {
//
reportId() {
this.run()
}
},
methods: {
run() {
let testPlan = createComponent('TestPlan');
testPlan.clazzName = TYPE_TO_C.get(testPlan.type);
let threadGroup = createComponent('ThreadGroup');
threadGroup.clazzName = TYPE_TO_C.get(threadGroup.type);
threadGroup.hashTree = [];
threadGroup.name = this.reportId;
threadGroup.enableCookieShare = this.runData.enableCookieShare;
threadGroup.onSampleError = this.runData.onSampleError;
let map = this.environment;
this.runData.projectId = getCurrentProjectID();
this.runData.clazzName = TYPE_TO_C.get(this.runData.type);
threadGroup.hashTree.push(this.runData);
testPlan.hashTree.push(threadGroup);
let reqObj = {
id: this.reportId, reportId: this.reportId, scenarioName: this.runData.name, saved: this.saved,
scenarioId: this.runData.id, testElement: testPlan, projectId: getCurrentProjectID(), environmentMap: strMapToObj(map)
};
saveScenario('/api/automation/run/debug', reqObj, this.runData.hashTree, this, (response) => {
this.runId = response.data;
this.$emit('runRefresh', {});
});
},
}
}
</script>

View File

@ -225,7 +225,7 @@
<vue-fab id="fab" mainBtnColor="#783887" size="small" :global-options="globalOptions"
:click-auto-close="false" v-outside-click="outsideClick" ref="refFab">
<fab-item
v-for="(item, index) in buttons"
v-for="(item, index) in buttonData"
:key="index"
:idx="getIdx(index)"
:title="item.title"
@ -325,7 +325,7 @@
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {buttons, setComponent} from './menu/Menu';
import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import {ELEMENT_TYPE, ELEMENTS,TYPE_TO_C} from "./Setting";
import {
getUUID,
objToStrMap,
@ -448,6 +448,7 @@ export default {
message: "",
websocket: {},
messageWebSocket: {},
buttonData: []
}
},
created() {
@ -460,6 +461,8 @@ export default {
this.getWsProjects();
this.getMaintainerOptions();
this.getApiScenario();
this.initPlugins();
this.buttonData = buttons(this);
},
mounted() {
this.$nextTick(() => {
@ -471,12 +474,32 @@ export default {
},
directives: {OutsideClick},
computed: {
buttons,
projectId() {
return getCurrentProjectID();
},
},
methods: {
initPlugins() {
let url = "/plugin/list";
this.$get(url, response => {
let data = response.data;
if (data) {
data.forEach(item => {
let plugin = {
title: item.name,
show: this.showButton(item.name),
titleColor: "#555855",
titleBgColor: "#F4F4FF",
icon: "colorize",
click: () => {
this.addComponent(item.name, item)
}
}
this.buttonData.push(plugin);
});
}
});
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, response => {
@ -812,14 +835,16 @@ export default {
outsideClick(e) {
e.stopPropagation();
this.showAll();
this.buttonData = buttons(this);
this.initPlugins();
},
fabClick() {
if (this.operatingElements.length < 1) {
if (this.operatingElements && this.operatingElements.length < 1) {
this.$info("引用的场景或接口无法添加配置");
}
},
addComponent(type) {
setComponent(type, this);
addComponent(type, plugin) {
setComponent(type, this, plugin);
},
nodeClick(data, node) {
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
@ -827,9 +852,13 @@ export default {
} else {
this.operatingElements = [];
}
if (!this.operatingElements) {
this.operatingElements = ELEMENTS.get("ALL");
}
this.selectedTreeNode = data;
this.selectedNode = node;
this.$store.state.selectStep = data;
this.buttonData = buttons(this);
},
suggestClick(node) {
this.response = {};
@ -864,6 +893,9 @@ export default {
&& stepArray[i].hashTree.length > 1) {
stepArray[i].countController.proceed = true;
}
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (!stepArray[i].projectId) {
// IDIDIDID
stepArray[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
@ -1115,7 +1147,7 @@ export default {
if (dropType != "inner") {
return true;
} else if (dropType === "inner" && dropNode.data.referenced !== 'REF' && dropNode.data.referenced !== 'Deleted'
&& ELEMENTS.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1 && !draggingNode.data.disabled) {
&& ELEMENTS.get(dropNode.data.type) && ELEMENTS.get(dropNode.data.type).indexOf(draggingNode.data.type) != -1 && !draggingNode.data.disabled) {
return true;
}
return false;
@ -1145,9 +1177,10 @@ export default {
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
this.setParameter();
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, (response) => {
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, this,(response) => {
this.$success(this.$t('commons.save_success'));
this.path = "/api/automation/update";
this.$store.state.pluginFiles = [];
if (response.data) {
this.currentScenario.id = response.data.id;
}
@ -1259,6 +1292,7 @@ export default {
enableCookieShare: this.enableCookieShare,
name: this.currentScenario.name,
type: "scenario",
clazzName: TYPE_TO_C.get("scenario"),
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: 'Created',

View File

@ -1,14 +1,14 @@
export const ELEMENTS = new Map([
['ALL', ["scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "IfController","TransactionController", "LoopController", "ConstantTimer", "JSR223Processor", "CustomizeReq"]],
['ALL', ["Plugin","scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "IfController", "TransactionController", "LoopController", "ConstantTimer", "JSR223Processor", "CustomizeReq"]],
['scenario', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "CASE", "OT_IMPORT", "IfController", "ConstantTimer", "JSR223Processor", "CustomizeReq"]],
['HTTPSamplerProxy', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor',"Assertions", "Extract"]],
['DubboSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor',"Assertions", "Extract"]],
['JDBCSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor', "Assertions", "Extract"]],
['TCPSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor', "Assertions", "Extract"]],
['OT_IMPORT', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor', "Assertions", "Extract"]],
['IfController', ["IfController","LoopController", "TransactionController","scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor',"Assertions", "Extract", "CustomizeReq"]],
['TransactionController', ["TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['LoopController', ["IfController", "TransactionController","scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor','JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['HTTPSamplerProxy', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['DubboSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['JDBCSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['TCPSampler', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['OT_IMPORT', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract"]],
['IfController', ["IfController", "LoopController", "TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['TransactionController', ["TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['LoopController', ["IfController", "TransactionController", "scenario", "HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", 'JDBCPreProcessor', 'JDBCPostProcessor', "Assertions", "Extract", "CustomizeReq"]],
['ConstantTimer', []],
['JSR223Processor', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['JSR223PreProcessor', []],
@ -18,8 +18,8 @@ export const ELEMENTS = new Map([
['Assertions', []],
['Extract', []],
['JmeterElement', []],
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor","JSR223PostProcessor", "JDBCPostProcessor", "JDBCPreProcessor", "Assertions", "Extract"]],
['MaxSamplerProxy', ["JSR223PreProcessor", "JSR223PostProcessor", "JDBCPreProcessor","JDBCPostProcessor","Assertions", "Extract"]],
['CustomizeReq', ["ConstantTimer", "JSR223PreProcessor", "JSR223PostProcessor", "JDBCPostProcessor", "JDBCPreProcessor", "Assertions", "Extract"]],
['MaxSamplerProxy', ["JSR223PreProcessor", "JSR223PostProcessor", "JDBCPreProcessor", "JDBCPostProcessor", "Assertions", "Extract"]],
['AllSamplerProxy', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"]],
['AllCanExecType', ["HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor"]]
])
@ -34,11 +34,36 @@ export const ELEMENT_TYPE = {
JSR223Processor: "JSR223Processor",
JSR223PreProcessor: "JSR223PreProcessor",
JSR223PostProcessor: "JSR223PostProcessor",
JDBCPostProcessor : "JDBCPostProcessor",
JDBCPreProcessor : "JDBCPreProcessor",
JDBCPostProcessor: "JDBCPostProcessor",
JDBCPreProcessor: "JDBCPreProcessor",
Assertions: "Assertions",
Extract: "Extract",
CustomizeReq: "CustomizeReq",
LoopController: "LoopController"
LoopController: "LoopController",
Plugin: "Plugin"
}
export const TYPE_TO_C = new Map([
['scenario', "io.metersphere.api.dto.definition.request.MsScenario"],
['HTTPSamplerProxy', "io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy"],
['DubboSampler', "io.metersphere.api.dto.definition.request.sampler.MsDubboSampler"],
['JDBCSampler', "io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler"],
['TCPSampler', "io.metersphere.api.dto.definition.request.sampler.MsTCPSampler"],
['IfController', "io.metersphere.api.dto.definition.request.controller.MsIfController"],
['TransactionController', "io.metersphere.api.dto.definition.request.controller.MsTransactionController"],
['LoopController', "io.metersphere.api.dto.definition.request.controller.MsLoopController"],
['ConstantTimer', "io.metersphere.api.dto.definition.request.timer.MsConstantTimer"],
['JSR223Processor', "io.metersphere.api.dto.definition.request.processors.MsJSR223Processor"],
['JSR223PreProcessor', "io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor"],
['JSR223PostProcessor', "io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor"],
['JDBCPreProcessor', "io.metersphere.api.dto.definition.request.processors.pre.MsJDBCPreProcessor"],
['JDBCPostProcessor', "io.metersphere.api.dto.definition.request.processors.post.MsJDBCPostProcessor"],
['Assertions', "io.metersphere.api.dto.definition.request.assertions.MsAssertions"],
['Extract', "io.metersphere.api.dto.definition.request.extract.MsExtract"],
['JmeterElement', "io.metersphere.api.dto.definition.request.unknown.MsJmeterElement"],
['TestPlan', "io.metersphere.api.dto.definition.request.MsTestPlan"],
['ThreadGroup', "io.metersphere.api.dto.definition.request.MsThreadGroup"],
['DNSCacheManager', "io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager"],
['DebugSampler', "io.metersphere.api.dto.definition.request.sampler.MsDebugSampler"],
])

View File

@ -6,7 +6,7 @@
<div class="el-step__icon-inner">{{ data.index }}</div>
</div>
<el-tag class="ms-left-btn" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{ title }}</el-tag>
<el-tag size="mini" v-if="data.method">{{ getMethod() }}</el-tag>
<el-tag size="mini" v-if="data.method && !data.pluginId">{{ getMethod() }}</el-tag>
</slot>
<slot name="behindHeaderLeft" v-if="!isMax"></slot>

View File

@ -0,0 +1,136 @@
<template>
<span>
<el-upload
action="#"
class="api-body-upload"
list-type="picture-card"
:http-request="upload"
:beforeUpload="uploadValidate"
:file-list="plugin.files"
:on-exceed="exceed"
ref="upload">
<div class="upload-default">
<i class="el-icon-plus"/>
</div>
<div class="upload-item" slot="file" slot-scope="{file}">
<span>{{ file.file ? file.file.name : file.name }}</span>
<span class="el-upload-list__item-actions">
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file)">
<i class="el-icon-delete"/>
</span>
</span>
</div>
</el-upload>
</span>
</template>
<script>
export default {
name: "MsPluginUpload",
data() {
return {
disabled: false,
plugin: {files: []}
};
},
props: {
value: String
},
mounted() {
if (this.value) {
this.plugin.files = JSON.parse(this.value);
}
},
methods: {
handleRemove(file) {
this.$refs.upload.handleRemove(file);
for (let i = 0; i < this.plugin.files.length; i++) {
let fileName = file.file ? file.file.name : file.name;
let paramFileName = this.plugin.files[i].file ?
this.plugin.files[i].file.name : this.plugin.files[i].name;
if (fileName === paramFileName) {
this.plugin.files.splice(i, 1);
this.$refs.upload.handleRemove(file);
break;
}
}
},
exceed() {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
upload(file) {
this.plugin.files.push(file);
let files = [];
if (!(this.$store.state.pluginFiles instanceof Array)) {
this.$store.state.pluginFiles = [];
}
this.plugin.files.forEach(item => {
if (item.file) {
files.push({uid: item.file.uid, name: item.file.name, size: item.file.size});
this.$store.state.pluginFiles.push({name: item.file.name, file: item.file});
} else {
files.push(item);
}
})
this.$emit('input', JSON.stringify(files));
},
uploadValidate(file) {
if (file.size / 1024 / 1024 > 500) {
this.$warning(this.$t('api_test.request.body_upload_limit_size'));
return false;
}
return true;
},
},
created() {
if (this.plugin && !this.plugin.files) {
this.plugin.files = [];
}
}
}
</script>
<style scoped>
.el-upload {
background-color: black;
}
.api-body-upload >>> .el-upload {
height: 30px;
width: 32px;
}
.upload-default {
min-height: 30px;
width: 32px;
line-height: 32px;
}
.el-icon-plus {
font-size: 16px;
}
.api-body-upload >>> .el-upload-list__item {
height: 30px;
width: auto;
padding: 6px;
margin-bottom: 0px;
}
.api-body-upload >>> .el-upload-list--picture-card {
}
.api-body-upload {
min-height: 30px;
border: 1px solid #EBEEF5;
padding: 2px;
border-radius: 4px;
}
.upload-item {
}
</style>

View File

@ -10,170 +10,190 @@
</template>
<script>
import MsIfController from "./IfController";
import MsTransactionController from "./TransactionController";
import {ELEMENT_TYPE} from "../Setting";
import MsApiComponent from "./ApiComponent";
import MsLoopController from "./LoopController";
import MsApiScenarioComponent from "./ApiScenarioComponent";
import JmeterElementComponent from "./JmeterElementComponent";
import MsIfController from "./IfController";
import MsTransactionController from "./TransactionController";
import {ELEMENT_TYPE} from "../Setting";
import MsApiComponent from "./ApiComponent";
import MsLoopController from "./LoopController";
import MsApiScenarioComponent from "./ApiScenarioComponent";
import JmeterElementComponent from "./JmeterElementComponent";
import PluginComponent from "./PluginComponent";
export default {
name: "ComponentConfig",
components: {
MsIfController ,
MsTransactionController ,
MsApiComponent ,
MsLoopController ,
MsApiScenarioComponent ,
JmeterElementComponent,
MsConstantTimer: () => import("./ConstantTimer"),
MsJsr233Processor: () => import("./Jsr233Processor"),
MsApiAssertions: () => import("../../../definition/components/assertion/ApiAssertions"),
MsApiExtract: () => import("../../../definition/components/extract/ApiExtract"),
MsJdbcProcessor: () => import("@/business/components/api/automation/scenario/component/JDBCProcessor"),
export default {
name: "ComponentConfig",
components: {
PluginComponent,
MsIfController ,
MsTransactionController ,
MsApiComponent ,
MsLoopController ,
MsApiScenarioComponent ,
JmeterElementComponent,
MsConstantTimer: () => import("./ConstantTimer"),
MsJsr233Processor: () => import("./Jsr233Processor"),
MsApiAssertions: () => import("../../../definition/components/assertion/ApiAssertions"),
MsApiExtract: () => import("../../../definition/components/extract/ApiExtract"),
MsJdbcProcessor: () => import("@/business/components/api/automation/scenario/component/JDBCProcessor"),
},
props: {
type: String,
message: String,
scenario: {},
draggable: {
type: Boolean,
default: true,
},
props: {
type: String,
message: String,
scenario: {},
draggable: {
type: Boolean,
default: true,
},
isMax: {
type: Boolean,
default: false,
},
showBtn: {
type: Boolean,
default: true,
},
currentScenario: {},
expandedNode: Array,
currentEnvironmentId: String,
response: {},
node: {},
projectList: Array,
envMap: Map
isMax: {
type: Boolean,
default: false,
},
data() {
return {
title: "",
titleColor: "",
backgroundColor: "",
showBtn: {
type: Boolean,
default: true,
},
currentScenario: {},
expandedNode: Array,
currentEnvironmentId: String,
response: {},
node: {},
projectList: Array,
envMap: Map
},
data() {
return {
title: "",
titleColor: "",
backgroundColor: "",
}
},
computed: {
component({type}) {
let name;
switch (type) {
case ELEMENT_TYPE.IfController:
name = "MsIfController";
break;
case ELEMENT_TYPE.TransactionController:
name = "MsTransactionController";
break;
case ELEMENT_TYPE.ConstantTimer:
name = "MsConstantTimer";
break;
case ELEMENT_TYPE.JSR223Processor:
name = this.getComponent(ELEMENT_TYPE.JSR223Processor);
break;
case ELEMENT_TYPE.JSR223PreProcessor:
name = this.getComponent(ELEMENT_TYPE.JSR223PreProcessor);
break;
case ELEMENT_TYPE.JSR223PostProcessor:
name = this.getComponent(ELEMENT_TYPE.JSR223PostProcessor);
break;
case ELEMENT_TYPE.JDBCPostProcessor:
name = this.getComponent(ELEMENT_TYPE.JDBCPostProcessor);
break;
case ELEMENT_TYPE.JDBCPreProcessor:
name = this.getComponent(ELEMENT_TYPE.JDBCPreProcessor);
break;
case ELEMENT_TYPE.Assertions:
name = "MsApiAssertions";
break;
case ELEMENT_TYPE.Extract:
name = "MsApiExtract";
break;
case ELEMENT_TYPE.CustomizeReq:
name = "MsApiComponent";
break;
case ELEMENT_TYPE.LoopController:
name = "MsLoopController";
break;
case ELEMENT_TYPE.scenario:
name = "MsApiScenarioComponent";
break;
case "AuthManager":
break;
case "JmeterElement":
name = "JmeterElementComponent";
break;
case "DubboSampler":
name = "MsApiComponent";
break;
case "HTTPSamplerProxy":
name = "MsApiComponent";
break;
case "JDBCSampler":
name = "MsApiComponent";
break;
case "TCPSampler":
name = "MsApiComponent";
break;
default:
name = "MsApiComponent";
break;
}
},
computed: {
component({type}) {
let name;
switch (type) {
case ELEMENT_TYPE.IfController:
name = "MsIfController";
break;
case ELEMENT_TYPE.TransactionController:
name = "MsTransactionController";
break;
case ELEMENT_TYPE.ConstantTimer:
name = "MsConstantTimer";
break;
case ELEMENT_TYPE.JSR223Processor:
name = this.getComponent(ELEMENT_TYPE.JSR223Processor);
break;
case ELEMENT_TYPE.JSR223PreProcessor:
name = this.getComponent(ELEMENT_TYPE.JSR223PreProcessor);
break;
case ELEMENT_TYPE.JSR223PostProcessor:
name = this.getComponent(ELEMENT_TYPE.JSR223PostProcessor);
break;
case ELEMENT_TYPE.JDBCPostProcessor:
name = this.getComponent(ELEMENT_TYPE.JDBCPostProcessor);
break;
case ELEMENT_TYPE.JDBCPreProcessor:
name = this.getComponent(ELEMENT_TYPE.JDBCPreProcessor);
break;
case ELEMENT_TYPE.Assertions:
name = "MsApiAssertions";
break;
case ELEMENT_TYPE.Extract:
name = "MsApiExtract";
break;
case ELEMENT_TYPE.CustomizeReq:
name = "MsApiComponent";
break;
case ELEMENT_TYPE.LoopController:
name = "MsLoopController";
break;
case ELEMENT_TYPE.scenario:
name = "MsApiScenarioComponent";
break;
case "AuthManager":
break;
case "JmeterElement":
name = "JmeterElementComponent";
break;
default:
name = "MsApiComponent";
break;
return name;
}
},
methods: {
getComponent(type) {
if (type === ELEMENT_TYPE.JSR223PreProcessor) {
this.title = this.$t('api_test.definition.request.pre_script');
this.titleColor = "#b8741a";
this.backgroundColor = "#F9F1EA";
return "MsJsr233Processor";
} else if (type === ELEMENT_TYPE.JSR223PostProcessor) {
this.title = this.$t('api_test.definition.request.post_script');
this.titleColor = "#783887";
this.backgroundColor = "#F2ECF3";
return "MsJsr233Processor";
}if (type === ELEMENT_TYPE.JDBCPreProcessor) {
this.title = this.$t('api_test.definition.request.pre_sql');
this.titleColor = "#FE6F71";
this.backgroundColor = "#F2ECF3";
return "MsJdbcProcessor";
} else if (type === ELEMENT_TYPE.JDBCPostProcessor) {
this.title = this.$t('api_test.definition.request.post_sql');
this.titleColor = "#1483F6";
this.backgroundColor = "#F2ECF3";
return "MsJdbcProcessor";
}
return name;
}
},
methods: {
getComponent(type) {
if (type === ELEMENT_TYPE.JSR223PreProcessor) {
this.title = this.$t('api_test.definition.request.pre_script');
this.titleColor = "#b8741a";
this.backgroundColor = "#F9F1EA";
return "MsJsr233Processor";
} else if (type === ELEMENT_TYPE.JSR223PostProcessor) {
this.title = this.$t('api_test.definition.request.post_script');
this.titleColor = "#783887";
this.backgroundColor = "#F2ECF3";
return "MsJsr233Processor";
}if (type === ELEMENT_TYPE.JDBCPreProcessor) {
this.title = this.$t('api_test.definition.request.pre_sql');
this.titleColor = "#FE6F71";
this.backgroundColor = "#F2ECF3";
return "MsJdbcProcessor";
} else if (type === ELEMENT_TYPE.JDBCPostProcessor) {
this.title = this.$t('api_test.definition.request.post_sql');
else if (type === ELEMENT_TYPE.Plugin) {
this.titleColor = "#1483F6";
this.backgroundColor = "#F2ECF3";
return "MsJdbcProcessor";
} else {
this.title = this.$t('api_test.automation.customize_script');
this.titleColor = "#7B4D12";
this.backgroundColor = "#F1EEE9";
return "MsJsr233Processor";
return "PluginComponent";
}
},
remove(row, node) {
this.$emit('remove', row, node);
},
copyRow(row, node) {
this.$emit('copyRow', row, node);
},
openScenario(data) {
this.$emit('openScenario', data);
},
suggestClick(node) {
this.$emit('suggestClick', node);
},
refReload(data, node) {
this.$emit('refReload', data, node);
else {
this.title = this.$t('api_test.automation.customize_script');
this.titleColor = "#7B4D12";
this.backgroundColor = "#F1EEE9";
return "MsJsr233Processor";
}
},
remove(row, node) {
this.$emit('remove', row, node);
},
copyRow(row, node) {
this.$emit('copyRow', row, node);
},
openScenario(data) {
this.$emit('openScenario', data);
},
suggestClick(node) {
this.$emit('suggestClick', node);
},
refReload(data, node) {
this.$emit('refReload', data, node);
}
}
}
</script>
<style scoped>
.request-form >>> .debug-button {
margin-left: auto;
display: block;
margin-right: 10px;
}
.request-form >>> .debug-button {
margin-left: auto;
display: block;
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,287 @@
<template>
<api-base-component
@copy="copyRow"
@remove="remove"
@active="active"
:data="request"
:draggable="draggable"
:color="defColor"
:is-max="isMax"
:show-btn="showBtn"
:background-color="defBackgroundColor"
:title="request.type">
<template v-slot:request>
<legend style="width: 100%">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<div class="ms-form">
<div class="ms-form-create" v-loading="loading">
<formCreate
v-model="pluginForm"
:rule="rules"
:option="option"
:value.sync="data"
@prefix-change="change"
@prefix-click="change"
@prefix-visible-change="visibleChange"
/>
</div>
</div>
</legend>
</template>
<template v-slot:debugStepCode>
<span v-if="request.testing" class="ms-test-running">
<i class="el-icon-loading" style="font-size: 16px"/>
{{ $t('commons.testing') }}
</span>
<span class="ms-step-debug-code" :class="request.requestResult[0].success?'ms-req-success':'ms-req-error'" v-if="!loading && request.debug && request.requestResult[0] && request.requestResult[0].responseResult">
{{ request.requestResult[0].success ? 'success' : 'error' }}
</span>
</template>
<!-- 这个不确定是否所以组件都有-->
<template v-slot:result>
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<div v-if="request.result">
<div v-for="(scenario,h) in request.result.scenarios" :key="h">
<el-tabs v-model="request.activeName" closable class="ms-tabs">
<el-tab-pane v-for="(item,i) in scenario.requestResults" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component :currentProtocol="request.protocol" :apiActive="true" :result="item"/>
</el-tab-pane>
</el-tabs>
</div>
</div>
<div v-else>
<el-tabs v-model="request.activeName" closable class="ms-tabs" v-if="request.requestResult && request.requestResult.length > 1">
<el-tab-pane v-for="(item,i) in request.requestResult" :label="'循环'+(i+1)" :key="i" style="margin-bottom: 5px">
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="item"
/>
</el-tab-pane>
</el-tabs>
<api-response-component
:currentProtocol="request.protocol"
:apiActive="true"
:result="request.requestResult[0]"
v-else/>
</div>
</template>
</api-base-component>
</template>
<script>
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import formCreate from "@form-create/element-ui";
import MsUpload from "../common/MsPluginUpload";
formCreate.component("msUpload", MsUpload);
export default {
name: "PluginComponent",
components: {ApiBaseComponent, ApiResponseComponent},
props: {
draggable: {
type: Boolean,
default: false,
},
message: String,
isReadOnly: {
type: Boolean,
default:
false
},
isMax: {
type: Boolean,
default: false,
},
showBtn: {
type: Boolean,
default: true,
},
request: {
type: Object,
},
defTitle: {type: String, default: "Plugin"},
defColor: {type: String, default: "#555855"},
defBackgroundColor: {type: String, default: "#F4F4FF"},
node: {},
},
data() {
return {
loading: false,
pluginForm: {},
execEntry: "",
data: {},
rules: [],
option: formCreate.parseJson(
'{"form":{"labelPosition":"right","size":"mini","labelWidth":"120px","hideRequiredAsterisk":false,"showMessage":false,"inlineMessage":false}}'
),
}
},
computed: {},
created() {
this.getPlugin();
if (!this.request.requestResult) {
this.request.requestResult = [];
}
this.data = this.request;
},
watch: {
message() {
this.reload();
},
data: {
handler: function () {
Object.assign(this.request, this.data);
},
deep: true
}
},
methods: {
blur(d) {
},
change(d) {
},
getValue(val) {
let reg = /\{(\w+)\}/gi;
if (val.indexOf("${") !== -1) {
let result;
while ((result = reg.exec(val)) !== null) {
if (this.pluginForm.getRule(result[1])) {
val = val.replace("$" + result[0], this.pluginForm.getRule(result[1]).value);
}
}
return val
}
return val;
},
visibleChange(d) {
if (d && d.inject) {
if (this.pluginForm.getRule(d.inject[0])) {
let req = {entry: this.execEntry, request: this.getValue(d.inject[1])};
this.$post('/plugin/customMethod/', req, response => {
if (response.data && this.pluginForm.getRule(d.inject[0]).options) {
this.pluginForm.getRule(d.inject[0]).options = JSON.parse(response.data);
}
})
this.reload();
}
}
},
getPlugin() {
let id = this.request.pluginId;
if (id) {
this.$get('/plugin/get/' + id, response => {
let plugin = response.data;
this.execEntry = plugin.execEntry;
if (plugin && plugin.formScript) {
this.rules = formCreate.parseJson(plugin.formScript);
}
if (plugin && plugin.formOption) {
this.option = formCreate.parseJson(plugin.formOption);
}
this.option.submitBtn = {show: false};
this.request.clazzName = plugin.clazzName;
if (this.request && this.request.active && this.pluginForm) {
this.pluginForm.setValue(this.request);
}
});
}
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
getCode() {
if (this.node && this.node.data.code && this.node.data.debug) {
if (this.node.data.code && this.node.data.code === 'error') {
return 'error';
} else {
return 'success';
}
}
return '';
},
remove() {
this.$emit('remove', this.request, this.node);
},
copyRow() {
this.$emit('copyRow', this.request, this.node);
},
active() {
this.request.active = !this.request.active;
if (this.request && this.request.active && this.pluginForm && this.pluginForm.setValue instanceof Function) {
this.pluginForm.setValue(this.request);
}
},
}
}
</script>
<style scoped>
/deep/ .el-divider {
margin-bottom: 10px;
}
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 100px;
}
/deep/ .el-select {
width: 100%;
}
/deep/ .fc-upload-btn {
width: 30px;
height: 30px;
line-height: 30px;
display: inline-block;
text-align: center;
border: 1px solid #c0ccda;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
-webkit-box-shadow: 2px 2px 5px rgb(0 0 0 / 10%);
box-shadow: 2px 2px 5px rgb(0 0 0 / 10%);
margin-right: 4px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.ms-test-running {
color: #6D317C;
}
.ms-form {
border: 1px #DCDFE6 solid;
height: 100%;
border-radius: 4px;
width: 100%;
}
.ms-form-create {
margin: 10px;
}
</style>

View File

@ -682,7 +682,7 @@ export default {
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
this.setParameter();
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, (response) => {
saveScenario(this.path, this.currentScenario, this.scenarioDefinition, this,(response) => {
this.$success(this.$t('commons.save_success'));
this.path = "/api/automation/update";
if (response.data) {

View File

@ -1,151 +1,151 @@
import {ELEMENT_TYPE} from "@/business/components/api/automation/scenario/Setting";
import {Assertions, ConstantTimer, Extract, IfController, JSR223Processor, JDBCProcessor,LoopController, TransactionController} from "@/business/components/api/definition/model/ApiTestModel";
import {Assertions, ConstantTimer, Extract, IfController, JSR223Processor, JDBCProcessor, LoopController, TransactionController, PluginController} from "@/business/components/api/definition/model/ApiTestModel";
export function buttons() {
export function buttons(this_) {
let buttons = [
{
title: this.$t('api_test.definition.request.extract_param'),
show: this.showButton("Extract"),
title: this_.$t('api_test.definition.request.extract_param'),
show: this_.showButton("Extract"),
titleColor: "#015478",
titleBgColor: "#E6EEF2",
icon: "colorize",
click: () => {
this.addComponent('Extract')
this_.addComponent('Extract')
}
},
{
title: this.$t('api_test.definition.request.post_script'),
show: this.showButton("JSR223PostProcessor"),
title: this_.$t('api_test.definition.request.post_script'),
show: this_.showButton("JSR223PostProcessor"),
titleColor: "#783887",
titleBgColor: "#F2ECF3",
icon: "skip_next",
click: () => {
this.addComponent('JSR223PostProcessor')
this_.addComponent('JSR223PostProcessor')
}
},
{
title: this.$t('api_test.definition.request.pre_script'),
show: this.showButton("JSR223PreProcessor"),
title: this_.$t('api_test.definition.request.pre_script'),
show: this_.showButton("JSR223PreProcessor"),
titleColor: "#B8741A",
titleBgColor: "#F9F1EA",
icon: "skip_previous",
click: () => {
this.addComponent('JSR223PreProcessor')
this_.addComponent('JSR223PreProcessor')
}
},
{
title: this.$t('api_test.definition.request.post_sql'),
show: this.showButton("JDBCPostProcessor"),
title: this_.$t('api_test.definition.request.post_sql'),
show: this_.showButton("JDBCPostProcessor"),
titleColor: "#1483F6",
titleBgColor: "#F2ECF3",
icon: "skip_next",
click: () => {
this.addComponent('JDBCPostProcessor')
this_.addComponent('JDBCPostProcessor')
}
},
{
title: this.$t('api_test.definition.request.pre_sql'),
show: this.showButton("JDBCPreProcessor"),
title: this_.$t('api_test.definition.request.pre_sql'),
show: this_.showButton("JDBCPreProcessor"),
titleColor: "#FE6F71",
titleBgColor: "#F9F1EA",
icon: "skip_previous",
click: () => {
this.addComponent('JDBCPreProcessor')
this_.addComponent('JDBCPreProcessor')
}
},
{
title: this.$t('api_test.automation.customize_script'),
show: this.showButton("JSR223Processor"),
title: this_.$t('api_test.automation.customize_script'),
show: this_.showButton("JSR223Processor"),
titleColor: "#7B4D12",
titleBgColor: "#F1EEE9",
icon: "code",
click: () => {
this.addComponent('JSR223Processor')
this_.addComponent('JSR223Processor')
}
},
{
title: this.$t('api_test.automation.if_controller'),
show: this.showButton("IfController"),
title: this_.$t('api_test.automation.if_controller'),
show: this_.showButton("IfController"),
titleColor: "#E6A23C",
titleBgColor: "#FCF6EE",
icon: "alt_route",
click: () => {
this.addComponent('IfController')
this_.addComponent('IfController')
}
},
{
title: this.$t('api_test.automation.loop_controller'),
show: this.showButton("LoopController"),
title: this_.$t('api_test.automation.loop_controller'),
show: this_.showButton("LoopController"),
titleColor: "#02A7F0",
titleBgColor: "#F4F4F5",
icon: "next_plan",
click: () => {
this.addComponent('LoopController')
this_.addComponent('LoopController')
}
},
{
title: this.$t('api_test.automation.transcation_controller'),
show: this.showButton("TransactionController"),
title: this_.$t('api_test.automation.transcation_controller'),
show: this_.showButton("TransactionController"),
titleColor: "#6D317C",
titleBgColor: "#F4F4F5",
icon: "alt_route",
click: () => {
this.addComponent('TransactionController')
this_.addComponent('TransactionController')
}
},
{
title: this.$t('api_test.automation.wait_controller'),
show: this.showButton("ConstantTimer"),
title: this_.$t('api_test.automation.wait_controller'),
show: this_.showButton("ConstantTimer"),
titleColor: "#67C23A",
titleBgColor: "#F2F9EE",
icon: "access_time",
click: () => {
this.addComponent('ConstantTimer')
this_.addComponent('ConstantTimer')
}
},
{
title: this.$t('api_test.definition.request.assertions_rule'),
show: this.showButton("Assertions"),
title: this_.$t('api_test.definition.request.assertions_rule'),
show: this_.showButton("Assertions"),
titleColor: "#A30014",
titleBgColor: "#F7E6E9",
icon: "next_plan",
click: () => {
this.addComponent('Assertions')
this_.addComponent('Assertions')
}
},
{
title: this.$t('api_test.automation.customize_req'),
show: this.showButton("CustomizeReq"),
title: this_.$t('api_test.automation.customize_req'),
show: this_.showButton("CustomizeReq"),
titleColor: "#008080",
titleBgColor: "#EBF2F2",
icon: "tune",
click: () => {
this.addComponent('CustomizeReq')
this_.addComponent('CustomizeReq')
}
},
{
title: this.$t('api_test.automation.scenario_import'),
show: this.showButton("scenario"),
title: this_.$t('api_test.automation.scenario_import'),
show: this_.showButton("scenario"),
titleColor: "#606266",
titleBgColor: "#F4F4F5",
icon: "movie",
click: () => {
this.addComponent('scenario')
this_.addComponent('scenario')
}
},
{
title: this.$t('api_test.automation.api_list_import'),
show: this.showButton("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"),
title: this_.$t('api_test.automation.api_list_import'),
show: this_.showButton("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"),
titleColor: "#F56C6C",
titleBgColor: "#FCF1F1",
icon: "api",
click: this.apiListImport
click: this_.apiListImport
}
];
return buttons.filter(btn => btn.show);
}
export function setComponent(type, _this) {
export function setComponent(type, _this, plugin) {
switch (type) {
case ELEMENT_TYPE.IfController:
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new IfController()) :
@ -200,7 +200,7 @@ export function setComponent(type, _this) {
_this.$refs.scenarioRelevance.open();
break;
default:
_this.$refs.apiImport.open();
_this.scenarioDefinition.push(new PluginController({type: plugin.name, pluginId: plugin.pluginId}));
break;
}
if (_this.selectedNode) {

View File

@ -5,6 +5,7 @@
import {getBodyUploadFiles, getCurrentProjectID, strMapToObj} from "@/common/js/utils";
import ThreadGroup from "./jmeter/components/thread-group";
import TestPlan from "./jmeter/components/test-plan";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
export default {
name: 'MsRun',
@ -70,14 +71,19 @@ export default {
}
let testPlan = new TestPlan();
testPlan.clazzName = TYPE_TO_C.get(testPlan.type);
let threadGroup = new ThreadGroup();
threadGroup.clazzName = TYPE_TO_C.get(threadGroup.type);
threadGroup.hashTree = [];
testPlan.hashTree = [threadGroup];
this.runData.forEach(item => {
item.projectId = projectId;
if (!item.clazzName) {
item.clazzName = TYPE_TO_C.get(item.type);
}
threadGroup.hashTree.push(item);
})
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type, projectId: projectId, environmentMap: strMapToObj(this.envMap)};
let reqObj = {id: this.reportId, testElement: testPlan, type: this.type, clazzName: this.clazzName ? this.clazzName : TYPE_TO_C.get(this.type), projectId: projectId, environmentMap: strMapToObj(this.envMap)};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
if (this.runData[0].url) {
reqObj.name = this.runData[0].url;

View File

@ -1036,6 +1036,34 @@ export class IfController extends Controller {
}
}
export class PluginController extends BaseConfig {
constructor(options = {}) {
super("Plugin", options);
this.type = "Plugin";
this.active = false;
this.enable = true;
this.hashTree = [];
this.set(options);
}
isValid() {
if (!!this.operator && this.operator.indexOf("empty") > 0) {
return !!this.variable && !!this.operator;
}
return !!this.variable && !!this.operator && !!this.value;
}
label() {
if (this.isValid()) {
let label = this.variable;
if (this.operator) label += " " + this.operator;
if (this.value) label += " " + this.value;
return label;
}
return "";
}
}
export class LoopController extends Controller {
constructor(options = {}) {
super("LoopController", options);

View File

@ -0,0 +1,165 @@
<template>
<el-form :model="currentConfig" :rules="rules" label-width="105px" v-loading="result.loading" ref="form">
<el-row>
<el-upload
class="jar-upload"
drag
action="#"
:http-request="upload"
:limit="1"
:beforeUpload="uploadValidate"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:file-list="fileList"
ref="fileUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
<div class="el-upload__tip" slot="tip">只能上传JAR包</div>
</el-upload>
<el-col>
<div class="buttons">
<el-button type="primary" size="small" @click="save()">{{ $t('commons.confirm') }}</el-button>
</div>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: "JarConfig",
data() {
return {
visible: false,
result: {},
currentConfig: {
name: '',
description: '',
fileName: '',
},
rules: {
name: [
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
{max: 200, message: this.$t('commons.input_limit', [1, 200]), trigger: 'blur'}
],
execEntry: [
{required: true, message: this.$t('plugin.script_entry'), trigger: 'blur'},
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
},
fileList: []
}
},
props: {
readOnly: {
type: Boolean,
default: false
},
config: {
type: Object,
default() {
return {};
}
},
callback: {
type: Function
},
},
watch: {
config() {
this.currentConfig = {
name: '',
description: '',
fileName: ''
};
if (this.config.fileName) {
this.fileList = [{name: this.config.fileName}];
} else {
this.fileList = [];
}
Object.assign(this.currentConfig, this.config);
}
},
mounted() {
Object.assign(this.currentConfig, this.config);
},
methods: {
upload(file) {
this.fileList.push(file.file)
},
handleExceed(files, fileList) {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
handleRemove(file, fileList) {
this.fileList = [];
},
uploadValidate(file, fileList) {
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
if (suffix != 'jar') {
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
return false;
}
return true;
},
save() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.fileList <= 0) {
this.$warning(this.$t('commons.please_upload'));
return;
}
let url = "/plugin/add";
this.result = this.$fileUpload(url, this.fileList[0], null, null, () => {
this.$success(this.$t('organization.integration.successful_operation'));
this.$emit("close");
});
} else {
return false;
}
}
);
},
clear() {
this.$refs['form'].clearValidate();
this.fileList = [];
}
}
}
</script>
<style scoped>
.el-divider {
height: 200px;
}
.jar-upload {
text-align: center;
margin: auto 0;
}
.jar-upload >>> .el-upload {
width: 100%;
max-width: 350px;
}
.jar-upload >>> .el-upload-dragger {
width: 100%;
}
.el-form {
border: solid #E1E1E1 1px;
margin: 10px 0;
padding: 20px 10px;
border-radius: 3px;
}
.buttons {
margin-top: 20px;
margin-bottom: -10px;
float: right;
}
</style>

View File

@ -0,0 +1,125 @@
<template>
<div class="jar-config-list">
<el-card class="table-card">
<template v-slot:header>
<ms-table-header
:showCreate="false"
:create-permission="['SYSTEM_USER:READ+CREATE']"
:condition.sync="condition" @search="search"
:import-tip="$t('test_track.case.import.click_upload')"
:tip="$t('commons.search_by_name_or_id')"
:create-tip="$t('user.create')"
:title="$t('plugin.title')"
@import="importJar"
:show-import="true"/>
</template>
<el-table border :data="tableData" class="adjust-table table-content">
<el-table-column prop="name" :label="$t('commons.name')" show-overflow-tooltip/>
<el-table-column prop="sourceName" :label="$t('api_test.jar_config.jar_file')" show-overflow-tooltip/>
<el-table-column prop="pluginId" :label="$t('plugin.plugin_id')" show-overflow-tooltip/>
<el-table-column prop="createUserId" :label="$t('report.user_name')" show-overflow-tooltip/>
<el-table-column prop="updateTime" :label="$t('commons.update_time')" show-overflow-tooltip>
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('commons.operating')" min-width="100">
<template v-slot:default="scope">
<div>
<ms-table-operator-button
:tip="$t('commons.delete')"
icon="el-icon-delete"
type="danger"
@exec="handleDelete(scope.row.id)"/>
<ms-table-operator-button
:tip="$t('plugin.script_view')"
icon="el-icon-view"
@exec="handleView(scope.row)"/>
</div>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog :title="$t('commons.import')" :visible.sync="dialogVisible" @close="close">
<ms-jar-config @close="close"/>
</el-dialog>
<ms-script-view ref="scriptView"/>
</div>
</template>
<script>
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import MsTableHeader from "../../common/components/MsTableHeader";
import MsJarConfig from "./JarConfig";
import MsScriptView from "./ScriptView";
export default {
name: "PluginConfig",
components: {MsTableOperatorButton, MsTableHeader, MsJarConfig,MsScriptView},
props: {},
data() {
return {
result: {},
condition: {},
tableData: [],
dialogVisible: false,
}
},
created() {
this.initPlugins();
},
methods: {
search() {
},
importJar() {
this.dialogVisible = true;
},
initPlugins() {
let url = "/plugin/list";
this.$get(url, response => {
this.tableData = response.data;
});
},
close() {
this.dialogVisible = false;
this.initPlugins();
},
handleView(row){
this.$refs.scriptView.open(row.pluginId);
},
handleDelete(id) {
this.$confirm(this.$t('api_test.jar_config.delete_tip'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning'
}).then(() => {
this.result = this.$get("/plugin/delete/" + id, () => {
this.$success(this.$t('commons.delete_success'));
this.initPlugins();
});
}).catch(() => {
this.$message({
type: 'info',
message: this.$t('commons.delete_cancelled')
});
});
},
}
}
</script>
<style scoped>
.el-icon-check {
font-size: 20px;
font-weight: bold;
color: green;
margin-left: 20px;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<div v-if="!loading">
<el-dialog :title="$t('plugin.script_view')" :visible.sync="dialogVisible" @close="close">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="表单配置" name="formOption">
<ms-code-edit
height="400px"
:data.sync="plugin.formOption"
:modes="modes"
:mode="'json'"
ref="codeEdit"/>
</el-tab-pane>
<el-tab-pane label="表单内容" name="formScript">
<ms-code-edit
height="400px"
:data.sync="plugin.formScript"
:modes="modes"
:mode="'json'"
ref="codeEdit"/>
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import MsCodeEdit from "../../common/components/MsCodeEdit";
export default {
name: "ScriptView",
components: {
MsCodeEdit
},
data() {
return {
dialogVisible: false,
activeName: "formScript",
modes: ['text', 'json', 'xml', 'html'],
plugin: {},
loading: false,
}
},
methods: {
getPlugin(id) {
if (id) {
this.$get('/plugin/get/' + id, response => {
this.plugin = response.data;
this.reload();
});
}
},
open(id) {
this.getPlugin(id);
this.dialogVisible = true;
},
close() {
this.dialogVisible = false;
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
});
},
handleClick() {
}
}
}
</script>
<style scoped>
</style>

View File

@ -132,26 +132,31 @@ export default {
{
path: 'operatingLog/system',
component: () => import('@/business/components/settings/operatinglog/OperatingLog'),
name:'system',
name: 'system',
meta: {system: true, title: 'operating_log.title', permissions: ['SYSTEM_OPERATING_LOG:READ']}
},
{
path: 'operatingLog/organization',
component: () => import('@/business/components/settings/operatinglog/OperatingLog'),
name:'organization',
name: 'organization',
meta: {organization: true, title: 'operating_log.title', permissions: ['ORGANIZATION_OPERATING_LOG:READ']}
},
{
path: 'operatingLog/workspace',
component: () => import('@/business/components/settings/operatinglog/OperatingLog'),
name:'workspace',
name: 'workspace',
meta: {workspace: true, title: 'operating_log.title', permissions: ['WORKSPACE_OPERATING_LOG:READ']}
},
{
path: 'operatingLog/project',
name:'project',
name: 'project',
component: () => import('@/business/components/settings/operatinglog/OperatingLog'),
meta: {project: true, title: 'operating_log.title', permissions: ['PROJECT_OPERATING_LOG:READ']}
}
},
{
path: 'plugin',
component: () => import('@/business/components/settings/plugin/PluginConfig'),
meta: {system: true, title: 'plugin.title', permissions: ['SYSTEM_USER:READ']}
},
]
};

View File

@ -23,6 +23,7 @@ import JsonSchemaEditor from './components/common/json-schema/schema/index';
import JSONPathPicker from 'vue-jsonpath-picker';
import VueClipboard from 'vue-clipboard2'
import vueMinderEditor from 'vue-minder-editor-plus'
import formCreate from "@form-create/element-ui"
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
@ -33,6 +34,7 @@ Vue.use(vueMinderEditor)
Vue.use(JsonSchemaEditor);
import VuePapaParse from 'vue-papa-parse'
Vue.use(VuePapaParse)
Vue.use(formCreate);
Vue.config.productionTip = false;
Vue.use(icon);

View File

@ -1988,5 +1988,11 @@ export default {
share: "Share",
change_history: "Change history",
change_content: "Change content"
},
plugin: {
title: "Plug-in management",
script_entry: "Script execution entry",
plugin_id: "Plug-in id",
script_view: "View script",
}
};

View File

@ -2000,5 +2000,11 @@ export default {
share: "分享",
change_history: "变更历史",
change_content: "变更内容"
},
plugin: {
title: "插件管理",
script_entry: "脚本执行入口",
plugin_id: "插件ID",
script_view: "查看脚本",
}
};

View File

@ -411,7 +411,7 @@ export default {
jira_storytype: '需求類型',
input_api_account: '請輸入賬號',
input_api_password: '請輸入密碼',
input_api_pat:'請输入 Personal Access Token',
input_api_pat: '請输入 Personal Access Token',
input_jira_url: '請輸入Jira地址https://metersphere.atlassian.net/',
input_jira_issuetype: '請輸入問題類型',
input_jira_storytype: '請輸入需求類型',
@ -438,12 +438,12 @@ export default {
azure_storytype: '需求類型',
input_azure_issuetype: '請輸入問題類型',
input_azure_storytype: '請輸入需求類型',
azure_pat:'PersonalAccessTokens',
azure_devops_url:'Azure Devops 地址',
azure_organization_id:'Azure 組織ID',
input_azure_pat:'請輸入 Personal Access Token',
input_azure_url:'請輸入 Azure Devops 地址',
input_azure_id:'請輸入 Azure 組織ID',
azure_pat: 'PersonalAccessTokens',
azure_devops_url: 'Azure Devops 地址',
azure_organization_id: 'Azure 組織ID',
input_azure_pat: '請輸入 Personal Access Token',
input_azure_url: '請輸入 Azure Devops 地址',
input_azure_id: '請輸入 Azure 組織ID',
use_tip_azure: 'Azure Devops 地址+令牌(賬戶設置-個人訪問令牌-創建令牌)',
}
},
@ -518,7 +518,7 @@ export default {
select_project: '請選擇項目',
select_group: '請選擇用戶組',
add_user_group_batch: '批量添加用戶組',
add_project_batch : '批量添加到項目',
add_project_batch: '批量添加到項目',
add_project_batch_tip: '默認為成員添加只讀用戶組(系統)',
},
group: {
@ -2000,5 +2000,11 @@ export default {
share: "分享",
change_history: "變更歷史",
change_content: "變更内容"
},
plugin: {
title: "插件管理",
script_entry: "脚本执行入口",
plugin_id: "插件ID",
script_view: "查看腳本",
}
};

View File

@ -25,6 +25,7 @@ const state = {
testPlanViewSelectNode: {},
selectStep: {},
currentApiCase: {},
pluginFiles: [],
}
const store = new Vuex.Store({