feat(接口调试): 定义断言和提取数据结构

This commit is contained in:
AgAngle 2023-11-24 14:05:45 +08:00 committed by jianxing
parent 55a3304800
commit 0eb16af5f0
57 changed files with 913 additions and 355 deletions

View File

@ -0,0 +1,88 @@
package io.metersphere.sdk.constants;
/**
* @Author: jianxing
* @CreateTime: 2023-11-23 10:21
*/
public enum MsAssertionCondition {
/**
* 不校验
*/
UNCHECK,
/**
* 包含
*/
INCLUDE,
/**
* 不包含
*/
NOT_INCLUDE,
/**
* 等于
*/
EQUALS,
/**
* 不等于
*/
NOT_EQUALS,
/**
* 大于
*/
GT,
/**
* 大于或等于
*/
GT_OR_EQUALS,
/**
* 小于
*/
LT,
/**
* 小于或等于
*/
LT_OR_EQUALS,
/**
* ...开始
*/
START_WITH,
/**
* ...结束
*/
END_WITH,
/**
* 为空
*/
EMPTY,
/**
* 不为空
*/
NOT_EMPTY,
/**
* 正则匹配
*/
REGEX,
/**
* 长度等于
*/
LENGTH_EQUALS,
/**
* 长度不等于
*/
LENGTH_NOT_EQUALS,
/**
* 长度大于
*/
LENGTH_GT,
/**
* 长度大于或等于
*/
LENGTH_GT_OR_EQUALS,
/**
* 长度小于
*/
LENGTH_LT,
/**
* 长度小于或等于
*/
LENGTH_LT_OR_EQUALS,
}

View File

@ -0,0 +1,28 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
/**
* 断言
*/
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "assertionType")
@JsonSubTypes({
@JsonSubTypes.Type(value = ResponseCodeAssertion.class),
@JsonSubTypes.Type(value = ResponseHeaderAssertion.class),
@JsonSubTypes.Type(value = ResponseBodyAssertion.class),
@JsonSubTypes.Type(value = ResponseTimeAssertion.class),
@JsonSubTypes.Type(value = ScriptAssertion.class),
})
public abstract class MsAssertion {
/**
* 是否启用
*/
private Boolean enable = true;
/**
* 断言名称
*/
private String name;
}

View File

@ -0,0 +1,22 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import java.util.List;
/**
* 断言设置
* @Author: jianxing
* @CreateTime: 2023-11-23 17:26
*/
@Data
public class MsAssertionConfig {
/**
* 是否启用全局断言
*/
private Boolean enableGlobal;
/**
* 断言列表
*/
private List<MsAssertion> assertions;
}

View File

@ -1,18 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsAssertionDuration extends MsAssertionType {
private long value;
public MsAssertionDuration() {
setType(MsAssertionType.DURATION);
}
public boolean isValid() {
return value > 0 && isEnable();
}
}

View File

@ -1,26 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsAssertionJSR223 extends MsAssertionType {
private String variable;
private String operator;
private String value;
private String desc;
private String name;
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
public MsAssertionJSR223() {
setType(MsAssertionType.JSR223);
}
public boolean isValid() {
return StringUtils.isNotBlank(script) && StringUtils.isNotBlank(scriptLanguage) && isEnable();
}
}

View File

@ -1,22 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsAssertionJsonPath extends MsAssertionType {
private String expect;
private String expression;
private String description;
private String option = "REGEX";
public MsAssertionJsonPath() {
setType(MsAssertionType.JSON_PATH);
}
public boolean isValid() {
return StringUtils.isNotBlank(expression) && isEnable();
}
}

View File

@ -1,23 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsAssertionRegex extends MsAssertionType {
private String subject;
private String expression;
private String description;
private boolean assumeSuccess;
private int testType = 2;
public MsAssertionRegex() {
setType(MsAssertionType.REGEX);
}
public boolean isValid() {
return StringUtils.isNotBlank(subject) && StringUtils.isNotBlank(expression) && isEnable();
}
}

View File

@ -1,17 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
@Data
public class MsAssertionType {
public final static String REGEX = "Regex";
public final static String DURATION = "Duration";
public final static String JSON_PATH = "JSONPath";
public final static String JSR223 = "JSR223";
public final static String TEXT = "Text";
public final static String XPATH2 = "XPath2";
private boolean enable = true;
public String label;
private String type;
}

View File

@ -1,19 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsAssertionXPath2 extends MsAssertionType {
private String expression;
public MsAssertionXPath2() {
setType(MsAssertionType.XPATH2);
}
public boolean isValid() {
return StringUtils.isNotBlank(expression) && isEnable();
}
}

View File

@ -1,21 +0,0 @@
package io.metersphere.sdk.dto.api.request.assertion;
import io.metersphere.plugin.api.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MsAssertions")
public class MsAssertions extends TestElementDTO {
private String xpathType;
private boolean scenarioAss;
private List<MsAssertionRegex> regex;
private List<MsAssertionJsonPath> jsonPath;
private List<MsAssertionJSR223> jsr223;
private List<MsAssertionXPath2> xpath2;
private MsAssertionDuration duration;
}

View File

@ -0,0 +1,23 @@
package io.metersphere.sdk.dto.api.request.assertion;
/**
* body断言中的断言类型
*/
public enum MsBodyAssertionType {
/**
* 正则断言
*/
REGEX,
/**
* XPath断言
*/
XPATH,
/**
* JSONPath断言
*/
JSON_PATH,
/**
* 文档断言
*/
DOCUMENT
}

View File

@ -0,0 +1,43 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.sdk.dto.api.request.assertion.body.DocumentAssertion;
import io.metersphere.sdk.dto.api.request.assertion.body.JSONPathAssertion;
import io.metersphere.sdk.dto.api.request.assertion.body.RegexAssertion;
import io.metersphere.sdk.dto.api.request.assertion.body.XPathAssertion;
import lombok.Data;
/**
* 请求体断言
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("RESPONSE_BODY")
public class ResponseBodyAssertion extends MsAssertion {
/**
* 断言类型
* 根据断言类型选择对应的断言
* 这里跟前端数据结构有差异
* 后端从设计层面支持多种断言前端只支持一种
* 同时切换可以同时持久化两种类型
* 值为 MsBodyAssertionType
*/
private String assertionType;
/**
* jsonPath断言
*/
private JSONPathAssertion jsonPathAssertion;
/**
* xpath断言
*/
private XPathAssertion xpathAssertion;
/**
* 文档断言
*/
private DocumentAssertion documentAssertion;
/**
* 正则断言
*/
private RegexAssertion regexAssertion;
}

View File

@ -0,0 +1,25 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
/**
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("RESPONSE_CODE")
public class ResponseCodeAssertion extends MsAssertion {
/**
* 匹配条件
* 不校验即忽略状态
* 选择其他条件时也忽略状态
* 不校验可搭配其他校验使用
* 值为 MsAssertionCondition
*/
private String condition;
/**
* 匹配值
*/
private String value;
}

View File

@ -0,0 +1,40 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
import java.util.List;
/**
* 响应头断言
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("RESPONSE_HEADER")
public class ResponseHeaderAssertion extends MsAssertion {
private List<ResponseHeaderAssertionItem> assertions;
@Data
public static class ResponseHeaderAssertionItem {
/**
* 是否启用
*/
private Boolean enable = true;
/**
* 响应头
*/
private String header;
/**
* 匹配条件
* 值为 MsAssertionCondition
*/
private String condition;
/**
* 匹配值
*/
private String value;
}
}

View File

@ -0,0 +1,19 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
/**
* 响应时间断言
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("RESPONSE_TIME")
public class ResponseTimeAssertion extends MsAssertion {
/**
* 最大响应时间
* 响应时间在xx毫秒内
*/
private Long maxResponseTime;
}

View File

@ -0,0 +1,31 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
/**
* 变量断言
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("SCRIPT")
public class ScriptAssertion extends MsAssertion {
/**
* 脚本描述
*/
private String description;
/**
* 脚本内容
*/
private String content;
/**
* 是否使用功能脚本
* 公共脚本和手动录入脚本只能二选一
*/
private Boolean enableCommonScript;
/**
* 引用公共脚本的ID
*/
private String commonScriptId;
}

View File

@ -0,0 +1,38 @@
package io.metersphere.sdk.dto.api.request.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
import java.util.List;
/**
* 变量断言
* @Author: jianxing
* @CreateTime: 2023-11-22 15:33
*/
@Data
@JsonTypeName("VARIABLE")
public class VariableAssertion {
private List<VariableAssertionItem> variableAssertionItem;
@Data
public static class VariableAssertionItem {
/**
* 是否启用
*/
private Boolean enable = true;
/**
* 变量名
*/
private String name;
/**
* 匹配条件
* 值为 MsAssertionCondition
*/
private String condition;
/**
* 匹配值
*/
private String value;
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
/**
* body 断言基类
* @Author: jianxing
* @CreateTime: 2023-11-23 14:25
*/
@Data
public abstract class BodyAssertionItem {
private Boolean enable = true;
}

View File

@ -0,0 +1,34 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
/**
* 文档断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:19
*/
@Data
public class DocumentAssertion extends BodyAssertionItem {
/**
* 跟随定义的apiId
* 传空为不跟随接口定义
*/
private String followApiId;
/**
* 文档类型
* json 或者 xml
* 根据文档类型选择对应的文档
* 这里跟前端数据结构有差异
* 后端从设计层面支持多种文档格式前端只支持一种
* 同时切换可以同时持久化两种格式
*/
private String documentType;
/**
* json格式的文档断言
*/
private DocumentAssertionElement jsonAssertion;
/**
* xml格式的文档断言
*/
private DocumentAssertionElement xmlAssertion;
}

View File

@ -0,0 +1,47 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2023-11-23 11:43
*/
@Data
public class DocumentAssertionElement {
private String id;
/**
* 参数名
*/
private String paramName;
/**
* 必含
*/
private Boolean include = false;
/**
* 类型
*/
private String type;
/**
* 类型校验
*/
private Boolean typeVerification = false;
/**
* 匹配条件
*/
private String condition;
/**
* 匹配值
* 即预期结果
*/
private Object expectedResult;
/**
* 组内校验
*/
private Boolean arrayVerification;
/**
* 子对象
*/
private List<DocumentAssertionElement> children;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
import java.util.List;
/**
*
* JSONPath断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:04
*/
@Data
public class JSONPathAssertion {
/**
* 断言列表
*/
private List<JSONPathAssertionItem> assertions;
}

View File

@ -0,0 +1,17 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
/**
*
* JSONPath断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:04
*/
@Data
public class JSONPathAssertionItem extends BodyAssertionItem {
private String expression;
private String condition;
private String value;
}

View File

@ -0,0 +1,18 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
import java.util.List;
/**
* 正则断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:03
*/
@Data
public class RegexAssertion {
/**
* 断言列表
*/
private List<RegexAssertionItem> assertions;
}

View File

@ -0,0 +1,13 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
/**
* 正则断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:03
*/
@Data
public class RegexAssertionItem extends BodyAssertionItem {
private String expression;
}

View File

@ -0,0 +1,24 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
import java.util.List;
/**
* XPath断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:18
*/
@Data
public class XPathAssertion {
/**
* 响应内容格式
* xml 或者 html
*/
private String format;
/**
* xpath断言
*/
private List<XPathAssertionItem> assertions;
}

View File

@ -0,0 +1,15 @@
package io.metersphere.sdk.dto.api.request.assertion.body;
import lombok.Data;
/**
* XPath断言
* @Author: jianxing
* @CreateTime: 2023-11-23 14:18
*/
@Data
public class XPathAssertionItem extends BodyAssertionItem {
private String expression;
private String condition;
private String value;
}

View File

@ -7,6 +7,6 @@ import lombok.Data;
* @CreateTime: 2023-11-06 16:59
*/
@Data
public class Header extends KeyValueParam {
public class Header extends KeyValueEnableParam {
}

View File

@ -0,0 +1,19 @@
package io.metersphere.sdk.dto.api.request.http;
import lombok.Data;
/**
* @Author: jianxing
* @CreateTime: 2023-11-06 17:27
*/
@Data
public class KeyValueEnableParam extends KeyValueParam {
/**
* 是否启用
*/
private Boolean enable = true;
/**
* 描述
*/
private String description;
}

View File

@ -16,12 +16,4 @@ public class KeyValueParam {
*
*/
private String value;
/**
* 是否启用
*/
private Boolean enable = true;
/**
* 描述
*/
private String description;
}

View File

@ -1,9 +1,10 @@
package io.metersphere.sdk.dto.api.request.http;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.sdk.dto.api.request.assertion.MsAssertionConfig;
import io.metersphere.sdk.dto.api.request.http.auth.HTTPAuth;
import io.metersphere.sdk.dto.api.request.http.body.Body;
import io.metersphere.sdk.dto.api.request.processors.MsProcessor;
import io.metersphere.sdk.dto.api.request.processors.MsProcessorConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -51,12 +52,15 @@ public class MsHTTPElement extends AbstractMsTestElement {
*/
private HTTPAuth authConfig;
/**
* 前置处理器
* 前置处理器配置
*/
private List<MsProcessor> preProcessors;
private MsProcessorConfig preProcessorConfig;
/**
* 后置处理器
* 后置处理器配置
*/
private List<MsProcessor> postProcessors;
// todo 断言和提取 待设计
private MsProcessorConfig postProcessorConfig;
/**
* 断言配置
*/
private MsAssertionConfig assertionConfig;
}

View File

@ -7,7 +7,7 @@ import lombok.Data;
* @CreateTime: 2023-11-06 16:59
*/
@Data
public class QueryParam extends KeyValueParam {
public class QueryParam extends KeyValueEnableParam {
/**
* 参数类型

View File

@ -7,7 +7,7 @@ import lombok.Data;
* @CreateTime: 2023-11-06 16:59
*/
@Data
public class RestParam extends KeyValueParam {
public class RestParam extends KeyValueEnableParam {
/**
* 参数类型
* 默认string可选integernumberarray

View File

@ -1,6 +1,6 @@
package io.metersphere.sdk.dto.api.request.http.body;
import io.metersphere.sdk.dto.api.request.http.KeyValueParam;
import io.metersphere.sdk.dto.api.request.http.KeyValueEnableParam;
import lombok.Data;
/**
@ -8,7 +8,7 @@ import lombok.Data;
* @CreateTime: 2023-11-06 18:11
*/
@Data
public class FormDataKV extends KeyValueParam {
public class FormDataKV extends KeyValueEnableParam {
private String paramType;
private Boolean required = false;
private Integer minLength;

View File

@ -1,18 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import io.metersphere.plugin.api.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MsExtract")
public class MsExtract extends TestElementDTO {
private String xpathType;
private List<MsExtractRegex> regex;
private List<MsExtractJSONPath> json;
private List<MsExtractXPath> xpath;
}

View File

@ -1,19 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsExtractCommon extends MsExtractType {
private String variable;
private String value;
private String expression;
private String description;
private boolean multipleMatching;
public boolean isValid() {
return StringUtils.isNotBlank(variable) && StringUtils.isNotBlank(expression);
}
}

View File

@ -1,12 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsExtractJSONPath extends MsExtractCommon {
public MsExtractJSONPath() {
setType(JSON_PATH);
}
}

View File

@ -1,14 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsExtractRegex extends MsExtractCommon {
private String useHeaders;
private String template;
public MsExtractRegex() {
setType(MsExtractType.REGEX);
}
}

View File

@ -1,12 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import lombok.Data;
@Data
public class MsExtractType {
public final static String REGEX = "Regex";
public final static String JSON_PATH = "JSONPath";
public final static String XPATH = "XPath";
private String type;
}

View File

@ -1,12 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.extract;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class MsExtractXPath extends MsExtractCommon {
public MsExtractXPath() {
setType(MsExtractType.XPATH);
}
}

View File

@ -1,16 +0,0 @@
package io.metersphere.sdk.dto.api.request.post.processors;
import io.metersphere.plugin.api.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MSPostJSR223Processor")
public class MsPostJSR223Processor extends TestElementDTO {
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
}

View File

@ -1,15 +0,0 @@
package io.metersphere.sdk.dto.api.request.pre.processors;
import io.metersphere.plugin.api.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MSPreJSR223Processor")
public class MsPreJSR223Processor extends TestElementDTO {
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
}

View File

@ -0,0 +1,25 @@
package io.metersphere.sdk.dto.api.request.processors;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.sdk.dto.api.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;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.sdk.dto.api.request.processors;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.sdk.dto.api.request.processors.extract.MsExtract;
import lombok.Data;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2023-11-22 11:08
*/
@Data
@JsonTypeName("EXTRACT")
public class ExtractPostProcessor extends MsProcessor {
/**
* 提取器列表
*/
private List<MsExtract> extractors;
}

View File

@ -1,15 +0,0 @@
package io.metersphere.sdk.dto.api.request.processors;
import io.metersphere.plugin.api.annotation.PluginSubType;
import io.metersphere.plugin.api.dto.TestElementDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@PluginSubType("MsJSR223Processor")
public class MsJSR223Processor extends TestElementDTO {
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
}

View File

@ -14,6 +14,16 @@ 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 {
/**
* 名称
*/
private String name;
/**
* 是否启用
*/
private Boolean enable = true;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.sdk.dto.api.request.processors;
import lombok.Data;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2023-11-07 10:17
*/
@Data
public class MsProcessorConfig {
/**
* 是否启用全局前置
*/
private Boolean enableGlobal;
/**
* 处理器
*/
private List<MsProcessor> processors;
}

View File

@ -1,6 +1,7 @@
package io.metersphere.sdk.dto.api.request.processors;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.sdk.dto.api.request.http.KeyValueEnableParam;
import io.metersphere.sdk.dto.api.request.http.KeyValueParam;
import lombok.Data;
@ -32,7 +33,7 @@ public class SQLProcessor extends MsProcessor {
/**
* 变量列表
*/
private List<KeyValueParam> variables;
private List<KeyValueEnableParam> variables;
/**
* 环境ID
*/
@ -42,7 +43,7 @@ public class SQLProcessor extends MsProcessor {
*/
private String dataSourceId;
/**
* 是否启用
* 提取参数
*/
private Boolean enable;
private List<KeyValueParam> extractParams;
}

View File

@ -13,5 +13,4 @@ public class ScriptProcessor extends MsProcessor {
private String script;
private String scriptLanguage;
private Boolean jsrEnable;
private Boolean enable;
}

View File

@ -11,5 +11,4 @@ import lombok.Data;
@JsonTypeName("TIME_WAITING")
public class TimeWaitingProcessor extends MsProcessor {
private Integer delay;
private Boolean enable;
}

View File

@ -0,0 +1,12 @@
package io.metersphere.sdk.dto.api.request.processors.extract;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
/**
* JSONPath提取
*/
@Data
@JsonTypeName("JSON_PATH")
public class JSONPathExtract extends ResultMatchingExtract {
}

View File

@ -0,0 +1,31 @@
package io.metersphere.sdk.dto.api.request.processors.extract;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "extractType")
@JsonSubTypes({
@JsonSubTypes.Type(value = RegexExtract.class),
@JsonSubTypes.Type(value = JSONPathExtract.class),
@JsonSubTypes.Type(value = XPathExtract.class)
})
public abstract class MsExtract {
/**
* 参数名
*/
private String paramName;
/**
* 参数类型
*/
private String paramType;
/**
* 提取范围
*/
private String extractScope;
/**
* 表达式
*/
private String expression;
}

View File

@ -0,0 +1,25 @@
package io.metersphere.sdk.dto.api.request.processors.extract;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
@Data
@JsonTypeName("REGEX")
public class RegexExtract extends ResultMatchingExtract {
/**
* 表达式匹配规则
* 值为 ExpressionRuleType
*/
private String expressionMatchingRule;
public enum ExpressionRuleType {
/**
* 匹配表达式
*/
EXPRESSION,
/**
* 匹配组
*/
GROUP
}
}

View File

@ -0,0 +1,31 @@
package io.metersphere.sdk.dto.api.request.processors.extract;
import lombok.Data;
@Data
public abstract class ResultMatchingExtract extends MsExtract {
/**
* 结果匹配规则
* 值为 ResultMatchingRuleType
*/
private String resultMatchingRule;
/**
* 匹配第几条结果
*/
private Integer resultMatchingRuleNum;
public enum ResultMatchingRuleType {
/**
* 随机匹配
*/
RANDOM,
/**
* 指定匹配
*/
SPECIFIC,
/**
* 全部匹配
*/
ALL
}
}

View File

@ -0,0 +1,13 @@
package io.metersphere.sdk.dto.api.request.processors.extract;
import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;
/**
* XPath提取
*/
@Data
@JsonTypeName("X_PATH")
public class XPathExtract extends MsExtract {
private String responseFormat;
}

View File

@ -10,7 +10,6 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.type.CollectionType;
import io.metersphere.sdk.dto.api.request.post.processors.MsPostJSR223Processor;
import io.metersphere.sdk.dto.api.request.sampler.MsDebugSampler;
import io.metersphere.sdk.exception.MSException;
@ -32,7 +31,6 @@ public class ApiDataUtils {
static {
// 默认内置的子组件
namedTypes.add(new NamedType(MsPostJSR223Processor.class, MsPostJSR223Processor.class.getSimpleName()));
namedTypes.add(new NamedType(MsDebugSampler.class, MsDebugSampler.class.getSimpleName()));
setObjectMapper(objectMapper);

View File

@ -4,15 +4,19 @@ import io.metersphere.sdk.dto.api.request.http.body.Body;
import io.metersphere.api.dto.definition.HttpResponse;
import io.metersphere.api.util.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.sdk.dto.api.request.assertion.*;
import io.metersphere.sdk.dto.api.request.assertion.body.*;
import io.metersphere.sdk.dto.api.request.http.*;
import io.metersphere.sdk.dto.api.request.http.auth.BasicAuth;
import io.metersphere.sdk.dto.api.request.http.auth.DigestAuth;
import io.metersphere.sdk.dto.api.request.http.auth.HTTPAuth;
import io.metersphere.sdk.dto.api.request.http.auth.NoAuth;
import io.metersphere.sdk.dto.api.request.http.body.*;
import io.metersphere.sdk.dto.api.request.processors.SQLProcessor;
import io.metersphere.sdk.dto.api.request.processors.ScriptProcessor;
import io.metersphere.sdk.dto.api.request.processors.TimeWaitingProcessor;
import io.metersphere.sdk.dto.api.request.processors.*;
import io.metersphere.sdk.dto.api.request.processors.extract.JSONPathExtract;
import io.metersphere.sdk.dto.api.request.processors.extract.RegexExtract;
import io.metersphere.sdk.dto.api.request.processors.extract.XPathExtract;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -127,7 +131,7 @@ public class MsHTTPElementTest {
sqlProcessor.setScript("script");
sqlProcessor.setEnable(true);
sqlProcessor.setDataSourceId("dataSourceId");
KeyValueParam keyValueParam = new KeyValueParam();
KeyValueEnableParam keyValueParam = new KeyValueEnableParam();
keyValueParam.setKey("key");
keyValueParam.setValue("value");
sqlProcessor.setVariables(List.of(keyValueParam));
@ -141,8 +145,83 @@ public class MsHTTPElementTest {
timeWaitingProcessor.setEnable(true);
processors.add(timeWaitingProcessor);
msHTTPElement.setPreProcessors(processors);
msHTTPElement.setPostProcessors(processors);
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);
ExtractPostProcessor extractPostProcessor = new ExtractPostProcessor();
RegexExtract regexExtract = new RegexExtract();
regexExtract.setExpressionMatchingRule("");
JSONPathExtract jsonPathExtract = new JSONPathExtract();
jsonPathExtract.setExpression("");
XPathExtract xPathExtract = new XPathExtract();
xPathExtract.setExpression("");
extractPostProcessor.setExtractors(List.of(regexExtract, jsonPathExtract, xPathExtract));
processors.add(extractPostProcessor);
MsProcessorConfig msProcessorConfig = new MsProcessorConfig();
msProcessorConfig.setProcessors(processors);
msHTTPElement.setPreProcessorConfig(msProcessorConfig);
msHTTPElement.setPostProcessorConfig(msProcessorConfig);
String json = ApiDataUtils.toJSONString(msHTTPElement);
Assertions.assertNotNull(json);
Assertions.assertEquals(ApiDataUtils.parseObject(json, AbstractMsTestElement.class), msHTTPElement);
}
@Test
public void msAssertionTest() {
MsHTTPElement msHTTPElement = getMsHttpElement();
List assertions = new ArrayList<>();
ResponseCodeAssertion responseCodeAssertion = new ResponseCodeAssertion();
responseCodeAssertion.setCondition(MsAssertionCondition.EMPTY.name());
responseCodeAssertion.setValue("value");
responseCodeAssertion.setName("name");
assertions.add(responseCodeAssertion);
ResponseHeaderAssertion responseHeaderAssertion = new ResponseHeaderAssertion();
ResponseHeaderAssertion.ResponseHeaderAssertionItem responseHeaderAssertionItem = new ResponseHeaderAssertion.ResponseHeaderAssertionItem();
responseHeaderAssertionItem.setHeader("header");
responseHeaderAssertionItem.setValue("value");
responseHeaderAssertionItem.setCondition(MsAssertionCondition.EMPTY.name());
responseHeaderAssertion.setAssertions(List.of(responseHeaderAssertionItem));
assertions.add(responseHeaderAssertion);
ResponseBodyAssertion responseBodyAssertion = new ResponseBodyAssertion();
responseBodyAssertion.setAssertionType(MsBodyAssertionType.JSON_PATH.name());
RegexAssertion regexAssertion = new RegexAssertion();
regexAssertion.setAssertions(List.of(new RegexAssertionItem()));
responseBodyAssertion.setRegexAssertion(regexAssertion);
responseBodyAssertion.setDocumentAssertion(new DocumentAssertion());
responseBodyAssertion.setJsonPathAssertion(new JSONPathAssertion());
responseBodyAssertion.setXpathAssertion(new XPathAssertion());
assertions.add(responseBodyAssertion);
ResponseTimeAssertion responseTimeAssertion = new ResponseTimeAssertion();
responseTimeAssertion.setMaxResponseTime(1000L);
responseTimeAssertion.setEnable(true);
responseTimeAssertion.setName("aa");
assertions.add(responseTimeAssertion);
ScriptAssertion scriptAssertion = new ScriptAssertion();
scriptAssertion.setCommonScriptId("1111");
scriptAssertion.setContent("1111");
scriptAssertion.setDescription("1111");
scriptAssertion.setName("1111");
assertions.add(scriptAssertion);
MsAssertionConfig msAssertionConfig = new MsAssertionConfig();
msAssertionConfig.setEnableGlobal(false);
msAssertionConfig.setAssertions(assertions);
msHTTPElement.setAssertionConfig(msAssertionConfig);
String json = ApiDataUtils.toJSONString(msHTTPElement);
Assertions.assertNotNull(json);
Assertions.assertEquals(ApiDataUtils.parseObject(json, AbstractMsTestElement.class), msHTTPElement);

View File

@ -5,19 +5,19 @@ import io.metersphere.api.util.ApiDataUtils;
import io.metersphere.plugin.api.dto.TestElementDTO;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.plugin.api.spi.MsTestElement;
import io.metersphere.sdk.dto.api.request.http.MsHTTPElement;
import io.metersphere.sdk.dto.api.request.logic.controller.MsLoopController;
import io.metersphere.sdk.dto.api.request.post.processors.MsPostJSR223Processor;
import io.metersphere.sdk.dto.api.request.sampler.MsDebugSampler;
import io.metersphere.system.base.BaseApiPluginTestService;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ -33,34 +33,14 @@ public class PluginSubTypeTests {
@Test
@Order(0)
public void pluginSubTypeTest() throws Exception {
MsDebugSampler debugSampler = new MsDebugSampler();
debugSampler.setName("测试DebugSampler");
debugSampler.setUuid(IDGenerator.nextStr());
LinkedList<TestElementDTO> hashTree = new LinkedList<>();
hashTree.add(debugSampler);
MsPostJSR223Processor msjsr223Processor = new MsPostJSR223Processor();
msjsr223Processor.setName("测试jsr223");
msjsr223Processor.setJsrEnable(true);
msjsr223Processor.setChildren(hashTree);
String json = ApiDataUtils.toJSONString(msjsr223Processor);
Assertions.assertNotNull(json);
TestElementDTO testElementDTO = ApiDataUtils.parseObject(json, TestElementDTO.class);
Assertions.assertNotNull(testElementDTO);
}
@Test
@Order(1)
public void resolverTest() throws Exception {
// ApiDataUtils.setResolver(MsLoopController.class);
List<NamedType> namedTypes = new LinkedList<>();
namedTypes.add(new NamedType(MsLoopController.class, MsLoopController.class.getSimpleName()));
ApiDataUtils.setResolver(namedTypes);
}
@Test
@Order(2)
@Order(1)
public void newPluginSubTypeTest() throws Exception {
MsLoopController loopController = new MsLoopController();
loopController.setName("测试loopController");
@ -72,26 +52,7 @@ public class PluginSubTypeTests {
}
@Test
@Order(3)
public void retrySubTypeTest() throws Exception {
MsDebugSampler debugSampler = new MsDebugSampler();
debugSampler.setName("测试DebugSampler");
debugSampler.setUuid(IDGenerator.nextStr());
LinkedList<TestElementDTO> hashTree = new LinkedList<>();
hashTree.add(debugSampler);
MsPostJSR223Processor msjsr223Processor = new MsPostJSR223Processor();
msjsr223Processor.setName("测试jsr223");
msjsr223Processor.setJsrEnable(true);
msjsr223Processor.setChildren(hashTree);
String json = ApiDataUtils.toJSONString(msjsr223Processor);
Assertions.assertNotNull(json);
TestElementDTO testElementDTO = ApiDataUtils.parseObject(json, TestElementDTO.class);
Assertions.assertNotNull(testElementDTO);
}
@Test
@Order(4)
@Order(2)
public void jdbcPluginSubTypeTest() throws Exception {
// 上传 jdbc 插件
baseApiPluginTestService.addJdbcPlugin();
@ -110,4 +71,42 @@ public class PluginSubTypeTests {
AbstractMsTestElement testElementDTO = ApiDataUtils.parseObject(jdbcJson, AbstractMsTestElement.class);
Assertions.assertNotNull(testElementDTO);
}
@Test
@Order(3)
public void testApiDataUtils() throws Exception {
// 校验异常增加覆盖率
Assertions.assertTrue(isFuncSuccess((v) -> {
InputStream in = null;
ApiDataUtils.parseObject(in, AbstractMsTestElement.class);
}));
Assertions.assertTrue(isFuncSuccess((v) -> ApiDataUtils.parseObject("{")));
Assertions.assertTrue(isFuncSuccess((v) -> ApiDataUtils.parseArray(null, AbstractMsTestElement.class)));
ApiDataUtils.setResolver(MsHTTPElement.class);
// 检验 parseArray
String msHttpJson = """
[{
"polymorphicName": "MsHTTPElement",
"test": "测试MsHTTPElement"
}]
""";
ApiDataUtils.parseArray(msHttpJson, AbstractMsTestElement.class);
}
/**
* 判断函数是否抛出异常
*
* @param func
* @return
* @throws Exception
*/
public boolean isFuncSuccess(Consumer func) {
try {
func.accept("");
} catch (Exception e) {
return true;
}
return false;
}
}