diff --git a/backend/pom.xml b/backend/pom.xml
index 742a2efd97..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,6 +156,44 @@
+
+
+ org.apache.dubbo
+ dubbo
+ ${dubbo.version}
+
+
+ org.apache.zookeeper
+ zookeeper
+ 3.4.13
+
+
+ org.apache.curator
+ curator-framework
+ 4.0.1
+
+
+ org.apache.curator
+ 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
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;
+ }
+}
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);
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 032754e3ee..9e8ce06db8 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);
}
@@ -177,12 +177,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();
@@ -197,7 +191,6 @@ public class APITestService {
}
private ApiTest createTest(SaveAPITestRequest request) {
- checkNameExist(request);
final ApiTest test = new ApiTest();
test.setId(request.getId());
test.setName(request.getName());
@@ -294,10 +287,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/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/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=工作空間名已存在
diff --git a/frontend/src/business/components/api/test/ApiTestConfig.vue b/frontend/src/business/components/api/test/ApiTestConfig.vue
index 080c03aecb..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())
+ return !(this.test.isValid() && this.change);
}
},
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/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;
+ });
}
}
}
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/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) {
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 @@
-
-
-
-
-
+
-
+
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]
},
}