diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiTestEnvironmentController.java b/backend/src/main/java/io/metersphere/api/controller/ApiTestEnvironmentController.java index 887c2149c9..cf10a64019 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiTestEnvironmentController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiTestEnvironmentController.java @@ -65,16 +65,18 @@ public class ApiTestEnvironmentController { @PostMapping("/add") @MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#apiTestEnvironmentWithBLOBs.id)", msClass = ApiTestEnvironmentService.class) - public String create(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironmentWithBLOBs, @RequestPart(value = "files", required = false) List sslFiles) { + public String create(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironmentWithBLOBs, @RequestPart(value = "files", required = false) List sslFiles, + @RequestPart(value = "variablesFiles", required = false) List variableFile) { checkParams(apiTestEnvironmentWithBLOBs); - return apiTestEnvironmentService.add(apiTestEnvironmentWithBLOBs, sslFiles); + return apiTestEnvironmentService.add(apiTestEnvironmentWithBLOBs, sslFiles, variableFile); } @PostMapping(value = "/update") @MsAuditLog(module = OperLogModule.PROJECT_ENVIRONMENT_SETTING, type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#apiTestEnvironment.id)", content = "#msClass.getLogDetails(#apiTestEnvironment.id)", msClass = ApiTestEnvironmentService.class) - public void update(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironment, @RequestPart(value = "files", required = false) List sslFiles) { + public void update(@RequestPart("request") ApiTestEnvironmentDTO apiTestEnvironment, @RequestPart(value = "files", required = false) List sslFiles, + @RequestPart(value = "variablesFiles", required = false) List variableFile) { checkParams(apiTestEnvironment); - apiTestEnvironmentService.update(apiTestEnvironment, sslFiles); + apiTestEnvironmentService.update(apiTestEnvironment, sslFiles, variableFile); } private void checkParams(ApiTestEnvironmentDTO apiTestEnvironment) { diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiTestEnvironmentDTO.java b/backend/src/main/java/io/metersphere/api/dto/ApiTestEnvironmentDTO.java index d0afe5f521..62b571f5d0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/ApiTestEnvironmentDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/ApiTestEnvironmentDTO.java @@ -8,4 +8,5 @@ import java.util.List; @Data public class ApiTestEnvironmentDTO extends ApiTestEnvironmentWithBLOBs { private List uploadIds; + private List variablesFilesIds; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java index 711b319894..1482f5029c 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java @@ -11,7 +11,6 @@ import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.definition.request.controller.MsLoopController; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; -import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.request.BodyFile; import io.metersphere.api.service.ApiTestEnvironmentService; @@ -68,7 +67,7 @@ public class ElementUtil { arguments.setName(StringUtils.isNoneBlank(name) ? name : "Arguments"); arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); - config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> + config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).forEach(keyValue -> arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") ); if (arguments.getArguments().size() > 0) { @@ -100,9 +99,9 @@ public class ElementUtil { public static void addCsvDataSet(HashTree tree, List variables, ParameterConfig config, String shareMode) { if (CollectionUtils.isNotEmpty(variables)) { - List list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList()); + List list = variables.stream().filter(ScenarioVariable::isCSVValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); if (CollectionUtils.isEmpty(list) && CollectionUtils.isNotEmpty(config.getTransferVariables())) { - list = config.getTransferVariables().stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList()); + list = config.getTransferVariables().stream().filter(ScenarioVariable::isCSVValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); } if (CollectionUtils.isNotEmpty(list)) { list.forEach(item -> { @@ -139,7 +138,7 @@ public class ElementUtil { public static void addCounter(HashTree tree, List variables, boolean isInternal) { if (CollectionUtils.isNotEmpty(variables)) { - List list = variables.stream().filter(ScenarioVariable::isCounterValid).collect(Collectors.toList()); + List list = variables.stream().filter(ScenarioVariable::isCounterValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(list)) { list.forEach(item -> { CounterConfig counterConfig = new CounterConfig(); @@ -165,7 +164,7 @@ public class ElementUtil { public static void addRandom(HashTree tree, List variables) { if (CollectionUtils.isNotEmpty(variables)) { - List list = variables.stream().filter(ScenarioVariable::isRandom).collect(Collectors.toList()); + List list = variables.stream().filter(ScenarioVariable::isRandom).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(list)) { list.forEach(item -> { RandomVariableConfig randomVariableConfig = new RandomVariableConfig(); @@ -793,4 +792,62 @@ public class ElementUtil { return evlValue; } } + + public static Arguments getConfigArguments(ParameterConfig config, String name, String projectId, List variables) { + Arguments arguments = new Arguments(); + arguments.setEnabled(true); + arguments.setName(StringUtils.isNotEmpty(name) ? name : "Arguments"); + arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); + arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); + + // 场景变量 + if (CollectionUtils.isNotEmpty(variables)) { + variables.stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue -> + arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") + ); + + List variableList = variables.stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList()); + variableList.forEach(item -> { + String[] arrays = item.getValue().split(","); + for (int i = 0; i < arrays.length; i++) { + arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "="); + } + }); + } + // 环境通用变量 + if (config.isEffective(projectId) && config.getConfig().get(projectId).getCommonConfig() != null + && CollectionUtils.isNotEmpty(config.getConfig().get(projectId).getCommonConfig().getVariables())) { + //常量 + List constants = config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); + constants.forEach(keyValue -> + arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") + ); + // List类型的变量 + List variableList = config.getConfig().get(projectId).getCommonConfig().getVariables().stream().filter(ScenarioVariable::isListValid).filter(ScenarioVariable::isEnable).collect(Collectors.toList()); + variableList.forEach(item -> { + String[] arrays = item.getValue().split(","); + for (int i = 0; i < arrays.length; i++) { + arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "="); + } + }); + // 清空变量,防止重复添加 + config.getConfig().get(projectId).getCommonConfig().getVariables().remove(constants); + config.getConfig().get(projectId).getCommonConfig().getVariables().remove(variableList); + } + + if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { + return arguments; + } + return null; + } + + public static void addOtherVariables(ParameterConfig config, HashTree httpSamplerTree, String projectId) { + if (config.isEffective(projectId) && config.getConfig().get(projectId).getCommonConfig() != null + && CollectionUtils.isNotEmpty(config.getConfig().get(projectId).getCommonConfig().getVariables())) { + ElementUtil.addCsvDataSet(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables(), config, "shareMode.group"); + ElementUtil.addCounter(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables(), false); + ElementUtil.addRandom(httpSamplerTree, config.getConfig().get(projectId).getCommonConfig().getVariables()); + } + } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index e1859be01d..36201081aa 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -41,7 +41,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; @Data @EqualsAndHashCode(callSuper = true) @@ -127,7 +126,7 @@ public class MsScenario extends MsTestElement { } } } - if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) { + if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) { config.setVariables(this.variables); } HashTree scenarioTree = tree; @@ -145,7 +144,8 @@ public class MsScenario extends MsTestElement { scenarioTree = MsCriticalSectionController.createHashTree(tree, this.getName(), this.isEnable()); } // 环境变量 - Arguments arguments = arguments(this.isEnvironmentEnable() ? newConfig : config); + Arguments arguments = ElementUtil.getConfigArguments(this.isEnvironmentEnable() ? newConfig : config, this.getName(), this.getProjectId(), this.getVariables()); + if (arguments != null && (this.variableEnable == null || this.variableEnable)) { Arguments valueSupposeMock = ParameterConfig.valueSupposeMock(arguments); // 这里加入自定义变量解决ForEach循环控制器取值问题,循环控制器无法从vars中取值 @@ -309,41 +309,6 @@ public class MsScenario extends MsTestElement { } } - private Arguments arguments(ParameterConfig config) { - Arguments arguments = new Arguments(); - arguments.setEnabled(true); - arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments"); - arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); - arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); - // 场景变量 - if (CollectionUtils.isNotEmpty(this.getVariables())) { - this.getVariables().stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") - ); - - List variableList = this.getVariables().stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList()); - variableList.forEach(item -> { - String[] arrays = item.getValue().split(","); - for (int i = 0; i < arrays.length; i++) { - arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "="); - } - }); - } - // 环境通用变量 - if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null - && CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) { - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") - ); - // 清空变量,防止重复添加 - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear(); - } - if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { - return arguments; - } - return null; - } - private void setEnv(Map environmentMap, Map envConfig) { for (String projectId : environmentMap.keySet()) { ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/dns/MsDNSCacheManager.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/dns/MsDNSCacheManager.java index 7ac2af0177..a4ed2b877c 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/dns/MsDNSCacheManager.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/dns/MsDNSCacheManager.java @@ -2,8 +2,8 @@ package io.metersphere.api.dto.definition.request.dns; import com.alibaba.fastjson.annotation.JSONType; import io.metersphere.api.dto.definition.request.ParameterConfig; +import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; import io.metersphere.api.dto.scenario.HttpConfig; -import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.environment.Host; import io.metersphere.plugin.core.MsParameter; @@ -65,14 +65,14 @@ public class MsDNSCacheManager extends MsTestElement { } } - private static Arguments arguments(String name, List variables) { + private static Arguments arguments(String name, List variables) { Arguments arguments = new Arguments(); arguments.setEnabled(true); arguments.setName(name); arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); - variables.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") + variables.stream().filter(ScenarioVariable::isConstantValid).filter(ScenarioVariable::isEnable).forEach(ScenarioVariable -> + arguments.addArgument(ScenarioVariable.getName(), ScenarioVariable.getValue(), "=") ); return arguments; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java index 82741561c7..9a439d9003 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java @@ -226,10 +226,12 @@ public class MsHTTPSamplerProxy extends MsTestElement { setHeader(httpSamplerTree, config.getHeaders()); } // 环境通用请求头 - Arguments arguments = getConfigArguments(config); + Arguments arguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null); if (arguments != null) { httpSamplerTree.add(arguments); } + //添加csv + ElementUtil.addOtherVariables(config, httpSamplerTree, this.getProjectId()); //判断是否要开启DNS if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null && config.getConfig().get(this.getProjectId()).getCommonConfig().isEnableHost()) { @@ -353,6 +355,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { } } } catch (Exception e) { + LogUtil.error(e.getMessage(), e); } } if (StringUtils.isNotEmpty(useEvnId) && !StringUtils.equals(useEvnId, this.getEnvironmentId())) { @@ -682,7 +685,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { arguments.addArgument(httpArgument); } } catch (Exception e) { - + LogUtil.error(e.getMessage(), e); } } ); @@ -728,30 +731,6 @@ public class MsHTTPSamplerProxy extends MsTestElement { } } - /** - * 环境通用变量,这里只适用用接口定义和用例,场景自动化会加到场景中 - */ - private Arguments getConfigArguments(ParameterConfig config) { - Arguments arguments = new Arguments(); - arguments.setEnabled(true); - arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments"); - arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); - arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); - // 环境通用变量 - if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null - && CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) { - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") - ); - // 清空变量,防止重复添加 - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear(); - } - if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { - return arguments; - } - return null; - } - private void addArguments(HashTree tree, String key, String value) { Arguments arguments = new Arguments(); arguments.setEnabled(true); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java index cc1a27a9fb..a0ca9831b1 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java @@ -165,11 +165,12 @@ public class MsJDBCSampler extends MsTestElement { tree.add(arguments); } // 环境通用请求头 - Arguments envArguments = getConfigArguments(config); + Arguments envArguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null); if (envArguments != null) { tree.add(envArguments); } - + //添加csv + ElementUtil.addOtherVariables(config, tree, this.getProjectId()); //增加误报、全局断言 HashTreeUtil.addPositive(envConfig, samplerHashTree, config, this.getProjectId()); @@ -192,30 +193,6 @@ public class MsJDBCSampler extends MsTestElement { } - /** - * 环境通用变量 - */ - private Arguments getConfigArguments(ParameterConfig config) { - Arguments arguments = new Arguments(); - arguments.setEnabled(true); - arguments.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Arguments"); - arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); - arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); - // 环境通用变量 - if (config.isEffective(this.getProjectId()) && config.getConfig().get(this.getProjectId()).getCommonConfig() != null - && CollectionUtils.isNotEmpty(config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables())) { - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), ElementUtil.getEvlValue(keyValue.getValue()), "=") - ); - // 清空变量,防止重复添加 - config.getConfig().get(this.getProjectId()).getCommonConfig().getVariables().clear(); - } - if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { - return arguments; - } - return null; - } - private boolean isDataSource(List databaseConfigs) { List ids = databaseConfigs.stream().map(DatabaseConfig::getId).collect(Collectors.toList()); if (StringUtils.isNotEmpty(this.dataSourceId) && ids.contains(this.dataSourceId)) { diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java index ef0fbd76bd..1955f082cf 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java @@ -171,11 +171,12 @@ public class MsTCPSampler extends MsTestElement { } // 添加环境中的公共变量 - Arguments arguments = ElementUtil.addArguments(config, this.getProjectId(), this.getName()); + Arguments arguments = ElementUtil.getConfigArguments(config, this.getName(), this.getProjectId(), null); if (arguments != null) { tree.add(arguments); } - + //添加csv + ElementUtil.addOtherVariables(config, tree, this.getProjectId()); final HashTree samplerHashTree = new ListedHashTree(); samplerHashTree.add(tcpConfig()); tree.set(tcpSampler(config), samplerHashTree); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/variable/ScenarioVariable.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/variable/ScenarioVariable.java index d97c203110..33f6983a1a 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/variable/ScenarioVariable.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/variable/ScenarioVariable.java @@ -13,7 +13,7 @@ public class ScenarioVariable { /** * CONSTANT LIST CSV COUNTER RANDOM */ - private String type; + private String type = VariableTypeConstants.CONSTANT.name(); private String id; private String name; @@ -41,6 +41,8 @@ public class ScenarioVariable { private String minNumber; private String maxNumber; + private boolean enable = true; + public ScenarioVariable() { } diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/environment/CommonConfig.java b/backend/src/main/java/io/metersphere/api/dto/scenario/environment/CommonConfig.java index 9e8a748d2a..1ab6ddac27 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/environment/CommonConfig.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/environment/CommonConfig.java @@ -1,13 +1,13 @@ package io.metersphere.api.dto.scenario.environment; -import io.metersphere.api.dto.scenario.KeyValue; +import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; import lombok.Data; import java.util.List; @Data public class CommonConfig { - private List variables; + private List variables; private boolean enableHost; private List hosts; private int requestTimeout; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java b/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java index 7d6f90497b..2eb97a2a64 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java @@ -8,9 +8,12 @@ import io.metersphere.api.dto.mockconfig.MockConfigStaticData; import io.metersphere.api.tcp.TCPPool; import io.metersphere.base.domain.ApiTestEnvironmentExample; import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; +import io.metersphere.base.domain.FileAssociationExample; import io.metersphere.base.domain.Project; import io.metersphere.base.mapper.ApiTestEnvironmentMapper; +import io.metersphere.base.mapper.FileAssociationMapper; import io.metersphere.base.mapper.ext.ExtApiTestEnvironmentMapper; +import io.metersphere.commons.constants.FileAssociationType; import io.metersphere.commons.constants.ProjectApplicationType; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.CommonBeanFactory; @@ -25,6 +28,7 @@ import io.metersphere.log.utils.ReflexObjectUtil; import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.system.SystemReference; +import io.metersphere.metadata.service.FileAssociationService; import io.metersphere.service.EnvironmentGroupProjectService; import io.metersphere.service.ProjectApplicationService; import io.metersphere.service.ProjectService; @@ -50,6 +54,10 @@ public class ApiTestEnvironmentService { private ProjectApplicationService projectApplicationService; @Resource private ExtApiTestEnvironmentMapper extApiTestEnvironmentMapper; + @Resource + private FileAssociationService fileAssociationService; + @Resource + private FileAssociationMapper fileAssociationMapper; public List list(String projectId) { ApiTestEnvironmentExample example = new ApiTestEnvironmentExample(); @@ -85,6 +93,9 @@ public class ApiTestEnvironmentService { public void delete(String id) { apiTestEnvironmentMapper.deleteByPrimaryKey(id); environmentGroupProjectService.deleteRelateEnv(id); + FileAssociationExample associationExample = new FileAssociationExample(); + associationExample.createCriteria().andSourceIdEqualTo(id); + fileAssociationMapper.deleteByExample(associationExample); } public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) { @@ -99,16 +110,19 @@ public class ApiTestEnvironmentService { return apiTestEnvironmentWithBLOBs.getId(); } - public String add(ApiTestEnvironmentDTO request, List sslFiles) { + public String add(ApiTestEnvironmentDTO request, List sslFiles, List variableFile) { request.setId(UUID.randomUUID().toString()); request.setCreateUser(SessionUtils.getUserId()); checkEnvironmentExist(request); FileUtils.createFiles(request.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl"); + FileUtils.createBodyFiles(request.getVariablesFilesIds(), variableFile); //检查Config,判断isMock参数是否给True request = this.updateConfig(request, false); request.setCreateTime(System.currentTimeMillis()); request.setUpdateTime(System.currentTimeMillis()); apiTestEnvironmentMapper.insert(request); + // 存储附件关系 + fileAssociationService.saveEnvironment(request.getId(), request.getConfig(), FileAssociationType.ENVIRONMENT.name()); return request.getId(); } @@ -128,10 +142,13 @@ public class ApiTestEnvironmentService { return request; } - public void update(ApiTestEnvironmentDTO apiTestEnvironment, List sslFiles) { + public void update(ApiTestEnvironmentDTO apiTestEnvironment, List sslFiles, List variablesFiles) { checkEnvironmentExist(apiTestEnvironment); FileUtils.createFiles(apiTestEnvironment.getUploadIds(), sslFiles, FileUtils.BODY_FILE_DIR + "/ssl"); + FileUtils.createBodyFiles(apiTestEnvironment.getVariablesFilesIds(), variablesFiles); apiTestEnvironment.setUpdateTime(System.currentTimeMillis()); + // 存储附件关系 + fileAssociationService.saveEnvironment(apiTestEnvironment.getId(), apiTestEnvironment.getConfig(), FileAssociationType.ENVIRONMENT.name()); apiTestEnvironmentMapper.updateByPrimaryKeyWithBLOBs(apiTestEnvironment); } diff --git a/backend/src/main/java/io/metersphere/commons/constants/FileAssociationType.java b/backend/src/main/java/io/metersphere/commons/constants/FileAssociationType.java index eb7aef0f5c..5f8dff9fb9 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/FileAssociationType.java +++ b/backend/src/main/java/io/metersphere/commons/constants/FileAssociationType.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum FileAssociationType { - API, CASE, SCENARIO, UI + API, CASE, SCENARIO, UI, ENVIRONMENT } diff --git a/backend/src/main/java/io/metersphere/metadata/service/FileAssociationService.java b/backend/src/main/java/io/metersphere/metadata/service/FileAssociationService.java index dd69d21b11..94dc0ed64c 100644 --- a/backend/src/main/java/io/metersphere/metadata/service/FileAssociationService.java +++ b/backend/src/main/java/io/metersphere/metadata/service/FileAssociationService.java @@ -1,5 +1,6 @@ package io.metersphere.metadata.service; +import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.definition.request.MsScenario; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; @@ -104,7 +105,7 @@ public class FileAssociationService { } } - public void saveApi(String id, MsTestElement request,String type) { + public void saveApi(String id, MsTestElement request, String type) { this.deleteByResourceId(id); if (StringUtils.isNotEmpty(id) && request != null && StringUtils.equalsIgnoreCase(request.getType(), HTTPSamplerProxy.class.getSimpleName())) { MsHTTPSamplerProxy samplerProxy = (MsHTTPSamplerProxy) request; @@ -134,6 +135,22 @@ public class FileAssociationService { } } + public void saveEnvironment(String id, String config, String type) { + this.deleteByResourceId(id); + List files = new ArrayList<>(); + if (StringUtils.isNotEmpty(config)) { + JSONObject commonConfig = JSONObject.parseObject(config).getJSONObject("commonConfig"); + List list = JSONObject.parseArray(commonConfig.getString("variables"), ScenarioVariable.class); + list.stream().filter(ScenarioVariable::isCSVValid).forEach(keyValue -> { + files.addAll(keyValue.getFiles().stream().filter(BodyFile::isRef).collect(Collectors.toList())); + }); + } + if (!CollectionUtils.isEmpty(files)) { + List list = files.stream().distinct().collect(Collectors.toList()); + this.save(list, type, id); + } + } + private void getHashTree(List testElements, List files) { testElements.forEach(item -> { if (StringUtils.equalsIgnoreCase(item.getType(), HTTPSamplerProxy.class.getSimpleName())) { diff --git a/frontend/src/business/components/api/automation/scenario/variable/CsvFileUpload.vue b/frontend/src/business/components/api/automation/scenario/variable/CsvFileUpload.vue index f54cb6e764..31e794affe 100644 --- a/frontend/src/business/components/api/automation/scenario/variable/CsvFileUpload.vue +++ b/frontend/src/business/components/api/automation/scenario/variable/CsvFileUpload.vue @@ -129,11 +129,11 @@ export default { }, download() { // 本地文件 - if (this.parameter.files && this.parameter.files.length > 0 && this.parameter.files[0].file) { + if (this.parameter.files && this.parameter.files.length > 0 && this.parameter.files[0].file && this.parameter.files[0].file.name) { downloadFile(this.parameter.files[0].file.name, this.parameter.files[0].file); } // 远程下载文件 - if (this.parameter.files && this.parameter.files.length > 0 && !this.parameter.files[0].file) { + if (this.parameter.files && this.parameter.files.length > 0 && (!this.parameter.files[0].file || !this.parameter.files[0].file.name)) { let file = this.parameter.files[0]; let conf = { url: "/api/automation/file/download", @@ -157,15 +157,15 @@ export default { } }, handleRemove(file) { - let fileName = file.file ? file.file.name : file.name - this.$alert('是否确认删除CSV文件:【 ' + fileName + " 】?", '', { + let fileName = file.name ? file.name : file.file.name + this.$alert(this.$t('api_test.environment.csv_delete') + ':【 ' + fileName + " 】?", '', { confirmButtonText: this.$t('commons.confirm'), callback: (action) => { if (action === 'confirm') { this.$refs.upload.handleRemove(file); for (let i = 0; i < this.parameter.files.length; i++) { - let paramFileName = this.parameter.files[i].file ? - this.parameter.files[i].file.name : this.parameter.files[i].name; + let paramFileName = this.parameter.files[i].name ? + this.parameter.files[i].name : this.parameter.files[i].file.name; if (fileName === paramFileName) { this.parameter.files.splice(i, 1); this.$refs.upload.handleRemove(file); @@ -180,6 +180,7 @@ export default { this.$warning(this.$t('test_track.case.import.upload_limit_count')); }, upload(file) { + this.parameter.files = []; this.parameter.files.push(file); }, uploadValidate(file) { diff --git a/frontend/src/business/components/api/automation/scenario/variable/EditCsv.vue b/frontend/src/business/components/api/automation/scenario/variable/EditCsv.vue index 000595d890..907cba38dc 100644 --- a/frontend/src/business/components/api/automation/scenario/variable/EditCsv.vue +++ b/frontend/src/business/components/api/automation/scenario/variable/EditCsv.vue @@ -17,7 +17,7 @@ - {{$t('variables.add_file')}} + {{ $t('variables.add_file') }} @@ -40,7 +40,7 @@ - {{$t('variables.delimiter')}} + {{ $t('variables.delimiter') }} @@ -48,7 +48,7 @@ - {{$t('variables.quoted_data')}} + {{ $t('variables.quoted_data') }} @@ -66,10 +66,11 @@ height="200px" v-loading="loading"> - + @@ -79,70 +80,70 @@ diff --git a/frontend/src/business/components/api/automation/scenario/variable/VariableImport.vue b/frontend/src/business/components/api/automation/scenario/variable/VariableImport.vue new file mode 100644 index 0000000000..79962290f7 --- /dev/null +++ b/frontend/src/business/components/api/automation/scenario/variable/VariableImport.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue b/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue index e5e5243f44..07084cd002 100644 --- a/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue +++ b/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue @@ -37,9 +37,23 @@ {{ $t('commons.add') }} - - {{ $t("commons.batch_add") }} - + + + {{ $t('commons.more_operator') }} + + + + + {{ $t("commons.import_variable") }} + + + {{ $t("commons.export_variable") }} + + + {{ $t("commons.batch_add") }} + + + @@ -94,6 +108,13 @@ :label="$t('api_test.value')" sortable> + + @@ -149,6 +170,7 @@ + @@ -161,7 +183,7 @@ import MsEditCounter from "./EditCounter"; import MsEditRandom from "./EditRandom"; import MsEditListValue from "./EditListValue"; import MsEditCsv from "./EditCsv"; -import {getUUID} from "@/common/js/utils"; +import {downloadFile, getUUID} from "@/common/js/utils"; import MsApiKeyValue from "../../../definition/components/ApiKeyValue"; import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter"; import {KeyValue} from "../../../definition/model/ApiTestModel"; @@ -170,6 +192,7 @@ import {REQUEST_HEADERS} from "@/common/js/constants"; import MsTable from "@/business/components/common/components/table/MsTable"; import MsTableColumn from "@/business/components/common/components/table/MsTableColumn"; import {getCustomTableHeader, getCustomTableWidth} from "@/common/js/tableUtils"; +import VariableImport from "@/business/components/api/automation/scenario/variable/VariableImport"; const jsondiffpatch = require('jsondiffpatch'); @@ -188,6 +211,7 @@ export default { BatchAddParameter, MsTableColumn, MsTable, + VariableImport }, data() { return { @@ -230,6 +254,46 @@ export default { }; }, methods: { + importVariable() { + this.$refs.variableImport.open(); + }, + mergeData(data, modeId) { + JSON.parse(data).map(importData => { + importData.id = getUUID(); + importData.enable = true; + importData.showMore = false; + let sameNameIndex = this.variables.findIndex(d => d.name === importData.name); + if (sameNameIndex !== -1) { + if (modeId === 'fullCoverage') { + this.variables.splice(sameNameIndex, 1, importData); + } + } else { + this.variables.splice(this.variables.length - 1, 0, importData); + } + }) + }, + exportVariable() { + if (this.$refs.variableTable.selectIds.length < 1) { + this.$warning(this.$t('api_test.environment.select_environment')); + return; + } + let variablesJson = []; + let messages = ''; + let rows = this.$refs.variableTable.selectRows; + rows.forEach(row => { + if (row.type === 'CSV') { + messages = this.$t('variables.csv_download') + } + if (row.name) { + variablesJson.push(row); + } + }) + if (messages !== '') { + this.$warning(messages); + return; + } + downloadFile('MS_' + variablesJson.length + '_Environments_variables.json', JSON.stringify(variablesJson)); + }, batchAddParameter() { this.$refs.batchAddParameter.open(); }, @@ -241,20 +305,21 @@ export default { let params = data.split("\n"); let keyValues = []; params.forEach(item => { - let line = item.split(/:|:/); - let required = false; - keyValues.unshift(new KeyValue({ - name: line[0], - required: required, - value: line[1], - description: line[2], - type: "text", - valid: false, - file: false, - encode: true, - enable: true, - contentType: "text/plain" - })); + if (item) { + let line = item.split(/:|:/); + let required = false; + keyValues.push(new KeyValue({ + name: line[0], + required: required, + value: line[1], + description: line[2], + type: "CONSTANT", + valid: false, + file: false, + encode: true, + enable: true, + })); + } }) return keyValues; } @@ -278,7 +343,7 @@ export default { } } if (isAdd) { - this.headers.unshift(obj); + this.headers.splice(this.headers.indexOf(h => !h.name), 0, obj); } } }, @@ -346,6 +411,18 @@ export default { this.disabled = disabled; this.$nextTick(() => { this.$refs.variableTable.doLayout(); + let variable = []; + let messages = ''; + this.variables.forEach(item => { + if (variable.indexOf(item.name) !== -1) { + messages += item.name + ' ,'; + } else { + variable.push(item.name); + } + }) + if (messages !== '') { + this.$alert(this.$t('api_test.scenario.variables') + "【" + messages.substr(0, messages.length - 1) + "】" + this.$t('load_test.param_is_duplicate')); + } }); }, save() { @@ -382,6 +459,18 @@ export default { this.$warning(this.$t('api_test.automation.variable_warning')); return; } + let repeatKey = ""; + if (!this.showDelete) { + this.variables.forEach((item, index) => { + if (item.name === this.editData.name) { + repeatKey = item.name; + } + }); + } + if (repeatKey !== "") { + this.$warning(this.$t('api_test.scenario.variables') + "【" + repeatKey + "】" + this.$t('load_test.param_is_duplicate')); + return; + } if (this.editData.type === 'CSV' && this.$refs.csv) { if (this.editData.files.length === 0) { this.$warning(this.$t('api_test.automation.csv_warning')); @@ -407,7 +496,7 @@ export default { deleteVariable() { let ids = [this.editData.id]; if (ids.length == 0) { - this.$warning("请选择一条数据删除"); + this.$warning(this.$t('api_test.environment.delete_info')); return; } let message = ""; @@ -419,7 +508,7 @@ export default { }); if (message !== "") { message = message.substr(0, message.length - 1); - this.$alert('是否确认删除变量:【 ' + message + " 】?", '', { + this.$alert(this.$t('api_test.environment.variables_delete_info') + ':【 ' + message + " 】?", '', { confirmButtonText: this.$t('commons.confirm'), callback: (action) => { if (action === 'confirm') { @@ -442,7 +531,7 @@ export default { } }, handleDeleteBatch() { - this.$alert("是否确认删除所选变量" + ' ' + " ?", '', { + this.$alert(this.$t('api_test.environment.variables_delete_info') + ' ' + " ?", '', { confirmButtonText: this.$t('commons.confirm'), callback: (action) => { if (action === 'confirm') { diff --git a/frontend/src/business/components/api/definition/components/basis/BatchAddParameter.vue b/frontend/src/business/components/api/definition/components/basis/BatchAddParameter.vue index 3f9622084a..8698a8ab91 100644 --- a/frontend/src/business/components/api/definition/components/basis/BatchAddParameter.vue +++ b/frontend/src/business/components/api/definition/components/basis/BatchAddParameter.vue @@ -8,12 +8,15 @@
- {{$t('commons.cancel')}} - {{$t('commons.confirm')}} + {{ $t('commons.cancel') }} + + {{ $t('commons.confirm') }} +
-
@@ -22,59 +25,75 @@ diff --git a/frontend/src/business/components/api/definition/components/body/ApiBody.vue b/frontend/src/business/components/api/definition/components/body/ApiBody.vue index df1bd6236c..956df43c29 100644 --- a/frontend/src/business/components/api/definition/components/body/ApiBody.vue +++ b/frontend/src/business/components/api/definition/components/body/ApiBody.vue @@ -302,7 +302,7 @@ export default { } } if (isAdd) { - this.body.kvs.unshift(obj); + this.body.kvs.splice(this.body.kvs.indexOf(kv => !kv.name), 0, obj); } } }, @@ -311,22 +311,24 @@ export default { let params = data.split("\n"); let keyValues = []; params.forEach(item => { - let line = []; - line[0] = item.substring(0, item.indexOf(":")); - line[1] = item.substring(item.indexOf(":") + 1, item.length); - let required = false; - keyValues.unshift(new KeyValue({ - name: line[0], - required: required, - value: line[1], - description: line[2], - type: "text", - valid: false, - file: false, - encode: true, - enable: true, - contentType: "text/plain" - })); + if (item) { + let line = []; + line[0] = item.substring(0, item.indexOf(":")); + line[1] = item.substring(item.indexOf(":") + 1, item.length); + let required = false; + keyValues.push(new KeyValue({ + name: line[0], + required: required, + value: line[1], + description: line[2], + type: "text", + valid: false, + file: false, + encode: true, + enable: true, + contentType: "text/plain" + })); + } }) keyValues.forEach(item => { this.format(this.body.kvs, item); diff --git a/frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue b/frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue index 1555643d9f..9fb27b6228 100644 --- a/frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue +++ b/frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue @@ -2,19 +2,22 @@ - {{$t('api_test.environment.name')}} + {{ $t('api_test.environment.name') }} - + - + - + @@ -34,136 +37,237 @@ diff --git a/frontend/src/business/components/api/definition/components/mock/Components/MockApiBody.vue b/frontend/src/business/components/api/definition/components/mock/Components/MockApiBody.vue index 7df6840bbf..4d0017555a 100644 --- a/frontend/src/business/components/api/definition/components/mock/Components/MockApiBody.vue +++ b/frontend/src/business/components/api/definition/components/mock/Components/MockApiBody.vue @@ -274,22 +274,24 @@ export default { let params = data.split("\n"); let keyValues = []; params.forEach(item => { - let line = []; - line[0] = item.substring(0,item.indexOf(":")); - line[1] = item.substring(item.indexOf(":")+1,item.length); - let required = false; - keyValues.unshift(new KeyValue({ - name: line[0], - required: required, - value: line[1], - description: line[2], - type: "text", - valid: false, - file: false, - encode: true, - enable: true, - contentType: "text/plain" - })); + if (item) { + let line = []; + line[0] = item.substring(0, item.indexOf(":")); + line[1] = item.substring(item.indexOf(":") + 1, item.length); + let required = false; + keyValues.push(new KeyValue({ + name: line[0], + required: required, + value: line[1], + description: line[2], + type: "text", + valid: false, + file: false, + encode: true, + enable: true, + contentType: "text/plain" + })); + } }) keyValues.forEach(item => { this.format(this.body.kvs, item); diff --git a/frontend/src/business/components/api/definition/components/mock/Components/MockApiResponseBody.vue b/frontend/src/business/components/api/definition/components/mock/Components/MockApiResponseBody.vue index 2870f54a39..2ed4bbfb3b 100644 --- a/frontend/src/business/components/api/definition/components/mock/Components/MockApiResponseBody.vue +++ b/frontend/src/business/components/api/definition/components/mock/Components/MockApiResponseBody.vue @@ -19,51 +19,51 @@ + v-if="body.format==='JSON-SCHEMA'" + :body="body" + :show-mock-vars="true" + ref="jsonCodeEdit"/> + v-else-if="codeEditActive && loadIsOver" + :read-only="isReadOnly" + :data.sync="body.raw" + :modes="modes" + :mode="'json'" + height="90%" + ref="codeEdit"/>
+ :read-only="true" + :data.sync="body.apiRspRaw" + :modes="modes" + :mode="'text'" + v-if="loadIsOver" + height="90%" + ref="fromApiCodeEdit"/>
+ :read-only="isReadOnly" + :data.sync="body.xmlRaw" + :modes="modes" + :mode="'xml'" + v-if="loadIsOver" + height="90%" + ref="codeEdit"/>
+ :read-only="isReadOnly" + :data.sync="body.raw" + :modes="modes" + v-if="loadIsOver" + height="90%" + ref="codeEdit"/>
@@ -309,22 +309,24 @@ export default { let params = data.split("\n"); let keyValues = []; params.forEach(item => { - let line = []; - line[0] = item.substring(0, item.indexOf(":")); - line[1] = item.substring(item.indexOf(":") + 1, item.length); - let required = false; - keyValues.unshift(new KeyValue({ - name: line[0], - required: required, - value: line[1], - description: line[2], - type: "text", - valid: false, - file: false, - encode: true, - enable: true, - contentType: "text/plain" - })); + if (item) { + let line = []; + line[0] = item.substring(0, item.indexOf(":")); + line[1] = item.substring(item.indexOf(":") + 1, item.length); + let required = false; + keyValues.push(new KeyValue({ + name: line[0], + required: required, + value: line[1], + description: line[2], + type: "text", + valid: false, + file: false, + encode: true, + enable: true, + contentType: "text/plain" + })); + } }) keyValues.forEach(item => { this.format(this.body.kvs, item); diff --git a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue index ddde944779..9b47523f66 100644 --- a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue +++ b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue @@ -19,14 +19,14 @@
+ @editScenarioAdvance="editScenarioAdvance" + :scenario-definition="scenarioDefinition" + :show-desc="true" + :is-read-only="isReadOnly" + :isShowEnable="isShowEnable" + :suggestions="headerSuggestions" + :items="headers" + :need-mock="true" v-if="activeName === 'headers'"/>
@@ -45,13 +45,13 @@ @@ -72,13 +72,13 @@ @@ -105,17 +105,17 @@ @@ -128,13 +128,13 @@ @@ -145,13 +145,13 @@ @@ -162,14 +162,14 @@ + :request="request" + :apiId="request.id" + :scenarioId="scenarioId" + :response="response" + @reload="reloadBody" + :tab-type="'assertionsRule'" + ref="assertionsRule" + v-if="activeName === 'assertionsRule'"/> @@ -424,13 +424,13 @@ export default { if (isAdd) { switch (this.activeName) { case "parameters": - this.request.arguments.unshift(obj); + this.request.arguments.splice(this.request.arguments.indexOf(h => !h.name), 0, obj); break; case "rest": - this.request.rest.unshift(obj); + this.request.rest.splice(this.request.rest.indexOf(h => !h.name), 0, obj); break; case "headers": - this.request.headers.unshift(obj); + this.request.headers.splice(this.request.headers.indexOf(h => !h.name), 0, obj); break; default: break; @@ -443,20 +443,22 @@ export default { let params = data.split("\n"); let keyValues = []; params.forEach(item => { - let line = item.split(/:|:/); - let values = item.split(line[0] + ":"); - let required = false; - keyValues.unshift(new KeyValue({ - name: line[0], - required: required, - value: values[1], - type: "text", - valid: false, - file: false, - encode: true, - enable: true, - contentType: "text/plain" - })); + if (item) { + let line = item.split(/:|:/); + let values = item.split(line[0] + ":"); + let required = false; + keyValues.push(new KeyValue({ + name: line[0], + required: required, + value: values[1], + type: "text", + valid: false, + file: false, + encode: true, + enable: true, + contentType: "text/plain" + })); + } }) keyValues.forEach(item => { diff --git a/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue b/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue index 39cf4c4f84..5e5b652252 100644 --- a/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue +++ b/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue @@ -8,9 +8,9 @@ :data="environments" :item-operators="environmentOperators" :add-fuc="addEnvironment" :env-add-permission="ENV_CREATE" :delete-fuc="openDelEnv" @itemSelected="environmentSelected" ref="environmentItems"/> - diff --git a/frontend/src/business/components/api/test/components/ApiScenarioVariables.vue b/frontend/src/business/components/api/test/components/ApiScenarioVariables.vue index d9280d6fa4..0aa8c97a18 100644 --- a/frontend/src/business/components/api/test/components/ApiScenarioVariables.vue +++ b/frontend/src/business/components/api/test/components/ApiScenarioVariables.vue @@ -112,7 +112,7 @@ export default { let line = item.split(/:|:/); let values = item.split(line[0] + ":"); let required = false; - keyValues.unshift(new KeyValue({ + keyValues.push(new KeyValue({ name: line[0], required: required, value: values[1], diff --git a/frontend/src/business/components/api/test/components/environment/ApiScenarioVariables.vue b/frontend/src/business/components/api/test/components/environment/ApiScenarioVariables.vue new file mode 100644 index 0000000000..9d8e2077dc --- /dev/null +++ b/frontend/src/business/components/api/test/components/environment/ApiScenarioVariables.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/frontend/src/business/components/api/test/components/environment/ApiVariableAdvance.vue b/frontend/src/business/components/api/test/components/environment/ApiVariableAdvance.vue new file mode 100644 index 0000000000..0a9cd8435f --- /dev/null +++ b/frontend/src/business/components/api/test/components/environment/ApiVariableAdvance.vue @@ -0,0 +1,306 @@ + + + + + diff --git a/frontend/src/business/components/api/test/components/environment/ApiVariableSetting.vue b/frontend/src/business/components/api/test/components/environment/ApiVariableSetting.vue new file mode 100644 index 0000000000..aebd2b303e --- /dev/null +++ b/frontend/src/business/components/api/test/components/environment/ApiVariableSetting.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/frontend/src/business/components/api/test/components/environment/CsvFileUpload.vue b/frontend/src/business/components/api/test/components/environment/CsvFileUpload.vue new file mode 100644 index 0000000000..fff18d06d3 --- /dev/null +++ b/frontend/src/business/components/api/test/components/environment/CsvFileUpload.vue @@ -0,0 +1,273 @@ + + + + + diff --git a/frontend/src/business/components/api/test/components/environment/EnvironmentCommonConfig.vue b/frontend/src/business/components/api/test/components/environment/EnvironmentCommonConfig.vue index 4dbff648b8..96f3666521 100644 --- a/frontend/src/business/components/api/test/components/environment/EnvironmentCommonConfig.vue +++ b/frontend/src/business/components/api/test/components/environment/EnvironmentCommonConfig.vue @@ -30,7 +30,7 @@ @@ -468,10 +541,11 @@ span:not(:first-child) { margin-top: 15px; } -.errorReportConfigSwitch /deep/ .el-switch__label{ +.errorReportConfigSwitch /deep/ .el-switch__label { color: #D8DAE2; } -.errorReportConfigSwitch /deep/ .is-active{ + +.errorReportConfigSwitch /deep/ .is-active { color: var(--count_number); } diff --git a/frontend/src/business/components/api/test/components/environment/EnvironmentHttpConfig.vue b/frontend/src/business/components/api/test/components/environment/EnvironmentHttpConfig.vue index 02fae440dc..5c7f141656 100644 --- a/frontend/src/business/components/api/test/components/environment/EnvironmentHttpConfig.vue +++ b/frontend/src/business/components/api/test/components/environment/EnvironmentHttpConfig.vue @@ -6,7 +6,8 @@ {{ $t('api_test.environment.socket') }} - + - + @@ -153,7 +157,15 @@ export default { }, loading: false, pathDetails: new KeyValue({name: "", value: "contains"}), - condition: {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]}, + condition: { + type: "NONE", + details: [new KeyValue({name: "", value: "contains"})], + protocol: "http", + socket: "", + domain: "", + port: 0, + headers: [new KeyValue()] + }, beforeCondition: {} }; }, @@ -174,7 +186,16 @@ export default { this.condition.description = this.httpConfig.description; this.add(); } - this.condition = {id: undefined, type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]}; + this.condition = { + id: undefined, + type: "NONE", + details: [new KeyValue({name: "", value: "contains"})], + protocol: "http", + socket: "", + domain: "", + port: 0, + headers: [new KeyValue()] + }; }, }, methods: { @@ -216,7 +237,15 @@ export default { } }, selectRow(row) { - this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]}; + this.condition = { + type: "NONE", + details: [new KeyValue({name: "", value: "contains"})], + protocol: "http", + socket: "", + domain: "", + port: 0, + headers: [new KeyValue()] + }; if (row) { this.httpConfig.socket = row.socket; this.httpConfig.protocol = row.protocol; @@ -309,7 +338,14 @@ export default { this.$refs.envTable.setCurrentRow(0); }, clear() { - this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]}; + this.condition = { + type: "NONE", + details: [new KeyValue({name: "", value: "contains"})], + protocol: "http", + socket: "", + domain: "", + headers: [new KeyValue()] + }; this.$refs.envTable.setCurrentRow(0); }, reload() { @@ -336,8 +372,15 @@ export default { } this.validateSocket(); let obj = { - id: getUUID(), type: this.condition.type, socket: this.condition.socket, protocol: this.condition.protocol, headers: this.condition.headers, - domain: this.condition.domain, port: this.condition.port, time: new Date().getTime(), description: this.condition.description + id: getUUID(), + type: this.condition.type, + socket: this.condition.socket, + protocol: this.condition.protocol, + headers: this.condition.headers, + domain: this.condition.domain, + port: this.condition.port, + time: new Date().getTime(), + description: this.condition.description }; if (this.condition.type === "PATH") { obj.details = [JSON.parse(JSON.stringify(this.pathDetails))]; @@ -358,7 +401,16 @@ export default { return; } const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id); - let obj = {id: getUUID(), type: row.type, socket: row.socket, details: row.details, protocol: row.protocol, headers: JSON.parse(JSON.stringify(row.headers)), domain: row.domain, time: new Date().getTime()}; + let obj = { + id: getUUID(), + type: row.type, + socket: row.socket, + details: row.details, + protocol: row.protocol, + headers: JSON.parse(JSON.stringify(row.headers)), + domain: row.domain, + time: new Date().getTime() + }; if (index != -1) { this.httpConfig.conditions.splice(index, 0, obj); } else { @@ -402,7 +454,7 @@ export default { let line = item.split(/:|:/); let values = item.split(line[0] + ":"); let required = false; - keyValues.unshift(new KeyValue({ + keyValues.push(new KeyValue({ name: line[0], required: required, value: values[1], @@ -429,7 +481,7 @@ export default { } } if (isAdd) { - this.condition.headers.unshift(keyValue); + this.condition.headers.splice(this.condition.headers.indexOf(h => !h.name), 0, keyValue); } }) } diff --git a/frontend/src/business/components/api/test/components/environment/VariableImport.vue b/frontend/src/business/components/api/test/components/environment/VariableImport.vue new file mode 100644 index 0000000000..8f887c9ac2 --- /dev/null +++ b/frontend/src/business/components/api/test/components/environment/VariableImport.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/frontend/src/business/components/common/components/MsDialogHeader.vue b/frontend/src/business/components/common/components/MsDialogHeader.vue index a7dfaf3eb3..a280ede9f1 100644 --- a/frontend/src/business/components/common/components/MsDialogHeader.vue +++ b/frontend/src/business/components/common/components/MsDialogHeader.vue @@ -2,7 +2,12 @@
{{ title }} - +
+ + + +
@@ -39,6 +44,9 @@ export default { }, confirm() { this.$emit("confirm"); + }, + fullScreen() { + this.$emit("fullScreen"); } } } @@ -53,4 +61,9 @@ export default { .msDialogHeader { margin-bottom: 5px; } + +.alt-ico { + font-size: 13px; + color: #8c939d; +} diff --git a/frontend/src/business/components/project/menu/EnvironmentList.vue b/frontend/src/business/components/project/menu/EnvironmentList.vue index 1af238c1d2..e3d5a5a6a0 100644 --- a/frontend/src/business/components/project/menu/EnvironmentList.vue +++ b/frontend/src/business/components/project/menu/EnvironmentList.vue @@ -32,7 +32,9 @@ @@ -57,18 +59,20 @@ - + + @confirm="save" :is-project="true" + :project-list="projectList" @refreshAfterSave="refresh"> - + @@ -94,12 +98,14 @@ {{ row.conditionType ? "-" : getDetails(row) }} - + - +