diff --git a/.github/stale.yml b/.github/stale.yml index 7525aae70b..a7e5a09541 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,6 +7,7 @@ exemptLabels: - lifecycle/frozen - pinned - security + - plan staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java index 17a4575b73..19e078a3e0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java @@ -58,6 +58,7 @@ import org.apache.jmeter.extractor.RegexExtractor; import org.apache.jmeter.extractor.XPath2Extractor; import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor; import org.apache.jmeter.modifiers.JSR223PreProcessor; +import org.apache.jmeter.protocol.http.control.HeaderManager; import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; import org.apache.jmeter.protocol.http.util.HTTPFileArg; import org.apache.jmeter.protocol.java.sampler.JSR223Sampler; @@ -77,13 +78,17 @@ import java.util.*; public class MsJmeterParser extends ApiImportAbstractParser { private final String ENV_NAME = "导入数据环境"; + /** + * todo 存放单个请求下的Header 为了和平台对应 + */ + private Map> headerMap = new HashMap<>(); @Override public ScenarioImport parse(InputStream inputSource, ApiTestImportRequest request) { try { Object scriptWrapper = SaveService.loadElement(inputSource); HashTree testPlan = this.getHashTree(scriptWrapper); - // 优先初始化数据源 + // 优先初始化数据源及部分参数 preInitPool(request.getProjectId(), testPlan); MsScenario scenario = new MsScenario(); @@ -126,8 +131,9 @@ public class MsJmeterParser extends ApiImportAbstractParser { return (HashTree) field.get(scriptWrapper); } - private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, HTTPSamplerProxy source) { + private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) { try { + HTTPSamplerProxy source = (HTTPSamplerProxy) key; BeanUtils.copyBean(samplerProxy, source); if (source != null && source.getHTTPFiles().length > 0) { samplerProxy.getBody().setBinary(new ArrayList<>()); @@ -170,10 +176,23 @@ public class MsJmeterParser extends ApiImportAbstractParser { samplerProxy.setPath(source.getPath()); samplerProxy.setMethod(source.getMethod()); if (source.getUrl() != null) { - // samplerProxy.setUrl(source.getUrl().toString()); + samplerProxy.setUrl(source.getUrl().toString()); } samplerProxy.setId(UUID.randomUUID().toString()); samplerProxy.setType("HTTPSamplerProxy"); + // 处理HTTP协议的请求头 + if (headerMap.containsKey(key.hashCode())) { + List keyValues = new LinkedList<>(); + headerMap.get(key.hashCode()).forEach(item -> { + HeaderManager headerManager = (HeaderManager) item; + if (headerManager.getHeaders() != null) { + for (int i = 0; i < headerManager.getHeaders().size(); i++) { + keyValues.add(new KeyValue(headerManager.getHeader(i).getName(), headerManager.getHeader(i).getValue())); + } + } + }); + samplerProxy.setHeaders(keyValues); + } } catch (Exception e) { e.printStackTrace(); } @@ -258,7 +277,7 @@ public class MsJmeterParser extends ApiImportAbstractParser { // 初始化已有数据池 initDataSource(projectId, ENV_NAME); // 添加当前jmx 中新的数据池 - preCreatePool(hashTree); + preCreate(hashTree); // 更新数据源 ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); dataPools.getEnvConfig().setDatabaseConfigs(new ArrayList<>(dataPools.getDataSources().values())); @@ -272,7 +291,7 @@ public class MsJmeterParser extends ApiImportAbstractParser { } } - private void preCreatePool(HashTree tree) { + private void preCreate(HashTree tree) { for (Object key : tree.keySet()) { // JDBC 数据池 if (key instanceof DataSourceElement) { @@ -304,12 +323,29 @@ public class MsJmeterParser extends ApiImportAbstractParser { } dataPools.getDataSources().put(dataSourceElement.getPropertyAsString("dataSource"), newConfig); } + } else if (key instanceof HTTPSamplerProxy) { + // 把HTTP 请求下的HeaderManager 取出来 + HashTree node = tree.get(key); + if (node != null) { + for (Object nodeKey : node.keySet()) { + if (nodeKey instanceof HeaderManager) { + if (headerMap.containsKey(key.hashCode())) { + headerMap.get(key.hashCode()).add(nodeKey); + } else { + List objects = new LinkedList() {{ + this.add(nodeKey); + }}; + headerMap.put(key.hashCode(), objects); + } + } + } + } } // 递归子项 HashTree node = tree.get(key); if (node != null) { - preCreatePool(node); + preCreate(node); } } } @@ -507,7 +543,7 @@ public class MsJmeterParser extends ApiImportAbstractParser { else if (key instanceof HTTPSamplerProxy) { elementNode = new MsHTTPSamplerProxy(); ((MsHTTPSamplerProxy) elementNode).setBody(new Body()); - convertHttpSampler((MsHTTPSamplerProxy) elementNode, (HTTPSamplerProxy) key); + convertHttpSampler((MsHTTPSamplerProxy) elementNode, key); } // TCP请求 else if (key instanceof TCPSampler) { @@ -610,6 +646,10 @@ public class MsJmeterParser extends ApiImportAbstractParser { } // 平台不能识别的Jmeter步骤 else { + // HTTP 请求下的所有HeaderManager已经加到请求中 + if (scenario instanceof MsHTTPSamplerProxy && key instanceof HeaderManager) { + continue; + } elementNode = new MsJmeterElement(); elementNode.setType("JmeterElement"); TestElement testElement = (TestElement) key; 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 03039f7909..175345cb1b 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 @@ -78,11 +78,28 @@ public class MsScenario extends MsTestElement { JSONObject element = JSON.parseObject(scenario.getScenarioDefinition()); hashTree = mapper.readValue(element.getString("hashTree"), new TypeReference>() { }); + // 场景变量 + if (StringUtils.isNotEmpty(element.getString("variables"))) { + LinkedList variables = mapper.readValue(element.getString("variables"), + new TypeReference>() { + }); + this.setVariables(variables); + } + // 场景请求头 + if (StringUtils.isNotEmpty(element.getString("headers"))) { + LinkedList headers = mapper.readValue(element.getString("headers"), + new TypeReference>() { + }); + this.setHeaders(headers); + } + } + } catch (Exception ex) { ex.printStackTrace(); } } + // 设置共享cookie config.setEnableCookieShare(enableCookieShare); if (StringUtils.isNotEmpty(environmentId)) { ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); @@ -95,7 +112,10 @@ public class MsScenario extends MsTestElement { config.setVariables(this.variables); } // 场景变量和环境变量 - tree.add(arguments(config)); + Arguments arguments = arguments(config); + if (arguments != null) { + tree.add(arguments); + } this.addCsvDataSet(tree, variables); this.addCounter(tree, variables); this.addRandom(tree, variables); @@ -139,11 +159,11 @@ public class MsScenario extends MsTestElement { arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); if (CollectionUtils.isNotEmpty(this.getVariables())) { - variables.stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue -> + this.getVariables().stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue -> arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") ); - List variableList = variables.stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList()); + 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++) { @@ -157,8 +177,10 @@ public class MsScenario extends MsTestElement { arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") ); } - - return arguments; + if (arguments.getArguments() != null && arguments.getArguments().size() > 0) { + return arguments; + } + return null; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java index fb30feb4b1..cfcbe910bb 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java @@ -41,7 +41,6 @@ import org.apache.jmeter.config.Arguments; import org.apache.jmeter.config.CSVDataSet; import org.apache.jmeter.config.RandomVariableConfig; import org.apache.jmeter.modifiers.CounterConfig; -import org.apache.jmeter.protocol.http.control.AuthManager; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.testelement.TestElement; import org.apache.jorphan.collections.HashTree; @@ -75,7 +74,7 @@ import java.util.stream.Collectors; }) @JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223Processor.class, MsJSR223PostProcessor.class, - MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class, + MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, MsAuthManager.class, MsAssertions.class, MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class, MsLoopController.class, MsJmeterElement.class}, typeKey = "type") @Data public abstract class MsTestElement { @@ -152,7 +151,7 @@ public abstract class MsTestElement { ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class); ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - ApiDefinitionWithBLOBs apiDefinition = apiDefinitionService.getBLOBs(this.getId()); + ApiDefinitionWithBLOBs apiDefinition = apiDefinitionService.getBLOBs(element.getId()); if (apiDefinition != null) { element = mapper.readValue(apiDefinition.getRequest(), new TypeReference() { }); @@ -160,6 +159,7 @@ public abstract class MsTestElement { } } catch (Exception ex) { ex.printStackTrace(); + LogUtil.error(ex.getMessage()); } } 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 0a7a2a5420..f782806146 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 @@ -173,6 +173,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { sampler.setPort(urlObject.getPort()); sampler.setProtocol(urlObject.getProtocol()); String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath(); + sampler.setPath(envPath); if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) { envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8")); sampler.setPath(envPath); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java index ac24fb0019..96fcf10f33 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.save.SaveService; +import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestPlan; import org.apache.jmeter.threads.ThreadGroup; import org.apache.jorphan.collections.HashTree; @@ -40,7 +41,9 @@ public class MsJmeterElement extends MsTestElement { } else if (!(scriptWrapper instanceof TestPlan) && !(scriptWrapper instanceof ThreadGroup)) { elementTree = tree.add(scriptWrapper); } - + if (scriptWrapper instanceof TestElement) { + ((TestElement) scriptWrapper).setName(this.getName()); + } if (CollectionUtils.isNotEmpty(hashTree)) { for (MsTestElement el : hashTree) { el.toHashTree(elementTree, el.getHashTree(), config); diff --git a/backend/src/main/java/io/metersphere/api/service/APITestService.java b/backend/src/main/java/io/metersphere/api/service/APITestService.java index 7e30d8b9c7..44504fbe8a 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -35,7 +35,6 @@ import org.aspectj.util.FileUtil; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; -import org.dom4j.QName; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -582,9 +581,11 @@ public class APITestService { for (Element itemElement : sampleProxyElementList) { if (isFromScenario) { testName = itemElement.attributeValue(attribute_testName); - String[] testNameArr = testName.split(scenarioCaseNameSplit); - if (testNameArr.length > 0) { - testName = testNameArr[0]; + if (StringUtils.isNotBlank(testName)) { + String[] testNameArr = testName.split(scenarioCaseNameSplit); + if (testNameArr.length > 0) { + testName = testNameArr[0]; + } } } itemElement.attribute(attribute_testName).setText(testName); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 481ef11984..1328607458 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -457,12 +457,15 @@ public class ApiAutomationService { }); scenario.setHashTree(elements); } - if (StringUtils.isNotEmpty(element.getString("variables"))) { + if (element != null && StringUtils.isNotEmpty(element.getString("variables"))) { LinkedList variables = mapper.readValue(element.getString("variables"), new TypeReference>() { }); scenario.setVariables(variables); } + if (scenario == null) { + return null; + } // 针对导入的jmx 处理 if (CollectionUtils.isNotEmpty(scenario.getHashTree()) && (scenario.getHashTree().get(0) instanceof MsJmeterElement)) { scenario.toHashTree(jmeterHashTree, scenario.getHashTree(), config); @@ -499,7 +502,7 @@ public class ApiAutomationService { List ids = request.getIds(); //检查是否有正在执行中的情景 - this.checkScenarioIsRunnng(ids); + this.checkScenarioIsRunning(ids); List apiScenarios = extApiScenarioMapper.selectIds(ids); String runMode = ApiRunMode.SCENARIO.name(); @@ -516,7 +519,7 @@ public class ApiAutomationService { return request.getId(); } - public void checkScenarioIsRunnng(List ids) { + public void checkScenarioIsRunning(List ids) { List lastReportStatusByIds = apiReportService.selectLastReportByIds(ids); for (ApiScenarioReport report : lastReportStatusByIds) { if (StringUtils.equals(report.getStatus(), APITestStatus.Running.name())) { @@ -879,9 +882,13 @@ public class ApiAutomationService { // 生成jmx List resList = new ArrayList<>(); apiScenarioWithBLOBs.forEach(item -> { - String jmx = generateJmx(item); - ApiScenrioExportJmx scenrioExportJmx = new ApiScenrioExportJmx(item.getName(), apiTestService.updateJmxString(jmx, null, true)); - resList.add(scenrioExportJmx); + if (StringUtils.isNotEmpty(item.getScenarioDefinition())) { + String jmx = generateJmx(item); + if (StringUtils.isNotEmpty(jmx)) { + ApiScenrioExportJmx scenrioExportJmx = new ApiScenrioExportJmx(item.getName(), apiTestService.updateJmxString(jmx, null, true)); + resList.add(scenrioExportJmx); + } + } }); return resList; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index e86d9a5601..0ed3d739cd 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -391,9 +391,12 @@ public class ApiDefinitionService { if (apiTestCase.getName().length() > 255) { apiTestCase.setName(apiTestCase.getName().substring(0, 255)); } - if (!isInsert) { + /* if (!isInsert) { apiTestCase.setName(apiTestCase.getName() + "_" + apiTestCase.getId().substring(0, 5)); - } + }*/ + ApiTestCaseExample example = new ApiTestCaseExample(); + example.createCriteria().andApiDefinitionIdEqualTo(apiDefinition.getId()); + apiTestCaseMapper.deleteByExample(example); apiTestCaseMapper.insert(apiTestCase); } } catch (Exception e) { diff --git a/backend/src/main/java/io/metersphere/base/domain/TestResourcePool.java b/backend/src/main/java/io/metersphere/base/domain/TestResourcePool.java index bf7ee5fcc7..7a85d96c96 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestResourcePool.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestResourcePool.java @@ -22,5 +22,9 @@ public class TestResourcePool implements Serializable { private String image; + private String heap; + + private String gcAlgo; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/TestResourcePoolExample.java b/backend/src/main/java/io/metersphere/base/domain/TestResourcePoolExample.java index 6cc15d65d4..0b1337b505 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestResourcePoolExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestResourcePoolExample.java @@ -643,6 +643,146 @@ public class TestResourcePoolExample { addCriterion("image not between", value1, value2, "image"); return (Criteria) this; } + + public Criteria andHeapIsNull() { + addCriterion("`heap` is null"); + return (Criteria) this; + } + + public Criteria andHeapIsNotNull() { + addCriterion("`heap` is not null"); + return (Criteria) this; + } + + public Criteria andHeapEqualTo(String value) { + addCriterion("`heap` =", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapNotEqualTo(String value) { + addCriterion("`heap` <>", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapGreaterThan(String value) { + addCriterion("`heap` >", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapGreaterThanOrEqualTo(String value) { + addCriterion("`heap` >=", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapLessThan(String value) { + addCriterion("`heap` <", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapLessThanOrEqualTo(String value) { + addCriterion("`heap` <=", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapLike(String value) { + addCriterion("`heap` like", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapNotLike(String value) { + addCriterion("`heap` not like", value, "heap"); + return (Criteria) this; + } + + public Criteria andHeapIn(List values) { + addCriterion("`heap` in", values, "heap"); + return (Criteria) this; + } + + public Criteria andHeapNotIn(List values) { + addCriterion("`heap` not in", values, "heap"); + return (Criteria) this; + } + + public Criteria andHeapBetween(String value1, String value2) { + addCriterion("`heap` between", value1, value2, "heap"); + return (Criteria) this; + } + + public Criteria andHeapNotBetween(String value1, String value2) { + addCriterion("`heap` not between", value1, value2, "heap"); + return (Criteria) this; + } + + public Criteria andGcAlgoIsNull() { + addCriterion("gc_algo is null"); + return (Criteria) this; + } + + public Criteria andGcAlgoIsNotNull() { + addCriterion("gc_algo is not null"); + return (Criteria) this; + } + + public Criteria andGcAlgoEqualTo(String value) { + addCriterion("gc_algo =", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoNotEqualTo(String value) { + addCriterion("gc_algo <>", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoGreaterThan(String value) { + addCriterion("gc_algo >", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoGreaterThanOrEqualTo(String value) { + addCriterion("gc_algo >=", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoLessThan(String value) { + addCriterion("gc_algo <", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoLessThanOrEqualTo(String value) { + addCriterion("gc_algo <=", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoLike(String value) { + addCriterion("gc_algo like", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoNotLike(String value) { + addCriterion("gc_algo not like", value, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoIn(List values) { + addCriterion("gc_algo in", values, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoNotIn(List values) { + addCriterion("gc_algo not in", values, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoBetween(String value1, String value2) { + addCriterion("gc_algo between", value1, value2, "gcAlgo"); + return (Criteria) this; + } + + public Criteria andGcAlgoNotBetween(String value1, String value2) { + addCriterion("gc_algo not between", value1, value2, "gcAlgo"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestResourcePoolMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/TestResourcePoolMapper.xml index 23969480f4..d36b8e20dc 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/TestResourcePoolMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/TestResourcePoolMapper.xml @@ -10,6 +10,8 @@ + + @@ -70,7 +72,8 @@ - id, `name`, `type`, description, `status`, create_time, update_time, image + id, `name`, `type`, description, `status`, create_time, update_time, image, `heap`, + gc_algo @@ -198,6 +215,12 @@ image = #{record.image,jdbcType=VARCHAR}, + + `heap` = #{record.heap,jdbcType=VARCHAR}, + + + gc_algo = #{record.gcAlgo,jdbcType=VARCHAR}, + @@ -212,7 +235,9 @@ `status` = #{record.status,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT}, - image = #{record.image,jdbcType=VARCHAR} + image = #{record.image,jdbcType=VARCHAR}, + `heap` = #{record.heap,jdbcType=VARCHAR}, + gc_algo = #{record.gcAlgo,jdbcType=VARCHAR} @@ -241,6 +266,12 @@ image = #{image,jdbcType=VARCHAR}, + + `heap` = #{heap,jdbcType=VARCHAR}, + + + gc_algo = #{gcAlgo,jdbcType=VARCHAR}, + where id = #{id,jdbcType=VARCHAR} @@ -252,7 +283,9 @@ `status` = #{status,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, - image = #{image,jdbcType=VARCHAR} + image = #{image,jdbcType=VARCHAR}, + `heap` = #{heap,jdbcType=VARCHAR}, + gc_algo = #{gcAlgo,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java index 476dec1c96..11b281cd2d 100644 --- a/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java +++ b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java @@ -25,6 +25,7 @@ public class ShiroUtils { filterChainDefinitionMap.put("/favicon.ico", "anon"); filterChainDefinitionMap.put("/display/file/**", "anon"); filterChainDefinitionMap.put("/jmeter/download/**", "anon"); + filterChainDefinitionMap.put("/jmeter/ping", "anon"); filterChainDefinitionMap.put("/authsource/list/allenable", "anon"); filterChainDefinitionMap.put("/sso/signin", "anon"); filterChainDefinitionMap.put("/sso/callback", "anon"); diff --git a/backend/src/main/java/io/metersphere/config/JmeterProperties.java b/backend/src/main/java/io/metersphere/config/JmeterProperties.java index af59bb8fb2..6d3e5d6cd3 100644 --- a/backend/src/main/java/io/metersphere/config/JmeterProperties.java +++ b/backend/src/main/java/io/metersphere/config/JmeterProperties.java @@ -17,4 +17,5 @@ public class JmeterProperties { private String home; private String heap = "-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"; + private String gcAlgo = "-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20"; } diff --git a/backend/src/main/java/io/metersphere/performance/controller/JmeterFileController.java b/backend/src/main/java/io/metersphere/performance/controller/JmeterFileController.java index f39070d3b8..6ad3c39089 100644 --- a/backend/src/main/java/io/metersphere/performance/controller/JmeterFileController.java +++ b/backend/src/main/java/io/metersphere/performance/controller/JmeterFileController.java @@ -18,6 +18,11 @@ public class JmeterFileController { @Resource private JmeterFileService jmeterFileService; + @GetMapping("ping") + public String checkStatus() { + return "PONG"; + } + @GetMapping("download") public ResponseEntity downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("resourceId") String resourceId, @RequestParam("ratio") double ratio, @RequestParam("startTime") long startTime, diff --git a/backend/src/main/java/io/metersphere/performance/engine/AbstractEngine.java b/backend/src/main/java/io/metersphere/performance/engine/AbstractEngine.java index 73b3b50833..5c5e9d88fb 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/AbstractEngine.java +++ b/backend/src/main/java/io/metersphere/performance/engine/AbstractEngine.java @@ -24,6 +24,8 @@ import java.util.UUID; public abstract class AbstractEngine implements Engine { protected String JMETER_IMAGE; + protected String HEAP; + protected String GC_ALGO; private Long startTime; private String reportId; protected LoadTestWithBLOBs loadTest; @@ -38,6 +40,8 @@ public abstract class AbstractEngine implements Engine { testResourcePoolService = CommonBeanFactory.getBean(TestResourcePoolService.class); testResourceService = CommonBeanFactory.getBean(TestResourceService.class); JMETER_IMAGE = CommonBeanFactory.getBean(JmeterProperties.class).getImage(); + HEAP = CommonBeanFactory.getBean(JmeterProperties.class).getHeap(); + GC_ALGO = CommonBeanFactory.getBean(JmeterProperties.class).getGcAlgo(); this.startTime = System.currentTimeMillis(); this.reportId = UUID.randomUUID().toString(); } @@ -71,6 +75,16 @@ public abstract class AbstractEngine implements Engine { if (StringUtils.isNotEmpty(image)) { JMETER_IMAGE = image; } + // heap + String heap = resourcePool.getHeap(); + if (StringUtils.isNotEmpty(heap)) { + HEAP = heap; + } + // gc_algo + String gcAlgo = resourcePool.getGcAlgo(); + if (StringUtils.isNotEmpty(gcAlgo)) { + GC_ALGO = gcAlgo; + } this.resourceList = testResourceService.getResourcesByPoolId(resourcePool.getId()); if (CollectionUtils.isEmpty(this.resourceList)) { MSException.throwException("Test Resource is empty"); diff --git a/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java b/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java index c59a8664e1..2e357a04d0 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java +++ b/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java @@ -7,7 +7,6 @@ import io.metersphere.commons.constants.ResourceStatusEnum; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.UrlTestUtils; -import io.metersphere.config.JmeterProperties; import io.metersphere.config.KafkaProperties; import io.metersphere.controller.ResultHolder; import io.metersphere.dto.BaseSystemConfigDTO; @@ -73,15 +72,14 @@ public class DockerTestEngine extends AbstractEngine { BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo(); KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class); - JmeterProperties jmeterProperties = CommonBeanFactory.getBean(JmeterProperties.class); - String metersphereUrl = "http://localhost:8081"; + String metersphereUrl = "http://localhost:8081"; // 占位符 if (baseInfo != null) { metersphereUrl = baseInfo.getUrl(); } - + String jmeterPingUrl = metersphereUrl + "/jmeter/ping"; // 检查下载地址是否正确 // docker 不能从 localhost 中下载文件 if (StringUtils.contains(metersphereUrl, "http://localhost") - || !UrlTestUtils.testUrlWithTimeOut(metersphereUrl, 1000)) { + || !UrlTestUtils.testUrlWithTimeOut(jmeterPingUrl, 1000)) { MSException.throwException(Translator.get("run_load_test_file_init_error")); } @@ -96,7 +94,8 @@ public class DockerTestEngine extends AbstractEngine { env.put("LOG_TOPIC", kafkaProperties.getLog().getTopic()); env.put("RESOURCE_ID", resource.getId()); env.put("THREAD_NUM", "0");// 传入0表示不用修改线程数 - env.put("HEAP", jmeterProperties.getHeap()); + env.put("HEAP", HEAP); + env.put("GC_ALGO", GC_ALGO); StartTestRequest startTestRequest = new StartTestRequest(); diff --git a/backend/src/main/java/io/metersphere/performance/engine/producer/LoadTestProducer.java b/backend/src/main/java/io/metersphere/performance/engine/producer/LoadTestProducer.java index c8a6bf3c62..8a9a4ff877 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/producer/LoadTestProducer.java +++ b/backend/src/main/java/io/metersphere/performance/engine/producer/LoadTestProducer.java @@ -1,8 +1,6 @@ package io.metersphere.performance.engine.producer; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.metersphere.commons.utils.LogUtil; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Service; @@ -11,22 +9,16 @@ import javax.annotation.Resource; @Service public class LoadTestProducer { + private static final String SEPARATOR = " "; - @Value("${kafka.topic}") + @Value("${kafka.log.topic}") private String topic; @Resource private KafkaTemplate kafkaTemplate; - @Resource - private ObjectMapper objectMapper; public void sendMessage(String reportId) { - Metric metric = new Metric(); - metric.setReportId(reportId); - metric.setThreadName("tearDown Thread Group"); // 发送停止消息 - try { - this.kafkaTemplate.send(topic, objectMapper.writeValueAsString(metric)); - } catch (JsonProcessingException e) { - LogUtil.error("发送停止消息失败", e); - } + String[] contents = new String[]{reportId, "none", "0", "Notifying test listeners of end of test"}; + String log = StringUtils.join(contents, SEPARATOR); + this.kafkaTemplate.send(topic, log); } } diff --git a/backend/src/main/java/io/metersphere/performance/engine/producer/Metric.java b/backend/src/main/java/io/metersphere/performance/engine/producer/Metric.java deleted file mode 100644 index c2de345a7f..0000000000 --- a/backend/src/main/java/io/metersphere/performance/engine/producer/Metric.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.metersphere.performance.engine.producer; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.Date; -import java.util.List; - -@Data -public class Metric { - @JsonProperty("test.id") - private String testId; - @JsonProperty("test.name") - private String testName; - @JsonProperty("test.startTime") - private Long clusterStartTime; - @JsonProperty("test.reportId") - private String reportId; - @JsonProperty("ContentType") - private String contentType; - @JsonProperty("IdleTime") - private Integer idleTime; - @JsonProperty("ElapsedTime") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ") - private Date elapsedTime; - @JsonProperty("ErrorCount") - private Integer errorCount; - @JsonProperty("Timestamp") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ") - private Date timestamp; - @JsonProperty("URL") - private String url; - @JsonProperty("SampleStartTime") - private String sampleStartTime; - @JsonProperty("Success") - private Boolean success; - @JsonProperty("Bytes") - private Integer bytes; - @JsonProperty("SentBytes") - private Integer sentBytes; - @JsonProperty("AllThreads") - private Integer allThreads; - @JsonProperty("TestElement.name") - private String testElementName; - @JsonProperty("DataType") - private String dataType; - @JsonProperty("ResponseTime") - private Integer responseTime; - @JsonProperty("SampleCount") - private Integer sampleCount; - @JsonProperty("FailureMessage") - private String failureMessage; - @JsonProperty("ConnectTime") - private Integer connectTime; - @JsonProperty("ResponseCode") - private String responseCode; - @JsonProperty("TestStartTime") - private Long testStartTime; - @JsonProperty("AssertionResults") - private List assertionResults; - @JsonProperty("Latency") - private Integer latency; - @JsonProperty("InjectorHostname") - private String injectorHostname; - @JsonProperty("GrpThreads") - private Integer grpThreads; - @JsonProperty("SampleEndTime") - private String sampleEndTime; - @JsonProperty("BodySize") - private Long bodySize; - @JsonProperty("ThreadName") - private String threadName; - @JsonProperty("SampleLabel") - private String sampleLabel; - -} diff --git a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java index 73f401036e..8c956b18f5 100644 --- a/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java +++ b/backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java @@ -89,8 +89,6 @@ public class JmeterDocumentParser implements DocumentParser { if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) { parseHashTree(ele); } else if (nodeNameEquals(ele, TEST_PLAN)) { - processSetupTestPlan(ele); - processTearDownTestPlan(ele); processCheckoutConfigTestElement(ele); processCheckoutDnsCacheManager(ele); processCheckoutArguments(ele); @@ -484,187 +482,18 @@ public class JmeterDocumentParser implements DocumentParser { } } - private void processSetupTestPlan(Element ele) { - Document document = ele.getOwnerDocument(); - Node hashTree = ele.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - - KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class); - String bootstrapServers = kafkaProperties.getBootstrapServers(); - String[] servers = StringUtils.split(bootstrapServers, ","); - for (String s : servers) { - String[] ipAndPort = StringUtils.split(s, ":"); - Element setupElement = document.createElement("SetupThreadGroup"); - setupElement.setAttribute("guiclass", "SetupThreadGroupGui"); - setupElement.setAttribute("testclass", "SetupThreadGroup"); - setupElement.setAttribute("testname", "setUp Thread Group"); - setupElement.setAttribute("enabled", "true"); - setupElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "stoptestnow")); - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "ThreadGroup.main_controller"); - elementProp.setAttribute("elementType", "LoopController"); - elementProp.setAttribute("guiclass", "LoopControlPanel"); - elementProp.setAttribute("testclass", "LoopController"); - elementProp.setAttribute("testname", "Loop Controller"); - elementProp.setAttribute("enabled", "true"); - elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false)); - elementProp.appendChild(createIntProp(document, "LoopController.loops", 1)); - setupElement.appendChild(elementProp); - setupElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1")); - setupElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1")); - setupElement.appendChild(createStringProp(document, "ThreadGroup.duration", "")); - setupElement.appendChild(createStringProp(document, "ThreadGroup.delay", "")); - setupElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false)); - setupElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true)); - hashTree.appendChild(setupElement); - - Element setupHashTree = document.createElement(HASH_TREE_ELEMENT); - - Element tcpSampler = document.createElement("TCPSampler"); - tcpSampler.setAttribute("guiclass", "TCPSamplerGui"); - tcpSampler.setAttribute("testclass", "TCPSampler"); - tcpSampler.setAttribute("testname", "TCP Sampler"); - tcpSampler.setAttribute("enabled", "true"); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.classname", "TCPClientImpl")); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.server", ipAndPort[0])); - tcpSampler.appendChild(createBoolProp(document, "TCPSampler.reUseConnection", true)); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.port", ipAndPort[1])); - tcpSampler.appendChild(createBoolProp(document, "TCPSampler.nodelay", false)); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.timeout", "100")); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.ctimeout", "100")); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.request", "1010")); - tcpSampler.appendChild(createBoolProp(document, "TCPSampler.closeConnection", false)); - tcpSampler.appendChild(createStringProp(document, "TCPSampler.EolByte", "0")); - tcpSampler.appendChild(createStringProp(document, "ConfigTestElement.username", "")); - tcpSampler.appendChild(createStringProp(document, "ConfigTestElement.password", "")); - - Element tcpSamplerHashTree = document.createElement(HASH_TREE_ELEMENT); - - Element responseAssertion = document.createElement("ResponseAssertion"); - responseAssertion.setAttribute("guiclass", "AssertionGui"); - responseAssertion.setAttribute("testclass", "ResponseAssertion"); - responseAssertion.setAttribute("testname", "Response Assertion"); - responseAssertion.setAttribute("enabled", "true"); - Element collectionProp = document.createElement("collectionProp"); - collectionProp.setAttribute("name", "Asserion.test_strings"); - collectionProp.appendChild(createStringProp(document, "49586", "200")); - responseAssertion.appendChild(collectionProp); - responseAssertion.appendChild(createStringProp(document, "Assertion.custom_message", "")); - responseAssertion.appendChild(createStringProp(document, "Assertion.test_field", "Assertion.response_code")); - responseAssertion.appendChild(createBoolProp(document, "Assertion.assume_success", false)); - responseAssertion.appendChild(createIntProp(document, "Assertion.test_type", 8)); - tcpSamplerHashTree.appendChild(responseAssertion); - // 添加空的hashtree - tcpSamplerHashTree.appendChild(document.createElement(HASH_TREE_ELEMENT)); - - setupHashTree.appendChild(tcpSampler); - setupHashTree.appendChild(tcpSamplerHashTree); - - hashTree.appendChild(setupHashTree); - } - } - - private void processTearDownTestPlan(Element ele) { - /*true*/ - Document document = ele.getOwnerDocument(); - Element tearDownSwitch = createBoolProp(document, "TestPlan.tearDown_on_shutdown", true); - ele.appendChild(tearDownSwitch); - - Node hashTree = ele.getNextSibling(); - while (!(hashTree instanceof Element)) { - hashTree = hashTree.getNextSibling(); - } - /* - - continue - - false - 1 - - 1 - 1 - false - - - true - - */ - Element tearDownElement = document.createElement("PostThreadGroup"); - tearDownElement.setAttribute("guiclass", "PostThreadGroupGui"); - tearDownElement.setAttribute("testclass", "PostThreadGroup"); - tearDownElement.setAttribute("testname", "tearDown Thread Group"); - tearDownElement.setAttribute("enabled", "true"); - tearDownElement.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue")); - tearDownElement.appendChild(createStringProp(document, "ThreadGroup.num_threads", "1")); - tearDownElement.appendChild(createStringProp(document, "ThreadGroup.ramp_time", "1")); - tearDownElement.appendChild(createStringProp(document, "ThreadGroup.duration", "")); - tearDownElement.appendChild(createStringProp(document, "ThreadGroup.delay", "")); - tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.scheduler", false)); - tearDownElement.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true)); - Element elementProp = document.createElement("elementProp"); - elementProp.setAttribute("name", "ThreadGroup.main_controller"); - elementProp.setAttribute("elementType", "LoopController"); - elementProp.setAttribute("guiclass", "LoopControlPanel"); - elementProp.setAttribute("testclass", "LoopController"); - elementProp.setAttribute("testname", "Loop Controller"); - elementProp.setAttribute("enabled", "true"); - elementProp.appendChild(createBoolProp(document, "LoopController.continue_forever", false)); - elementProp.appendChild(createStringProp(document, "LoopController.loops", "1")); - tearDownElement.appendChild(elementProp); - hashTree.appendChild(tearDownElement); - - Element tearDownHashTree = document.createElement(HASH_TREE_ELEMENT); - /* - - */ - Element onceOnlyController = document.createElement("OnceOnlyController"); - onceOnlyController.setAttribute("guiclass", "OnceOnlyControllerGui"); - onceOnlyController.setAttribute("testclass", "OnceOnlyController"); - onceOnlyController.setAttribute("testname", "Once Only Controller"); - onceOnlyController.setAttribute("enabled", "true"); - tearDownHashTree.appendChild(onceOnlyController); - /* - - - false - true - false - - - - */ - Element onceOnlyHashTree = document.createElement(HASH_TREE_ELEMENT); - Element debugSampler = document.createElement("DebugSampler"); - debugSampler.setAttribute("guiclass", "TestBeanGUI"); - debugSampler.setAttribute("testclass", "DebugSampler"); - debugSampler.setAttribute("testname", "Debug Sampler"); - debugSampler.setAttribute("enabled", "true"); - debugSampler.appendChild(createBoolProp(document, "displayJMeterProperties", false)); - debugSampler.appendChild(createBoolProp(document, "displayJMeterVariables", true)); - debugSampler.appendChild(createBoolProp(document, "displaySystemProperties", false)); - onceOnlyHashTree.appendChild(debugSampler); - // 添加空的 hashTree - onceOnlyHashTree.appendChild(document.createElement(HASH_TREE_ELEMENT)); - tearDownHashTree.appendChild(onceOnlyHashTree); - hashTree.appendChild(tearDownHashTree); - // 添加backend listener - processCheckoutBackendListener(tearDownElement); - } - private Element createBoolProp(Document document, String name, boolean value) { - Element tearDownSwitch = document.createElement("boolProp"); - tearDownSwitch.setAttribute("name", name); - tearDownSwitch.appendChild(document.createTextNode(String.valueOf(value))); - return tearDownSwitch; + Element boolProp = document.createElement("boolProp"); + boolProp.setAttribute("name", name); + boolProp.appendChild(document.createTextNode(String.valueOf(value))); + return boolProp; } private Element createIntProp(Document document, String name, int value) { - Element tearDownSwitch = document.createElement("intProp"); - tearDownSwitch.setAttribute("name", name); - tearDownSwitch.appendChild(document.createTextNode(String.valueOf(value))); - return tearDownSwitch; + Element intProp = document.createElement("intProp"); + intProp.setAttribute("name", name); + intProp.appendChild(document.createTextNode(String.valueOf(value))); + return intProp; } private void processBackendListener(Element backendListener) { diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index 2e2589acfa..bfacfd6067 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -169,7 +169,7 @@ public class TestPlanService { testPlan.setActualEndTime(null); } // 已完成->进行中,结束时间置空 } else if (!res.getStatus().equals(TestPlanStatus.Prepare.name()) && - testPlan.getStatus().equals(TestPlanStatus.Prepare.name())) { + TestPlanStatus.Prepare.name().equals(testPlan.getStatus())) { testPlan.setActualStartTime(null); testPlan.setActualEndTime(null); } // 非未开始->未开始,时间都置空 @@ -183,7 +183,7 @@ public class TestPlanService { List userIds = new ArrayList<>(); userIds.add(testPlan.getPrincipal()); AddTestPlanRequest testPlans = new AddTestPlanRequest(); - int i = testPlanMapper.updateByPrimaryKey(testPlan); // 更新 + int i = testPlanMapper.updateByPrimaryKeySelective(testPlan); // 更新 if (!StringUtils.isBlank(testPlan.getStatus())) { BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId())); String context = getTestPlanContext(testPlans, NoticeConstants.Event.UPDATE); diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index b9042074b7..e6af25ffb8 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit b9042074b780205e275c674f64417799110519fd +Subproject commit e6af25ffb8cabdfc2de5ae07cb04492cc78345f3 diff --git a/backend/src/main/resources/db/migration/V78__test_resource_pool_heap_gc.sql b/backend/src/main/resources/db/migration/V78__test_resource_pool_heap_gc.sql new file mode 100644 index 0000000000..7035f97475 --- /dev/null +++ b/backend/src/main/resources/db/migration/V78__test_resource_pool_heap_gc.sql @@ -0,0 +1,4 @@ +ALTER TABLE test_resource_pool + ADD heap VARCHAR(200) NULL; +ALTER TABLE test_resource_pool + ADD gc_algo VARCHAR(200) NULL; \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 8497b76b09..32eec058b7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,6 +20,7 @@ "diffable-html": "^4.0.0", "echarts": "^4.6.0", "el-table-infinite-scroll": "^1.0.10", + "el-tree-transfer": "^2.4.7", "element-ui": "^2.13.0", "generate-schema": "^2.6.0", "html2canvas": "^1.0.0-rc.7", diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index ace39ff1bc..33a1ad6dd4 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -12,8 +12,7 @@ @select-all="handleSelectAll" @select="handleSelect" @header-dragend="headerDragend" - :height="screenHeight" - v-loading="loading"> + :height="screenHeight"> @@ -29,7 +28,7 @@ - - - - - - - - -