feat(接口测试): 处理执行时引用公共脚本

This commit is contained in:
AgAngle 2024-02-23 14:44:38 +08:00 committed by Craftsman
parent 03fde1b4a3
commit 7a453643ad
24 changed files with 445 additions and 84 deletions

View File

@ -0,0 +1,42 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.request.MsCommonElement;
import io.metersphere.api.dto.request.http.MsHTTPElement;
import lombok.Data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 执行场景解析参数时的临时参数
*
* @Author: jianxing
* @CreateTime: 2024-02-22 11:27
*/
@Data
public class ApiScenarioParseParam {
/**
* 步骤详情 Map
* key 为步骤ID
* value 为步骤详情字符串
*/
private Map<String, String> stepDetailMap;
/**
* 资源的请求内容 Map
* key 为资源ID
* value 为请求详情字符串
*/
private Map<String, String> resourceDetailMap;
/**
* MsHTTPElement Map
* key stepType
* value MsHTTPElement
*/
private Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = new HashMap<>();
/**
* 场景中所有的 MsCommonElement 列表
*/
private List<MsCommonElement> commonElements = new ArrayList<>();
}

View File

@ -16,6 +16,7 @@ import org.apache.jorphan.collections.HashTree;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.USER_PARAMETERS_GUI; import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.USER_PARAMETERS_GUI;
@ -53,6 +54,9 @@ public class MsCommentScriptElementConverter extends AbstractJmeterElementConver
scriptElement = new BeanShellSampler(); scriptElement = new BeanShellSampler();
} }
ScriptProcessorConverter.parse(scriptElement, scriptProcessor); ScriptProcessorConverter.parse(scriptElement, scriptProcessor);
// 添加公共脚本的参数
Optional.ofNullable(ScriptProcessorConverter.getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add);
hashTree.add(scriptElement); hashTree.add(scriptElement);
} }

View File

@ -20,4 +20,5 @@ public class JmeterAlias {
public static final String COOKIE_PANEL = "CookiePanel"; public static final String COOKIE_PANEL = "CookiePanel";
public static final String HEADER_PANEL = "HeaderPanel"; public static final String HEADER_PANEL = "HeaderPanel";
public static final String AUTH_PANEL = "AuthPanel"; public static final String AUTH_PANEL = "AuthPanel";
public static final String ARGUMENTS_PANEL = "ArgumentsPanel";
} }

View File

@ -8,6 +8,8 @@ import org.apache.jmeter.protocol.java.sampler.JSR223Sampler;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.Optional;
/** /**
* 环境场景级前置处理器处理 * 环境场景级前置处理器处理
* *
@ -31,6 +33,11 @@ public class ScenarioScriptProcessorConverter extends ScriptProcessorConverter {
} }
parse(processor, scriptProcessor); parse(processor, scriptProcessor);
// 添加公共脚本的参数
Optional.ofNullable(getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add);
// 标记当前处理器是否关联场景结果 // 标记当前处理器是否关联场景结果
processor.setName("ASSOCIATE_RESULT_PROCESSOR_" + associateScenarioResult); processor.setName("ASSOCIATE_RESULT_PROCESSOR_" + associateScenarioResult);
hashTree.add(processor); hashTree.add(processor);

View File

@ -7,6 +7,8 @@ import org.apache.jmeter.extractor.JSR223PostProcessor;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.Optional;
/** /**
* @Author: jianxing * @Author: jianxing
* @CreateTime: 2023-12-26 14:49 * @CreateTime: 2023-12-26 14:49
@ -17,7 +19,6 @@ public class ScriptPostProcessorConverter extends ScriptProcessorConverter {
if (!needParse(scriptProcessor, config) || !scriptProcessor.isValid()) { if (!needParse(scriptProcessor, config) || !scriptProcessor.isValid()) {
return; return;
} }
// todo 处理公共脚本
TestElement processor; TestElement processor;
if (isJSR233(scriptProcessor)) { if (isJSR233(scriptProcessor)) {
processor = new JSR223PostProcessor(); processor = new JSR223PostProcessor();
@ -25,6 +26,11 @@ public class ScriptPostProcessorConverter extends ScriptProcessorConverter {
processor = new BeanShellPostProcessor(); processor = new BeanShellPostProcessor();
} }
parse(processor, scriptProcessor); parse(processor, scriptProcessor);
// 添加公共脚本的参数
Optional.ofNullable(getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add);
hashTree.add(processor); hashTree.add(processor);
} }
} }

View File

@ -1,12 +1,14 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.processor.ScriptProcessor;
import org.apache.jmeter.modifiers.BeanShellPreProcessor; import org.apache.jmeter.modifiers.BeanShellPreProcessor;
import org.apache.jmeter.modifiers.JSR223PreProcessor; import org.apache.jmeter.modifiers.JSR223PreProcessor;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.Optional;
/** /**
* @Author: jianxing * @Author: jianxing
* @CreateTime: 2023-12-26 14:49 * @CreateTime: 2023-12-26 14:49
@ -17,7 +19,6 @@ public class ScriptPreProcessorConverter extends ScriptProcessorConverter {
if (!needParse(scriptProcessor, config) || !scriptProcessor.isValid()) { if (!needParse(scriptProcessor, config) || !scriptProcessor.isValid()) {
return; return;
} }
// todo 处理公共脚本
TestElement processor; TestElement processor;
if (isJSR233(scriptProcessor)) { if (isJSR233(scriptProcessor)) {
processor = new JSR223PreProcessor(); processor = new JSR223PreProcessor();
@ -25,6 +26,11 @@ public class ScriptPreProcessorConverter extends ScriptProcessorConverter {
processor = new BeanShellPreProcessor(); processor = new BeanShellPreProcessor();
} }
parse(processor, scriptProcessor); parse(processor, scriptProcessor);
// 添加公共脚本的参数
Optional.ofNullable(getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add);
hashTree.add(processor); hashTree.add(processor);
} }
} }

View File

@ -1,14 +1,22 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.plugin.api.constants.ElementProperty;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.api.parser.jmeter.constants.JmeterAlias; import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
import io.metersphere.api.parser.jmeter.constants.JmeterProperty; import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
import io.metersphere.plugin.api.constants.ElementProperty;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.CommonScriptInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import java.util.List;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.ARGUMENTS_PANEL;
/** /**
* @Author: jianxing * @Author: jianxing
@ -38,9 +46,48 @@ public abstract class ScriptProcessorConverter extends MsProcessorConverter<Scri
testElement.setProperty(JmeterProperty.CACHE_KEY, cacheKey); testElement.setProperty(JmeterProperty.CACHE_KEY, cacheKey);
testElement.setProperty(TestElement.TEST_CLASS, testElement.getClass().getSimpleName()); testElement.setProperty(TestElement.TEST_CLASS, testElement.getClass().getSimpleName());
testElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(JmeterAlias.TEST_BEAN_GUI)); testElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(JmeterAlias.TEST_BEAN_GUI));
testElement.setProperty(JmeterProperty.SCRIPT_LANGUAGE, scriptProcessor.getScriptLanguage());
testElement.setProperty(JmeterProperty.SCRIPT, scriptProcessor.getScript());
testElement.setProperty(ElementProperty.PROJECT_ID.name(), scriptProcessor.getProjectId()); testElement.setProperty(ElementProperty.PROJECT_ID.name(), scriptProcessor.getProjectId());
String scriptLanguage = scriptProcessor.getScriptLanguage();
String script = scriptProcessor.getScript();
if (scriptProcessor.isEnableCommonScript()) {
scriptLanguage = scriptProcessor.getCommonScriptInfo().getScriptLanguage();
script = scriptProcessor.getCommonScriptInfo().getScript();
}
if (scriptLanguage == null) {
scriptLanguage = ScriptLanguageType.BEANSHELL.name();
}
testElement.setProperty(JmeterProperty.SCRIPT, script);
testElement.setProperty(JmeterProperty.SCRIPT_LANGUAGE, scriptLanguage.toLowerCase());
}
public static Arguments getScriptArguments(ScriptProcessor scriptProcessor) {
if (scriptProcessor == null || !scriptProcessor.isEnableCommonScript() || !scriptProcessor.isValid()) {
return null;
}
CommonScriptInfo commonScriptInfo = scriptProcessor.getCommonScriptInfo();
if (CollectionUtils.isEmpty(commonScriptInfo.getParams())) {
return null;
}
List<KeyValueParam> params = commonScriptInfo.getParams()
.stream()
.filter(KeyValueParam::isValid)
.toList();
if (CollectionUtils.isEmpty(commonScriptInfo.getParams())) {
return null;
}
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(scriptProcessor.getName() + "_Arguments");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(ARGUMENTS_PANEL));
for (KeyValueParam param : params) {
arguments.addArgument(param.getKey(), param.getValue(), "=");
}
return arguments;
} }
public static boolean isJSR233(ScriptProcessor scriptProcessor) { public static boolean isJSR233(ScriptProcessor scriptProcessor) {

View File

@ -1,14 +1,15 @@
package io.metersphere.api.parser.jmeter.processor.assertion; package io.metersphere.api.parser.jmeter.processor.assertion;
import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter; import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.assertions.JSR223Assertion; import org.apache.jmeter.assertions.JSR223Assertion;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.Optional;
/** /**
* @Author: jianxing * @Author: jianxing
* @CreateTime: 2023-12-27 21:01 * @CreateTime: 2023-12-27 21:01
@ -16,17 +17,18 @@ import org.apache.jorphan.collections.HashTree;
public class ScriptAssertionConverter extends AssertionConverter<MsScriptAssertion> { public class ScriptAssertionConverter extends AssertionConverter<MsScriptAssertion> {
@Override @Override
public void parse(HashTree hashTree, MsScriptAssertion msAssertion, ParameterConfig config, boolean isIgnoreStatus) { public void parse(HashTree hashTree, MsScriptAssertion msAssertion, ParameterConfig config, boolean isIgnoreStatus) {
if (!needParse(msAssertion, config) || !isValid(msAssertion)) { if (!needParse(msAssertion, config) || !msAssertion.isValid()) {
return; return;
} }
JSR223Assertion jsr223Assertion = new JSR223Assertion(); JSR223Assertion jsr223Assertion = new JSR223Assertion();
ScriptProcessorConverter.parse(jsr223Assertion, BeanUtils.copyBean(new ScriptProcessor(), msAssertion)); ScriptProcessor scriptProcessor = BeanUtils.copyBean(new ScriptProcessor(), msAssertion);
ScriptProcessorConverter.parse(jsr223Assertion, scriptProcessor);
// 添加公共脚本的参数
Optional.ofNullable(ScriptProcessorConverter.getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add);
hashTree.add(jsr223Assertion); hashTree.add(jsr223Assertion);
} }
public boolean isValid(MsScriptAssertion msAssertion) {
// todo 公共脚本库
return StringUtils.isNotBlank(msAssertion.getScript());
}
} }

View File

@ -3,16 +3,25 @@ package io.metersphere.api.service;
import io.metersphere.api.dto.ApiFile; import io.metersphere.api.dto.ApiFile;
import io.metersphere.api.dto.definition.ResponseBinaryBody; import io.metersphere.api.dto.definition.ResponseBinaryBody;
import io.metersphere.api.dto.definition.ResponseBody; import io.metersphere.api.dto.definition.ResponseBody;
import io.metersphere.api.dto.request.MsCommonElement;
import io.metersphere.api.dto.request.http.MsHTTPElement; import io.metersphere.api.dto.request.http.MsHTTPElement;
import io.metersphere.api.dto.request.http.body.BinaryBody; import io.metersphere.api.dto.request.http.body.BinaryBody;
import io.metersphere.api.dto.request.http.body.Body; import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.dto.request.http.body.FormDataBody; import io.metersphere.api.dto.request.http.body.FormDataBody;
import io.metersphere.api.dto.request.http.body.FormDataKV; import io.metersphere.api.dto.request.http.body.FormDataKV;
import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.api.processor.MsProcessor;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.project.domain.CustomFunction;
import io.metersphere.project.domain.CustomFunctionBlob;
import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.FileAssociation;
import io.metersphere.project.domain.FileMetadata; import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.project.service.CustomFunctionService;
import io.metersphere.project.service.FileAssociationService; import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService; import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.util.JSON;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -22,6 +31,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -35,8 +46,12 @@ public class ApiCommonService {
private FileAssociationService fileAssociationService; private FileAssociationService fileAssociationService;
@Resource @Resource
private FileMetadataService fileMetadataService; private FileMetadataService fileMetadataService;
@Resource
private CustomFunctionService customFunctionService;
/** /**
* 根据 fileId 查找 MsHTTPElement 中的 ApiFile * 根据 fileId 查找 MsHTTPElement 中的 ApiFile
*
* @param fileId * @param fileId
* @param msTestElement * @param msTestElement
* @return * @return
@ -63,24 +78,26 @@ public class ApiCommonService {
/** /**
* 设置关联的文件的最新信息 * 设置关联的文件的最新信息
* 包括文件别名和是否被删除 * 包括文件别名和是否被删除
*
* @param resourceId * @param resourceId
* @param msTestElement * @param msTestElement
*/ */
public void updateLinkFileInfo(String resourceId, AbstractMsTestElement msTestElement) { public void setLinkFileInfo(String resourceId, AbstractMsTestElement msTestElement) {
updateLinkFileInfo(resourceId, getApiFiles(msTestElement)); setLinkFileInfo(resourceId, getApiFiles(msTestElement));
} }
/** /**
* 设置关联的文件的最新信息 * 设置关联的文件的最新信息
* 包括文件别名和是否被删除 * 包括文件别名和是否被删除
*
* @param resourceId * @param resourceId
* @param responseBody * @param responseBody
*/ */
public void updateLinkFileInfo(String resourceId, ResponseBody responseBody) { public void setLinkFileInfo(String resourceId, ResponseBody responseBody) {
updateLinkFileInfo(resourceId, getApiBodyFiles(responseBody)); setLinkFileInfo(resourceId, getApiBodyFiles(responseBody));
} }
private void updateLinkFileInfo(String resourceId, List<ApiFile> apiFiles) { private void setLinkFileInfo(String resourceId, List<ApiFile> apiFiles) {
List<ApiFile> linkFiles = apiFiles.stream() List<ApiFile> linkFiles = apiFiles.stream()
.filter(file -> !file.getLocal() && !file.getDelete()) .filter(file -> !file.getLocal() && !file.getDelete())
.toList(); .toList();
@ -114,7 +131,6 @@ public class ApiCommonService {
/** /**
*
* @param body * @param body
* @return * @return
*/ */
@ -155,8 +171,96 @@ public class ApiCommonService {
public void replaceApiFileInfo(List<ApiFile> updateFiles, FileMetadata newFileMetadata) { public void replaceApiFileInfo(List<ApiFile> updateFiles, FileMetadata newFileMetadata) {
for (ApiFile updateFile : updateFiles) { for (ApiFile updateFile : updateFiles) {
updateFile.setFileId(newFileMetadata.getId()); updateFile.setFileId(newFileMetadata.getId());
// todo 重新设置文件名 updateFile.setFileName(newFileMetadata.getOriginalName());
// updateFile.setFileName();
} }
} }
/**
* 设置使用脚本前后置的公共脚本信息
* @param msTestElement
*/
public void setEnableCommonScriptProcessorInfo(AbstractMsTestElement msTestElement) {
MsCommonElement msCommonElement = getMsCommonElement(msTestElement);
Optional.ofNullable(msCommonElement).ifPresent(item -> setEnableCommonScriptProcessorInfo(List.of(item)));
}
/**
* 设置使用脚本前后置的公共脚本信息
*
* @param commonElements
*/
public void setEnableCommonScriptProcessorInfo(List<MsCommonElement> commonElements) {
List<ScriptProcessor> scriptsProcessors = getEnableCommonScriptProcessors(commonElements);
List<String> commonScriptIds = scriptsProcessors.stream()
.map(processor -> processor.getCommonScriptInfo().getId())
.toList();
Map<String, CustomFunctionBlob> customFunctionBlobMap = customFunctionService.getBlobByIds(commonScriptIds).stream()
.collect(Collectors.toMap(CustomFunctionBlob::getId, Function.identity()));
Map<String, CustomFunction> customFunctionMap = customFunctionService.getByIds(commonScriptIds).stream()
.collect(Collectors.toMap(CustomFunction::getId, Function.identity()));
for (ScriptProcessor processor : scriptsProcessors) {
CommonScriptInfo commonScriptInfo = processor.getCommonScriptInfo();
CustomFunctionBlob customFunctionBlob = customFunctionBlobMap.get(commonScriptInfo.getId());
CustomFunction customFunction = customFunctionMap.get(commonScriptInfo.getId());
// 设置公共脚本信息
Optional.ofNullable(customFunctionBlob.getParams()).ifPresent(paramsBlob -> {
List<KeyValueParam> commonParams = JSON.parseArray(new String(paramsBlob), KeyValueParam.class);
// 替换用户输入值
commonParams.forEach(commonParam ->
Optional.ofNullable(commonScriptInfo.getParams()).ifPresent(params ->
params.stream()
.filter(param -> StringUtils.equals(commonParam.getKey(), param.getKey()))
.findFirst()
.ifPresent(param -> commonParam.setValue(param.getValue()))
)
);
commonScriptInfo.setParams(commonParams);
});
Optional.ofNullable(customFunctionBlob.getScript()).ifPresent(script ->
commonScriptInfo.setScript(new String(script)));
commonScriptInfo.setScriptLanguage(customFunction.getType());
commonScriptInfo.setName(customFunction.getName());
}
}
/**
* 获取使用公共脚本的前后置
*
* @param commonElements
* @return
*/
private List<ScriptProcessor> getEnableCommonScriptProcessors(List<MsCommonElement> commonElements) {
List<MsProcessor> processors = new ArrayList<>();
for (MsCommonElement commonElement : commonElements) {
processors.addAll(commonElement.getPreProcessorConfig().getProcessors());
processors.addAll(commonElement.getPostProcessorConfig().getProcessors());
}
// 获取使用公共脚本的前后置
List<ScriptProcessor> scriptsProcessors = processors.stream()
.filter(processor -> processor instanceof ScriptProcessor)
.map(processor -> (ScriptProcessor) processor)
.filter(ScriptProcessor::getEnable)
.filter(ScriptProcessor::isEnableCommonScript)
.filter(ScriptProcessor::isValid)
.collect(Collectors.toList());
return scriptsProcessors;
}
public MsCommonElement getMsCommonElement(AbstractMsTestElement msTestElement) {
if (CollectionUtils.isNotEmpty(msTestElement.getChildren())) {
for (AbstractMsTestElement child : msTestElement.getChildren()) {
if (child instanceof MsCommonElement msCommonElement) {
return msCommonElement;
}
}
}
return null;
}
} }

View File

@ -132,9 +132,6 @@ public class ApiExecuteService {
parameterConfig.setGlobalParams(getGlobalParam(request)); parameterConfig.setGlobalParams(getGlobalParam(request));
// todo 获取接口插件和jar包
// todo 处理公共脚本
// todo 接口用例 method 获取定义中的数据库字段
String executeScript = parseExecuteScript(request.getTestElement(), parameterConfig); String executeScript = parseExecuteScript(request.getTestElement(), parameterConfig);
doDebug(reportId, testId, taskRequest, executeScript, request.getProjectId()); doDebug(reportId, testId, taskRequest, executeScript, request.getProjectId());
@ -318,7 +315,7 @@ public class ApiExecuteService {
List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskRequest.getProjectId())); List<FileMetadata> fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskRequest.getProjectId()));
taskRequest.setFuncJars(fileMetadataList.stream() taskRequest.setFuncJars(fileMetadataList.stream()
.map(file -> { .map(file -> {
String fileName = file.getName() + "." + file.getType(); String fileName = file.getOriginalName();
ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), fileName, file.getProjectId(), file.getStorage()); ApiExecuteFileInfo tempFileInfo = getApiExecuteFileInfo(file.getId(), fileName, file.getProjectId(), file.getStorage());
if (StorageType.isGit(file.getStorage())) { if (StorageType.isGit(file.getStorage())) {
// 设置Git信息 // 设置Git信息

View File

@ -78,7 +78,8 @@ public class ApiDebugService {
ApiDebugDTO apiDebugDTO = new ApiDebugDTO(); ApiDebugDTO apiDebugDTO = new ApiDebugDTO();
BeanUtils.copyBean(apiDebugDTO, apiDebug); BeanUtils.copyBean(apiDebugDTO, apiDebug);
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDebugBlob.getRequest()), AbstractMsTestElement.class); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDebugBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.updateLinkFileInfo(id, msTestElement); apiCommonService.setLinkFileInfo(id, msTestElement);
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
apiDebugDTO.setRequest(msTestElement); apiDebugDTO.setRequest(msTestElement);
apiDebugDTO.setResponse(apiDebugDTO.getResponse()); apiDebugDTO.setResponse(apiDebugDTO.getResponse());
return apiDebugDTO; return apiDebugDTO;
@ -218,6 +219,10 @@ public class ApiDebugService {
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
paramConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap()); paramConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap());
paramConfig.setReportId(reportId); paramConfig.setReportId(reportId);
// 设置使用脚本前后置的公共脚本信息
apiCommonService.setEnableCommonScriptProcessorInfo(runRequest.getTestElement());
apiExecuteService.debug(runRequest, paramConfig); apiExecuteService.debug(runRequest, paramConfig);
return runRequest.getReportId(); return runRequest.getReportId();
} }

View File

@ -872,13 +872,14 @@ public class ApiDefinitionService {
Optional<ApiDefinitionBlob> apiDefinitionBlobOptional = Optional.ofNullable(apiDefinitionBlobMapper.selectByPrimaryKey(id)); Optional<ApiDefinitionBlob> apiDefinitionBlobOptional = Optional.ofNullable(apiDefinitionBlobMapper.selectByPrimaryKey(id));
apiDefinitionBlobOptional.ifPresent(blob -> { apiDefinitionBlobOptional.ifPresent(blob -> {
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class);
apiCommonService.updateLinkFileInfo(id, msTestElement); apiCommonService.setLinkFileInfo(id, msTestElement);
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
apiDefinitionDTO.setRequest(msTestElement); apiDefinitionDTO.setRequest(msTestElement);
// blob.getResponse() null 时不进行转换 // blob.getResponse() null 时不进行转换
if (blob.getResponse() != null) { if (blob.getResponse() != null) {
List<HttpResponse> httpResponses = ApiDataUtils.parseArray(new String(blob.getResponse()), HttpResponse.class); List<HttpResponse> httpResponses = ApiDataUtils.parseArray(new String(blob.getResponse()), HttpResponse.class);
for (HttpResponse httpResponse : httpResponses) { for (HttpResponse httpResponse : httpResponses) {
apiCommonService.updateLinkFileInfo(id, httpResponse.getBody()); apiCommonService.setLinkFileInfo(id, httpResponse.getBody());
} }
apiDefinitionDTO.setResponse(httpResponses); apiDefinitionDTO.setResponse(httpResponses);
} }

View File

@ -210,7 +210,10 @@ public class ApiTestCaseService {
example.createCriteria().andCaseIdEqualTo(id).andUserIdEqualTo(userId); example.createCriteria().andCaseIdEqualTo(id).andUserIdEqualTo(userId);
List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example); List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example);
apiTestCaseDTO.setFollow(CollectionUtils.isNotEmpty(followers)); apiTestCaseDTO.setFollow(CollectionUtils.isNotEmpty(followers));
apiTestCaseDTO.setRequest(ApiDataUtils.parseObject(new String(testCaseBlob.getRequest()), AbstractMsTestElement.class)); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(testCaseBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(id, msTestElement);
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
apiTestCaseDTO.setRequest(msTestElement);
return apiTestCaseDTO; return apiTestCaseDTO;
} }

View File

@ -1054,11 +1054,11 @@ public class ApiScenarioService {
Map<String, List<String>> refResourceMap = new HashMap<>(); Map<String, List<String>> refResourceMap = new HashMap<>();
buildRefResourceIdMap(steps, refResourceMap); buildRefResourceIdMap(steps, refResourceMap);
ApiScenarioParseParam parseParam = new ApiScenarioParseParam();
// 查询引用的资源详情 // 查询引用的资源详情
Map<String, String> resourceBlobMap = getResourceBlobMap(refResourceMap); parseParam.setResourceDetailMap(getResourceDetailMap(refResourceMap));
// 查询复制的步骤详情 // 查询复制的步骤详情
Map<String, String> detailMap = getStepDetailMap(steps, request.getStepDetails()); parseParam.setStepDetailMap(getStepDetailMap(steps, request.getStepDetails()));
// 解析生成待执行的场景树 // 解析生成待执行的场景树
MsScenario msScenario = new MsScenario(); MsScenario msScenario = new MsScenario();
@ -1068,10 +1068,11 @@ public class ApiScenarioService {
// 获取场景环境相关配置 // 获取场景环境相关配置
ApiScenarioParseEnvInfo scenarioParseEnvInfo = getScenarioParseEnvInfo(refResourceMap, request.getEnvironmentId(), request.getGrouped()); ApiScenarioParseEnvInfo scenarioParseEnvInfo = getScenarioParseEnvInfo(refResourceMap, request.getEnvironmentId(), request.getGrouped());
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = new HashMap<>(); parseStep2MsElement(msScenario, steps, parseParam, scenarioParseEnvInfo);
parseStep2MsElement(msScenario, steps, resourceBlobMap, detailMap, stepTypeHttpElementMap, scenarioParseEnvInfo);
// 设置 HttpElement 的模块信息 // 设置 HttpElement 的模块信息
setHttpElementModuleId(stepTypeHttpElementMap); setHttpElementModuleId(parseParam.getStepTypeHttpElementMap());
// 设置使用脚本前后置的公共脚本信息
apiCommonService.setEnableCommonScriptProcessorInfo(parseParam.getCommonElements());
ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request); ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request);
runRequest.setProjectId(request.getProjectId()); runRequest.setProjectId(request.getProjectId());
@ -1230,13 +1231,15 @@ public class ApiScenarioService {
*/ */
private void parseStep2MsElement(AbstractMsTestElement parentElement, private void parseStep2MsElement(AbstractMsTestElement parentElement,
List<? extends ApiScenarioStepCommonDTO> steps, List<? extends ApiScenarioStepCommonDTO> steps,
Map<String, String> resourceBlobMap, ApiScenarioParseParam parseParam,
Map<String, String> stepDetailMap,
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap,
ApiScenarioParseEnvInfo scenarioParseEnvInfo) { ApiScenarioParseEnvInfo scenarioParseEnvInfo) {
if (CollectionUtils.isNotEmpty(steps)) { if (CollectionUtils.isNotEmpty(steps)) {
parentElement.setChildren(new LinkedList<>()); parentElement.setChildren(new LinkedList<>());
} }
Map<String, String> stepDetailMap = parseParam.getStepDetailMap();
Map<String, String> resourceDetailMap = parseParam.getResourceDetailMap();
Map<String, List<MsHTTPElement>> stepTypeHttpElementMap = parseParam.getStepTypeHttpElementMap();
for (ApiScenarioStepCommonDTO step : steps) { for (ApiScenarioStepCommonDTO step : steps) {
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType()); StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
if (BooleanUtils.isFalse(step.getEnable())) { if (BooleanUtils.isFalse(step.getEnable())) {
@ -1245,7 +1248,7 @@ public class ApiScenarioService {
setPartialRefStepEnable(step, stepDetailMap); setPartialRefStepEnable(step, stepDetailMap);
// 将步骤详情解析生成对应的MsTestElement // 将步骤详情解析生成对应的MsTestElement
AbstractMsTestElement msTestElement = stepParser.parseTestElement(step, resourceBlobMap.get(step.getResourceId()), stepDetailMap.get(step.getId())); AbstractMsTestElement msTestElement = stepParser.parseTestElement(step, resourceDetailMap.get(step.getResourceId()), stepDetailMap.get(step.getId()));
if (msTestElement != null) { if (msTestElement != null) {
if (msTestElement instanceof MsHTTPElement msHTTPElement) { if (msTestElement instanceof MsHTTPElement msHTTPElement) {
// 暂存http类型的步骤 // 暂存http类型的步骤
@ -1255,11 +1258,13 @@ public class ApiScenarioService {
msTestElement.setProjectId(step.getProjectId()); msTestElement.setProjectId(step.getProjectId());
msTestElement.setResourceId(step.getResourceId()); msTestElement.setResourceId(step.getResourceId());
setMsScenarioParam(scenarioParseEnvInfo, step, msTestElement); setMsScenarioParam(scenarioParseEnvInfo, step, msTestElement);
// 记录 msCommonElement
Optional.ofNullable(apiCommonService.getMsCommonElement(msTestElement))
.ifPresent(msCommonElement -> parseParam.getCommonElements().add(msCommonElement));
parentElement.getChildren().add(msTestElement); parentElement.getChildren().add(msTestElement);
} }
if (CollectionUtils.isNotEmpty(step.getChildren())) { if (CollectionUtils.isNotEmpty(step.getChildren())) {
parseStep2MsElement(msTestElement, step.getChildren(), resourceBlobMap, parseStep2MsElement(msTestElement, step.getChildren(), parseParam, scenarioParseEnvInfo);
stepDetailMap, stepTypeHttpElementMap, scenarioParseEnvInfo);
} }
} }
} }
@ -1383,7 +1388,7 @@ public class ApiScenarioService {
return stepDetails; return stepDetails;
} }
private Map<String, String> getResourceBlobMap(Map<String, List<String>> refResourceMap) { private Map<String, String> getResourceDetailMap(Map<String, List<String>> refResourceMap) {
Map<String, String> resourceBlobMap = new HashMap<>(); Map<String, String> resourceBlobMap = new HashMap<>();
List<String> apiIds = refResourceMap.get(ApiScenarioStepType.API.name()); List<String> apiIds = refResourceMap.get(ApiScenarioStepType.API.name());
List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionService.getBlobByIds(apiIds); List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionService.getBlobByIds(apiIds);
@ -1645,13 +1650,14 @@ public class ApiScenarioService {
} }
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType()); StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
Object stepDetail = stepParser.parseDetail(step); Object stepDetail = stepParser.parseDetail(step);
if (stepDetail instanceof MsHTTPElement msHTTPElement) { if (stepDetail instanceof AbstractMsTestElement msTestElement) {
// 设置关联的文件的最新信息 // 设置关联的文件的最新信息
if (isRef(step.getRefType())) { if (isRef(step.getRefType())) {
apiCommonService.updateLinkFileInfo(step.getResourceId(), msHTTPElement); apiCommonService.setLinkFileInfo(step.getResourceId(), msTestElement);
} else { } else {
apiCommonService.updateLinkFileInfo(step.getScenarioId(), msHTTPElement); apiCommonService.setLinkFileInfo(step.getScenarioId(), msTestElement);
} }
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
} }
return stepDetail; return stepDetail;
} }

View File

@ -28,10 +28,18 @@ import io.metersphere.api.service.BaseFileManagementTestService;
import io.metersphere.api.service.BaseResourcePoolTestService; import io.metersphere.api.service.BaseResourcePoolTestService;
import io.metersphere.api.utils.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.api.KeyValueEnableParam;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.domain.CustomFunction;
import io.metersphere.project.domain.ProjectTestResourcePool; import io.metersphere.project.domain.ProjectTestResourcePool;
import io.metersphere.project.domain.ProjectTestResourcePoolExample; import io.metersphere.project.domain.ProjectTestResourcePoolExample;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.project.dto.customfunction.request.CustomFunctionRequest;
import io.metersphere.project.dto.filemanagement.FileInfo; import io.metersphere.project.dto.filemanagement.FileInfo;
import io.metersphere.project.mapper.ProjectTestResourcePoolMapper; import io.metersphere.project.mapper.ProjectTestResourcePoolMapper;
import io.metersphere.project.service.CustomFunctionService;
import io.metersphere.project.service.FileAssociationService; import io.metersphere.project.service.FileAssociationService;
import io.metersphere.sdk.constants.DefaultRepositoryDir; import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
@ -93,6 +101,8 @@ public class ApiDebugControllerTests extends BaseTest {
private ProjectTestResourcePoolMapper projectTestResourcePoolMapper; private ProjectTestResourcePoolMapper projectTestResourcePoolMapper;
@Resource @Resource
private TestResourcePoolMapper testResourcePoolMapper; private TestResourcePoolMapper testResourcePoolMapper;
@Resource
private CustomFunctionService customFunctionService;
private static ApiDebug addApiDebug; private static ApiDebug addApiDebug;
private static ApiDebug anotherAddApiDebug; private static ApiDebug anotherAddApiDebug;
private static String fileMetadataId; private static String fileMetadataId;
@ -363,7 +373,7 @@ public class ApiDebugControllerTests extends BaseTest {
ApiDebugDTO copyApiDebugDTO = BeanUtils.copyBean(new ApiDebugDTO(), apiDebugMapper.selectByPrimaryKey(addApiDebug.getId())); ApiDebugDTO copyApiDebugDTO = BeanUtils.copyBean(new ApiDebugDTO(), apiDebugMapper.selectByPrimaryKey(addApiDebug.getId()));
ApiDebugBlob apiDebugBlob = apiDebugBlobMapper.selectByPrimaryKey(addApiDebug.getId()); ApiDebugBlob apiDebugBlob = apiDebugBlobMapper.selectByPrimaryKey(addApiDebug.getId());
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDebugBlob.getRequest()), AbstractMsTestElement.class); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDebugBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.updateLinkFileInfo(addApiDebug.getId(), msTestElement); apiCommonService.setLinkFileInfo(addApiDebug.getId(), msTestElement);
copyApiDebugDTO.setRequest(msTestElement); copyApiDebugDTO.setRequest(msTestElement);
Assertions.assertEquals(apiDebugDTO, copyApiDebugDTO); Assertions.assertEquals(apiDebugDTO, copyApiDebugDTO);
@ -477,6 +487,22 @@ public class ApiDebugControllerTests extends BaseTest {
msAssertionConfig.setAssertions(MsHTTPElementTest.getGeneralXmlAssertions()); msAssertionConfig.setAssertions(MsHTTPElementTest.getGeneralXmlAssertions());
msCommonElement = new MsCommonElement(); msCommonElement = new MsCommonElement();
msCommonElement.setAssertionConfig(msAssertionConfig); msCommonElement.setAssertionConfig(msAssertionConfig);
// 测试公共脚本
ScriptProcessor scriptProcessor = new ScriptProcessor();
scriptProcessor.setEnable(true);
scriptProcessor.setName("test");
scriptProcessor.setScriptLanguage(ScriptLanguageType.JAVASCRIPT.name());
CustomFunction customFunction = addCustomFunction();
scriptProcessor.setCommonScriptInfo(new CommonScriptInfo());
scriptProcessor.getCommonScriptInfo().setId(customFunction.getId());
scriptProcessor.setEnableCommonScript(true);
KeyValueParam keyValueParam = new KeyValueParam();
keyValueParam.setKey("a");
keyValueParam.setValue("bb");
scriptProcessor.getCommonScriptInfo().setParams(List.of(keyValueParam));
msCommonElement.getPostProcessorConfig().getProcessors().add(scriptProcessor);
linkedList = new LinkedList(); linkedList = new LinkedList();
linkedList.add(msCommonElement); linkedList.add(msCommonElement);
msHTTPElement = MsHTTPElementTest.getMsHttpElement(); msHTTPElement = MsHTTPElementTest.getMsHttpElement();
@ -485,7 +511,6 @@ public class ApiDebugControllerTests extends BaseTest {
request.setRequest(getMsElementParam(msHTTPElement)); request.setRequest(getMsElementParam(msHTTPElement));
this.requestPostWithOk(DEBUG, request); this.requestPostWithOk(DEBUG, request);
// 测试请求体 // 测试请求体
MockMultipartFile file = getMockMultipartFile(); MockMultipartFile file = getMockMultipartFile();
String fileId = doUploadTempFile(file); String fileId = doUploadTempFile(file);
@ -513,6 +538,19 @@ public class ApiDebugControllerTests extends BaseTest {
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_EXECUTE, DEBUG, request); requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_EXECUTE, DEBUG, request);
} }
private CustomFunction addCustomFunction() {
CustomFunctionRequest request = new CustomFunctionRequest();
request.setScript("aaa");
KeyValueEnableParam keyValueEnableParam = new KeyValueEnableParam();
keyValueEnableParam.setKey("a");
keyValueEnableParam.setValue("b");
request.setParams(JSON.toJSONString(keyValueEnableParam));
request.setProjectId(DEFAULT_PROJECT_ID);
request.setType(ScriptLanguageType.BEANSHELL.name());
request.setName(IDGenerator.nextStr());
return customFunctionService.add(request, "admin");
}
/** /**
* 测试关联的文件更新 * 测试关联的文件更新
* *

View File

@ -348,11 +348,11 @@ public class ApiDefinitionControllerTests extends BaseTest {
} }
if (apiDefinitionBlob != null) { if (apiDefinitionBlob != null) {
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiDefinitionBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.updateLinkFileInfo(apiDefinition.getId(), msTestElement); apiCommonService.setLinkFileInfo(apiDefinition.getId(), msTestElement);
copyApiDefinitionDTO.setRequest(msTestElement); copyApiDefinitionDTO.setRequest(msTestElement);
List<HttpResponse> httpResponses = ApiDataUtils.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class); List<HttpResponse> httpResponses = ApiDataUtils.parseArray(new String(apiDefinitionBlob.getResponse()), HttpResponse.class);
for (HttpResponse httpResponse : httpResponses) { for (HttpResponse httpResponse : httpResponses) {
apiCommonService.updateLinkFileInfo(apiDefinition.getId(), httpResponse.getBody()); apiCommonService.setLinkFileInfo(apiDefinition.getId(), httpResponse.getBody());
} }
copyApiDefinitionDTO.setResponse(httpResponses); copyApiDefinitionDTO.setResponse(httpResponses);
} }

View File

@ -415,12 +415,14 @@ public class ApiTestCaseControllerTests extends BaseTest {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId()); ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
copyApiDebugDTO.setMethod(apiDefinition.getMethod()); copyApiDebugDTO.setMethod(apiDefinition.getMethod());
copyApiDebugDTO.setPath(apiDefinition.getPath()); copyApiDebugDTO.setPath(apiDefinition.getPath());
ApiTestCaseBlob apiDebugBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId()); ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId());
ApiTestCaseFollowerExample example = new ApiTestCaseFollowerExample(); ApiTestCaseFollowerExample example = new ApiTestCaseFollowerExample();
example.createCriteria().andCaseIdEqualTo(apiTestCase.getId()).andUserIdEqualTo("admin"); example.createCriteria().andCaseIdEqualTo(apiTestCase.getId()).andUserIdEqualTo("admin");
List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example); List<ApiTestCaseFollower> followers = apiTestCaseFollowerMapper.selectByExample(example);
copyApiDebugDTO.setFollow(CollectionUtils.isNotEmpty(followers)); copyApiDebugDTO.setFollow(CollectionUtils.isNotEmpty(followers));
copyApiDebugDTO.setRequest(ApiDataUtils.parseObject(new String(apiDebugBlob.getRequest()), AbstractMsTestElement.class)); AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class);
apiCommonService.setLinkFileInfo(apiTestCase.getId(), msTestElement);
copyApiDebugDTO.setRequest(msTestElement);
Assertions.assertEquals(apiDebugDTO, copyApiDebugDTO); Assertions.assertEquals(apiDebugDTO, copyApiDebugDTO);
this.requestGetWithOk(GET + anotherApiTestCase.getId()) this.requestGetWithOk(GET + anotherApiTestCase.getId())
.andReturn(); .andReturn();

View File

@ -27,6 +27,7 @@ import io.metersphere.project.api.processor.extract.RegexExtract;
import io.metersphere.project.api.processor.extract.ResultMatchingExtract; import io.metersphere.project.api.processor.extract.ResultMatchingExtract;
import io.metersphere.project.api.processor.extract.XPathExtract; import io.metersphere.project.api.processor.extract.XPathExtract;
import io.metersphere.project.constants.ScriptLanguageType; import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.sdk.constants.MsAssertionCondition; import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@ -363,7 +364,8 @@ public class MsHTTPElementTest {
assertions.add(responseTimeAssertion); assertions.add(responseTimeAssertion);
MsScriptAssertion scriptAssertion = new MsScriptAssertion(); MsScriptAssertion scriptAssertion = new MsScriptAssertion();
scriptAssertion.setScriptId("1111"); scriptAssertion.setCommonScriptInfo(new CommonScriptInfo());
scriptAssertion.getCommonScriptInfo().setId("1111");
scriptAssertion.setScript("1111"); scriptAssertion.setScript("1111");
scriptAssertion.setName("1111"); scriptAssertion.setName("1111");
assertions.add(scriptAssertion); assertions.add(scriptAssertion);

View File

@ -1,11 +1,12 @@
package io.metersphere.project.api.assertion; package io.metersphere.project.api.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.constants.ScriptLanguageType; import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.CommonScriptInfo;
import jakarta.validation.Valid;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.BooleanUtils;
import java.util.List; import org.apache.commons.lang3.StringUtils;
/** /**
* 变量断言 * 变量断言
@ -27,13 +28,23 @@ public class MsScriptAssertion extends MsAssertion {
/** /**
* 是否启用公共脚本 * 是否启用公共脚本
*/ */
private Boolean enableCommonScript; private Boolean enableCommonScript = false;
/** /**
* 脚本ID * 公共脚本信息
* {@link CommonScriptInfo}
*/ */
private String scriptId; @Valid
/** private CommonScriptInfo commonScriptInfo;
* 公共脚本入参
*/ public boolean isValid() {
private List<KeyValueParam> params; if (isEnableCommonScript()) {
return commonScriptInfo != null && StringUtils.isNotBlank(commonScriptInfo.getId());
} else {
return StringUtils.isNotBlank(script);
}
}
public boolean isEnableCommonScript() {
return BooleanUtils.isTrue(enableCommonScript);
}
} }

View File

@ -2,16 +2,15 @@ package io.metersphere.project.api.processor;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.project.constants.ScriptLanguageType; import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.api.KeyValueParam; import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.system.valid.EnumValue; import io.metersphere.system.valid.EnumValue;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.List;
/** /**
* @Author: jianxing * @Author: jianxing
@ -29,6 +28,7 @@ public class ScriptProcessor extends MsProcessor {
* {@link ScriptLanguageType} * {@link ScriptLanguageType}
*/ */
@Size(max = 20) @Size(max = 20)
@NotBlank
@EnumValue(enumClass = ScriptLanguageType.class) @EnumValue(enumClass = ScriptLanguageType.class)
private String scriptLanguage; private String scriptLanguage;
/** /**
@ -38,20 +38,22 @@ public class ScriptProcessor extends MsProcessor {
*/ */
private Boolean enableCommonScript = false; private Boolean enableCommonScript = false;
/** /**
* 公共脚本ID * 公共脚本信息
*/ * {@link CommonScriptInfo}
@Size(max = 50)
private String scriptId;
/**
* 公共脚本入参
*/ */
@Valid @Valid
private List<KeyValueParam> params; private CommonScriptInfo commonScriptInfo;
public boolean isValid() { public boolean isValid() {
if (BooleanUtils.isTrue(enableCommonScript) && StringUtils.isBlank(scriptId)) { if (isEnableCommonScript()) {
return false; return commonScriptInfo != null && StringUtils.isNotBlank(commonScriptInfo.getId());
} else {
return StringUtils.isNotBlank(script);
} }
return StringUtils.isNotBlank(script); }
public boolean isEnableCommonScript() {
return BooleanUtils.isTrue(enableCommonScript);
} }
} }

View File

@ -0,0 +1,40 @@
package io.metersphere.project.dto;
import io.metersphere.project.api.KeyValueParam;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2024-02-23 13:34
*/
@Data
public class CommonScriptInfo {
/**
* 公共脚本ID
*/
@Size(min = 1, max = 50)
private String id;
/**
* 公共脚本的名字
* 页面展示需要
*/
private String name;
/**
* 公共脚本的内容
* 执行时设置
*/
private String script;
/**
* 脚本语言
*/
private String scriptLanguage;
/**
* 公共脚本入参
*/
@Valid
private List<KeyValueParam> params;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.project.service;
import io.metersphere.project.domain.CustomFunction; import io.metersphere.project.domain.CustomFunction;
import io.metersphere.project.domain.CustomFunctionBlob; import io.metersphere.project.domain.CustomFunctionBlob;
import io.metersphere.project.domain.CustomFunctionBlobExample;
import io.metersphere.project.domain.CustomFunctionExample; import io.metersphere.project.domain.CustomFunctionExample;
import io.metersphere.project.dto.customfunction.CustomFunctionDTO; import io.metersphere.project.dto.customfunction.CustomFunctionDTO;
import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest; import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest;
@ -162,4 +163,23 @@ public class CustomFunctionService {
} }
} }
public List<CustomFunctionBlob> getBlobByIds(List<String> commonScriptIds) {
if (CollectionUtils.isEmpty(commonScriptIds)) {
return List.of();
}
CustomFunctionBlobExample example = new CustomFunctionBlobExample();
example.createCriteria()
.andIdIn(commonScriptIds);
return customFunctionBlobMapper.selectByExampleWithBLOBs(example);
}
public List<CustomFunction> getByIds(List<String> commonScriptIds) {
if (CollectionUtils.isEmpty(commonScriptIds)) {
return List.of();
}
CustomFunctionExample example = new CustomFunctionExample();
example.createCriteria()
.andIdIn(commonScriptIds);
return customFunctionMapper.selectByExample(example);
}
} }

View File

@ -9,6 +9,7 @@ import io.metersphere.project.dto.customfunction.request.CustomFunctionUpdateReq
import io.metersphere.project.enums.result.ProjectResultCode; import io.metersphere.project.enums.result.ProjectResultCode;
import io.metersphere.project.mapper.CustomFunctionBlobMapper; import io.metersphere.project.mapper.CustomFunctionBlobMapper;
import io.metersphere.project.mapper.CustomFunctionMapper; import io.metersphere.project.mapper.CustomFunctionMapper;
import io.metersphere.project.service.CustomFunctionService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -29,6 +30,8 @@ import java.util.HashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* @author: LAN * @author: LAN
@ -54,7 +57,8 @@ public class CustomFunctionControllerTests extends BaseTest {
@Resource @Resource
private CustomFunctionBlobMapper customFunctionBlobMapper; private CustomFunctionBlobMapper customFunctionBlobMapper;
@Resource
private CustomFunctionService customFunctionService;
@Test @Test
@Order(1) @Order(1)
@ -328,6 +332,16 @@ public class CustomFunctionControllerTests extends BaseTest {
request.setFilter(filters); request.setFilter(filters);
} }
@Test
@Order(11)
public void testUncoveredFunc() {
// 在项目管理模块没有调用手动调用
customFunctionService.getBlobByIds(List.of());
customFunctionService.getByIds(List.of());
Assertions.assertEquals(customFunctionService.getBlobByIds(List.of(customFunction.getId())).size(), 1);
Assertions.assertEquals(customFunctionService.getByIds(List.of(customFunction.getId())).size(), 1);
}
@Test @Test
@Order(12) @Order(12)
public void testDel() throws Exception { public void testDel() throws Exception {
@ -348,5 +362,4 @@ public class CustomFunctionControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_DELETE, DELETE + "222"); requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_DELETE, DELETE + "222");
} }
} }

View File

@ -6,6 +6,7 @@ import io.metersphere.project.api.assertion.*;
import io.metersphere.project.api.assertion.body.*; import io.metersphere.project.api.assertion.body.*;
import io.metersphere.project.api.processor.SQLProcessor; import io.metersphere.project.api.processor.SQLProcessor;
import io.metersphere.project.api.processor.ScriptProcessor; import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.project.dto.environment.*; import io.metersphere.project.dto.environment.*;
import io.metersphere.project.dto.environment.auth.AuthConfig; import io.metersphere.project.dto.environment.auth.AuthConfig;
import io.metersphere.project.dto.environment.common.CommonParams; import io.metersphere.project.dto.environment.common.CommonParams;
@ -409,7 +410,8 @@ public class EnvironmentControllerTests extends BaseTest {
assertions.add(responseTimeAssertion); assertions.add(responseTimeAssertion);
MsScriptAssertion scriptAssertion = new MsScriptAssertion(); MsScriptAssertion scriptAssertion = new MsScriptAssertion();
scriptAssertion.setScriptId("1111"); scriptAssertion.setCommonScriptInfo(new CommonScriptInfo());
scriptAssertion.getCommonScriptInfo().setId("1111");
scriptAssertion.setScript("1111"); scriptAssertion.setScript("1111");
scriptAssertion.setName("1111"); scriptAssertion.setName("1111");
assertions.add(scriptAssertion); assertions.add(scriptAssertion);
@ -671,7 +673,7 @@ public class EnvironmentControllerTests extends BaseTest {
//校验日志 //校验日志
checkLog(response.getId(), OperationLogType.ADD); checkLog(response.getId(), OperationLogType.ADD);
//后置脚本 todo //后置脚本
envConfig.setPostProcessorConfig(createEnvironmentProcessorConfig()); envConfig.setPostProcessorConfig(createEnvironmentProcessorConfig());
request.setName("postScript"); request.setName("postScript");
request.setConfig(envConfig); request.setConfig(envConfig);