From b9586a2b5db749ab3f1bf6428748b7c6f739037c Mon Sep 17 00:00:00 2001 From: q4speed Date: Thu, 16 Jul 2020 13:09:40 +0800 Subject: [PATCH 01/11] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/test/model/ScenarioModel.js | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/frontend/src/business/components/api/test/model/ScenarioModel.js b/frontend/src/business/components/api/test/model/ScenarioModel.js index afa0c5b2ca..19f8d1a21b 100644 --- a/frontend/src/business/components/api/test/model/ScenarioModel.js +++ b/frontend/src/business/components/api/test/model/ScenarioModel.js @@ -400,12 +400,12 @@ class JMXRequest { this.pathname = decodeURIComponent(url.pathname); this.port = url.port; this.protocol = url.protocol.split(":")[0]; - this.pathname = this.getPostQueryParameters(request, this.pathname); + this.pathname = this.getPostQueryParameters(request, this.pathname); } else { this.environment = request.environment; this.port = request.environment.port; this.path = decodeURIComponent(request.path); - this.path = this.getPostQueryParameters(request, this.path); + this.path = this.getPostQueryParameters(request, this.path); } } } @@ -485,22 +485,26 @@ class JMXGenerator { }) } - addScenarioVariables(threadGroup, scenario) { - let scenarioVariableKeys = new Set(); - scenario.variables.forEach(item => { - scenarioVariableKeys.add(item.name); + addEnvironments(environments, target) { + let keys = new Set(); + target.forEach(item => { + keys.add(item.name); }); + let envArray = environments; + if (!(envArray instanceof Array)) { + envArray = JSON.parse(environments); + envArray.forEach(item => { + if (item.name && !keys.has(item.name)) { + target.push(new KeyValue(item.name, item.value)); + } + }) + } + } + + addScenarioVariables(threadGroup, scenario) { let environment = scenario.environment; if (environment) { - let envVariables = environment.variables; - if (!(envVariables instanceof Array)) { - envVariables = JSON.parse(environment.variables); - envVariables.forEach(item => { - if (item.name && !scenarioVariableKeys.has(item.name)) { - scenario.variables.push(new KeyValue(item.name, item.value)); - } - }) - } + this.addEnvironments(environment.variables, scenario.variables) } let args = this.filterKV(scenario.variables); if (args.length > 0) { @@ -510,21 +514,9 @@ class JMXGenerator { } addScenarioHeaders(threadGroup, scenario) { - let scenarioHeaderKeys = new Set(); - scenario.headers.forEach(item => { - scenarioHeaderKeys.add(item.name); - }); let environment = scenario.environment; if (environment) { - let envHeaders = environment.headers; - if (!(envHeaders instanceof Array)) { - envHeaders = JSON.parse(environment.headers); - envHeaders.forEach(item => { - if (item.name && !scenarioHeaderKeys.has(item.name)) { - scenario.headers.push(new KeyValue(item.name, item.value)); - } - }) - } + this.addEnvironments(environment.headers, scenario.headers) } let headers = this.filterKV(scenario.headers); if (headers.length > 0) { From e2c3809f8c11162548048aa49baf79822153f958 Mon Sep 17 00:00:00 2001 From: BugKing Date: Thu, 16 Jul 2020 16:00:16 +0800 Subject: [PATCH 02/11] =?UTF-8?q?docs:=20=E5=9C=A8=20=E7=83=ADa=E7=9A=84?= =?UTF-8?q?=E4=B9=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index d1f25726d0..3992f40dee 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,21 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu - [完整文档](https://metersphere.io/docs/) - [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4) +## 版本说明 + +MeterSphere 版本号命名规则为:v大版本.功能版本.Bug修复版本。比如: + +``` +v1.0.1 是 v1.0.0 之后的Bug修复版本; +v1.1.0 是 v1.0.0 之后的功能版本。 +``` +像其它优秀开源项目一样,MeterSphere 将每月发布一个功能版本,并同时维护 3 个功能版本。比如: + +``` +在 v1.3 发布前,我们会同时维护 v1.0、v1.1、v1.2; +在 v1.3 发布后,我们会同时维护 v1.1、v1.2、v1.3;v1.0 会停止维护。 +``` + ## 技术优势 - 全生命周期: 能够覆盖从测试计划到测试执行、测试报告分析的不同阶段; From 04e27d27c8e8369e313dba27e324c2d7e0466adf Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Thu, 16 Jul 2020 16:57:33 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/components/ApiEnvironmentConfig.vue | 29 ++++++++++++++----- .../environment/EnvironmentEdit.vue | 19 +++++++----- .../common/components/MsAsideItem.vue | 8 ++--- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue b/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue index f7a735befa..033d279310 100644 --- a/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue +++ b/frontend/src/business/components/api/test/components/ApiEnvironmentConfig.vue @@ -50,19 +50,34 @@ this.getEnvironments(); }, deleteEnvironment(environment) { - this.result = this.$get('/api/environment/delete/' + environment.id, response => { - this.$success(this.$t('commons.delete_success')); - this.getEnvironments(); - }); + if (environment.id) { + this.result = this.$get('/api/environment/delete/' + environment.id, () => { + this.$success(this.$t('commons.delete_success')); + this.getEnvironments(); + }); + } }, copyEnvironment(environment) { let newEnvironment = {}; Object.assign(newEnvironment, environment); newEnvironment.id = null; + newEnvironment.name = this.getNoRepeatName(newEnvironment.name); + this.$refs.environmentEdit._save(newEnvironment); this.environments.push(newEnvironment); + this.$refs.environmentItems.itemSelected(this.environments.length -1 , newEnvironment); + }, + getNoRepeatName(name) { + for (let i in this.environments) { + if (this.environments[i].name === name) { + return this.getNoRepeatName(name + ' copy'); + } + } + return name; }, addEnvironment() { - this.environments.push(this.getDefaultEnvironment()); + let newEnvironment = this.getDefaultEnvironment(); + this.environments.push(newEnvironment); + this.$refs.environmentItems.itemSelected(this.environments.length -1 , newEnvironment); }, environmentSelected(environment) { this.getEnvironment(environment); @@ -97,6 +112,7 @@ close() { this.$emit('close'); this.visible = false; + this.$refs.environmentEdit.clearValidate(); } } } @@ -116,7 +132,4 @@ height: 100%; position: absolute; } - - - diff --git a/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue b/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue index d34077a6db..3b3380c425 100644 --- a/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue +++ b/frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue @@ -78,30 +78,30 @@ save() { this.$refs['from'].validate((valid) => { if (valid) { - this._save(); + this._save(this.environment); } else { return false; } }); }, - _save() { - let param = this.buildParam(); + _save(environment) { + let param = this.buildParam(environment); let url = '/api/environment/add'; if (param.id) { url = '/api/environment/update'; } this.result = this.$post(url, param, response => { if (!param.id) { - this.environment.id = response.data; + environment.id = response.data; } this.$success(this.$t('commons.save_success')); }); }, - buildParam() { + buildParam(environment) { let param = {}; - Object.assign(param, this.environment); - param.variables = JSON.stringify(this.environment.variables); - param.headers = JSON.stringify(this.environment.headers); + Object.assign(param, environment); + param.variables = JSON.stringify(environment.variables); + param.headers = JSON.stringify(environment.headers); return param; }, validateSocket(socket) { @@ -135,6 +135,9 @@ }, cancel() { this.$emit('close'); + }, + clearValidate() { + this.$refs["from"].clearValidate(); } }, } diff --git a/frontend/src/business/components/common/components/MsAsideItem.vue b/frontend/src/business/components/common/components/MsAsideItem.vue index 48b0f33edb..2f37bbe9c7 100644 --- a/frontend/src/business/components/common/components/MsAsideItem.vue +++ b/frontend/src/business/components/common/components/MsAsideItem.vue @@ -10,14 +10,10 @@ -
- - - - + - +
From dc25e0fe63fc8a5d1f82926df39fedb6c763363a Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Thu, 16 Jul 2020 17:26:23 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E6=8E=A5=E5=8F=A3=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/test/components/ApiScenarioForm.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/business/components/api/test/components/ApiScenarioForm.vue b/frontend/src/business/components/api/test/components/ApiScenarioForm.vue index 383a82e190..deb002d984 100644 --- a/frontend/src/business/components/api/test/components/ApiScenarioForm.vue +++ b/frontend/src/business/components/api/test/components/ApiScenarioForm.vue @@ -16,10 +16,6 @@ - - - - @@ -86,6 +82,7 @@ for (let i in this.environments) { if (this.environments[i].id === this.scenario.environmentId) { this.scenario.environment = this.environments[i]; + this.setRequestEnvironments(); hasEnvironment = true; break; } @@ -104,9 +101,7 @@ for (let i in this.environments) { if (this.environments[i].id === value) { this.scenario.environment = this.environments[i]; - this.scenario.requests.forEach(request => { - request.environment = this.environments[i]; - }); + this.setRequestEnvironments(); break; } } @@ -126,6 +121,11 @@ }, environmentConfigClose() { this.getEnvironments(); + }, + setRequestEnvironments() { + this.scenario.requests.forEach(request => { + request.environment = this.scenario.environment; + }); } } } From c16f60e87dbabeebc68fff4cb55c45d5f33ea43a Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Thu, 16 Jul 2020 18:04:11 +0800 Subject: [PATCH 05/11] =?UTF-8?q?fix:=20=E4=BF=9D=E5=AD=98=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/api/service/ApiTestEnvironmentService.java | 2 +- frontend/src/business/components/api/test/ApiTestConfig.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 e2e485ae2a..acaa4e3551 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestEnvironmentService.java @@ -34,7 +34,7 @@ public class ApiTestEnvironmentService { } public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) { - apiTestEnvironmentMapper.updateByPrimaryKeySelective(apiTestEnvironment); + apiTestEnvironmentMapper.updateByPrimaryKey(apiTestEnvironment); } public String add(ApiTestEnvironmentWithBLOBs apiTestEnvironmentWithBLOBs) { diff --git a/frontend/src/business/components/api/test/ApiTestConfig.vue b/frontend/src/business/components/api/test/ApiTestConfig.vue index 080c03aecb..0d27df2b79 100644 --- a/frontend/src/business/components/api/test/ApiTestConfig.vue +++ b/frontend/src/business/components/api/test/ApiTestConfig.vue @@ -255,7 +255,7 @@ return this.test.isValid() && !this.change; }, isDisabled() { - return !(this.test.isValid()) + return !(this.test.isValid()) && !this.change; } }, From b29a4f91090b1693ae4e3f6ab4f136b68c85c5cb Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Thu, 16 Jul 2020 18:50:45 +0800 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20=E5=AF=BC=E5=85=A5=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=B8=8D=E6=A0=A1=E9=AA=8C=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metersphere/api/service/APITestService.java | 15 ++------------- .../components/api/test/ApiTestConfig.vue | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) 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 7f49463951..a41addfd2e 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -31,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.List; @@ -39,8 +40,6 @@ import java.util.Random; import java.util.UUID; import java.util.stream.Collectors; -import javax.annotation.Resource; - @Service @Transactional(rollbackFor = Exception.class) public class APITestService { @@ -76,6 +75,7 @@ public class APITestService { if (files == null || files.isEmpty()) { throw new IllegalArgumentException(Translator.get("file_cannot_be_null")); } + checkNameExist(request); ApiTest test = createTest(request); saveFile(test.getId(), files); } @@ -173,12 +173,6 @@ public class APITestService { } } - private Boolean isNameExist(SaveAPITestRequest request) { - ApiTestExample example = new ApiTestExample(); - example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); - return apiTestMapper.countByExample(example) > 0; - } - private ApiTest updateTest(SaveAPITestRequest request) { checkNameExist(request); final ApiTest test = new ApiTest(); @@ -193,7 +187,6 @@ public class APITestService { } private ApiTest createTest(SaveAPITestRequest request) { - checkNameExist(request); final ApiTest test = new ApiTest(); test.setId(request.getId()); test.setName(request.getName()); @@ -290,10 +283,6 @@ public class APITestService { request.setName(name.substring(0, name.length() - suffix.length())); } } - - if (isNameExist(request)) { - request.setName(request.getName() + "_" + request.getId().substring(0, 5)); - } return request; } } diff --git a/frontend/src/business/components/api/test/ApiTestConfig.vue b/frontend/src/business/components/api/test/ApiTestConfig.vue index 0d27df2b79..5d474723c5 100644 --- a/frontend/src/business/components/api/test/ApiTestConfig.vue +++ b/frontend/src/business/components/api/test/ApiTestConfig.vue @@ -255,7 +255,7 @@ return this.test.isValid() && !this.change; }, isDisabled() { - return !(this.test.isValid()) && !this.change; + return !(this.test.isValid() && this.change); } }, From d830cc85db51874b821f76cd6b58f0c633a74fec Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Fri, 17 Jul 2020 09:34:39 +0800 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20postman=20=E5=AF=BC=E5=85=A5body?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/api/parse/PostmanParser.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java index ed270d27b9..8f3988fb3a 100644 --- a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java @@ -14,10 +14,23 @@ import org.apache.commons.lang3.StringUtils; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class PostmanParser extends ApiImportAbstractParser { + private static Map postmanBodyRowMap; + + static { + postmanBodyRowMap = new HashMap<>(); + postmanBodyRowMap.put("json", "application/json"); + postmanBodyRowMap.put("text", "text/plain"); + postmanBodyRowMap.put("html", "text/html"); + postmanBodyRowMap.put("xml", "text/xml"); + postmanBodyRowMap.put("javascript", "application/x-javascript"); + } + @Override public ApiImport parse(InputStream source) { String testStr = getApiTestStr(source); @@ -69,7 +82,7 @@ public class PostmanParser extends ApiImportAbstractParser { if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) { body.setRaw(postmanBody.getString(bodyMode)); body.setType(MsRequestBodyType.RAW.value()); - String contentType = postmanBody.getJSONObject("options").getJSONObject("raw").getString("language"); + String contentType = postmanBodyRowMap.get(postmanBody.getJSONObject("options").getJSONObject("raw").getString("language")); addContentType(request, contentType); } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value()) || StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) { List postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class); From 1b898900167cb74816945c05f2a3065de53df883 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Fri, 17 Jul 2020 10:17:47 +0800 Subject: [PATCH 08/11] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=20dubbo=20=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 20 + .../metersphere/api/dubbo/MethodArgument.java | 92 +++ .../api/dubbo/ProviderService.java | 112 ++++ .../api/dubbo/RegistryServerSync.java | 171 +++++ .../api/dubbo/utils/Constants.java | 614 ++++++++++++++++++ .../api/dubbo/utils/JsonUtils.java | 52 ++ .../metersphere/api/dubbo/utils/MD5Util.java | 65 ++ .../api/dubbo/utils/StringUtils.java | 69 ++ 8 files changed, 1195 insertions(+) create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/MethodArgument.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/ProviderService.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/RegistryServerSync.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/utils/Constants.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/utils/JsonUtils.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/utils/MD5Util.java create mode 100644 backend/src/main/java/io/metersphere/api/dubbo/utils/StringUtils.java diff --git a/backend/pom.xml b/backend/pom.xml index 742a2efd97..8acf99d312 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -154,6 +154,26 @@ + + org.apache.dubbo + dubbo + 2.7.7 + + + org.apache.zookeeper + zookeeper + 3.4.13 + + + org.apache.curator + curator-framework + 4.0.1 + + + org.apache.curator + curator-recipes + 4.0.1 + com.alibaba diff --git a/backend/src/main/java/io/metersphere/api/dubbo/MethodArgument.java b/backend/src/main/java/io/metersphere/api/dubbo/MethodArgument.java new file mode 100644 index 0000000000..a9efb359b8 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/MethodArgument.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.metersphere.api.dubbo; + + +import io.metersphere.api.dubbo.utils.JsonUtils; +import io.metersphere.api.dubbo.utils.StringUtils; + +import java.io.Serializable; + + +/** + * MethodArgument + */ +public class MethodArgument implements Serializable { + + private static final long serialVersionUID = -2567457932227227262L; + private String paramType; + private String paramValue; + + public MethodArgument(String paramType, String paramValue) { + setParamType(paramType); + setParamValue(paramValue); + } + + public String getParamType() { + return paramType; + } + + public void setParamType(String paramType) { + this.paramType = (paramType == null ? null : StringUtils.trimAllWhitespace(paramType)); + } + + public String getParamValue() { + return paramValue; + } + + public void setParamValue(String paramValue) { + this.paramValue = (paramValue == null ? null : StringUtils.trimWhitespace(paramValue)); + } + + @Override + public String toString() { + return JsonUtils.toJson(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((paramType == null) ? 0 : paramType.hashCode()); + result = prime * result + ((paramValue == null) ? 0 : paramValue.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MethodArgument other = (MethodArgument) obj; + if (paramType == null) { + if (other.paramType != null) + return false; + } else if (!paramType.equals(other.paramType)) + return false; + if (paramValue == null) { + if (other.paramValue != null) + return false; + } else if (!paramValue.equals(other.paramValue)) + return false; + return true; + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/ProviderService.java b/backend/src/main/java/io/metersphere/api/dubbo/ProviderService.java new file mode 100644 index 0000000000..3478a864ac --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/ProviderService.java @@ -0,0 +1,112 @@ +package io.metersphere.api.dubbo; + +import io.metersphere.api.dubbo.utils.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.ReferenceConfigBase; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.utils.ReferenceConfigCache; +import org.apache.dubbo.registry.RegistryService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * ProviderService + */ +public class ProviderService implements Serializable { + + private static final Logger log = LoggerFactory.getLogger(ProviderService.class); + + private static final long serialVersionUID = -750353929981409079L; + ConcurrentMap> providerUrls = null; + + private static ConcurrentMap cache = new ConcurrentHashMap<>(); + + public static ProviderService get(String key) { + ProviderService service = cache.get(key); + if (service == null) { + cache.putIfAbsent(key, new ProviderService()); + service = cache.get(key); + } + return service; + } + + public Map findByService(String serviceName) { + return providerUrls == null ? null : providerUrls.get(serviceName); + } + + public List getProviders(String protocol, String address, String group) throws RuntimeException { + if (protocol.equals("zookeeper") || protocol.equals("nacos") || protocol.equals("redis")) { + return executeRegistry(protocol, address, group); +// } else if (protocol.equals("none")) { +// return executeTelnet(); + } else { + throw new RuntimeException("Registry Protocol please use zookeeper or nacos or redis!"); + } + } + + private List executeTelnet() throws RuntimeException { + throw new RuntimeException(); + } + + private List executeRegistry(String protocol, String address, String group) throws RuntimeException { + ReferenceConfig reference = new ReferenceConfig(); + // set application + reference.setApplication(new ApplicationConfig("DubboSample")); + RegistryConfig registry = null; + switch (protocol) { + case Constants.REGISTRY_ZOOKEEPER: + registry = new RegistryConfig(); + registry.setProtocol(Constants.REGISTRY_ZOOKEEPER); + registry.setGroup(group); + registry.setAddress(address); + reference.setRegistry(registry); + break; + case Constants.REGISTRY_NACOS: + registry = new RegistryConfig(); + registry.setProtocol(Constants.REGISTRY_NACOS); + registry.setGroup(group); + registry.setAddress(address); + reference.setRegistry(registry); + break; + case Constants.REGISTRY_REDIS: + registry = new RegistryConfig(); + registry.setProtocol(Constants.REGISTRY_REDIS); + registry.setGroup(group); + registry.setAddress(address); + reference.setRegistry(registry); + break; + } + reference.setInterface("org.apache.dubbo.registry.RegistryService"); + try { + ReferenceConfigCache cache = ReferenceConfigCache.getCache(address + "_" + group, new ReferenceConfigCache.KeyGenerator() { + + @Override + public String generateKey(ReferenceConfigBase referenceConfig) { + return referenceConfig.toString(); + } + }); + RegistryService registryService = (RegistryService) cache.get(reference); + if (registryService == null) { + throw new RuntimeException("Can't get the interface list, please check if the address is wrong!"); + } + RegistryServerSync registryServerSync = RegistryServerSync.get(address + "_" + group); + registryService.subscribe(RegistryServerSync.SUBSCRIBE, registryServerSync); + List ret = new ArrayList(); + providerUrls = registryServerSync.getRegistryCache().get(com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY); + if (providerUrls != null) ret.addAll(providerUrls.keySet()); + return ret; + } catch (Exception e) { + log.error("get provider list is error!", e); + throw new RuntimeException("Can't get the interface list, please check if the address is wrong!", e); + } + } +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/RegistryServerSync.java b/backend/src/main/java/io/metersphere/api/dubbo/RegistryServerSync.java new file mode 100644 index 0000000000..6a58c8349d --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/RegistryServerSync.java @@ -0,0 +1,171 @@ +package io.metersphere.api.dubbo; + +import io.metersphere.api.dubbo.utils.MD5Util; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.constants.RegistryConstants; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.registry.Constants; +import org.apache.dubbo.registry.NotifyListener; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * RegistryServerSync + */ +public class RegistryServerSync implements NotifyListener, Serializable { + + private static final long serialVersionUID = -1744756264793278229L; + private static ConcurrentMap cache = new ConcurrentHashMap<>(); + + public static RegistryServerSync get(String key) { + RegistryServerSync sync = cache.get(key); + if (sync == null) { + cache.putIfAbsent(key, new RegistryServerSync()); + sync = cache.get(key); + } + return sync; + } + + public static final URL SUBSCRIBE = new URL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "", + CommonConstants.INTERFACE_KEY, CommonConstants.ANY_VALUE, + CommonConstants.GROUP_KEY, CommonConstants.ANY_VALUE, + CommonConstants.VERSION_KEY, CommonConstants.ANY_VALUE, + CommonConstants.CLASSIFIER_KEY, CommonConstants.ANY_VALUE, + RegistryConstants.CATEGORY_KEY, RegistryConstants.PROVIDERS_CATEGORY, +// Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," +// + Constants.CONSUMERS_CATEGORY + "," +// + Constants.ROUTERS_CATEGORY + "," +// + Constants.CONFIGURATORS_CATEGORY, + CommonConstants.ENABLED_KEY, CommonConstants.ANY_VALUE, + CommonConstants.CHECK_KEY, String.valueOf(false)); + + // ConcurrentMap>> + private final ConcurrentMap>> + registryCache = new ConcurrentHashMap<>(); + /** + * Make sure ID never changed when the same url notified many times + */ + private final ConcurrentHashMap URL_IDS_MAPPER = new ConcurrentHashMap<>(); + + public RegistryServerSync() { + } + + public ConcurrentMap>> getRegistryCache() { + return registryCache; + } + + @Override + public void notify(List urls) { + if (urls == null || urls.isEmpty()) { + return; + } + // Map>> + final Map>> categories = new HashMap<>(); + String interfaceName = null; + for (URL url : urls) { + String category = url.getParameter(RegistryConstants.CATEGORY_KEY, RegistryConstants.PROVIDERS_CATEGORY); + if (RegistryConstants.EMPTY_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { // NOTE: group and version in empty protocol is * + ConcurrentMap> services = registryCache.get(category); + if (services != null) { + String group = url.getParameter(CommonConstants.GROUP_KEY); + String version = url.getParameter(CommonConstants.VERSION_KEY); + // NOTE: group and version in empty protocol is * + if (!CommonConstants.ANY_VALUE.equals(group) && !CommonConstants.ANY_VALUE.equals(version)) { + services.remove(url.getServiceKey()); + } else { + for (Map.Entry> serviceEntry : services.entrySet()) { + String service = serviceEntry.getKey(); + if (this.getInterface(service).equals(url.getServiceInterface()) + && (CommonConstants.ANY_VALUE.equals(group) || StringUtils.isEquals(group, this.getGroup(service))) + && (CommonConstants.ANY_VALUE.equals(version) || StringUtils.isEquals(version, this.getVersion(service)))) { + services.remove(service); + } + } + } + } + } else { + if (StringUtils.isEmpty(interfaceName)) { + interfaceName = url.getServiceInterface(); + } + Map> services = categories.get(category); + if (services == null) { + services = new HashMap<>(); + categories.put(category, services); + } + String service = url.getServiceKey(); + Map ids = services.get(service); + if (ids == null) { + ids = new HashMap<>(); + services.put(service, ids); + } + + // Make sure we use the same ID for the same URL + if (URL_IDS_MAPPER.containsKey(url.toFullString())) { + ids.put(URL_IDS_MAPPER.get(url.toFullString()), url); + } else { + String md5 = MD5Util.MD5_16bit(url.toFullString()); + ids.put(md5, url); + URL_IDS_MAPPER.putIfAbsent(url.toFullString(), md5); + } + } + } + if (categories.size() == 0) { + return; + } + for (Map.Entry>> categoryEntry : categories.entrySet()) { + String category = categoryEntry.getKey(); + ConcurrentMap> services = registryCache.get(category); + if (services == null) { + services = new ConcurrentHashMap>(); + registryCache.put(category, services); + } else {// Fix map can not be cleared when service is unregistered: when a unique “group/service:version” service is unregistered, but we still have the same services with different version or group, so empty protocols can not be invoked. + Set keys = new HashSet(services.keySet()); + for (String key : keys) { + if (this.getInterface(key).equals(interfaceName) && !categoryEntry.getValue().entrySet().contains(key)) { + services.remove(key); + } + } + } + services.putAll(categoryEntry.getValue()); + } + } + + public String getInterface(String service) { + if (service != null && service.length() > 0) { + int i = service.indexOf('/'); + if (i >= 0) { + service = service.substring(i + 1); + } + i = service.lastIndexOf(':'); + if (i >= 0) { + service = service.substring(0, i); + } + } + return service; + } + + public String getGroup(String service) { + if (service != null && service.length() > 0) { + int i = service.indexOf('/'); + if (i >= 0) { + return service.substring(0, i); + } + } + return null; + } + + public String getVersion(String service) { + if (service != null && service.length() > 0) { + int i = service.lastIndexOf(':'); + if (i >= 0) { + return service.substring(i + 1); + } + } + return null; + } +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/utils/Constants.java b/backend/src/main/java/io/metersphere/api/dubbo/utils/Constants.java new file mode 100644 index 0000000000..16ff47dc56 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/utils/Constants.java @@ -0,0 +1,614 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.metersphere.api.dubbo.utils; + +import io.metersphere.api.dubbo.MethodArgument; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jmeter.testelement.property.IntegerProperty; +import org.apache.jmeter.testelement.property.StringProperty; + +import java.util.ArrayList; +import java.util.List; + +/** + * Constants + */ +public class Constants { + + //Registry Protocol + public static final String REGISTRY_NONE = "none"; + public static final String REGISTRY_ZOOKEEPER = "zookeeper"; + public static final String REGISTRY_NACOS = "nacos"; + public static final String APOLLO = "apollo"; + public static final String REGISTRY_MULTICAST = "multicast"; + public static final String REGISTRY_REDIS = "redis"; + public static final String REGISTRY_SIMPLE = "simple"; + + //RPC Protocol + public static final String RPC_PROTOCOL_DUBBO = "dubbo"; + public static final String RPC_PROTOCOL_RMI = "rmi"; + public static final String RPC_PROTOCOL_HESSIAN = "hessian"; + public static final String RPC_PROTOCOL_HTTP = "http"; + public static final String RPC_PROTOCOL_WEBSERVICE = "webservice"; + public static final String RPC_PROTOCOL_THRIFT = "thrift"; + public static final String RPC_PROTOCOL_MEMCACHED = "memcached"; + public static final String RPC_PROTOCOL_REDIS = "redis"; + + public static final String ASYNC = "async"; + public static final String SYMBOL = "://"; + + public static final int INT_DEFAULT = 0; + public static final double DOUBLE_DEFAULT = 0.0d; + public static final boolean BOOLEAN_DEFAULT = false; + public static final char CHAR_DEFAULT = '\u0000'; + public static final float FLOAT_DEFAULT = 0.0f; + public static final byte BYTE_DEFAULT = 0; + public static final long LONG_DEFAULT = 0l; + public static final short SHORT_DEFAULT = 0; + public static final int[] INT_ARRAY_DEFAULT = null; + public static final double[] DOUBLE_ARRAY_DEFAULT = null; + public static final boolean[] BOOLEAN_ARRAY_DEFAULT = null; + public static final char[] CHAT_ARRAY_DEFAULT = null; + public static final float[] FLOAT_ARRAY_DEFAULT = null; + public static final byte[] BYTE_ARRAY_DEFAULT = null; + public static final long[] LONG_ARRAY_DEFAULT = null; + public static final short[] SHORT_ARRAY_DEFAULT = null; + + public static final String FIELD_DUBBO_REGISTRY_PROTOCOL = "FIELD_DUBBO_REGISTRY_PROTOCOL"; + public static final String FIELD_DUBBO_REGISTRY_GROUP = "FIELD_DUBBO_REGISTRY_GROUP"; + public static final String FIELD_DUBBO_REGISTRY_USER_NAME = "FIELD_DUBBO_REGISTRY_USER_NAME"; + public static final String FIELD_DUBBO_REGISTRY_PASSWORD = "FIELD_DUBBO_REGISTRY_PASSWORD"; + public static final String FIELD_DUBBO_REGISTRY_TIMEOUT = "FIELD_DUBBO_REGISTRY_TIMEOUT"; + public static final String FIELD_DUBBO_CONFIG_CENTER_PROTOCOL = "FIELD_DUBBO_CONFIG_CENTER_PROTOCOL"; + public static final String FIELD_DUBBO_CONFIG_CENTER_GROUP = "FIELD_DUBBO_CONFIG_CENTER_GROUP"; + public static final String FIELD_DUBBO_CONFIG_CENTER_NAMESPACE = "FIELD_DUBBO_CONFIG_CENTER_NAMESPACE"; + public static final String FIELD_DUBBO_CONFIG_CENTER_USER_NAME = "FIELD_DUBBO_CONFIG_CENTER_USER_NAME"; + public static final String FIELD_DUBBO_CONFIG_CENTER_PASSWORD = "FIELD_DUBBO_CONFIG_CENTER_PASSWORD"; + public static final String FIELD_DUBBO_CONFIG_CENTER_TIMEOUT = "FIELD_DUBBO_CONFIG_CENTER_TIMEOUT"; + public static final String FIELD_DUBBO_CONFIG_CENTER_ADDRESS = "FIELD_DUBBO_CONFIG_CENTER_ADDRESS"; + public static final String FIELD_DUBBO_RPC_PROTOCOL = "FIELD_DUBBO_RPC_PROTOCOL"; + public static final String FIELD_DUBBO_ADDRESS = "FIELD_DUBBO_ADDRESS"; + public static final String FIELD_DUBBO_TIMEOUT = "FIELD_DUBBO_TIMEOUT"; + public static final String FIELD_DUBBO_VERSION = "FIELD_DUBBO_VERSION"; + public static final String FIELD_DUBBO_RETRIES = "FIELD_DUBBO_RETRIES"; + public static final String FIELD_DUBBO_CLUSTER = "FIELD_DUBBO_CLUSTER"; + public static final String FIELD_DUBBO_GROUP = "FIELD_DUBBO_GROUP"; + public static final String FIELD_DUBBO_CONNECTIONS = "FIELD_DUBBO_CONNECTIONS"; + public static final String FIELD_DUBBO_LOADBALANCE = "FIELD_DUBBO_LOADBALANCE"; + public static final String FIELD_DUBBO_ASYNC = "FIELD_DUBBO_ASYNC"; + public static final String FIELD_DUBBO_INTERFACE = "FIELD_DUBBO_INTERFACE"; + public static final String FIELD_DUBBO_METHOD = "FIELD_DUBBO_METHOD"; + public static final String FIELD_DUBBO_METHOD_ARGS = "FIELD_DUBBO_METHOD_ARGS"; + public static final String FIELD_DUBBO_METHOD_ARGS_SIZE = "FIELD_DUBBO_METHOD_ARGS_SIZE"; + public static final String FIELD_DUBBO_ATTACHMENT_ARGS = "FIELD_DUBBO_ATTACHMENT_ARGS"; + public static final String FIELD_DUBBO_ATTACHMENT_ARGS_SIZE = "FIELD_DUBBO_ATTACHMENT_ARGS_SIZE"; + public static final String DEFAULT_TIMEOUT = "1000"; + public static final String DEFAULT_VERSION = "1.0"; + public static final String DEFAULT_RETRIES = "0"; + public static final String DEFAULT_CLUSTER = "failfast"; + public static final String DEFAULT_CONNECTIONS = "100"; + + //冗余配置元件中的address、protocols、group,用于在sample gui获取配置元件中的默认值 + public static String DEFAULT_PANEL_ADDRESS = ""; + public static String DEFAULT_PANEL_PROTOCOLS = ""; + public static String DEFAULT_PANEL_GROUP = ""; + + public static final void redundancy(TestElement element) { + DEFAULT_PANEL_ADDRESS = Constants.getAddress(element); + DEFAULT_PANEL_PROTOCOLS = Constants.getRegistryProtocol(element); + DEFAULT_PANEL_GROUP = Constants.getRegistryGroup(element); + } + + /** + * get Registry Protocol + * + * @return the protocol + */ + public static final String getRegistryProtocol(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_REGISTRY_PROTOCOL); + } + + /** + * set Registry Protocol + * + * @param registryProtocol the protocol to set + */ + public static final void setRegistryProtocol(String registryProtocol, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_REGISTRY_PROTOCOL, StringUtils.trimAllWhitespace(registryProtocol))); + } + + /** + * get Registry Group + * + * @return the group + */ + public static final String getRegistryGroup(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_REGISTRY_GROUP); + } + + /** + * set Registry Group + * + * @param registryGroup the group to set + */ + public static final void setRegistryGroup(String registryGroup, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_REGISTRY_GROUP, StringUtils.trimAllWhitespace(registryGroup))); + } + + /** + * get Registry username + * + * @return the username + */ + public static final String getRegistryUserName(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_REGISTRY_USER_NAME); + } + + /** + * set Registry username + * + * @param username the username to set + */ + public static final void setRegistryUserName(String username, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_REGISTRY_USER_NAME, StringUtils.trimAllWhitespace(username))); + } + + /** + * get Registry password + * + * @return the password + */ + public static final String getRegistryPassword(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_REGISTRY_PASSWORD); + } + + /** + * set Registry password + * + * @param password the password to set + */ + public static final void setRegistryPassword(String password, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_REGISTRY_PASSWORD, StringUtils.trimAllWhitespace(password))); + } + + /** + * get Registry timeout + * + * @return the timeout + */ + public static final String getRegistryTimeout(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_REGISTRY_TIMEOUT); + } + + /** + * set Registry timeout + * + * @param timeout the group to set + */ + public static final void setRegistryTimeout(String timeout, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_REGISTRY_TIMEOUT, StringUtils.trimAllWhitespace(timeout))); + } + + /** + * get ConfigCenter protocol + * + * @return the protocol + */ + public static final String getConfigCenterProtocol(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_PROTOCOL); + } + + /** + * set ConfigCenter protocol + * + * @param protocol the protocol to set + */ + public static final void setConfigCenterProtocol(String protocol, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_PROTOCOL, StringUtils.trimAllWhitespace(protocol))); + } + + /** + * get ConfigCenter group + * + * @return the group + */ + public static final String getConfigCenterGroup(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_GROUP); + } + + /** + * set ConfigCenter group + * + * @param group the group to set + */ + public static final void setConfigCenterGroup(String group, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_GROUP, StringUtils.trimAllWhitespace(group))); + } + + /** + * get ConfigCenter namespace + * + * @return the namespace + */ + public static final String getConfigCenterNamespace(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_NAMESPACE); + } + + /** + * set ConfigCenter namespace + * + * @param namespace the namespace to set + */ + public static final void setConfigCenterNamespace(String namespace, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_NAMESPACE, StringUtils.trimAllWhitespace(namespace))); + } + + /** + * get ConfigCenter username + * + * @return the username + */ + public static final String getConfigCenterUserName(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_USER_NAME); + } + + /** + * set ConfigCenter username + * + * @param username the username to set + */ + public static final void setConfigCenterUserName(String username, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_USER_NAME, StringUtils.trimAllWhitespace(username))); + } + + /** + * get ConfigCenter password + * + * @return the password + */ + public static final String getConfigCenterPassword(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_PASSWORD); + } + + /** + * set ConfigCenter password + * + * @param password the password to set + */ + public static final void setConfigCenterPassword(String password, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_PASSWORD, StringUtils.trimAllWhitespace(password))); + } + + /** + * get ConfigCenter address + * + * @return the address + */ + public static final String getConfigCenterAddress(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_ADDRESS); + } + + /** + * set ConfigCenter namespace + * + * @param address the address to set + */ + public static final void setConfigCenterAddress(String address, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_ADDRESS, StringUtils.trimAllWhitespace(address))); + } + + /** + * get ConfigCenter timeout + * + * @return the timeout + */ + public static final String getConfigCenterTimeout(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONFIG_CENTER_TIMEOUT); + } + + /** + * set ConfigCenter namespace + * + * @param timeout the timeout to set + */ + public static final void setConfigCenterTimeout(String timeout, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONFIG_CENTER_TIMEOUT, StringUtils.trimAllWhitespace(timeout))); + } + + /** + * get RPC protocol + * + * @return the RPC protocol + */ + public static final String getRpcProtocol(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_RPC_PROTOCOL); + } + + /** + * set RPC protocol + * + * @param rpcProtocol the protocol to set + */ + public static final void setRpcProtocol(String rpcProtocol, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_RPC_PROTOCOL, StringUtils.trimAllWhitespace(rpcProtocol))); + } + + /** + * get address + * + * @return the address + */ + public static final String getAddress(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_ADDRESS); + } + + /** + * set address + * + * @param address the address to set + */ + public static final void setAddress(String address, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_ADDRESS, StringUtils.trimAllWhitespace(address))); + } + + /** + * get timeout + * + * @return the timeout + */ + public static final String getTimeout(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_TIMEOUT, DEFAULT_TIMEOUT); + } + + /** + * set timeout + * + * @param timeout the timeout to set + */ + public static final void setTimeout(String timeout, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_TIMEOUT, StringUtils.trimAllWhitespace(timeout))); + } + + /** + * get version + * + * @return the version + */ + public static final String getVersion(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_VERSION, DEFAULT_VERSION); + } + + /** + * set version + * + * @param version the version to set + */ + public static final void setVersion(String version, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_VERSION, StringUtils.trimAllWhitespace(version))); + } + + /** + * get retries + * + * @return the retries + */ + public static final String getRetries(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_RETRIES, DEFAULT_RETRIES); + } + + /** + * set retries + * + * @param retries the retries to set + */ + public static final void setRetries(String retries, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_RETRIES, StringUtils.trimAllWhitespace(retries))); + } + + /** + * get cluster + * + * @return the cluster + */ + public static final String getCluster(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CLUSTER, DEFAULT_CLUSTER); + } + + /** + * set cluster + * + * @param cluster the cluster to set + */ + public static final void setCluster(String cluster, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CLUSTER, StringUtils.trimAllWhitespace(cluster))); + } + + /** + * get group + * + * @return the group + */ + public static final String getGroup(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_GROUP, null); + } + + /** + * set group + * + * @param group the group to set + */ + public static final void setGroup(String group, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_GROUP, StringUtils.trimAllWhitespace(group))); + } + + /** + * get connections + * + * @return the group + */ + public static final String getConnections(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_CONNECTIONS, DEFAULT_CONNECTIONS); + } + + /** + * set connections + * + * @param connections the connections to set + */ + public static final void setConnections(String connections, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_CONNECTIONS, StringUtils.trimAllWhitespace(connections))); + } + + /** + * get loadbalance + * + * @return the loadbalance + */ + public static final String getLoadbalance(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_LOADBALANCE); + } + + /** + * set loadbalance + * + * @param loadbalance the loadbalance to set + */ + public static final void setLoadbalance(String loadbalance, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_LOADBALANCE, StringUtils.trimAllWhitespace(loadbalance))); + } + + /** + * get async + * + * @return the async + */ + public static final String getAsync(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_ASYNC); + } + + /** + * set async + * + * @param async the async to set + */ + public static final void setAsync(String async, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_ASYNC, StringUtils.trimAllWhitespace(async))); + } + + /** + * get interfaceName + * + * @return the interfaceName + */ + public static final String getInterface(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_INTERFACE); + } + + /** + * set interfaceName + * + * @param interfaceName the interfaceName to set + */ + public static final void setInterfaceName(String interfaceName, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_INTERFACE, StringUtils.trimAllWhitespace(interfaceName))); + } + + /** + * get method + * + * @return the method + */ + public static final String getMethod(TestElement element) { + return element.getPropertyAsString(FIELD_DUBBO_METHOD); + } + + /** + * set method + * + * @param method the method to set + */ + public static final void setMethod(String method, TestElement element) { + element.setProperty(new StringProperty(FIELD_DUBBO_METHOD, StringUtils.trimAllWhitespace(method))); + } + + /** + * get methodArgs + * + * @return the methodArgs + */ + public static final List getMethodArgs(TestElement element) { + int paramsSize = element.getPropertyAsInt(FIELD_DUBBO_METHOD_ARGS_SIZE, 0); + List list = new ArrayList(); + for (int i = 1; i <= paramsSize; i++) { + String paramType = element.getPropertyAsString(FIELD_DUBBO_METHOD_ARGS + "_PARAM_TYPE" + i); + String paramValue = element.getPropertyAsString(FIELD_DUBBO_METHOD_ARGS + "_PARAM_VALUE" + i); + MethodArgument args = new MethodArgument(paramType, paramValue); + list.add(args); + } + return list; + } + + /** + * set methodArgs + * + * @param methodArgs the methodArgs to set + */ + public static final void setMethodArgs(List methodArgs, TestElement element) { + int size = methodArgs == null ? 0 : methodArgs.size(); + element.setProperty(new IntegerProperty(FIELD_DUBBO_METHOD_ARGS_SIZE, size)); + if (size > 0) { + for (int i = 1; i <= methodArgs.size(); i++) { + element.setProperty(new StringProperty(FIELD_DUBBO_METHOD_ARGS + "_PARAM_TYPE" + i, methodArgs.get(i - 1).getParamType())); + element.setProperty(new StringProperty(FIELD_DUBBO_METHOD_ARGS + "_PARAM_VALUE" + i, methodArgs.get(i - 1).getParamValue())); + } + } + } + + /** + * get attachmentArgs + * + * @return the attachmentArgs + */ + public static final List getAttachmentArgs(TestElement element) { + int paramsSize = element.getPropertyAsInt(FIELD_DUBBO_ATTACHMENT_ARGS_SIZE, 0); + List list = new ArrayList(); + for (int i = 1; i <= paramsSize; i++) { + String paramType = element.getPropertyAsString(FIELD_DUBBO_ATTACHMENT_ARGS + "_KEY" + i); + String paramValue = element.getPropertyAsString(FIELD_DUBBO_ATTACHMENT_ARGS + "_VALUE" + i); + MethodArgument args = new MethodArgument(paramType, paramValue); + list.add(args); + } + return list; + } + + /** + * set attachmentArgs + * + * @param methodArgs the attachmentArgs to set + */ + public static final void setAttachmentArgs(List methodArgs, TestElement element) { + int size = methodArgs == null ? 0 : methodArgs.size(); + element.setProperty(new IntegerProperty(FIELD_DUBBO_ATTACHMENT_ARGS_SIZE, size)); + if (size > 0) { + for (int i = 1; i <= methodArgs.size(); i++) { + element.setProperty(new StringProperty(FIELD_DUBBO_ATTACHMENT_ARGS + "_KEY" + i, methodArgs.get(i - 1).getParamType())); + element.setProperty(new StringProperty(FIELD_DUBBO_ATTACHMENT_ARGS + "_VALUE" + i, methodArgs.get(i - 1).getParamValue())); + } + } + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/utils/JsonUtils.java b/backend/src/main/java/io/metersphere/api/dubbo/utils/JsonUtils.java new file mode 100644 index 0000000000..e3022ab121 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/utils/JsonUtils.java @@ -0,0 +1,52 @@ +package io.metersphere.api.dubbo.utils; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Type; + +/** + * JsonUtils + */ +public class JsonUtils { + + private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class); + + private static final Gson gson = new GsonBuilder() + .setDateFormat("yyyy-MM-dd HH:mm:ss") + .setPrettyPrinting() + .disableHtmlEscaping() + .serializeNulls() + .create(); + + public static String toJson(Object obj) { + return gson.toJson(obj); + } + + public static String toJson(Object obj, Type type) { + return gson.toJson(obj, type); + } + + public static T formJson(String json, Class classOfT) { + try { + return gson.fromJson(json, classOfT); + } catch (JsonSyntaxException e) { + logger.error("json to class[" + classOfT.getName() + "] is error!", + e); + } + return null; + } + + public static T formJson(String json, Type type) { + try { + return gson.fromJson(json, type); + } catch (JsonSyntaxException e) { + logger.error("json to class[" + type.getClass().getName() + + "] is error!", e); + } + return null; + } +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/utils/MD5Util.java b/backend/src/main/java/io/metersphere/api/dubbo/utils/MD5Util.java new file mode 100644 index 0000000000..23786ab5fd --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/utils/MD5Util.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.metersphere.api.dubbo.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * MD5Util + */ +public class MD5Util { + private static MessageDigest md; + private static final char[] hexCode = "0123456789ABCDEF".toCharArray(); + + static { + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + public static String MD5_16bit(String input) { + String hash = MD5_32bit(input); + if (hash == null) { + return null; + } + return hash.substring(8, 24); + } + + public static String MD5_32bit(String input) { + if (input == null || input.length() == 0) { + return null; + } + md.update(input.getBytes()); + byte[] digest = md.digest(); + String hash = convertToString(digest); + return hash; + } + + private static String convertToString(byte[] data) { + StringBuilder r = new StringBuilder(data.length * 2); + for (byte b : data) { + r.append(hexCode[(b >> 4) & 0xF]); + r.append(hexCode[(b & 0xF)]); + } + return r.toString(); + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dubbo/utils/StringUtils.java b/backend/src/main/java/io/metersphere/api/dubbo/utils/StringUtils.java new file mode 100644 index 0000000000..5f9f4814d2 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dubbo/utils/StringUtils.java @@ -0,0 +1,69 @@ +package io.metersphere.api.dubbo.utils; + +/** + * StringUtils + */ +public class StringUtils { + + public static boolean hasLength(String str) { + return str != null && !str.isEmpty(); + } + + public static String trimAllWhitespace(String str) { + if (!hasLength(str)) { + return str; + } else { + int len = str.length(); + StringBuilder sb = new StringBuilder(str.length()); + + for (int i = 0; i < len; ++i) { + char c = str.charAt(i); + if (!Character.isWhitespace(c)) { + sb.append(c); + } + } + + return sb.toString(); + } + } + + public static String trimWhitespace(String str) { + if (!hasLength(str)) { + return str; + } else { + StringBuilder sb = new StringBuilder(str); + + while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { + sb.deleteCharAt(0); + } + + while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { + sb.deleteCharAt(sb.length() - 1); + } + + return sb.toString(); + } + } + + public static boolean isBlank(CharSequence cs) { + int strLen; + if (cs != null && (strLen = cs.length()) != 0) { + for (int i = 0; i < strLen; ++i) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + + return true; + } else { + return true; + } + } + + public static boolean isBlank1(String paramValue) { + if (isBlank(paramValue) || "null".equals(paramValue.toLowerCase())) { + return true; + } + return false; + } +} From 142a1fb7486e2c0310df07ebadf9fbab4bcae7ee Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Fri, 17 Jul 2020 10:28:51 +0800 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=E5=81=9C=E6=AD=A2=E5=A4=B1=E8=B4=A5=E7=9A=84=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metersphere/performance/engine/docker/DockerTestEngine.java | 2 +- backend/src/main/resources/i18n/messages_en_US.properties | 1 + backend/src/main/resources/i18n/messages_zh_CN.properties | 1 + backend/src/main/resources/i18n/messages_zh_TW.properties | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) 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 41964c9967..4519e5916e 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 @@ -111,7 +111,7 @@ public class DockerTestEngine extends AbstractEngine { restTemplateWithTimeOut.getForObject(uri, String.class); } catch (Exception e) { LogUtil.error("stop load test fail... " + testId); - MSException.throwException(Translator.get("delete_fail")); + MSException.throwException(Translator.get("container_delete_fail")); } }); } diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 3235997a3b..c5fa1e1c84 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -46,6 +46,7 @@ max_thread_insufficient=The number of concurrent users exceeds related_case_del_fail_prefix=Connected to related_case_del_fail_suffix=TestCase, please disassociate first jmx_content_valid=JMX content is invalid +container_delete_fail=The container failed to stop, please try again #workspace workspace_name_is_null=Workspace name cannot be null workspace_name_already_exists=The workspace name already exists diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index 45c659347c..fca626535e 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -46,6 +46,7 @@ max_thread_insufficient=并发用户数超额 related_case_del_fail_prefix=已关联到 related_case_del_fail_suffix=测试用例,请先解除关联 jmx_content_valid=JMX 内容无效,请检查 +container_delete_fail=容器停止失败,请重试 #workspace workspace_name_is_null=工作空间名不能为空 workspace_name_already_exists=工作空间名已存在 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 61d3091cd7..3c8ede8304 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -46,6 +46,7 @@ max_thread_insufficient=並發用戶數超額 related_case_del_fail_prefix=已關聯到 related_case_del_fail_suffix=測試用例,請先解除關聯 jmx_content_valid=JMX 內容無效,請檢查 +container_delete_fail=容器停止失敗,請重試 #workspace workspace_name_is_null=工作空間名不能為空 workspace_name_already_exists=工作空間名已存在 From ff42d6c96ef3a0be80474a5b37d8304db5109201 Mon Sep 17 00:00:00 2001 From: q4speed Date: Fri, 17 Jul 2020 10:59:26 +0800 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=AB=98?= =?UTF-8?q?=E7=BA=A7=E6=90=9C=E7=B4=A2=E8=BE=93=E5=85=A5=E6=A1=86=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E8=BE=93=E5=85=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/components/search/MsTableAdvSearchBar.vue | 10 +++++++--- .../common/components/search/search-components.js | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue b/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue index add1b2f22e..280852ed60 100644 --- a/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue +++ b/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue @@ -72,9 +72,13 @@ reset() { let source = this.condition.components; this.config.components.forEach((component, index) => { - let operator = source[index].operator.value; - component.operator.value = operator === undefined ? component.operator.options[0].value : operator; - component.value = source[index].value; + if (component.operator.value !== undefined) { + let operator = source[index].operator.value; + component.operator.value = operator === undefined ? component.operator.options[0].value : operator; + } + if (component.value !== undefined) { + component.value = source[index].value; + } }) }, open() { diff --git a/frontend/src/business/components/common/components/search/search-components.js b/frontend/src/business/components/common/components/search/search-components.js index 5010e134f2..4e30c4ec1b 100644 --- a/frontend/src/business/components/common/components/search/search-components.js +++ b/frontend/src/business/components/common/components/search/search-components.js @@ -215,8 +215,8 @@ export const MODULE = { name: 'MsTableSearchInput', label: "test_track.case.module", operator: { - value: OPERATORS.LIKE.value, // 如果未设置value初始值,则value初始值为options[0] - options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项 + value: OPERATORS.LIKE.value, + options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] }, } From e15ad8f02516dc19a42393312408e646c6b97117 Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Fri, 17 Jul 2020 11:18:46 +0800 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0cacos=E4=BD=9C?= =?UTF-8?q?=E4=B8=BAdubbo=E7=9A=84=E6=B3=A8=E5=86=8C=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pom.xml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/backend/pom.xml b/backend/pom.xml index 8acf99d312..d1a8a67030 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -18,6 +18,8 @@ 1.5.1 1.8 5.2.1 + 1.1.3 + 2.7.7 @@ -154,10 +156,11 @@ + org.apache.dubbo dubbo - 2.7.7 + ${dubbo.version} org.apache.zookeeper @@ -174,6 +177,23 @@ curator-recipes 4.0.1 + + + + org.apache.dubbo + dubbo-registry-nacos + ${dubbo.version} + + + com.alibaba.nacos + nacos-api + ${nacos.version} + + + com.alibaba.nacos + nacos-client + ${nacos.version} + com.alibaba