feat(接口设置): 处理http环境配置解析

This commit is contained in:
AgAngle 2024-02-20 09:45:36 +08:00 committed by Craftsman
parent 282f6493d9
commit 92cbcc1939
26 changed files with 591 additions and 54 deletions

View File

@ -3,6 +3,7 @@ package io.metersphere.api.dto;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.GlobalParams;
import lombok.Data;
import java.util.HashMap;
@ -18,10 +19,18 @@ public class ApiParamConfig extends ParameterConfig {
* 报告ID
*/
private String reportId;
/**
* 使用全局cookie
*/
private Boolean enableGlobalCookie = true;
/**
* 环境配置信息
*/
private EnvironmentInfoDTO envConfig;
/**
* 全局参数
*/
private GlobalParams globalParams;
/**
* AbstractMsTestElement 实现类与插件 ID 的映射
* key AbstractMsTestElement 实现类对象

View File

@ -0,0 +1,19 @@
package io.metersphere.api.dto;
import lombok.Data;
/**
* @Author: jianxing
* @CreateTime: 2024-02-17 18:46
*/
@Data
public class ApiResourceModuleInfo {
/**
* 模块Id
*/
private String moduleId;
/**
* 资源id接口定义接口用例等
*/
private String resourceId;
}

View File

@ -15,8 +15,6 @@ public class ApiDebugRunRequest {
@Schema(description = "报告ID")
@NotNull
private String reportId;
@Schema(description = "环境ID")
private String environmentId;
@Schema(description = "点击调试时尚未保存的文件ID列表")
private List<String> tempFileIds;
@NotNull

View File

@ -43,6 +43,7 @@ public class MsScenario extends AbstractMsTestElement {
private Boolean grouped;
/**
* {@link io.metersphere.api.constants.ApiScenarioStepRefType}
* DIRECT 表示当前根场景
*/
private String refType;
}

View File

@ -72,4 +72,9 @@ public class MsHTTPElement extends AbstractMsTestElement {
*/
@Valid
private HTTPAuth authConfig;
/**
* 模块ID
* 运行时参数接口无需设置
*/
private String moduleId;
}

View File

@ -15,7 +15,7 @@ public class ScenarioOtherConfig {
/**
* 是否共享cookie
*/
private Boolean enableCookieShare;
private Boolean enableCookieShare = false;
/**
* 场景步骤等待时间
* 每一个步骤执行后都会等待相应的时间

View File

@ -2,6 +2,7 @@ package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiDefinition;
import io.metersphere.api.domain.ApiDefinitionCustomField;
import io.metersphere.api.dto.ApiResourceModuleInfo;
import io.metersphere.api.dto.converter.ApiDefinitionImportDetail;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.scenario.ScenarioSystemRequest;
@ -61,4 +62,6 @@ public interface ExtApiDefinitionMapper {
Long getPrePos(@Param("projectId") String projectId, @Param("basePos") Long basePos);
Long getLastPos(@Param("projectId") String projectId, @Param("basePos") Long basePos);
List<ApiResourceModuleInfo> getModuleInfoByIds(@Param("ids") List<String> ids);
}

View File

@ -541,4 +541,12 @@
</if>
order by `pos` desc limit 1;
</select>
<select id="getModuleInfoByIds" resultType="io.metersphere.api.dto.ApiResourceModuleInfo">
select id as resource_id, module_id
from api_definition
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -34,4 +34,6 @@ public interface ExtApiDefinitionModuleMapper {
List<BaseTreeNode> selectNodeByIds(@Param("ids") List<String> ids);
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
List<String> getModuleIdsByParentIds(@Param("parentIds") List<String> parentIds);
}

View File

@ -115,6 +115,14 @@
</foreach>
ORDER BY pos
</select>
<select id="getModuleIdsByParentIds" resultType="java.lang.String">
SELECT id
FROM api_definition_module
WHERE parent_id IN
<foreach collection="parentIds" item="parentId" open="(" separator="," close=")">
#{parentId}
</foreach>
</select>
<sql id="api_request">
<where>

View File

@ -10,10 +10,12 @@ import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.OptionDTO;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @author jianxing
@ -62,4 +64,6 @@ public interface ExtApiTestCaseMapper {
List<OptionDTO> selectVersionOptionByIds(@Param("ids") List<String> ids);
List<String> getIdsByModules(@Param("request") ScenarioSystemRequest caseRequest);
List<ApiTestCase> getApiCaseDefinitionInfo(@Param("ids") List<String> ids);
}

View File

@ -274,6 +274,14 @@
and api_test_case.version_id = #{request.versionId}
</if>
</select>
<select id="getApiCaseDefinitionInfo" resultType="io.metersphere.api.domain.ApiTestCase">
select api_definition_id, id
from api_test_case
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
<sql id="report_filters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">

View File

@ -1,24 +1,42 @@
package io.metersphere.api.parser.jmeter;
import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.parser.jmeter.body.MsBodyConverter;
import io.metersphere.api.parser.jmeter.body.MsBodyConverterFactory;
import io.metersphere.api.parser.jmeter.body.MsFormDataBodyConverter;
import io.metersphere.api.parser.jmeter.body.MsWWWFormBodyConverter;
import io.metersphere.jmeter.mock.Mock;
import io.metersphere.plugin.api.constants.ElementProperty;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.GlobalParams;
import io.metersphere.project.dto.environment.http.HttpConfig;
import io.metersphere.project.dto.environment.http.HttpConfigPathMatchRule;
import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.sdk.util.EnumValidator;
import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
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;
import org.springframework.http.HttpMethod;
import java.util.*;
import java.util.stream.Collectors;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.HEADER_PANEL;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.HTTP_TEST_SAMPLE_GUI;
/**
@ -29,7 +47,8 @@ import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.HTTP_TEST_S
*/
public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTTPElement> {
private ParameterConfig config;
public static final String URL_ENCODE = "${__urlencode(%s)}";
public static final String COOKIE = "Cookie";
@Override
public void toHashTree(HashTree tree, MsHTTPElement msHTTPElement, ParameterConfig config) {
@ -37,26 +56,161 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
LogUtils.info("MsHTTPElement is disabled");
return;
}
this.config = config;
ApiParamConfig apiParamConfig = (ApiParamConfig) config;
HttpConfig httpConfig = getHttpConfig(msHTTPElement, apiParamConfig);
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setName(msHTTPElement.getName());
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(HTTP_TEST_SAMPLE_GUI));
// TODO: 当前步骤唯一标识很重要结果和步骤匹配的关键
setStepIdentification(msHTTPElement, config, sampler);
sampler.setMethod(msHTTPElement.getMethod());
// path 设置完整的url
sampler.setPath(getPath(msHTTPElement, httpConfig));
// 处理请求体
handleBody(sampler, msHTTPElement, config);
HashTree httpTree = tree.add(sampler);
// 处理请求头
HeaderManager httpHeader = getHttpHeader(msHTTPElement, apiParamConfig, httpConfig);
if (httpHeader != null) {
httpTree.add(httpHeader);
}
parseChild(httpTree, msHTTPElement, config);
}
/**
* 设置步骤标识
* 当前步骤唯一标识结果和步骤匹配的关键
* @param msHTTPElement
* @param config
* @param sampler
*/
private void setStepIdentification(MsHTTPElement msHTTPElement, ParameterConfig config, HTTPSamplerProxy sampler) {
sampler.setProperty(ElementProperty.MS_RESOURCE_ID.name(), msHTTPElement.getResourceId());
sampler.setProperty(ElementProperty.MS_STEP_ID.name(), msHTTPElement.getStepId());
sampler.setProperty(ElementProperty.MS_REPORT_ID.name(), config.getReportId());
sampler.setProperty(ElementProperty.PROJECT_ID.name(), msHTTPElement.getProjectId());
}
sampler.setMethod(msHTTPElement.getMethod());
// todo 根据环境设置
sampler.setDomain(msHTTPElement.getUrl());
sampler.setPath(msHTTPElement.getPath());
private String getPath(MsHTTPElement msHTTPElement, HttpConfig httpConfig) {
String url = msHTTPElement.getPath();
if (httpConfig != null) {
// 接口调试没有环境不取环境的配置
String protocol = httpConfig.getProtocol().toLowerCase();
url = protocol + "://" + (httpConfig.getUrl() + "/" + url).replace("//", "/");
}
return getPathWithQuery(url, msHTTPElement.getQuery());
}
handleBody(sampler, msHTTPElement);
HashTree httpTree = tree.add(sampler);
parseChild(httpTree, msHTTPElement, config);
private HeaderManager getHttpHeader(MsHTTPElement msHTTPElement, ApiParamConfig apiParamConfig, HttpConfig httpConfig) {
Map<String, String> headerMap = new HashMap<>();
// 获取全局参数中的请求头
GlobalParams globalParams = apiParamConfig.getGlobalParams();
if (globalParams != null) {
setHeaderMap(headerMap, globalParams.getHeaders());
}
// 获取环境中的请求头
if (httpConfig != null && CollectionUtils.isNotEmpty(httpConfig.getHeaders())) {
Boolean enableGlobalCookie = apiParamConfig.getEnableGlobalCookie();
List<KeyValueEnableParam> envHeaders = httpConfig.getHeaders();
if (BooleanUtils.isFalse(enableGlobalCookie)) {
// 如果不启用全局 cookie则过滤 cookie
envHeaders = envHeaders.stream()
.filter(header -> !StringUtils.equalsIgnoreCase(header.getKey(), COOKIE))
.toList();
}
setHeaderMap(headerMap, envHeaders);
}
// 获取请求中的请求头
if (CollectionUtils.isNotEmpty(msHTTPElement.getHeaders())) {
setHeaderMap(headerMap, msHTTPElement.getHeaders());
}
if (headerMap.isEmpty()) {
return null;
}
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setName(StringUtils.isNotEmpty(msHTTPElement.getName()) ? msHTTPElement.getName() + "_HeaderManager" : "HeaderManager");
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(HEADER_PANEL));
headerMap.forEach((k, v) -> headerManager.add(new Header(k, Mock.buildFunctionCallString(v))));
return headerManager;
}
private void setHeaderMap(Map<String, String> headerMap, List<? extends KeyValueEnableParam> headers) {
if (CollectionUtils.isEmpty(headers)) {
return;
}
headers.stream()
.filter(KeyValueEnableParam::getEnable)
.filter(KeyValueParam::isValid)
.forEach(header -> {
if (StringUtils.equalsIgnoreCase(header.getKey(), COOKIE)) {
String cookieValue = header.getValue();
if (headerMap.get(COOKIE) != null && header.getValue() != null) {
// 合并 cookie
cookieValue = headerMap.get(COOKIE) + ";" + header.getValue();
}
headerMap.put(COOKIE, cookieValue);
} else {
headerMap.put(header.getKey(), header.getValue());
}
});
}
/**
* 获取环境 http 配置
*
* @param msHTTPElement
* @param config
* @return
*/
private HttpConfig getHttpConfig(MsHTTPElement msHTTPElement, ApiParamConfig config) {
ApiParamConfig apiParamConfig = config;
EnvironmentInfoDTO envConfig = apiParamConfig.getEnvConfig();
if (envConfig == null) {
return null;
}
// http配置按优先级排序
List<HttpConfig> httpConfigs = envConfig.getConfig().getHttpConfig()
.stream()
.sorted(Comparator.comparing(HttpConfig::getModuleMatchRuleOrder))
.toList();
for (HttpConfig httpConfig : httpConfigs) {
boolean match;
if (httpConfig.isPathMatchRule()) {
// 匹配路径
HttpConfigPathMatchRule pathMatchRule = httpConfig.getPathMatchRule();
HttpConfigPathMatchRule.MatchRuleCondition matchRuleCondition =
EnumValidator.validateEnum(HttpConfigPathMatchRule.MatchRuleCondition.class, pathMatchRule.getCondition());
match = matchRuleCondition.match(pathMatchRule.getPath(), msHTTPElement.getPath());
} else if (httpConfig.isModuleMatchRule()) {
// 匹配模块
Set<String> moduleIds = httpConfig.getModuleMatchRule().getModules()
.stream()
.map(SelectModule::getModuleId)
.collect(Collectors.toSet());
match = moduleIds.contains(msHTTPElement.getModuleId());
} else {
// 无条件匹配
match = true;
}
if (match) {
return httpConfig;
}
}
return null;
}
/**
@ -65,7 +219,7 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
* @param sampler
* @param msHTTPElement
*/
private void handleBody(HTTPSamplerProxy sampler, MsHTTPElement msHTTPElement) {
private void handleBody(HTTPSamplerProxy sampler, MsHTTPElement msHTTPElement, ParameterConfig config) {
Body body = msHTTPElement.getBody();
// 请求体处理
if (body != null) {
@ -80,4 +234,44 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
converter.parse(sampler, body.getBodyDataByType(), config);
}
}
/**
* query 参数添加到 url
*
* @param path
* @param query
* @return
*/
private String getPathWithQuery(String path, List<QueryParam> query) {
if (CollectionUtils.isEmpty(query)) {
return path;
}
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(path);
if (path.contains("?")) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
query.stream()
.filter(KeyValueEnableParam::getEnable)
.filter(KeyValueParam::isValid)
.forEach(queryParam -> {
stringBuffer.append(queryParam.getEncode() ? String.format(URL_ENCODE, queryParam.getKey()) : queryParam.getKey());
if (queryParam.getValue() != null) {
try {
String value = queryParam.getValue().startsWith("@") ? Mock.buildFunctionCallString(queryParam.getValue()) : queryParam.getValue();
value = queryParam.getEncode() ? String.format(URL_ENCODE, value.replace(",", "\\,")) : value;
if (StringUtils.isNotEmpty(value) && value.contains(StringUtils.CR)) {
value = value.replaceAll(StringUtils.CR, StringUtils.EMPTY);
}
stringBuffer.append("=").append(value);
} catch (Exception e) {
LogUtils.error(e);
}
}
stringBuffer.append("&");
});
return stringBuffer.substring(0, stringBuffer.length() - 1);
}
}

View File

@ -21,12 +21,17 @@ import io.metersphere.sdk.util.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.COOKIE_PANEL;
/**
* @Author: jianxing
* @CreateTime: 2023-10-27 10:07
@ -40,11 +45,17 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
ApiScenarioParamConfig config = (ApiScenarioParamConfig) msParameter;
EnvironmentInfoDTO envInfo = config.getEnvConfig(msScenario.getProjectId());
if (isRootScenario(msScenario.getRefType()) && msScenario.getScenarioConfig().getOtherConfig().getEnableGlobalCookie()) {
// 根场景设置共享cookie
tree.add(getCookieManager());
}
// 添加环境的前置
addEnvScenarioProcessor(tree, msScenario, config, envInfo, true);
// 添加场景前置
addScenarioProcessor(tree, msScenario, config, true);
// 解析子步骤
ApiScenarioParamConfig chileConfig = getChileConfig(msScenario, config);
parseChild(tree, msScenario, chileConfig);
@ -165,6 +176,10 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
return StringUtils.equalsAny(refType, ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name());
}
private boolean isRootScenario(String refType) {
return StringUtils.equals(refType, ApiScenarioStepRefType.DIRECT.name());
}
private boolean isCopy(String refType) {
return StringUtils.equals(refType, ApiScenarioStepRefType.COPY.name());
}
@ -178,29 +193,47 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
* @return
*/
private ApiScenarioParamConfig getChileConfig(MsScenario msScenario, ApiScenarioParamConfig config) {
ApiScenarioParamConfig childConfig = config;
if (!isRef(msScenario.getRefType())) {
// 非引用的场景使用当前环境参数
return config;
return childConfig;
}
ScenarioStepConfig scenarioStepConfig = msScenario.getScenarioStepConfig();
if (scenarioStepConfig != null && BooleanUtils.isTrue(scenarioStepConfig.getEnableScenarioEnv())) {
// 使用源场景环境
ApiScenarioParamConfig chileConfig = BeanUtils.copyBean(new ApiScenarioParamConfig(), config);
chileConfig.setGrouped(msScenario.getGrouped());
childConfig = BeanUtils.copyBean(new ApiScenarioParamConfig(), config);
childConfig.setGrouped(msScenario.getGrouped());
// 清空环境信息
chileConfig.setEnvConfig(null);
chileConfig.setProjectEnvMap(null);
childConfig.setEnvConfig(null);
childConfig.setProjectEnvMap(null);
if (BooleanUtils.isTrue(msScenario.getGrouped())) {
// 环境组设置环境Map
Map<String, EnvironmentInfoDTO> projectEnvMap = msScenario.getProjectEnvMap();
chileConfig.setProjectEnvMap(projectEnvMap);
childConfig.setProjectEnvMap(projectEnvMap);
} else {
// 设置环境信息
EnvironmentInfoDTO environmentInfo = msScenario.getEnvironmentInfo();
chileConfig.setEnvConfig(environmentInfo);
childConfig.setEnvConfig(environmentInfo);
}
return chileConfig;
}
return config;
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
if (scenarioConfig != null) {
// 设置是否使用全局cookie
childConfig.setEnableGlobalCookie(scenarioConfig.getOtherConfig().getEnableCookieShare());
}
return childConfig;
}
private CookieManager getCookieManager() {
CookieManager cookieManager = new CookieManager();
cookieManager.setProperty(TestElement.TEST_CLASS, CookieManager.class.getName());
cookieManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(COOKIE_PANEL));
cookieManager.setEnabled(true);
cookieManager.setName("CookieManager");
cookieManager.setClearEachIteration(false);
cookieManager.setControlledByThread(false);
return cookieManager;
}
}

View File

@ -17,4 +17,6 @@ public class JmeterAlias {
public static final String XPATH_ASSERTION_GUI = "XPathAssertionGui";
public static final String X_PATH_2_ASSERTION_GUI = "XPath2AssertionGui";
public static final String USER_PARAMETERS_GUI = "UserParametersGui";
public static final String COOKIE_PANEL = "CookiePanel";
public static final String HEADER_PANEL = "HeaderPanel";
}

View File

@ -13,10 +13,9 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.dto.customfunction.request.CustomFunctionRunRequest;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileManagementService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.ProjectApplicationService;
import io.metersphere.project.dto.environment.GlobalParams;
import io.metersphere.project.dto.environment.GlobalParamsDTO;
import io.metersphere.project.service.*;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ProjectApplicationType;
@ -82,6 +81,8 @@ public class ApiExecuteService {
private FileManagementService fileManagementService;
@Resource
private ApiPluginService apiPluginService;
@Resource
private GlobalParamsService globalParamsService;
@PostConstruct
private void init() {
@ -128,6 +129,8 @@ public class ApiExecuteService {
taskRequest.setMsRegexList(projectApplicationService.get(Collections.singletonList(request.getProjectId())));
}
parameterConfig.setGlobalParams(getGlobalParam(request));
// todo 获取接口插件和jar包
// todo 处理公共脚本
// todo 接口用例 method 获取定义中的数据库字段
@ -136,6 +139,14 @@ public class ApiExecuteService {
doDebug(reportId, testId, taskRequest, executeScript, request.getProjectId());
}
private GlobalParams getGlobalParam(ApiResourceRunRequest request) {
GlobalParamsDTO globalParamsDTO = globalParamsService.get(request.getProjectId());
if (globalParamsDTO != null) {
return globalParamsDTO.getGlobalParams();
}
return null;
}
/**
* 发送执行任务
*

View File

@ -13,8 +13,6 @@ import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.service.EnvironmentService;
import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.exception.MSException;
@ -55,8 +53,6 @@ public class ApiDebugService {
private ApiExecuteService apiExecuteService;
@Resource
private ApiPluginService apiPluginService;
@Resource
private EnvironmentService environmentService;
public static final Long ORDER_STEP = 5000L;
@ -203,19 +199,13 @@ public class ApiDebugService {
runRequest.setTestId(id);
runRequest.setReportId(reportId);
runRequest.setResourceType(ApiResourceType.API_DEBUG.name());
runRequest.setEnvironmentId(request.getEnvironmentId());
runRequest.setTestElement(ApiDataUtils.parseObject(JSON.toJSONString(request.getRequest()), AbstractMsTestElement.class));
ApiParamConfig paramConfig = new ApiParamConfig();
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
paramConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap());
paramConfig.setReportId(reportId);
EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId());
// 设置环境
paramConfig.setEnvConfig(environmentInfoDTO);
apiExecuteService.debug(runRequest, paramConfig);
return runRequest.getReportId();
}

View File

@ -32,6 +32,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -346,5 +347,10 @@ public class ApiDefinitionModuleService extends ModuleTreeService {
});
}
public List<String> getModuleIdsByParentIds(List<String> parentIds) {
if (CollectionUtils.isEmpty(parentIds)) {
return Collections.emptyList();
}
return extApiDefinitionModuleMapper.getModuleIdsByParentIds(parentIds);
}
}

View File

@ -4,6 +4,7 @@ import io.metersphere.api.constants.ApiDefinitionDocType;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.ApiResourceModuleInfo;
import io.metersphere.api.dto.converter.ApiDefinitionImport;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.definition.*;
@ -1024,4 +1025,8 @@ public class ApiDefinitionService {
}
}
}
public List<ApiResourceModuleInfo> getModuleInfoByIds(List<String> apiIds) {
return extApiDefinitionMapper.getModuleInfoByIds(apiIds);
}
}

View File

@ -2,6 +2,7 @@ package io.metersphere.api.service.definition;
import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.ApiResourceModuleInfo;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.request.http.MsHTTPElement;
@ -81,6 +82,8 @@ public class ApiTestCaseService {
private ApiDefinitionModuleMapper apiDefinitionModuleMapper;
@Resource
private OperationHistoryService operationHistoryService;
@Resource
private ExtApiDefinitionMapper extApiDefinitionMapper;
private static final String CASE_TABLE = "api_test_case";
private void checkProjectExist(String projectId) {
@ -581,4 +584,18 @@ public class ApiTestCaseService {
update.setUpdateTime(System.currentTimeMillis());
apiTestCaseMapper.updateByPrimaryKeySelective(update);
}
public List<ApiResourceModuleInfo> getModuleInfoByIds(List<String> ids) {
// 获取接口定义ID和用例ID的映射
Map<String, String> apiCaseDefinitionMap = extApiTestCaseMapper.getApiCaseDefinitionInfo(ids)
.stream()
.collect(Collectors.toMap(ApiTestCase::getApiDefinitionId, ApiTestCase::getId));
List<String> definitionIds = apiCaseDefinitionMap.keySet().stream().collect(Collectors.toList());
List<ApiResourceModuleInfo> moduleInfos = extApiDefinitionMapper.getModuleInfoByIds(definitionIds);
// resourceId 从定义ID替换成用例ID
moduleInfos.forEach(moduleInfo ->
moduleInfo.setResourceId(apiCaseDefinitionMap.get(moduleInfo.getResourceId())));
return moduleInfos;
}
}

View File

@ -4,12 +4,14 @@ import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.ApiResourceModuleInfo;
import io.metersphere.api.dto.ApiScenarioParamConfig;
import io.metersphere.api.dto.ApiScenarioParseEnvInfo;
import io.metersphere.api.dto.EnvironmentModeDTO;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.request.MsScenario;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
import io.metersphere.api.dto.scenario.*;
import io.metersphere.api.job.ApiScenarioScheduleJob;
@ -18,6 +20,7 @@ import io.metersphere.api.parser.step.StepParser;
import io.metersphere.api.parser.step.StepParserFactory;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.utils.ApiScenarioBatchOperationUtils;
@ -26,10 +29,16 @@ import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.http.HttpConfig;
import io.metersphere.project.dto.environment.http.HttpConfigModuleMatchRule;
import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.*;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.ScheduleResourceType;
import io.metersphere.sdk.domain.Environment;
import io.metersphere.sdk.domain.EnvironmentExample;
import io.metersphere.sdk.domain.EnvironmentGroup;
@ -157,6 +166,8 @@ public class ApiScenarioService {
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private ApiDefinitionModuleService apiDefinitionModuleService;
public static final String PRIORITY = "Priority";
public static final String STATUS = "Status";
@ -1046,7 +1057,10 @@ public class ApiScenarioService {
// 获取场景环境相关配置
ApiScenarioParseEnvInfo scenarioParseEnvInfo = getScenarioParseEnvInfo(refResourceMap, request.getEnvironmentId(), request.getGrouped());
parseStep2MsElement(msScenario, steps, resourceBlobMap, detailMap, scenarioParseEnvInfo);
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = new HashMap<>();
parseStep2MsElement(msScenario, steps, resourceBlobMap, detailMap, stepTypeHttpElementMap, scenarioParseEnvInfo);
// 设置 HttpElement 的模块信息
setHttpElementModuleId(stepTypeHttpElementMap);
ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request);
runRequest.setProjectId(request.getProjectId());
@ -1063,7 +1077,6 @@ public class ApiScenarioService {
parseConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap());
parseConfig.setGrouped(request.getGrouped());
parseConfig.setReportId(request.getReportId());
scenarioParseEnvInfo.getPluginClassEnvConfigMap();
if (BooleanUtils.isTrue(request.getGrouped())) {
// 设置环境组 map
parseConfig.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, request.getEnvironmentId()));
@ -1073,10 +1086,33 @@ public class ApiScenarioService {
}
apiExecuteService.debug(runRequest, parseConfig);
return request.getReportId();
}
/**
* 设置 HttpElement 的模块信息
* 用户环境中的模块过滤
* @param stepTypeHttpElementMap
*/
private void setHttpElementModuleId(Map<String, List<MsHTTPElement>> stepTypeHttpElementMap) {
setHttpElementModuleId(stepTypeHttpElementMap.get(ApiScenarioStepType.API.name()), apiDefinitionService::getModuleInfoByIds);
setHttpElementModuleId(stepTypeHttpElementMap.get(ApiScenarioStepType.API_CASE.name()), apiTestCaseService::getModuleInfoByIds);
}
private void setHttpElementModuleId(List<MsHTTPElement> httpElements, Function<List<String>, List<ApiResourceModuleInfo>> getModuleInfoFunc) {
if (CollectionUtils.isNotEmpty(httpElements)) {
List<String> apiIds = httpElements.stream().map(MsHTTPElement::getResourceId).collect(Collectors.toList());
// 获取接口模块信息
Map<String, String> resourceModuleMap = getModuleInfoFunc.apply(apiIds)
.stream()
.collect(Collectors.toMap(ApiResourceModuleInfo::getResourceId, ApiResourceModuleInfo::getModuleId));
httpElements.forEach(httpElement -> {
// httpElement 设置模块信息
httpElement.setModuleId(resourceModuleMap.get(httpElement.getResourceId()));
});
}
}
/**
* 设置脚本解析-环境相关参数
*/
@ -1128,9 +1164,48 @@ public class ApiScenarioService {
envInfo.setEnvGroupMap(envGroupMap);
envInfo.setEnvMap(envMap);
envMap.forEach((envId, envInfoDTO) -> handleHttpModuleMatchRule(envInfoDTO));
return envInfo;
}
/**
* 处理环境的 HTTP 配置模块匹配规则
* 查询新增子模块
* @param envInfoDTO
*/
private void handleHttpModuleMatchRule(EnvironmentInfoDTO envInfoDTO) {
List<HttpConfig> httpConfigs = envInfoDTO.getConfig().getHttpConfig();
for (HttpConfig httpConfig : httpConfigs) {
if (!httpConfig.isModuleMatchRule()) {
continue;
}
// 获取勾选了包含子模块的模块ID
HttpConfigModuleMatchRule moduleMatchRule = httpConfig.getModuleMatchRule();
List<SelectModule> selectModules = moduleMatchRule.getModules();
List<String> containChildModuleIds = selectModules.stream()
.filter(SelectModule::getContainChildModule)
.map(SelectModule::getModuleId)
.toList();
// 查询子模块ID, 并去重
Set<String> moduleIds = apiDefinitionModuleService.getModuleIdsByParentIds(containChildModuleIds)
.stream()
.collect(Collectors.toSet());
selectModules.forEach(selectModule -> moduleIds.add(selectModule.getModuleId()));
// 重新设置选中的模块ID
moduleMatchRule.setModules(null);
List<SelectModule> allSelectModules = moduleIds.stream().map(moduleId -> {
SelectModule module = new SelectModule();
module.setModuleId(moduleId);
return module;
}).collect(Collectors.toList());
moduleMatchRule.setModules(allSelectModules);
}
}
private List<ApiScenario> getApiScenarioByIds(List<String> apiScenarioIds) {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(apiScenarioIds);
@ -1144,6 +1219,7 @@ public class ApiScenarioService {
List<? extends ApiScenarioStepCommonDTO> steps,
Map<String, String> resourceBlobMap,
Map<String, String> stepDetailMap,
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap,
ApiScenarioParseEnvInfo scenarioParseEnvInfo) {
if (CollectionUtils.isNotEmpty(steps)) {
parentElement.setChildren(new LinkedList<>());
@ -1158,12 +1234,19 @@ public class ApiScenarioService {
// 将步骤详情解析生成对应的MsTestElement
AbstractMsTestElement msTestElement = stepParser.parseTestElement(step, resourceBlobMap.get(step.getResourceId()), stepDetailMap.get(step.getId()));
if (msTestElement != null) {
if (msTestElement instanceof MsHTTPElement msHTTPElement) {
// 暂存http类型的步骤
stepTypeHttpElementMap.putIfAbsent(step.getStepType(), new LinkedList<>());
stepTypeHttpElementMap.get(step.getStepType()).add(msHTTPElement);
}
msTestElement.setProjectId(step.getProjectId());
msTestElement.setResourceId(step.getResourceId());
setMsScenarioParam(scenarioParseEnvInfo, step, msTestElement);
parentElement.getChildren().add(msTestElement);
}
if (CollectionUtils.isNotEmpty(step.getChildren())) {
parseStep2MsElement(msTestElement, step.getChildren(), resourceBlobMap, stepDetailMap, scenarioParseEnvInfo);
parseStep2MsElement(msTestElement, step.getChildren(), resourceBlobMap,
stepDetailMap, stepTypeHttpElementMap, scenarioParseEnvInfo);
}
}
}

View File

@ -3,9 +3,12 @@ package io.metersphere.api.controller;
import io.metersphere.api.constants.*;
import io.metersphere.api.domain.*;
import io.metersphere.api.dto.assertion.MsAssertionConfig;
import io.metersphere.api.dto.debug.ModuleCreateRequest;
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
import io.metersphere.api.dto.request.http.Header;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.QueryParam;
import io.metersphere.api.dto.response.ApiScenarioBatchOperationResponse;
import io.metersphere.api.dto.response.OperationDataInfo;
import io.metersphere.api.dto.scenario.*;
@ -13,10 +16,12 @@ import io.metersphere.api.job.ApiScenarioScheduleJob;
import io.metersphere.api.mapper.*;
import io.metersphere.api.service.ApiScenarioBatchOperationTestService;
import io.metersphere.api.service.BaseResourcePoolTestService;
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.api.assertion.MsResponseCodeAssertion;
import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.api.processor.MsProcessor;
@ -25,6 +30,9 @@ import io.metersphere.project.dto.environment.EnvironmentConfig;
import io.metersphere.project.dto.environment.EnvironmentGroupProjectDTO;
import io.metersphere.project.dto.environment.EnvironmentGroupRequest;
import io.metersphere.project.dto.environment.EnvironmentRequest;
import io.metersphere.project.dto.environment.http.HttpConfig;
import io.metersphere.project.dto.environment.http.HttpConfigPathMatchRule;
import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.project.dto.environment.processors.EnvProcessorConfig;
import io.metersphere.project.dto.environment.processors.EnvRequestScriptProcessor;
import io.metersphere.project.dto.environment.processors.EnvScenarioScriptProcessor;
@ -49,10 +57,10 @@ import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.Schedule;
import io.metersphere.system.dto.request.PluginUpdateRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.PosRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.ScheduleMapper;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.service.PluginService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
@ -144,11 +152,11 @@ public class ApiScenarioControllerTests extends BaseTest {
@Resource
private PluginService pluginService;
@Resource
private PluginLoadService pluginLoadService;
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ApiDefinitionModuleService apiDefinitionModuleService;
private static String fileMetadataId;
private static String localFileId;
private static ApiScenario addApiScenario;
@ -159,6 +167,7 @@ public class ApiScenarioControllerTests extends BaseTest {
private static ApiTestCase apiTestCase;
private static String envId;
private static String envGroupId;
private static String moduleId;
private static final List<CheckLogModel> LOG_CHECK_LIST = new ArrayList<>();
@ -284,6 +293,7 @@ public class ApiScenarioControllerTests extends BaseTest {
@Test
@Order(1)
public void add() throws Exception {
initModule();
initEnv();
initTestData();
@ -482,6 +492,18 @@ public class ApiScenarioControllerTests extends BaseTest {
}
private void initTestData() {
Header header1 = new Header();
header1.setKey("a");
header1.setValue("aaa");
Header header2 = new Header();
header2.setKey("c");
header2.setValue("cc");
Header header3 = new Header();
header3.setKey("Cookie");
header3.setValue("b=c");
ApiDefinitionAddRequest apiDefinitionAddRequest = new ApiDefinitionAddRequest();
apiDefinitionAddRequest.setName("test scenario");
apiDefinitionAddRequest.setProtocol(ApiConstants.HTTP_PROTOCOL);
@ -489,11 +511,22 @@ public class ApiScenarioControllerTests extends BaseTest {
apiDefinitionAddRequest.setMethod("POST");
apiDefinitionAddRequest.setPath("/api/admin/posts");
apiDefinitionAddRequest.setStatus(ApiDefinitionStatus.PREPARE.getValue());
apiDefinitionAddRequest.setModuleId("default");
apiDefinitionAddRequest.setModuleId(moduleId);
apiDefinitionAddRequest.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID));
apiDefinitionAddRequest.setDescription("描述内容");
apiDefinitionAddRequest.setName("test scenario");
MsHTTPElement msHttpElement = MsHTTPElementTest.getAddProcessorHttpElement();
msHttpElement.setHeaders(List.of(header1, header2, header3));
msHttpElement.setPath(apiDefinitionAddRequest.getPath());
QueryParam queryParam1 = new QueryParam();
queryParam1.setEncode(true);
queryParam1.setKey("aa");
queryParam1.setValue("bbb");
QueryParam queryParam2 = new QueryParam();
queryParam2.setEncode(false);
queryParam2.setKey("aa2");
queryParam2.setValue("bbb2");
msHttpElement.setQuery(List.of(queryParam1, queryParam2));
apiDefinitionAddRequest.setRequest(getMsElementParam(msHttpElement));
apiDefinitionAddRequest.setResponse("{}");
apiDefinition = apiDefinitionService.create(apiDefinitionAddRequest, "admin");
@ -654,6 +687,8 @@ public class ApiScenarioControllerTests extends BaseTest {
pluginStepDetail.put("port", "port");
pluginStepDetail.put("projectId", DEFAULT_PROJECT_ID);
request.getStepDetails().put(pluginStep.getId(), pluginStepDetail);
request.getScenarioConfig().getOtherConfig().setEnableCookieShare(true);
request.getScenarioConfig().getOtherConfig().setEnableGlobalCookie(false);
Plugin plugin = addEnvTestPlugin();
this.requestPostWithOk(DEBUG, request);
@ -678,6 +713,14 @@ public class ApiScenarioControllerTests extends BaseTest {
return pluginService.add(request, mockMultipartFile);
}
private void initModule() {
ModuleCreateRequest request = new ModuleCreateRequest();
request.setName("test");
request.setProjectId(DEFAULT_PROJECT_ID);
request.setParentId(ModuleConstants.ROOT_NODE_PARENT_ID);
moduleId = apiDefinitionModuleService.add(request, "admin");
}
private void initEnv() {
EnvironmentRequest envRequest = new EnvironmentRequest();
envRequest.setProjectId(DEFAULT_PROJECT_ID);
@ -730,6 +773,41 @@ public class ApiScenarioControllerTests extends BaseTest {
responseCodeAssertion.setName("test");
environmentConfig.getAssertionConfig().getAssertions().add(responseCodeAssertion);
KeyValueEnableParam header1 = new KeyValueEnableParam();
header1.setKey("a");
header1.setValue("aa");
KeyValueEnableParam header2 = new KeyValueEnableParam();
header2.setKey("b");
header2.setValue("bb");
KeyValueEnableParam header3 = new KeyValueEnableParam();
header3.setKey("Cookie");
header3.setValue("a=b");
HttpConfig httpNoneConfig = new HttpConfig();
httpNoneConfig.setUrl("localhost:8081");
httpNoneConfig.setType(HttpConfig.HttpConfigMatchType.NONE.name());
httpNoneConfig.setHeaders(List.of(header1, header2, header3));
HttpConfig httpModuleConfig = new HttpConfig();
httpModuleConfig.setUrl("localhost:8081");
httpModuleConfig.setType(HttpConfig.HttpConfigMatchType.MODULE.name());
SelectModule selectModule = new SelectModule();
selectModule.setModuleId(moduleId);
selectModule.setContainChildModule(true);
httpModuleConfig.getModuleMatchRule().setModules(List.of(selectModule));
httpModuleConfig.setHeaders(List.of(header1, header2, header3));
HttpConfig httpPathConfig = new HttpConfig();
httpPathConfig.setUrl("localhost:8081");
httpPathConfig.setType(HttpConfig.HttpConfigMatchType.PATH.name());
httpPathConfig.getPathMatchRule().setPath("/test");
httpPathConfig.getPathMatchRule().setCondition(HttpConfigPathMatchRule.MatchRuleCondition.CONTAINS.name());
httpPathConfig.setHeaders(List.of(header1, header2, header3));
environmentConfig.setHttpConfig(List.of(httpNoneConfig, httpModuleConfig, httpPathConfig));
environmentConfig.setPluginConfigMap(pluginConfigMap);
envRequest.setConfig(environmentConfig);
Environment environment = environmentService.add(envRequest, "admin", null);

View File

@ -1,10 +1,12 @@
package io.metersphere.project.dto.environment.http;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.io.Serial;
import java.io.Serializable;
@ -15,7 +17,9 @@ import java.util.List;
public class HttpConfig implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "http协议类型(http/https)")
@EnumValue(enumClass = HttpProtocolType.class)
private String protocol = HttpProtocolType.HTTP.name();
@Schema(description = "环境域名")
private String url;
/**
@ -34,6 +38,24 @@ public class HttpConfig implements Serializable {
@Schema(description = "请求头")
private List<@Valid KeyValueEnableParam> headers = new ArrayList<>(0);
public boolean isModuleMatchRule() {
return StringUtils.equals(HttpConfigMatchType.MODULE.name(), type);
}
public boolean isPathMatchRule() {
return StringUtils.equals(HttpConfigMatchType.PATH.name(), type);
}
public int getModuleMatchRuleOrder() {
if (isPathMatchRule()) {
return 0;
} else if (isModuleMatchRule()) {
return 1;
}
return 2;
}
/**
* 启用条件匹配类型
*/
@ -51,4 +73,23 @@ public class HttpConfig implements Serializable {
*/
NONE
}
/**
* 启用条件匹配类型
*/
public enum HttpProtocolType implements ValueEnum {
HTTP("http"),
HTTPS("https");
private String value;
HttpProtocolType(String value) {
this.value = value;
}
@Override
public String getValue() {
return this.value;
}
}
}

View File

@ -3,9 +3,11 @@ package io.metersphere.project.dto.environment.http;
import io.metersphere.system.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.io.Serial;
import java.io.Serializable;
import java.util.function.BiFunction;
/**
* @Author: jianxing
@ -30,10 +32,20 @@ public class HttpConfigPathMatchRule implements Serializable {
/**
* 包含
*/
CONTAINS,
CONTAINS((envPath, path) -> StringUtils.contains(path, envPath)),
/**
* 等于
*/
EQUALS
EQUALS((envPath, path) -> StringUtils.equals(path, envPath));
MatchRuleCondition(BiFunction<String, String, Boolean> matchFunc) {
this.matchFunc = matchFunc;
}
private BiFunction<String, String, Boolean> matchFunc;
public boolean match(String value, String expect) {
return matchFunc.apply(value, expect);
}
}
}

View File

@ -60,7 +60,7 @@ public class PluginLoadService {
* @param fileName
* @return
*/
public String loadPlugin(String fileName) {
public synchronized String loadPlugin(String fileName) {
MsFileUtils.validateFileName(fileName);
String filePath = LocalRepositoryDir.getPluginDir() + "/" + fileName;
File file = new File(filePath);

View File

@ -56,7 +56,7 @@ public class BasePluginTestService {
* @return
* @throws Exception
*/
public Plugin addJiraPlugin() throws Exception {
public synchronized Plugin addJiraPlugin() throws Exception {
if (hasJiraPlugin()) {
return jiraPlugin;
}
@ -92,7 +92,7 @@ public class BasePluginTestService {
return serviceIntegration;
}
public Plugin getJiraPlugin() throws Exception {
public synchronized Plugin getJiraPlugin() throws Exception {
if (!hasJiraPlugin()) {
return this.addJiraPlugin();
}
@ -107,7 +107,7 @@ public class BasePluginTestService {
return jiraPlugin != null;
}
public void deleteJiraPlugin() {
public synchronized void deleteJiraPlugin() {
if (jiraPlugin != null) {
pluginService.delete(jiraPlugin.getId());
jiraPlugin = null;