feat(接口测试): 接口调试执行示例
This commit is contained in:
parent
4e4f17f195
commit
d8e0fd0bc7
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere;
|
package io.metersphere;
|
||||||
|
|
||||||
|
import io.metersphere.api.config.JmeterProperties;
|
||||||
import io.metersphere.system.config.MinioProperties;
|
import io.metersphere.system.config.MinioProperties;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
@ -21,7 +22,8 @@ import org.springframework.context.annotation.PropertySource;
|
||||||
}, encoding = "UTF-8", ignoreResourceNotFound = true)
|
}, encoding = "UTF-8", ignoreResourceNotFound = true)
|
||||||
@ServletComponentScan
|
@ServletComponentScan
|
||||||
@EnableConfigurationProperties({
|
@EnableConfigurationProperties({
|
||||||
MinioProperties.class
|
MinioProperties.class,
|
||||||
|
JmeterProperties.class
|
||||||
})
|
})
|
||||||
public class Application {
|
public class Application {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -2,9 +2,9 @@ package io.metersphere.listener;
|
||||||
|
|
||||||
import io.metersphere.api.event.ApiEventSource;
|
import io.metersphere.api.event.ApiEventSource;
|
||||||
import io.metersphere.plan.listener.ExecEventListener;
|
import io.metersphere.plan.listener.ExecEventListener;
|
||||||
import io.metersphere.system.service.PluginLoadService;
|
|
||||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
|
import io.metersphere.system.service.PluginLoadService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package io.metersphere.plugin.api.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-27 17:30
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ParameterConfig {
|
||||||
|
private String reportId;
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package io.metersphere.plugin.api.spi;
|
package io.metersphere.plugin.api.spi;
|
||||||
|
|
||||||
|
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
import org.apache.jorphan.collections.HashTree;
|
import org.apache.jorphan.collections.HashTree;
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.HashMap;
|
import java.util.function.Function;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jianxing
|
* @author jianxing
|
||||||
|
@ -15,44 +15,39 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJmeterElementConverter<T extends MsTestElement> {
|
public abstract class AbstractJmeterElementConverter<T extends MsTestElement> {
|
||||||
|
|
||||||
|
public Class<? extends MsTestElement> testElementClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析器集合
|
* 获取转换器的函数
|
||||||
* key 为 MsTestElement 实现类的 Class
|
* 主应用在实例化转换器的时候会设置
|
||||||
* value 为对应的转换器
|
|
||||||
*/
|
*/
|
||||||
private static final Map<MsTestElement, AbstractJmeterElementConverter<?>> parserMap = new HashMap<>();
|
private Function<Class<? extends MsTestElement>, AbstractJmeterElementConverter> getConverterFunc;
|
||||||
|
|
||||||
|
public void setGetConverterFunc(Function<Class<? extends MsTestElement>, AbstractJmeterElementConverter> getConverterFunc) {
|
||||||
|
this.getConverterFunc = getConverterFunc;
|
||||||
|
}
|
||||||
|
|
||||||
public AbstractJmeterElementConverter() {
|
public AbstractJmeterElementConverter() {
|
||||||
Type genericSuperclass = getClass().getGenericSuperclass();
|
Type genericSuperclass = getClass().getGenericSuperclass();
|
||||||
if (genericSuperclass instanceof ParameterizedType parameterizedType) {
|
if (genericSuperclass instanceof ParameterizedType parameterizedType) {
|
||||||
// 获取泛型的具体类型,即 MsTestElement 的具体实现类
|
// 获取泛型的具体类型,即 MsTestElement 的具体实现类
|
||||||
MsTestElement baseClass = (MsTestElement) parameterizedType.getActualTypeArguments()[0];
|
testElementClass = ((Class) parameterizedType.getActualTypeArguments()[0]);
|
||||||
// 注册到解析器集合中
|
|
||||||
parserMap.put(baseClass, this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 MsTestElement 具体实现类转换为 HashTree
|
* 将 MsTestElement 具体实现类转换为 HashTree
|
||||||
*/
|
*/
|
||||||
public abstract void toHashTree(HashTree tree, T element, MsParameter config);
|
public abstract void toHashTree(HashTree tree, T element, ParameterConfig config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 MsTestElement 的子节点
|
* 解析 MsTestElement 的子节点
|
||||||
*/
|
*/
|
||||||
public void parseChild(HashTree tree, AbstractMsTestElement element, MsParameter config) {
|
public void parseChild(HashTree tree, AbstractMsTestElement element, ParameterConfig config) {
|
||||||
if (element != null && element.getChildren() != null) {
|
if (element != null && element.getChildren() != null) {
|
||||||
element.getChildren().forEach(child -> {
|
element.getChildren().forEach(child ->
|
||||||
getConverter(child).toHashTree(tree, element, config);
|
getConverterFunc.apply(child.getClass())
|
||||||
});
|
.toHashTree(tree, element, config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对应组件的转换器
|
|
||||||
*/
|
|
||||||
public static AbstractJmeterElementConverter getConverter(MsTestElement element) {
|
|
||||||
return parserMap.get(element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package io.metersphere.plugin.api.spi;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: jianxing
|
|
||||||
* @CreateTime: 2023-10-27 17:30
|
|
||||||
*/
|
|
||||||
public class MsParameter {
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package io.metersphere.sdk.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口执行时的资源类型
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-12-08 10:53
|
||||||
|
*/
|
||||||
|
public enum ApiExecuteResourceType {
|
||||||
|
API_DEBUG, API, API_CASE, API_SCENARIO
|
||||||
|
// todo plan api
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package io.metersphere.sdk.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口执行时的资源类型
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-12-08 10:53
|
||||||
|
*/
|
||||||
|
public enum ApiExecuteRunMode {
|
||||||
|
/**
|
||||||
|
* 手动运行
|
||||||
|
*/
|
||||||
|
RUN,
|
||||||
|
/**
|
||||||
|
* 调试
|
||||||
|
*/
|
||||||
|
DEBUG,
|
||||||
|
/**
|
||||||
|
* jenkins 触发
|
||||||
|
*/
|
||||||
|
JENKINS,
|
||||||
|
/**
|
||||||
|
* 定时任务
|
||||||
|
*/
|
||||||
|
SCENARIO
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.api.enums;
|
package io.metersphere.sdk.constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: LAN
|
* @author: LAN
|
|
@ -1,10 +0,0 @@
|
||||||
package io.metersphere.sdk.dto.api.request;
|
|
||||||
|
|
||||||
import io.metersphere.plugin.api.spi.MsParameter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: jianxing
|
|
||||||
* @CreateTime: 2023-10-27 17:30
|
|
||||||
*/
|
|
||||||
public class ParameterConfig extends MsParameter {
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package io.metersphere.sdk.dto.api.request.sampler;
|
|
||||||
|
|
||||||
import io.metersphere.plugin.api.annotation.PluginSubType;
|
|
||||||
import io.metersphere.plugin.api.dto.TestElementDTO;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.jmeter.sampler.DebugSampler;
|
|
||||||
import org.apache.jmeter.save.SaveService;
|
|
||||||
import org.apache.jmeter.testelement.TestElement;
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@PluginSubType("MsDebugSampler")
|
|
||||||
public class MsDebugSampler extends TestElementDTO {
|
|
||||||
private boolean displayJMeterProperties = false;
|
|
||||||
private boolean displayJMeterVariables = true;
|
|
||||||
private boolean displaySystemProperties = false;
|
|
||||||
|
|
||||||
|
|
||||||
private DebugSampler debugSampler() {
|
|
||||||
DebugSampler debugSampler = new DebugSampler();
|
|
||||||
debugSampler.setEnabled(this.isEnable());
|
|
||||||
if (StringUtils.isEmpty(this.getName())) {
|
|
||||||
this.setName(MsDebugSampler.class.getSimpleName());
|
|
||||||
}
|
|
||||||
debugSampler.setName(this.getName());
|
|
||||||
debugSampler.setProperty(TestElement.TEST_CLASS, DebugSampler.class.getName());
|
|
||||||
debugSampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
|
||||||
|
|
||||||
debugSampler.setDisplaySystemProperties(this.displaySystemProperties);
|
|
||||||
debugSampler.setDisplayJMeterVariables(this.displayJMeterVariables);
|
|
||||||
debugSampler.setDisplayJMeterProperties(this.displayJMeterProperties);
|
|
||||||
|
|
||||||
//上面三行直接Set属性会导致DebugSampler构建时取不到值,可能是JMeter的Bug,需要SetProperty
|
|
||||||
debugSampler.setProperty("displayJMeterProperties", this.displayJMeterProperties);
|
|
||||||
debugSampler.setProperty("displayJMeterVariables", this.displayJMeterVariables);
|
|
||||||
debugSampler.setProperty("displaySystemProperties", this.displaySystemProperties);
|
|
||||||
return debugSampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package io.metersphere.sdk.dto.api.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MsRegexDTO {
|
||||||
|
private String subject;
|
||||||
|
private String condition;
|
||||||
|
private String value;
|
||||||
|
private String errorCode;
|
||||||
|
private boolean pass;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package io.metersphere.sdk.dto.api.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际请求详情
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RequestResult {
|
||||||
|
// 请求ID
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
// 步骤请求唯一ID
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
private String threadName;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
private long requestSize;
|
||||||
|
|
||||||
|
private long startTime;
|
||||||
|
|
||||||
|
private long endTime;
|
||||||
|
|
||||||
|
private int error;
|
||||||
|
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
private String headers;
|
||||||
|
|
||||||
|
private String cookies;
|
||||||
|
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private int totalAssertionCount = 0;
|
||||||
|
|
||||||
|
private int passAssertionsCount= 0;
|
||||||
|
|
||||||
|
private List<RequestResult> subRequestResults = new ArrayList<>();
|
||||||
|
|
||||||
|
private ResponseResult responseResult = new ResponseResult();
|
||||||
|
|
||||||
|
public void increasePassAssertionCount() {
|
||||||
|
this.passAssertionsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fakeErrorMessage;
|
||||||
|
// 误报编码名称
|
||||||
|
private String fakeErrorCode;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.metersphere.sdk.dto.api.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断言结果
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ResponseAssertionResult {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private String script;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private boolean pass;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package io.metersphere.sdk.dto.api.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应结果
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ResponseResult {
|
||||||
|
|
||||||
|
private String responseCode;
|
||||||
|
|
||||||
|
private String responseMessage;
|
||||||
|
|
||||||
|
private long responseTime;
|
||||||
|
|
||||||
|
private long latency;
|
||||||
|
|
||||||
|
private long responseSize;
|
||||||
|
|
||||||
|
private String headers;
|
||||||
|
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
private String vars;
|
||||||
|
|
||||||
|
private String console;
|
||||||
|
|
||||||
|
private String contentType;
|
||||||
|
|
||||||
|
private byte[] imageUrl;
|
||||||
|
|
||||||
|
private final List<ResponseAssertionResult> assertions = new ArrayList<>();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package io.metersphere.sdk.dto.api.result;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TaskResult implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
// TODO: 补充任务执行结果数据结构
|
||||||
|
|
||||||
|
private List<RequestResult> requestResults;
|
||||||
|
private String runMode;
|
||||||
|
private String queueId;
|
||||||
|
private String reportId;
|
||||||
|
private String reportType;
|
||||||
|
private String testPlanReportId;
|
||||||
|
private String testId;
|
||||||
|
private String runType;
|
||||||
|
private String console;
|
||||||
|
private String runningDebugSampler;
|
||||||
|
private Boolean hasEnded;
|
||||||
|
private boolean retryEnable;
|
||||||
|
private Map<String, Object> arbitraryData;
|
||||||
|
Map<String, List<MsRegexDTO>> fakeErrorMap;
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
package io.metersphere.sdk.dto.api.task;
|
package io.metersphere.sdk.dto.api.task;
|
||||||
|
|
||||||
import io.metersphere.sdk.exception.MSException;
|
|
||||||
import io.metersphere.sdk.util.JSON;
|
|
||||||
import io.metersphere.sdk.util.RsaUtils;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务请求参数数据
|
* 任务请求参数数据
|
||||||
|
@ -24,27 +19,28 @@ public class TaskRequest implements Serializable {
|
||||||
private String kafkaConfig;
|
private String kafkaConfig;
|
||||||
private String minioConfig;
|
private String minioConfig;
|
||||||
private String poolId;
|
private String poolId;
|
||||||
|
/**
|
||||||
|
* 是否需要实时接收单个步骤的结果
|
||||||
|
*/
|
||||||
|
private Boolean realTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行的资源ID
|
||||||
|
*/
|
||||||
|
private String testId;
|
||||||
|
/**
|
||||||
|
* 点击调试时,尚未保存的文件ID列表
|
||||||
|
*/
|
||||||
|
private List<String> tempFileIds;
|
||||||
|
/**
|
||||||
|
* 执行模式
|
||||||
|
*/
|
||||||
|
private String runMode;
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
|
||||||
// TODO 其它执行参数
|
// TODO 其它执行参数
|
||||||
|
|
||||||
// 默认声明对象时获取配置参数
|
|
||||||
public void setKafkaConfig(Map<String, String> kafkaConfig) {
|
|
||||||
if (MapUtils.isNotEmpty(kafkaConfig)) {
|
|
||||||
try {
|
|
||||||
this.kafkaConfig = RsaUtils.publicEncrypt(JSON.toJSONString(kafkaConfig), this.getReportId());
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new MSException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinioConfig(Map<String, String> minioConfig) {
|
|
||||||
if (MapUtils.isNotEmpty(minioConfig)) {
|
|
||||||
try {
|
|
||||||
this.minioConfig = RsaUtils.publicEncrypt(JSON.toJSONString(minioConfig), this.getReportId());
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new MSException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package io.metersphere.sdk.dto.api.task;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class TaskResult implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
// TODO: 补充任务执行结果数据结构
|
|
||||||
}
|
|
|
@ -6,11 +6,13 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Component
|
||||||
public class CommonBeanFactory implements ApplicationContextAware {
|
public class CommonBeanFactory implements ApplicationContextAware {
|
||||||
private static ApplicationContext context;
|
private static ApplicationContext context;
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,14 @@ public class EncryptUtils extends CodingUtils {
|
||||||
private static final String iv = "1234567890123456";
|
private static final String iv = "1234567890123456";
|
||||||
|
|
||||||
|
|
||||||
public static Object aesEncrypt(Object o) {
|
public static String aesEncrypt(Object o) {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return aesEncrypt(o.toString(), secretKey, iv);
|
return aesEncrypt(o.toString(), secretKey, iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object aesDecrypt(Object o) {
|
public static String aesDecrypt(Object o) {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public class EncryptUtils extends CodingUtils {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object md5Encrypt(Object o) {
|
public static String md5Encrypt(Object o) {
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,9 @@ public class FilterChainUtils {
|
||||||
//用户通过邮箱邀请自行注册的接口
|
//用户通过邮箱邀请自行注册的接口
|
||||||
filterChainDefinitionMap.put("/system/user/register-by-invite", "anon");
|
filterChainDefinitionMap.put("/system/user/register-by-invite", "anon");
|
||||||
|
|
||||||
|
// 下载测试资源
|
||||||
|
filterChainDefinitionMap.put("/api/execute/resource/**", "anon");
|
||||||
|
|
||||||
|
|
||||||
// for swagger
|
// for swagger
|
||||||
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
||||||
|
|
|
@ -296,3 +296,6 @@ api_debug_exist=接口已存在
|
||||||
follow=关注
|
follow=关注
|
||||||
unfollow=取消关注
|
unfollow=取消关注
|
||||||
api_definition_exist=接口已存在
|
api_definition_exist=接口已存在
|
||||||
|
|
||||||
|
execute_resource_pool_not_config_error=请在【项目管理-应用管理-接口测试】中选择资源池
|
||||||
|
resource_pool_execute_error=资源池调用失败
|
||||||
|
|
|
@ -304,3 +304,5 @@ api_debug_exist=The API already exists
|
||||||
follow=Follow
|
follow=Follow
|
||||||
unfollow=Unfollow
|
unfollow=Unfollow
|
||||||
api_definition_exist=The API already exists
|
api_definition_exist=The API already exists
|
||||||
|
execute_resource_pool_not_config_error=Select a resource pool in 【Project Management - Application Management - Interface Testing】
|
||||||
|
resource_pool_execute_error=The resource pool call failed
|
||||||
|
|
|
@ -304,3 +304,5 @@ api_debug_exist=接口已存在
|
||||||
follow=关注
|
follow=关注
|
||||||
unfollow=取消关注
|
unfollow=取消关注
|
||||||
api_definition_exist=接口已存在
|
api_definition_exist=接口已存在
|
||||||
|
execute_resource_pool_not_config_error=请在【项目管理-应用管理-接口测试】中选择资源池
|
||||||
|
resource_pool_execute_error=资源池调用失败
|
||||||
|
|
|
@ -304,3 +304,5 @@ api_debug_exist=接口已存在
|
||||||
follow=关注
|
follow=关注
|
||||||
unfollow=取消关注
|
unfollow=取消关注
|
||||||
api_definition_exist=接口已存在
|
api_definition_exist=接口已存在
|
||||||
|
execute_resource_pool_not_config_error=請在【項目管理-應用管理-接口測試】中選擇資源池
|
||||||
|
resource_pool_execute_error=資源池調用失敗
|
||||||
|
|
|
@ -47,6 +47,11 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.jmeter</groupId>
|
||||||
|
<artifactId>ApacheJMeter_http</artifactId>
|
||||||
|
<version>${jmeter.version}</version>
|
||||||
|
</dependency>
|
||||||
<!-- swagger 解析 -->
|
<!-- swagger 解析 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.swagger.parser.v3</groupId>
|
<groupId>io.swagger.parser.v3</groupId>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package io.metersphere.api.config;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@ConfigurationProperties(prefix = JmeterProperties.JMETER_PREFIX)
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class JmeterProperties {
|
||||||
|
|
||||||
|
public static final String JMETER_PREFIX = "jmeter";
|
||||||
|
private String home;
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.api.enums;
|
package io.metersphere.api.constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author: LAN
|
* @author: LAN
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.api.enums;
|
package io.metersphere.api.constants;
|
||||||
|
|
||||||
public enum ApiImportPlatform {
|
public enum ApiImportPlatform {
|
||||||
MeterSphere, Postman, Swagger3, Plugin, Jmeter, Har
|
MeterSphere, Postman, Swagger3, Plugin, Jmeter, Har
|
|
@ -0,0 +1,42 @@
|
||||||
|
package io.metersphere.api.controller;
|
||||||
|
|
||||||
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-12-05 17:52
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/execute/resource")
|
||||||
|
public class ApiExecuteResourceController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
@Resource
|
||||||
|
private ApiExecuteService apiExecuteService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取执行脚本
|
||||||
|
* @param reportId
|
||||||
|
* @param testId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@GetMapping("script")
|
||||||
|
public String getScript(@RequestParam("reportId") String reportId, @RequestParam("testId") String testId) {
|
||||||
|
String key = apiExecuteService.getScriptRedisKey(reportId, testId);
|
||||||
|
LogUtils.info("获取执行脚本: ", key);
|
||||||
|
String script = stringRedisTemplate.opsForValue().get(key);
|
||||||
|
stringRedisTemplate.delete(key);
|
||||||
|
return Optional.ofNullable(script).orElse(StringUtils.EMPTY);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
package io.metersphere.api.controller.debug;
|
package io.metersphere.api.controller.debug;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiDebug;
|
import io.metersphere.api.domain.ApiDebug;
|
||||||
import io.metersphere.api.dto.debug.ApiDebugAddRequest;
|
import io.metersphere.api.dto.debug.*;
|
||||||
import io.metersphere.api.dto.debug.ApiDebugDTO;
|
|
||||||
import io.metersphere.api.dto.debug.ApiDebugSimpleDTO;
|
|
||||||
import io.metersphere.api.dto.debug.ApiDebugUpdateRequest;
|
|
||||||
import io.metersphere.api.service.debug.ApiDebugLogService;
|
import io.metersphere.api.service.debug.ApiDebugLogService;
|
||||||
import io.metersphere.api.service.debug.ApiDebugService;
|
import io.metersphere.api.service.debug.ApiDebugService;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
|
@ -78,4 +75,11 @@ public class ApiDebugController {
|
||||||
public void delete(@PathVariable String id) {
|
public void delete(@PathVariable String id) {
|
||||||
apiDebugService.delete(id, SessionUtils.getUserId());
|
apiDebugService.delete(id, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/debug")
|
||||||
|
@Operation(summary = "运行接口调试")
|
||||||
|
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_EXECUTE)
|
||||||
|
public String debug(@Validated @RequestBody ApiDebugRunRequest request) {
|
||||||
|
return apiDebugService.debug(request);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,9 @@ public enum ApiResultCode implements IResultCode {
|
||||||
API_DEBUG_EXIST(104001, "api_debug_exist"),
|
API_DEBUG_EXIST(104001, "api_debug_exist"),
|
||||||
API_DEFINITION_EXIST(104002, "api_definition_exist"),
|
API_DEFINITION_EXIST(104002, "api_definition_exist"),
|
||||||
API_DEFINITION_NOT_EXIST(104003, "resource_not_exist"),
|
API_DEFINITION_NOT_EXIST(104003, "resource_not_exist"),
|
||||||
API_DEFINITION_MODULE_NOT_EXIST(10404, "resource_not_exist");
|
API_DEFINITION_MODULE_NOT_EXIST(10404, "resource_not_exist"),
|
||||||
|
RESOURCE_POOL_EXECUTE_ERROR(104005, "resource_pool_execute_error"),
|
||||||
|
EXECUTE_RESOURCE_POOL_NOT_CONFIG(104006, "execute_resource_pool_not_config_error");
|
||||||
|
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package io.metersphere.api.dto.debug;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ApiDebugRunRequest {
|
||||||
|
private String id;
|
||||||
|
private String environmentId;
|
||||||
|
|
||||||
|
@Schema(description = "点击调试时尚未保存的文件ID列表")
|
||||||
|
private List<String> tempFileIds;
|
||||||
|
|
||||||
|
private String request;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package io.metersphere.api.dto.debug;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ApiResourceRunRequest {
|
||||||
|
private String id;
|
||||||
|
private String projectId;
|
||||||
|
private String testId;
|
||||||
|
private String reportId;
|
||||||
|
private String environmentId;
|
||||||
|
/**
|
||||||
|
* 执行模式
|
||||||
|
*/
|
||||||
|
private String runMode;
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
private String resourceType;
|
||||||
|
@Schema(description = "点击调试时尚未保存的文件ID列表")
|
||||||
|
private List<String> tempFileIds;
|
||||||
|
private String request;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.api.dto.definition;
|
package io.metersphere.api.dto.definition;
|
||||||
|
|
||||||
import io.metersphere.sdk.dto.api.request.http.Header;
|
import io.metersphere.api.dto.request.http.Header;
|
||||||
import io.metersphere.sdk.dto.api.request.http.body.Body;
|
import io.metersphere.api.dto.request.http.body.Body;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request;
|
package io.metersphere.api.dto.request;
|
||||||
|
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,10 +0,0 @@
|
||||||
package io.metersphere.api.dto.request;
|
|
||||||
|
|
||||||
import io.metersphere.plugin.api.spi.MsParameter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: jianxing
|
|
||||||
* @CreateTime: 2023-10-27 17:30
|
|
||||||
*/
|
|
||||||
public class ParameterConfig extends MsParameter {
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* body断言中的断言类型
|
* body断言中的断言类型
|
|
@ -1,10 +1,10 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.metersphere.sdk.dto.api.request.assertion.body.DocumentAssertion;
|
import io.metersphere.api.dto.request.assertion.body.DocumentAssertion;
|
||||||
import io.metersphere.sdk.dto.api.request.assertion.body.JSONPathAssertion;
|
import io.metersphere.api.dto.request.assertion.body.JSONPathAssertion;
|
||||||
import io.metersphere.sdk.dto.api.request.assertion.body.RegexAssertion;
|
import io.metersphere.api.dto.request.assertion.body.RegexAssertion;
|
||||||
import io.metersphere.sdk.dto.api.request.assertion.body.XPathAssertion;
|
import io.metersphere.api.dto.request.assertion.body.XPathAssertion;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion;
|
package io.metersphere.api.dto.request.assertion;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.assertion.body;
|
package io.metersphere.api.dto.request.assertion.body;
|
||||||
|
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.logic.controller;
|
package io.metersphere.api.dto.request.controller;
|
||||||
|
|
||||||
import io.metersphere.plugin.api.annotation.PluginSubType;
|
import io.metersphere.plugin.api.annotation.PluginSubType;
|
||||||
import io.metersphere.plugin.api.dto.TestElementDTO;
|
import io.metersphere.plugin.api.dto.TestElementDTO;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.sdk.dto.api.request.assertion.MsAssertionConfig;
|
import io.metersphere.api.dto.request.assertion.MsAssertionConfig;
|
||||||
import io.metersphere.sdk.dto.api.request.http.auth.HTTPAuth;
|
import io.metersphere.api.dto.request.http.auth.HTTPAuth;
|
||||||
import io.metersphere.sdk.dto.api.request.http.body.Body;
|
import io.metersphere.api.dto.request.http.body.Body;
|
||||||
import io.metersphere.sdk.dto.api.request.processors.MsProcessorConfig;
|
import io.metersphere.api.dto.request.processors.MsProcessorConfig;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http;
|
package io.metersphere.api.dto.request.http;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.auth;
|
package io.metersphere.api.dto.request.http.auth;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.auth;
|
package io.metersphere.api.dto.request.http.auth;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.auth;
|
package io.metersphere.api.dto.request.http.auth;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.auth;
|
package io.metersphere.api.dto.request.http.auth;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import io.metersphere.sdk.dto.api.request.http.KeyValueEnableParam;
|
import io.metersphere.api.dto.request.http.KeyValueEnableParam;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.http.body;
|
package io.metersphere.api.dto.request.http.body;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.metersphere.sdk.dto.api.request.http.KeyValueParam;
|
import io.metersphere.api.dto.request.http.KeyValueParam;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.metersphere.sdk.dto.api.request.processors.extract.MsExtract;
|
import io.metersphere.api.dto.request.processors.extract.MsExtract;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.metersphere.sdk.dto.api.request.http.KeyValueEnableParam;
|
import io.metersphere.api.dto.request.http.KeyValueEnableParam;
|
||||||
import io.metersphere.sdk.dto.api.request.http.KeyValueParam;
|
import io.metersphere.api.dto.request.http.KeyValueParam;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors;
|
package io.metersphere.api.dto.request.processors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors.extract;
|
package io.metersphere.api.dto.request.processors.extract;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors.extract;
|
package io.metersphere.api.dto.request.processors.extract;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors.extract;
|
package io.metersphere.api.dto.request.processors.extract;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors.extract;
|
package io.metersphere.api.dto.request.processors.extract;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.dto.api.request.processors.extract;
|
package io.metersphere.api.dto.request.processors.extract;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
|
@ -1,6 +1,6 @@
|
||||||
package io.metersphere.api.parser;
|
package io.metersphere.api.parser;
|
||||||
|
|
||||||
import io.metersphere.api.enums.ApiImportPlatform;
|
import io.metersphere.api.constants.ApiImportPlatform;
|
||||||
import io.metersphere.api.parser.api.PostmanParser;
|
import io.metersphere.api.parser.api.PostmanParser;
|
||||||
import io.metersphere.api.parser.api.Swagger3Parser;
|
import io.metersphere.api.parser.api.Swagger3Parser;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.metersphere.api.parser;
|
||||||
|
|
||||||
|
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-27 10:07
|
||||||
|
*
|
||||||
|
* 执行对象解析器
|
||||||
|
*/
|
||||||
|
public interface TestElementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 MsTestElement 转换为对应执行引擎的执行对象
|
||||||
|
* @param msTestElement
|
||||||
|
* @param config
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String parse(AbstractMsTestElement msTestElement, ParameterConfig config);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.metersphere.api.parser;
|
||||||
|
|
||||||
|
import io.metersphere.api.parser.jmeter.JmeterTestElementParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-30 10:59
|
||||||
|
* 解析器工厂
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestElementParserFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认解析器
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static TestElementParser getDefaultParser() {
|
||||||
|
return new JmeterTestElementParser();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package io.metersphere.api.parser.jmeter;
|
||||||
|
|
||||||
|
import io.metersphere.api.parser.TestElementParser;
|
||||||
|
import io.metersphere.api.utils.JmeterElementConverterRegister;
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
|
import org.apache.jmeter.config.Arguments;
|
||||||
|
import org.apache.jmeter.control.LoopController;
|
||||||
|
import org.apache.jmeter.sampler.DebugSampler;
|
||||||
|
import org.apache.jmeter.save.SaveService;
|
||||||
|
import org.apache.jmeter.testelement.TestElement;
|
||||||
|
import org.apache.jmeter.testelement.TestPlan;
|
||||||
|
import org.apache.jmeter.threads.ThreadGroup;
|
||||||
|
import org.apache.jorphan.collections.HashTree;
|
||||||
|
import org.apache.jorphan.collections.ListedHashTree;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-27 10:07
|
||||||
|
* <p>
|
||||||
|
* 将 Ms 的组件转换为 jmx 脚本
|
||||||
|
*/
|
||||||
|
public class JmeterTestElementParser implements TestElementParser {
|
||||||
|
|
||||||
|
private Boolean onSampleError;
|
||||||
|
private String name;
|
||||||
|
private Boolean enable = true;
|
||||||
|
private ParameterConfig config;
|
||||||
|
private boolean displayJMeterProperties = false;
|
||||||
|
|
||||||
|
private boolean displayJMeterVariables = true;
|
||||||
|
|
||||||
|
private boolean displaySystemProperties = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String parse(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
HashTree hashTree = new ListedHashTree();
|
||||||
|
TestPlan testPlan = getPlan();
|
||||||
|
name = msTestElement.getName();
|
||||||
|
enable = msTestElement.getEnable();
|
||||||
|
final HashTree testPlanTree = hashTree.add(testPlan);
|
||||||
|
final HashTree groupTree = testPlanTree.add(getThreadGroup());
|
||||||
|
// 添加 debugSampler
|
||||||
|
groupTree.add(getDebugSampler());
|
||||||
|
|
||||||
|
// 解析 msTestElement
|
||||||
|
JmeterElementConverterRegister.getConverter(msTestElement.getClass())
|
||||||
|
.toHashTree(groupTree, msTestElement, config);
|
||||||
|
|
||||||
|
return getJmx(hashTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJmx(HashTree hashTree) {
|
||||||
|
try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) {
|
||||||
|
SaveService.saveTree(hashTree, bas);
|
||||||
|
return bas.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(e);
|
||||||
|
throw new MSException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestPlan getPlan() {
|
||||||
|
TestPlan testPlan = new TestPlan(name);
|
||||||
|
testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
|
||||||
|
testPlan.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestPlanGui"));
|
||||||
|
testPlan.setEnabled(true);
|
||||||
|
testPlan.setFunctionalMode(false);
|
||||||
|
testPlan.setSerialized(false);
|
||||||
|
testPlan.setTearDownOnShutdown(true);
|
||||||
|
testPlan.setUserDefinedVariables(new Arguments());
|
||||||
|
return testPlan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadGroup getThreadGroup() {
|
||||||
|
LoopController loopController = new LoopController();
|
||||||
|
loopController.setName("LoopController");
|
||||||
|
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
|
||||||
|
loopController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("LoopControlPanel"));
|
||||||
|
loopController.setEnabled(this.enable);
|
||||||
|
loopController.setLoops(1);
|
||||||
|
|
||||||
|
ThreadGroup threadGroup = new ThreadGroup();
|
||||||
|
threadGroup.setEnabled(this.enable);
|
||||||
|
threadGroup.setName(config.getReportId());
|
||||||
|
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
|
||||||
|
threadGroup.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ThreadGroupGui"));
|
||||||
|
threadGroup.setNumThreads(1);
|
||||||
|
threadGroup.setRampUp(1);
|
||||||
|
threadGroup.setDelay(0);
|
||||||
|
threadGroup.setDuration(0);
|
||||||
|
threadGroup.setProperty(ThreadGroup.ON_SAMPLE_ERROR, ThreadGroup.ON_SAMPLE_ERROR_CONTINUE);
|
||||||
|
threadGroup.setScheduler(false);
|
||||||
|
if (onSampleError != null && !onSampleError) {
|
||||||
|
threadGroup.setProperty("ThreadGroup.on_sample_error", "stopthread");
|
||||||
|
}
|
||||||
|
threadGroup.setSamplerController(loopController);
|
||||||
|
return threadGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DebugSampler getDebugSampler() {
|
||||||
|
DebugSampler debugSampler = new DebugSampler();
|
||||||
|
debugSampler.setEnabled(true);
|
||||||
|
debugSampler.setName("DebugSampler");
|
||||||
|
debugSampler.setProperty(TestElement.TEST_CLASS, DebugSampler.class.getName());
|
||||||
|
debugSampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||||
|
|
||||||
|
debugSampler.setDisplaySystemProperties(this.displaySystemProperties);
|
||||||
|
debugSampler.setDisplayJMeterVariables(this.displayJMeterVariables);
|
||||||
|
debugSampler.setDisplayJMeterProperties(this.displayJMeterProperties);
|
||||||
|
|
||||||
|
// 上面三行直接Set属性会导致DebugSampler构建时取不到值,可能是JMeter的Bug,需要SetProperty
|
||||||
|
debugSampler.setProperty("displayJMeterProperties", this.displayJMeterProperties);
|
||||||
|
debugSampler.setProperty("displayJMeterVariables", this.displayJMeterVariables);
|
||||||
|
debugSampler.setProperty("displaySystemProperties", this.displaySystemProperties);
|
||||||
|
return debugSampler;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package io.metersphere.api.parser.jmeter;
|
||||||
|
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
|
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
|
||||||
|
import org.apache.jmeter.save.SaveService;
|
||||||
|
import org.apache.jmeter.testelement.TestElement;
|
||||||
|
import org.apache.jorphan.collections.HashTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-27 10:07
|
||||||
|
*
|
||||||
|
* 脚本解析器
|
||||||
|
*/
|
||||||
|
public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTTPElement> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toHashTree(HashTree tree, MsHTTPElement msHTTPElement, ParameterConfig msParameter) {
|
||||||
|
ParameterConfig config = msParameter;
|
||||||
|
|
||||||
|
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
|
||||||
|
sampler.setName(msHTTPElement.getName());
|
||||||
|
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
|
||||||
|
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
|
||||||
|
|
||||||
|
HashTree httpTree = tree.add(sampler);
|
||||||
|
parseChild(httpTree, msHTTPElement, config);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package io.metersphere.api.parser.jmeter;
|
||||||
|
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.request.MsScenario;
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
|
import org.apache.jorphan.collections.HashTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2023-10-27 10:07
|
||||||
|
*
|
||||||
|
* 脚本解析器
|
||||||
|
*/
|
||||||
|
public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenario> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toHashTree(HashTree tree, MsScenario msScenario, ParameterConfig msParameter) {
|
||||||
|
ParameterConfig config = msParameter;
|
||||||
|
|
||||||
|
parseChild(tree, msScenario, config);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
package io.metersphere.api.service;
|
||||||
|
|
||||||
|
import io.metersphere.api.config.JmeterProperties;
|
||||||
|
import io.metersphere.api.config.KafkaConfig;
|
||||||
|
import io.metersphere.api.controller.result.ApiResultCode;
|
||||||
|
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||||
|
import io.metersphere.api.parser.TestElementParser;
|
||||||
|
import io.metersphere.api.parser.TestElementParserFactory;
|
||||||
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||||
|
import io.metersphere.project.domain.ProjectApplication;
|
||||||
|
import io.metersphere.project.service.ProjectApplicationService;
|
||||||
|
import io.metersphere.sdk.constants.ProjectApplicationType;
|
||||||
|
import io.metersphere.sdk.dto.api.task.TaskRequest;
|
||||||
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.*;
|
||||||
|
import io.metersphere.system.config.MinioProperties;
|
||||||
|
import io.metersphere.system.domain.TestResourcePool;
|
||||||
|
import io.metersphere.system.dto.pool.TestResourceDTO;
|
||||||
|
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
|
||||||
|
import io.metersphere.system.service.CommonProjectService;
|
||||||
|
import io.metersphere.system.service.SystemParameterService;
|
||||||
|
import io.metersphere.system.service.TestResourcePoolService;
|
||||||
|
import io.metersphere.system.utils.TaskRunnerClient;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.jmeter.util.JMeterUtils;
|
||||||
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static io.metersphere.api.controller.result.ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jianxing
|
||||||
|
* @date : 2023-11-6
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class ApiExecuteService {
|
||||||
|
@Resource
|
||||||
|
private ProjectApplicationService projectApplicationService;
|
||||||
|
@Resource
|
||||||
|
private TestResourcePoolService testResourcePoolService;
|
||||||
|
@Resource
|
||||||
|
private CommonProjectService commonProjectService;
|
||||||
|
@Resource
|
||||||
|
private SystemParameterService systemParameterService;
|
||||||
|
@Resource
|
||||||
|
private StringRedisTemplate stringRedisTemplate;
|
||||||
|
@Resource
|
||||||
|
private JmeterProperties jmeterProperties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
String jmeterHome = getJmeterHome();
|
||||||
|
JMeterUtils.loadJMeterProperties(jmeterHome + "/bin/jmeter.properties");
|
||||||
|
JMeterUtils.setJMeterHome(jmeterHome);
|
||||||
|
JMeterUtils.setLocale(LocaleContextHolder.getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJmeterHome() {
|
||||||
|
String home = getClass().getResource("/").getPath() + "jmeter";
|
||||||
|
try {
|
||||||
|
File file = new File(home);
|
||||||
|
if (file.exists()) {
|
||||||
|
return home;
|
||||||
|
} else {
|
||||||
|
return jmeterProperties.getHome();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return jmeterProperties.getHome();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getScriptRedisKey(String reportId, String testId) {
|
||||||
|
return reportId + "_" + testId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug(ApiResourceRunRequest request) {
|
||||||
|
TestResourceDTO resourcePoolDTO = getAvailableResourcePoolDTO(request.getProjectId());
|
||||||
|
String reportId = request.getReportId();
|
||||||
|
String testId = request.getTestId();
|
||||||
|
|
||||||
|
TaskRequest taskRequest = new TaskRequest();
|
||||||
|
BeanUtils.copyBean(taskRequest, request);
|
||||||
|
|
||||||
|
String msUrl = systemParameterService.getBaseInfo().getUrl();
|
||||||
|
taskRequest.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
|
||||||
|
taskRequest.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
|
||||||
|
taskRequest.setMsUrl(msUrl);
|
||||||
|
taskRequest.setReportId(reportId);
|
||||||
|
taskRequest.setRealTime(true);
|
||||||
|
|
||||||
|
// todo 环境配置
|
||||||
|
// EnvironmentRequest environmentRequest = environmentService.get(request.getEnvironmentId());
|
||||||
|
// todo 误报
|
||||||
|
// todo 获取接口插件和jar包
|
||||||
|
// todo 处理公共脚本
|
||||||
|
|
||||||
|
ParameterConfig parameterConfig = new ParameterConfig();
|
||||||
|
parameterConfig.setReportId(reportId);
|
||||||
|
String executeScript = parseExecuteScript(request.getRequest(), parameterConfig);
|
||||||
|
|
||||||
|
// 将测试脚本缓存到 redis
|
||||||
|
String scriptRedisKey = getScriptRedisKey(reportId, testId);
|
||||||
|
stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript);
|
||||||
|
|
||||||
|
List<TestResourceNodeDTO> nodesList = resourcePoolDTO.getNodesList();
|
||||||
|
int index = new SecureRandom().nextInt(nodesList.size());
|
||||||
|
TestResourceNodeDTO testResourceNodeDTO = nodesList.get(index);
|
||||||
|
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
|
||||||
|
try {
|
||||||
|
LogUtils.info(String.format("开始发送请求【 %s 】到 %s 节点执行", testId, endpoint), reportId);
|
||||||
|
TaskRunnerClient.debugApi(endpoint, taskRequest);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(e);
|
||||||
|
// 调用失败清理脚本
|
||||||
|
stringRedisTemplate.delete(scriptRedisKey);
|
||||||
|
throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成执行脚本
|
||||||
|
* @param testElementStr
|
||||||
|
* @param msParameter
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String parseExecuteScript(String testElementStr, ParameterConfig msParameter) {
|
||||||
|
// 解析生成脚本
|
||||||
|
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
||||||
|
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(testElementStr, AbstractMsTestElement.class);
|
||||||
|
return defaultParser.parse(msTestElement, msParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Map<String, String> getMinio() {
|
||||||
|
MinioProperties minioProperties = CommonBeanFactory.getBean(MinioProperties.class);
|
||||||
|
Map<String, String> minioPros = new HashMap<>();
|
||||||
|
minioPros.put("endpoint", minioProperties.getEndpoint());
|
||||||
|
minioPros.put("accessKey", minioProperties.getAccessKey());
|
||||||
|
minioPros.put("secretKey", minioProperties.getSecretKey());
|
||||||
|
return minioPros;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前项目配置的接口默认资源池
|
||||||
|
* @param projectId
|
||||||
|
* @param
|
||||||
|
*/
|
||||||
|
public TestResourceDTO getAvailableResourcePoolDTO(String projectId) {
|
||||||
|
// 查询接口默认资源池
|
||||||
|
ProjectApplication resourcePoolConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
|
||||||
|
// 没有配置接口默认资源池
|
||||||
|
if (resourcePoolConfig == null || StringUtils.isBlank(resourcePoolConfig.getTypeValue())) {
|
||||||
|
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
||||||
|
}
|
||||||
|
String resourcePoolId = StringUtils.isBlank(resourcePoolConfig.getTypeValue()) ? null : resourcePoolConfig.getTypeValue();
|
||||||
|
TestResourcePool testResourcePool = testResourcePoolService.getTestResourcePool(resourcePoolId);
|
||||||
|
if (testResourcePool == null ||
|
||||||
|
// 资源池禁用
|
||||||
|
!testResourcePool.getEnable() ||
|
||||||
|
// 项目没有资源池权限
|
||||||
|
!commonProjectService.validateProjectResourcePool(testResourcePool, projectId)) {
|
||||||
|
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
||||||
|
}
|
||||||
|
return testResourcePoolService.getTestResourceDTO(resourcePoolId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.api.service;
|
package io.metersphere.api.service;
|
||||||
|
|
||||||
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.system.dto.ProtocolDTO;
|
import io.metersphere.system.dto.ProtocolDTO;
|
||||||
import io.metersphere.system.service.ApiPluginService;
|
import io.metersphere.system.service.ApiPluginService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -16,11 +17,18 @@ import java.util.List;
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public class ApiTestService {
|
public class ApiTestService {
|
||||||
|
|
||||||
|
private static final String HTTP_PROTOCOL = "HTTP";
|
||||||
@Resource
|
@Resource
|
||||||
private ApiPluginService apiPluginService;
|
private ApiPluginService apiPluginService;
|
||||||
|
|
||||||
public List<ProtocolDTO> getProtocols(String orgId) {
|
public List<ProtocolDTO> getProtocols(String orgId) {
|
||||||
return apiPluginService.getProtocols(orgId);
|
List<ProtocolDTO> protocols = apiPluginService.getProtocols(orgId);
|
||||||
|
// 将 http 协议放最前面
|
||||||
|
ProtocolDTO protocolDTO = new ProtocolDTO();
|
||||||
|
protocolDTO.setProtocol(HTTP_PROTOCOL);
|
||||||
|
protocolDTO.setPolymorphicName(MsHTTPElement.class.getSimpleName());
|
||||||
|
protocols.addFirst(protocolDTO);
|
||||||
|
return protocols;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,10 +8,12 @@ import io.metersphere.api.dto.debug.*;
|
||||||
import io.metersphere.api.mapper.ApiDebugBlobMapper;
|
import io.metersphere.api.mapper.ApiDebugBlobMapper;
|
||||||
import io.metersphere.api.mapper.ApiDebugMapper;
|
import io.metersphere.api.mapper.ApiDebugMapper;
|
||||||
import io.metersphere.api.mapper.ExtApiDebugMapper;
|
import io.metersphere.api.mapper.ExtApiDebugMapper;
|
||||||
|
import io.metersphere.api.service.ApiExecuteService;
|
||||||
import io.metersphere.api.service.ApiFileResourceService;
|
import io.metersphere.api.service.ApiFileResourceService;
|
||||||
import io.metersphere.sdk.util.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.project.service.ProjectService;
|
import io.metersphere.project.service.ProjectService;
|
||||||
|
import io.metersphere.sdk.constants.ApiExecuteRunMode;
|
||||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
@ -45,6 +47,8 @@ public class ApiDebugService {
|
||||||
private ExtApiDebugMapper extApiDebugMapper;
|
private ExtApiDebugMapper extApiDebugMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ApiFileResourceService apiFileResourceService;
|
private ApiFileResourceService apiFileResourceService;
|
||||||
|
@Resource
|
||||||
|
private ApiExecuteService apiExecuteService;
|
||||||
|
|
||||||
public List<ApiDebugSimpleDTO> list(String protocol, String userId) {
|
public List<ApiDebugSimpleDTO> list(String protocol, String userId) {
|
||||||
return extApiDebugMapper.list(protocol, userId);
|
return extApiDebugMapper.list(protocol, userId);
|
||||||
|
@ -162,4 +166,21 @@ public class ApiDebugService {
|
||||||
public String uploadTempFile(MultipartFile file) {
|
public String uploadTempFile(MultipartFile file) {
|
||||||
return apiFileResourceService.uploadTempFile(file);
|
return apiFileResourceService.uploadTempFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String debug(ApiDebugRunRequest request) {
|
||||||
|
String id = request.getId();
|
||||||
|
ApiDebug apiDebug = checkResourceExist(id);
|
||||||
|
|
||||||
|
ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request);
|
||||||
|
runRequest.setProjectId(apiDebug.getProjectId());
|
||||||
|
runRequest.setTestId(id);
|
||||||
|
runRequest.setReportId(id);
|
||||||
|
runRequest.setResourceType(ApiResourceType.API_DEBUG.name());
|
||||||
|
runRequest.setRunMode(ApiExecuteRunMode.DEBUG.name());
|
||||||
|
|
||||||
|
apiExecuteService.debug(runRequest);
|
||||||
|
|
||||||
|
return runRequest.getReportId();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,9 +6,10 @@ import io.metersphere.api.domain.*;
|
||||||
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.enums.ApiDefinitionDocType;
|
import io.metersphere.api.enums.ApiDefinitionDocType;
|
||||||
import io.metersphere.api.enums.ApiReportStatus;
|
|
||||||
import io.metersphere.api.mapper.*;
|
import io.metersphere.api.mapper.*;
|
||||||
import io.metersphere.api.service.ApiFileResourceService;
|
import io.metersphere.api.service.ApiFileResourceService;
|
||||||
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
|
import io.metersphere.sdk.constants.ApiReportStatus;
|
||||||
import io.metersphere.sdk.util.*;
|
import io.metersphere.sdk.util.*;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||||
|
|
|
@ -13,7 +13,7 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.mapper.ProjectMapper;
|
import io.metersphere.project.mapper.ProjectMapper;
|
||||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||||
import io.metersphere.sdk.util.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||||
import io.metersphere.api.dto.definition.*;
|
import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.mapper.*;
|
import io.metersphere.api.mapper.*;
|
||||||
import io.metersphere.api.service.ApiFileResourceService;
|
import io.metersphere.api.service.ApiFileResourceService;
|
||||||
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.mapper.ProjectMapper;
|
import io.metersphere.project.mapper.ProjectMapper;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.sdk.util;
|
package io.metersphere.api.utils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
@ -10,7 +10,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||||
import com.fasterxml.jackson.databind.type.CollectionType;
|
import com.fasterxml.jackson.databind.type.CollectionType;
|
||||||
import io.metersphere.sdk.dto.api.request.sampler.MsDebugSampler;
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -31,7 +31,7 @@ public class ApiDataUtils {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// 默认内置的子组件
|
// 默认内置的子组件
|
||||||
namedTypes.add(new NamedType(MsDebugSampler.class, MsDebugSampler.class.getSimpleName()));
|
namedTypes.add(new NamedType(MsHTTPElement.class, MsHTTPElement.class.getSimpleName()));
|
||||||
|
|
||||||
setObjectMapper(objectMapper);
|
setObjectMapper(objectMapper);
|
||||||
namedTypes.forEach(objectMapper::registerSubtypes);
|
namedTypes.forEach(objectMapper::registerSubtypes);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue