feat(接口测试): 解析前后置操作
This commit is contained in:
parent
63581bb769
commit
34279ebcc8
|
@ -9,4 +9,9 @@ import lombok.Data;
|
|||
@Data
|
||||
public class ParameterConfig {
|
||||
private String reportId;
|
||||
/**
|
||||
* 解析时,是否解析 enable 为 false 的组件
|
||||
* 导出时,需要解析
|
||||
*/
|
||||
private Boolean parseDisabledElement = false;
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package io.metersphere.api.dto.request.processors;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.metersphere.api.dto.request.http.KeyValueParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公共脚本处理器
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-11-07 09:59
|
||||
*/
|
||||
@Data
|
||||
@JsonTypeName("COMMON_SCRIPT")
|
||||
public class CommonScriptProcessor extends MsProcessor {
|
||||
/**
|
||||
* 脚本ID
|
||||
*/
|
||||
private String scriptId;
|
||||
/**
|
||||
* 入参
|
||||
*/
|
||||
private List<KeyValueParam> params;
|
||||
}
|
|
@ -14,7 +14,6 @@ import lombok.Data;
|
|||
@JsonSubTypes.Type(value = ScriptProcessor.class),
|
||||
@JsonSubTypes.Type(value = SQLProcessor.class),
|
||||
@JsonSubTypes.Type(value = TimeWaitingProcessor.class),
|
||||
@JsonSubTypes.Type(value = CommonScriptProcessor.class),
|
||||
@JsonSubTypes.Type(value = ExtractPostProcessor.class),
|
||||
})
|
||||
public abstract class MsProcessor {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package io.metersphere.api.dto.request.processors;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.metersphere.api.dto.request.http.KeyValueParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-11-06 21:12
|
||||
|
@ -10,7 +13,43 @@ import lombok.Data;
|
|||
@Data
|
||||
@JsonTypeName("SCRIPT")
|
||||
public class ScriptProcessor extends MsProcessor {
|
||||
/**
|
||||
* 脚本内容
|
||||
*/
|
||||
private String script;
|
||||
/**
|
||||
* 脚本语言
|
||||
* @see ScriptLanguageType
|
||||
*/
|
||||
private String scriptLanguage;
|
||||
private Boolean jsrEnable;
|
||||
/**
|
||||
* 是否启用公共脚本
|
||||
*/
|
||||
private Boolean enableCommonScript;
|
||||
/**
|
||||
* 脚本ID
|
||||
*/
|
||||
private String scriptId;
|
||||
/**
|
||||
* 公共脚本入参
|
||||
*/
|
||||
private List<KeyValueParam> params;
|
||||
|
||||
public enum ScriptLanguageType {
|
||||
BEANSHELL("beanshell"),
|
||||
BEANSHELL_JSR233("beanshell-JSR233"),
|
||||
GROOVY("groovy"),
|
||||
JAVASCRIPT("javascript"),
|
||||
PYTHON("python");
|
||||
|
||||
private String value;
|
||||
|
||||
ScriptLanguageType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.api.dto.request.processors.extract;
|
|||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@Data
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "extractType")
|
||||
|
@ -13,19 +14,19 @@ import lombok.Data;
|
|||
})
|
||||
public abstract class MsExtract {
|
||||
/**
|
||||
* 参数名
|
||||
* 变量名
|
||||
*/
|
||||
private String paramName;
|
||||
private String variableName;
|
||||
/**
|
||||
* 参数类型
|
||||
*/
|
||||
private String paramType;
|
||||
/**
|
||||
* 提取范围
|
||||
*/
|
||||
private String extractScope;
|
||||
private String variableType;
|
||||
/**
|
||||
* 表达式
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(variableName) && StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,54 @@ import lombok.Data;
|
|||
public class RegexExtract extends ResultMatchingExtract {
|
||||
/**
|
||||
* 表达式匹配规则
|
||||
* 值为 ExpressionRuleType
|
||||
* @see ExpressionRuleType
|
||||
*/
|
||||
private String expressionMatchingRule;
|
||||
/**
|
||||
* 提取范围
|
||||
* @see ExtractScope
|
||||
*/
|
||||
private String extractScope;
|
||||
|
||||
public enum ExpressionRuleType {
|
||||
/**
|
||||
* 匹配表达式
|
||||
*/
|
||||
EXPRESSION,
|
||||
EXPRESSION("$1$"),
|
||||
/**
|
||||
* 匹配组
|
||||
*/
|
||||
GROUP
|
||||
GROUP("$0$");
|
||||
|
||||
private String value;
|
||||
|
||||
ExpressionRuleType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExtractScope {
|
||||
BODY("false"),
|
||||
REQUEST_HEADERS("request_headers"),
|
||||
UNESCAPED_BODY("unescaped"),
|
||||
BODY_AS_DOCUMENT("as_document"),
|
||||
RESPONSE_HEADERS("true"),
|
||||
URL("URL"),
|
||||
RESPONSE_CODE("code"),
|
||||
RESPONSE_MESSAGE("message");
|
||||
|
||||
private String value;
|
||||
|
||||
ExtractScope(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,17 @@ import lombok.Data;
|
|||
*/
|
||||
@Data
|
||||
@JsonTypeName("X_PATH")
|
||||
public class XPathExtract extends MsExtract {
|
||||
public class XPathExtract extends ResultMatchingExtract {
|
||||
private String responseFormat;
|
||||
|
||||
public enum ResponseFormat {
|
||||
/**
|
||||
* XML
|
||||
*/
|
||||
XML,
|
||||
/**
|
||||
* HTML
|
||||
*/
|
||||
HTML
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package io.metersphere.api.parser.jmeter;
|
|||
|
||||
|
||||
import io.metersphere.api.dto.request.MsCommonElement;
|
||||
import io.metersphere.api.dto.request.processors.MsProcessorConfig;
|
||||
import io.metersphere.api.parser.jmeter.processor.MsProcessorConverterFactory;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
@ -17,6 +19,28 @@ public class MsCommonElementConverter extends AbstractJmeterElementConverter<MsC
|
|||
|
||||
@Override
|
||||
public void toHashTree(HashTree tree, MsCommonElement element, ParameterConfig config) {
|
||||
// todo 解析前后置和断言
|
||||
// todo 开关默认开启,关闭则运行该接口时不执行全局前置
|
||||
// preProcessorConfig.getEnableGlobal();
|
||||
|
||||
// 解析前置处理器
|
||||
handlePreProcessor(tree, element.getPreProcessorConfig(), config);
|
||||
// 解析后置处理器
|
||||
handlePostProcessor(tree, element.getPostProcessorConfig(), config);
|
||||
}
|
||||
|
||||
private void handlePreProcessor(HashTree tree, MsProcessorConfig preProcessorConfig, ParameterConfig config) {
|
||||
if (preProcessorConfig == null || preProcessorConfig.getProcessors() == null) {
|
||||
return;
|
||||
}
|
||||
preProcessorConfig.getProcessors()
|
||||
.forEach(processor -> MsProcessorConverterFactory.getPreConverter(processor.getClass()).parse(tree, processor, config));
|
||||
}
|
||||
|
||||
private void handlePostProcessor(HashTree tree, MsProcessorConfig postProcessorConfig , ParameterConfig config) {
|
||||
if (postProcessorConfig == null || postProcessorConfig.getProcessors() == null) {
|
||||
return;
|
||||
}
|
||||
postProcessorConfig.getProcessors()
|
||||
.forEach(processor -> MsProcessorConverterFactory.getPostConverter(processor.getClass()).parse(tree, processor, config));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.api.parser.jmeter.constants;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 19:45
|
||||
*/
|
||||
public class JmeterAlias {
|
||||
public static final String TEST_BEAN_GUI = "TestBeanGUI";
|
||||
public static final String CONSTANT_TIMER_GUI = "ConstantTimerGui";
|
||||
public static final String REGEX_EXTRACTOR_GUI = "RegexExtractorGui";
|
||||
public static final String JSON_POST_PROCESSOR_GUI = "JSONPostProcessorGui";
|
||||
public static final String X_PATH_EXTRACTOR_GUI = "XPathExtractorGui";
|
||||
public static final String X_PATH2_EXTRACTOR_GUI = "XPath2ExtractorGui";
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.api.parser.jmeter.constants;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 19:45
|
||||
*/
|
||||
public class JmeterProperty {
|
||||
public static final String SCRIPT = "script";
|
||||
public static final String CACHE_KEY = "cacheKey";
|
||||
public static final String BEAN_SAMPLER_QUERY = "BeanShellSampler.query";
|
||||
public static final String SCRIPT_LANGUAGE = "scriptLanguage";
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ExtractPostProcessor;
|
||||
import io.metersphere.api.dto.request.processors.extract.MsExtract;
|
||||
import io.metersphere.api.parser.jmeter.processor.extract.ExtractConverterFactory;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class ExtractPostProcessorConverter extends MsProcessorConverter<ExtractPostProcessor> {
|
||||
|
||||
@Override
|
||||
public void parse(HashTree hashTree, ExtractPostProcessor processor, ParameterConfig config) {
|
||||
if (!needParse(processor, config) || processor.getExtractors() == null) {
|
||||
return;
|
||||
}
|
||||
processor.getExtractors()
|
||||
.stream()
|
||||
.filter(MsExtract::isValid)
|
||||
.forEach(extract ->
|
||||
ExtractConverterFactory.getConverter(extract.getClass())
|
||||
.parse(hashTree, extract, config));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
|
||||
import io.metersphere.api.dto.request.processors.MsProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-10-27 10:07
|
||||
* <p>
|
||||
* body 解析器
|
||||
*/
|
||||
public abstract class MsProcessorConverter<T extends MsProcessor> {
|
||||
|
||||
/**
|
||||
* 解析对应的前后置处理器
|
||||
* @param hashTree
|
||||
* @param processor
|
||||
* @param config
|
||||
*/
|
||||
public abstract void parse(HashTree hashTree, T processor, ParameterConfig config);
|
||||
|
||||
protected boolean needParse(MsProcessor processor, ParameterConfig config) {
|
||||
// 如果组件是启用的,或者设置了解析禁用的组件,则返回 true
|
||||
if (BooleanUtils.isTrue(processor.getEnable()) || config.getParseDisabledElement()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ExtractPostProcessor;
|
||||
import io.metersphere.api.dto.request.processors.SQLProcessor;
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import io.metersphere.api.dto.request.processors.TimeWaitingProcessor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-21 19:19
|
||||
*/
|
||||
public class MsProcessorConverterFactory {
|
||||
|
||||
private static Map<Class, MsProcessorConverter> preConverterMap = new HashMap<>();
|
||||
private static Map<Class, MsProcessorConverter> postConverterMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
preConverterMap.put(ScriptProcessor.class, new ScriptPreProcessorConverter());
|
||||
preConverterMap.put(SQLProcessor.class, new SqlPreProcessorConverter());
|
||||
preConverterMap.put(TimeWaitingProcessor.class, new TimeWaitingProcessorConverter());
|
||||
|
||||
postConverterMap.put(ScriptProcessor.class, new ScriptPostProcessorConverter());
|
||||
postConverterMap.put(SQLProcessor.class, new SqlPostProcessorConverter());
|
||||
postConverterMap.put(TimeWaitingProcessor.class, new TimeWaitingProcessorConverter());
|
||||
postConverterMap.put(ExtractPostProcessor.class, new ExtractPostProcessorConverter());
|
||||
}
|
||||
|
||||
public static MsProcessorConverter getPreConverter(Class processorClass) {
|
||||
return preConverterMap.get(processorClass);
|
||||
}
|
||||
|
||||
public static MsProcessorConverter getPostConverter(Class processorClass) {
|
||||
return postConverterMap.get(processorClass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ScriptFilter {
|
||||
public static final String beanshell = "/blacklist/beanshell.bk";
|
||||
public static final String groovy = "/blacklist/groovy.bk";
|
||||
public static final String python = "/blacklist/python.bk";
|
||||
// 关键字内容较小,全局缓存下来避免重复读取
|
||||
public static final Map<String, List<String>> scriptCache = new HashMap<>();
|
||||
|
||||
static {
|
||||
// 初始化安全过滤脚本
|
||||
ScriptFilter.initScript(ScriptFilter.beanshell);
|
||||
ScriptFilter.initScript(ScriptFilter.python);
|
||||
ScriptFilter.initScript(ScriptFilter.groovy);
|
||||
}
|
||||
|
||||
public static void initScript(String path) {
|
||||
try {
|
||||
InputStream in = ScriptFilter.class.getResourceAsStream(path);
|
||||
List<String> bks = IOUtils.readLines(in, Charset.defaultCharset());
|
||||
if (CollectionUtils.isNotEmpty(bks)) {
|
||||
scriptCache.put(path, bks);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogUtils.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void blackList(StringBuffer buffer, String script, String path) {
|
||||
try {
|
||||
List<String> bks = scriptCache.get(path);
|
||||
if (CollectionUtils.isNotEmpty(bks)) {
|
||||
bks.forEach(item -> {
|
||||
if (script.contains(item) && script.indexOf(item) != -1) {
|
||||
buffer.append(item).append(",");
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LogUtils.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void verify(String language, String label, String script) {
|
||||
// 默认 groovy
|
||||
ScriptProcessor.ScriptLanguageType scriptLanguageType = Arrays.stream(ScriptProcessor.ScriptLanguageType.values())
|
||||
.filter(item -> StringUtils.equals(item.getValue(), language))
|
||||
.findFirst()
|
||||
.orElse(ScriptProcessor.ScriptLanguageType.GROOVY);
|
||||
|
||||
if (StringUtils.isNotEmpty(script)) {
|
||||
final StringBuffer buffer = new StringBuffer();
|
||||
switch (scriptLanguageType) {
|
||||
case BEANSHELL:
|
||||
blackList(buffer, script, beanshell);
|
||||
break;
|
||||
case PYTHON:
|
||||
blackList(buffer, script, python);
|
||||
break;
|
||||
default:
|
||||
blackList(buffer, script, groovy);
|
||||
break;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(buffer.toString())) {
|
||||
String message = "脚本内包含敏感函数:【" + buffer.toString().substring(0, buffer.toString().length() - 1) + "】";
|
||||
if (StringUtils.isNotEmpty(label)) {
|
||||
message = label + "," + message;
|
||||
}
|
||||
throw new MSException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jmeter.extractor.BeanShellPostProcessor;
|
||||
import org.apache.jmeter.extractor.JSR223PostProcessor;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class ScriptPostProcessorConverter extends ScriptProcessorConverter {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, ScriptProcessor scriptProcessor, ParameterConfig config) {
|
||||
if (!needParse(scriptProcessor, config)) {
|
||||
return;
|
||||
}
|
||||
// todo 处理公共脚本
|
||||
TestElement processor;
|
||||
if (isJSR233(scriptProcessor)) {
|
||||
processor = new JSR223PostProcessor();
|
||||
} else {
|
||||
processor = new BeanShellPostProcessor();
|
||||
}
|
||||
parse(processor, scriptProcessor);
|
||||
hashTree.add(processor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jmeter.modifiers.BeanShellPreProcessor;
|
||||
import org.apache.jmeter.modifiers.JSR223PreProcessor;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class ScriptPreProcessorConverter extends ScriptProcessorConverter {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, ScriptProcessor scriptProcessor, ParameterConfig config) {
|
||||
if (!needParse(scriptProcessor, config)) {
|
||||
return;
|
||||
}
|
||||
// todo 处理公共脚本
|
||||
TestElement processor;
|
||||
if (isJSR233(scriptProcessor)) {
|
||||
processor = new JSR223PreProcessor();
|
||||
} else {
|
||||
processor = new BeanShellPreProcessor();
|
||||
}
|
||||
parse(processor, scriptProcessor);
|
||||
hashTree.add(processor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public abstract class ScriptProcessorConverter extends MsProcessorConverter<ScriptProcessor> {
|
||||
|
||||
public static final String ENV_VARIABLE_EXPRESSION = "${__metersphere_env_id}";
|
||||
public static final String MS_RUNNING_ENV_PREFIX = "MS.ENV.";
|
||||
protected void parse(TestElement testElement, ScriptProcessor scriptProcessor) {
|
||||
// 脚本安全校验
|
||||
ScriptFilter.verify(scriptProcessor.getScriptLanguage(), scriptProcessor.getName(), scriptProcessor.getScript());
|
||||
|
||||
testElement.setEnabled(scriptProcessor.getEnable());
|
||||
String name = StringUtils.isEmpty(scriptProcessor.getName()) ? scriptProcessor.getClass().getSimpleName() : scriptProcessor.getName();
|
||||
testElement.setName(name);
|
||||
|
||||
// todo 替换环境变量
|
||||
// String evnId = scriptProcessor.getEnvironmentId();
|
||||
// if (StringUtils.isNotEmpty(scriptProcessor.getScript())) {
|
||||
// scriptProcessor.setScript(StringUtils.replace(scriptProcessor.getScript(), ENV_VARIABLE_EXPRESSION, "\"" + MS_RUNNING_ENV_PREFIX + evnId + ".\""));
|
||||
// }
|
||||
testElement.setProperty(JmeterProperty.CACHE_KEY, false);
|
||||
testElement.setProperty(TestElement.TEST_CLASS, testElement.getClass().getSimpleName());
|
||||
testElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(JmeterAlias.TEST_BEAN_GUI));
|
||||
testElement.setProperty(JmeterProperty.SCRIPT_LANGUAGE, scriptProcessor.getScriptLanguage());
|
||||
testElement.setProperty(JmeterProperty.SCRIPT, scriptProcessor.getScript());
|
||||
}
|
||||
|
||||
protected boolean isJSR233(ScriptProcessor scriptProcessor) {
|
||||
return !StringUtils.equals(scriptProcessor.getScriptLanguage(), ScriptProcessor.ScriptLanguageType.BEANSHELL.getValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.SQLProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class SqlPostProcessorConverter extends SqlProcessorConverter {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) {
|
||||
if (!needParse(scriptProcessor, config)) {
|
||||
return;
|
||||
}
|
||||
// todo 等环境开发完之后,补充
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.SQLProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class SqlPreProcessorConverter extends SqlProcessorConverter {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) {
|
||||
if (!needParse(scriptProcessor, config)) {
|
||||
return;
|
||||
}
|
||||
// todo 等环境开发完之后,补充
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.SQLProcessor;
|
||||
import io.metersphere.api.dto.request.processors.ScriptProcessor;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public abstract class SqlProcessorConverter extends MsProcessorConverter<SQLProcessor> {
|
||||
|
||||
protected void parse(TestElement testElement, ScriptProcessor scriptProcessor) {
|
||||
// todo 等环境开发完之后,补充
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package io.metersphere.api.parser.jmeter.processor;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.TimeWaitingProcessor;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jmeter.timers.ConstantTimer;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.CONSTANT_TIMER_GUI;
|
||||
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-26 14:49
|
||||
*/
|
||||
public class TimeWaitingProcessorConverter extends MsProcessorConverter<TimeWaitingProcessor> {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, TimeWaitingProcessor processor, ParameterConfig config) {
|
||||
ConstantTimer constantTimer = new ConstantTimer();
|
||||
constantTimer.setEnabled(processor.getEnable());
|
||||
constantTimer.setName(processor.getDelay() + " ms");
|
||||
constantTimer.setProperty(TestElement.TEST_CLASS, ConstantTimer.class.getName());
|
||||
constantTimer.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(CONSTANT_TIMER_GUI));
|
||||
constantTimer.setDelay(processor.getDelay().toString());
|
||||
hashTree.add(constantTimer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package io.metersphere.api.parser.jmeter.processor.extract;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.extract.MsExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.ResultMatchingExtract;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-27 10:32
|
||||
*/
|
||||
public abstract class ExtractConverter<T extends MsExtract> {
|
||||
/**
|
||||
* 解析对应的提取器
|
||||
* @param hashTree
|
||||
* @param extract
|
||||
* @param config
|
||||
*/
|
||||
public abstract void parse(HashTree hashTree, T extract, ParameterConfig config);
|
||||
|
||||
/**
|
||||
* 处理匹配多条等匹配规则
|
||||
* @param extract
|
||||
* @return
|
||||
*/
|
||||
protected Integer parseResultMatchingRule(ResultMatchingExtract extract) {
|
||||
String resultMatchingRule = extract.getResultMatchingRule();
|
||||
if (StringUtils.equals(resultMatchingRule, ResultMatchingExtract.ResultMatchingRuleType.ALL.name())) {
|
||||
return -1;
|
||||
} else if (StringUtils.equals(resultMatchingRule, ResultMatchingExtract.ResultMatchingRuleType.RANDOM.name())) {
|
||||
return 0;
|
||||
} else if (StringUtils.equals(resultMatchingRule, ResultMatchingExtract.ResultMatchingRuleType.SPECIFIC.name())
|
||||
&& extract.getResultMatchingRuleNum() != null) {
|
||||
return extract.getResultMatchingRuleNum();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package io.metersphere.api.parser.jmeter.processor.extract;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.extract.JSONPathExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.RegexExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.XPathExtract;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-27 10:31
|
||||
*/
|
||||
public class ExtractConverterFactory {
|
||||
private static Map<Class, ExtractConverter> converterMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
converterMap.put(RegexExtract.class, new RegexExtractConverter());
|
||||
converterMap.put(JSONPathExtract.class, new JSONPathExtractConverter());
|
||||
converterMap.put(XPathExtract.class, new XPathExtractConverter());
|
||||
}
|
||||
|
||||
public static ExtractConverter getConverter(Class processorClass) {
|
||||
return converterMap.get(processorClass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package io.metersphere.api.parser.jmeter.processor.extract;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.extract.JSONPathExtract;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.JSON_POST_PROCESSOR_GUI;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-27 10:32
|
||||
*/
|
||||
public class JSONPathExtractConverter extends ExtractConverter<JSONPathExtract> {
|
||||
|
||||
@Override
|
||||
public void parse(HashTree hashTree, JSONPathExtract msExtract, ParameterConfig config) {
|
||||
JSONPostProcessor extractor = new JSONPostProcessor();
|
||||
extractor.setName(msExtract.getVariableName());
|
||||
extractor.setProperty(TestElement.TEST_CLASS, JSONPostProcessor.class.getName());
|
||||
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(JSON_POST_PROCESSOR_GUI));
|
||||
extractor.setRefNames(msExtract.getVariableName());
|
||||
extractor.setJsonPathExpressions(msExtract.getExpression());
|
||||
// 处理匹配多条等匹配规则
|
||||
extractor.setMatchNumbers(parseResultMatchingRule(msExtract).toString());
|
||||
hashTree.add(extractor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package io.metersphere.api.parser.jmeter.processor.extract;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.extract.RegexExtract;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.extractor.RegexExtractor;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.REGEX_EXTRACTOR_GUI;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-27 10:32
|
||||
*/
|
||||
public class RegexExtractConverter extends ExtractConverter<RegexExtract> {
|
||||
@Override
|
||||
public void parse(HashTree hashTree, RegexExtract msExtract, ParameterConfig config) {
|
||||
RegexExtractor extractor = new RegexExtractor();
|
||||
extractor.setName(msExtract.getVariableName());
|
||||
extractor.setProperty(TestElement.TEST_CLASS, RegexExtractor.class.getName());
|
||||
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(REGEX_EXTRACTOR_GUI));
|
||||
extractor.setRefName(msExtract.getVariableName());
|
||||
extractor.setRegex(msExtract.getExpression());
|
||||
extractor.setUseField(msExtract.getExtractScope());
|
||||
|
||||
// 处理匹配多条等匹配规则
|
||||
extractor.setMatchNumber(parseResultMatchingRule(msExtract));
|
||||
|
||||
// $1$提取 JSON 响应中的第一个匹配项 $0$用于提取整个 JSON 响应
|
||||
if (StringUtils.isBlank(msExtract.getExpressionMatchingRule())) {
|
||||
extractor.setTemplate(RegexExtract.ExpressionRuleType.EXPRESSION.getValue());
|
||||
} else {
|
||||
extractor.setTemplate(msExtract.getExpressionMatchingRule());
|
||||
}
|
||||
hashTree.add(extractor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package io.metersphere.api.parser.jmeter.processor.extract;
|
||||
|
||||
import io.metersphere.api.dto.request.processors.extract.XPathExtract;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.extractor.XPath2Extractor;
|
||||
import org.apache.jmeter.extractor.XPathExtractor;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.X_PATH2_EXTRACTOR_GUI;
|
||||
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.X_PATH_EXTRACTOR_GUI;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2023-12-27 10:32
|
||||
*/
|
||||
public class XPathExtractConverter extends ExtractConverter<XPathExtract> {
|
||||
|
||||
@Override
|
||||
public void parse(HashTree hashTree, XPathExtract msExtract, ParameterConfig config) {
|
||||
if (StringUtils.equals(msExtract.getResponseFormat(), XPathExtract.ResponseFormat.HTML.name())) {
|
||||
hashTree.add(parseXPathExtract(msExtract));
|
||||
} else {
|
||||
hashTree.add(parseXPath2Extract(msExtract));
|
||||
}
|
||||
}
|
||||
|
||||
private XPathExtractor parseXPathExtract(XPathExtract msExtract) {
|
||||
XPathExtractor extractor = new XPathExtractor();
|
||||
extractor.setTolerant(true);
|
||||
extractor.setName(msExtract.getVariableName());
|
||||
extractor.setProperty(TestElement.TEST_CLASS, XPathExtractor.class.getName());
|
||||
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(X_PATH_EXTRACTOR_GUI));
|
||||
extractor.setRefName(msExtract.getVariableName());
|
||||
extractor.setXPathQuery(msExtract.getExpression());
|
||||
// 处理匹配多条等匹配规则
|
||||
extractor.setMatchNumber(parseResultMatchingRule(msExtract));
|
||||
return extractor;
|
||||
}
|
||||
|
||||
private XPath2Extractor parseXPath2Extract(XPathExtract msExtract) {
|
||||
XPath2Extractor extractor = new XPath2Extractor();
|
||||
extractor.setName(msExtract.getVariableName());
|
||||
extractor.setProperty(TestElement.TEST_CLASS, XPathExtractor.class.getName());
|
||||
extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(X_PATH2_EXTRACTOR_GUI));
|
||||
extractor.setRefName(msExtract.getVariableName());
|
||||
extractor.setXPathQuery(msExtract.getExpression());
|
||||
// 处理匹配多条等匹配规则
|
||||
extractor.setMatchNumber(parseResultMatchingRule(msExtract));
|
||||
return extractor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
os.system
|
|
@ -13,8 +13,12 @@ import io.metersphere.api.dto.request.http.body.*;
|
|||
import io.metersphere.api.dto.request.processors.*;
|
||||
import io.metersphere.api.dto.request.processors.extract.JSONPathExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.RegexExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.ResultMatchingExtract;
|
||||
import io.metersphere.api.dto.request.processors.extract.XPathExtract;
|
||||
import io.metersphere.api.parser.TestElementParser;
|
||||
import io.metersphere.api.parser.TestElementParserFactory;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.sdk.constants.MsAssertionCondition;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
@ -121,8 +125,7 @@ public class MsHTTPElementTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void msProcessorTest() {
|
||||
|
||||
public void processorParseTest() {
|
||||
MsHTTPElement msHTTPElement = getMsHttpElement();
|
||||
|
||||
List processors = new ArrayList<>();
|
||||
|
@ -130,10 +133,15 @@ public class MsHTTPElementTest {
|
|||
ScriptProcessor scriptProcessor = new ScriptProcessor();
|
||||
scriptProcessor.setEnable(true);
|
||||
scriptProcessor.setScript("script");
|
||||
scriptProcessor.setScriptLanguage("js");
|
||||
scriptProcessor.setJsrEnable(true);
|
||||
scriptProcessor.setScriptLanguage(ScriptProcessor.ScriptLanguageType.JAVASCRIPT.getValue());
|
||||
processors.add(scriptProcessor);
|
||||
|
||||
ScriptProcessor beanShellScriptProcessor = new ScriptProcessor();
|
||||
beanShellScriptProcessor.setEnable(true);
|
||||
beanShellScriptProcessor.setScript("script");
|
||||
beanShellScriptProcessor.setScriptLanguage(ScriptProcessor.ScriptLanguageType.BEANSHELL.getValue());
|
||||
processors.add(beanShellScriptProcessor);
|
||||
|
||||
SQLProcessor sqlProcessor = new SQLProcessor();
|
||||
sqlProcessor.setScript("script");
|
||||
sqlProcessor.setEnable(true);
|
||||
|
@ -152,39 +160,68 @@ public class MsHTTPElementTest {
|
|||
timeWaitingProcessor.setEnable(true);
|
||||
processors.add(timeWaitingProcessor);
|
||||
|
||||
CommonScriptProcessor commonScriptProcessor = new CommonScriptProcessor();
|
||||
commonScriptProcessor.setEnable(true);
|
||||
commonScriptProcessor.setScriptId("11111");
|
||||
KeyValueParam commonScriptParam = new KeyValueParam();
|
||||
commonScriptParam.setKey("11");
|
||||
commonScriptParam.setValue("11");
|
||||
commonScriptProcessor.setParams(List.of(commonScriptParam));
|
||||
processors.add(commonScriptProcessor);
|
||||
List postProcessors = new ArrayList<>();
|
||||
|
||||
ExtractPostProcessor extractPostProcessor = new ExtractPostProcessor();
|
||||
RegexExtract regexExtract = new RegexExtract();
|
||||
regexExtract.setExpressionMatchingRule("");
|
||||
regexExtract.setVariableName("test");
|
||||
regexExtract.setExpressionMatchingRule("$1$");
|
||||
regexExtract.setExpression("test");
|
||||
|
||||
RegexExtract regexExtract2 = new RegexExtract();
|
||||
regexExtract2.setVariableName("test");
|
||||
regexExtract2.setExpressionMatchingRule("$0$");
|
||||
regexExtract2.setResultMatchingRule(ResultMatchingExtract.ResultMatchingRuleType.ALL.name());
|
||||
regexExtract2.setExtractScope("unescaped");
|
||||
regexExtract2.setExpression("test");
|
||||
|
||||
JSONPathExtract jsonPathExtract = new JSONPathExtract();
|
||||
jsonPathExtract.setExpression("");
|
||||
jsonPathExtract.setExpression("test");
|
||||
jsonPathExtract.setVariableName("test");
|
||||
jsonPathExtract.setResultMatchingRule(ResultMatchingExtract.ResultMatchingRuleType.RANDOM.name());
|
||||
|
||||
XPathExtract xPathExtract = new XPathExtract();
|
||||
xPathExtract.setExpression("");
|
||||
extractPostProcessor.setExtractors(List.of(regexExtract, jsonPathExtract, xPathExtract));
|
||||
processors.add(extractPostProcessor);
|
||||
xPathExtract.setExpression("test");
|
||||
xPathExtract.setVariableName("test");
|
||||
xPathExtract.setResultMatchingRule(ResultMatchingExtract.ResultMatchingRuleType.SPECIFIC.name());
|
||||
xPathExtract.setResultMatchingRuleNum(2);
|
||||
|
||||
XPathExtract xPathExtract2 = new XPathExtract();
|
||||
xPathExtract2.setExpression("test");
|
||||
xPathExtract2.setVariableName("test");
|
||||
xPathExtract2.setResultMatchingRule(ResultMatchingExtract.ResultMatchingRuleType.SPECIFIC.name());
|
||||
xPathExtract2.setResultMatchingRuleNum(2);
|
||||
xPathExtract2.setResponseFormat(XPathExtract.ResponseFormat.HTML.name());
|
||||
|
||||
extractPostProcessor.setExtractors(List.of(regexExtract, regexExtract2, jsonPathExtract, xPathExtract, xPathExtract2));
|
||||
postProcessors.addAll(processors);
|
||||
postProcessors.add(extractPostProcessor);
|
||||
|
||||
MsProcessorConfig msProcessorConfig = new MsProcessorConfig();
|
||||
msProcessorConfig.setProcessors(processors);
|
||||
|
||||
MsProcessorConfig msPostProcessorConfig = new MsProcessorConfig();
|
||||
msPostProcessorConfig.setProcessors(postProcessors);
|
||||
|
||||
MsCommonElement msCommonElement = new MsCommonElement();
|
||||
msCommonElement.setPreProcessorConfig(msProcessorConfig);
|
||||
msCommonElement.setPostProcessorConfig(msProcessorConfig);
|
||||
msCommonElement.setPostProcessorConfig(msPostProcessorConfig);
|
||||
|
||||
LinkedList linkedList = new LinkedList();
|
||||
linkedList.add(msCommonElement);
|
||||
msHTTPElement.setChildren(linkedList);
|
||||
|
||||
// 测试序列化
|
||||
String json = ApiDataUtils.toJSONString(msHTTPElement);
|
||||
Assertions.assertNotNull(json);
|
||||
Assertions.assertEquals(ApiDataUtils.parseObject(json, AbstractMsTestElement.class), msHTTPElement);
|
||||
|
||||
// 测试脚本解析
|
||||
ParameterConfig parameterConfig = new ParameterConfig();
|
||||
parameterConfig.setReportId("reportId");
|
||||
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(json, AbstractMsTestElement.class);
|
||||
defaultParser.parse(msTestElement, parameterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -256,7 +293,7 @@ public class MsHTTPElementTest {
|
|||
msHTTPElement.setPath("/test");
|
||||
msHTTPElement.setMethod("GET");
|
||||
msHTTPElement.setName("name");
|
||||
msHTTPElement.setEnable(false);
|
||||
msHTTPElement.setEnable(true);
|
||||
|
||||
Header header = new Header();
|
||||
header.setEnable(false);
|
||||
|
|
|
@ -307,6 +307,7 @@ public class PluginLoadService {
|
|||
public void handlePluginAddNotified(String pluginId, String fileName) {
|
||||
if (!hasPlugin(pluginId)) {
|
||||
loadPluginFromRepository(fileName);
|
||||
msPluginManager.startPlugin(pluginId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue