Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
cf216d1d84
15
README.md
15
README.md
|
@ -33,6 +33,21 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
||||||
- [完整文档](https://metersphere.io/docs/)
|
- [完整文档](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)
|
- [演示视频](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 会停止维护。
|
||||||
|
```
|
||||||
|
|
||||||
## 技术优势
|
## 技术优势
|
||||||
|
|
||||||
- 全生命周期: 能够覆盖从测试计划到测试执行、测试报告分析的不同阶段;
|
- 全生命周期: 能够覆盖从测试计划到测试执行、测试报告分析的不同阶段;
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
<shiro.version>1.5.1</shiro.version>
|
<shiro.version>1.5.1</shiro.version>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<jmeter.version>5.2.1</jmeter.version>
|
<jmeter.version>5.2.1</jmeter.version>
|
||||||
|
<nacos.version>1.1.3</nacos.version>
|
||||||
|
<dubbo.version>2.7.7</dubbo.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -154,6 +156,44 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Zookeeper -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo</artifactId>
|
||||||
|
<version>${dubbo.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.zookeeper</groupId>
|
||||||
|
<artifactId>zookeeper</artifactId>
|
||||||
|
<version>3.4.13</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-framework</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-recipes</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- nacos -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-registry-nacos</artifactId>
|
||||||
|
<version>${dubbo.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-api</artifactId>
|
||||||
|
<version>${nacos.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.nacos</groupId>
|
||||||
|
<artifactId>nacos-client</artifactId>
|
||||||
|
<version>${nacos.version}</version>
|
||||||
|
</dependency>
|
||||||
<!-- easyexcel -->
|
<!-- easyexcel -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<String, Map<String, URL>> providerUrls = null;
|
||||||
|
|
||||||
|
private static ConcurrentMap<String, ProviderService> 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<String, URL> findByService(String serviceName) {
|
||||||
|
return providerUrls == null ? null : providerUrls.get(serviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> 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<String> executeTelnet() throws RuntimeException {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> 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<String> ret = new ArrayList<String>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String, RegistryServerSync> 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<category, ConcurrentMap<servicename, Map<MD5, URL>>>
|
||||||
|
private final ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>>
|
||||||
|
registryCache = new ConcurrentHashMap<>();
|
||||||
|
/**
|
||||||
|
* Make sure ID never changed when the same url notified many times
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMap<String, String> URL_IDS_MAPPER = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public RegistryServerSync() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentMap<String, ConcurrentMap<String, Map<String, URL>>> getRegistryCache() {
|
||||||
|
return registryCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(List<URL> urls) {
|
||||||
|
if (urls == null || urls.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Map<category, Map<servicename, Map<Long, URL>>>
|
||||||
|
final Map<String, Map<String, Map<String, URL>>> 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<String, Map<String, URL>> 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<String, Map<String, URL>> 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<String, Map<String, URL>> services = categories.get(category);
|
||||||
|
if (services == null) {
|
||||||
|
services = new HashMap<>();
|
||||||
|
categories.put(category, services);
|
||||||
|
}
|
||||||
|
String service = url.getServiceKey();
|
||||||
|
Map<String, URL> 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<String, Map<String, Map<String, URL>>> categoryEntry : categories.entrySet()) {
|
||||||
|
String category = categoryEntry.getKey();
|
||||||
|
ConcurrentMap<String, Map<String, URL>> services = registryCache.get(category);
|
||||||
|
if (services == null) {
|
||||||
|
services = new ConcurrentHashMap<String, Map<String, URL>>();
|
||||||
|
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<String> keys = new HashSet<String>(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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<MethodArgument> getMethodArgs(TestElement element) {
|
||||||
|
int paramsSize = element.getPropertyAsInt(FIELD_DUBBO_METHOD_ARGS_SIZE, 0);
|
||||||
|
List<MethodArgument> list = new ArrayList<MethodArgument>();
|
||||||
|
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<MethodArgument> 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<MethodArgument> getAttachmentArgs(TestElement element) {
|
||||||
|
int paramsSize = element.getPropertyAsInt(FIELD_DUBBO_ATTACHMENT_ARGS_SIZE, 0);
|
||||||
|
List<MethodArgument> list = new ArrayList<MethodArgument>();
|
||||||
|
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<MethodArgument> 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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> T formJson(String json, Class<T> 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> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,23 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PostmanParser extends ApiImportAbstractParser {
|
public class PostmanParser extends ApiImportAbstractParser {
|
||||||
|
|
||||||
|
private static Map<String, String> 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
|
@Override
|
||||||
public ApiImport parse(InputStream source) {
|
public ApiImport parse(InputStream source) {
|
||||||
String testStr = getApiTestStr(source);
|
String testStr = getApiTestStr(source);
|
||||||
|
@ -69,7 +82,7 @@ public class PostmanParser extends ApiImportAbstractParser {
|
||||||
if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) {
|
if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) {
|
||||||
body.setRaw(postmanBody.getString(bodyMode));
|
body.setRaw(postmanBody.getString(bodyMode));
|
||||||
body.setType(MsRequestBodyType.RAW.value());
|
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);
|
addContentType(request, contentType);
|
||||||
} else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value()) || StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) {
|
} else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value()) || StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) {
|
||||||
List<PostmanKeyValue> postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class);
|
List<PostmanKeyValue> postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -39,8 +40,6 @@ import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public class APITestService {
|
public class APITestService {
|
||||||
|
@ -76,6 +75,7 @@ public class APITestService {
|
||||||
if (files == null || files.isEmpty()) {
|
if (files == null || files.isEmpty()) {
|
||||||
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
|
||||||
}
|
}
|
||||||
|
checkNameExist(request);
|
||||||
ApiTest test = createTest(request);
|
ApiTest test = createTest(request);
|
||||||
saveFile(test.getId(), files);
|
saveFile(test.getId(), files);
|
||||||
}
|
}
|
||||||
|
@ -118,10 +118,14 @@ public class APITestService {
|
||||||
|
|
||||||
public APITestResult get(String id) {
|
public APITestResult get(String id) {
|
||||||
APITestResult apiTest = new APITestResult();
|
APITestResult apiTest = new APITestResult();
|
||||||
BeanUtils.copyBean(apiTest, apiTestMapper.selectByPrimaryKey(id));
|
ApiTest test = apiTestMapper.selectByPrimaryKey(id);
|
||||||
Schedule schedule = scheduleService.getScheduleByResource(id, ScheduleGroup.API_TEST.name());
|
if (test != null) {
|
||||||
apiTest.setSchedule(schedule);
|
BeanUtils.copyBean(apiTest, test);
|
||||||
return apiTest;
|
Schedule schedule = scheduleService.getScheduleByResource(id, ScheduleGroup.API_TEST.name());
|
||||||
|
apiTest.setSchedule(schedule);
|
||||||
|
return apiTest;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiTest getApiTestByTestId(String testId) {
|
public ApiTest getApiTestByTestId(String testId) {
|
||||||
|
@ -173,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) {
|
private ApiTest updateTest(SaveAPITestRequest request) {
|
||||||
checkNameExist(request);
|
checkNameExist(request);
|
||||||
final ApiTest test = new ApiTest();
|
final ApiTest test = new ApiTest();
|
||||||
|
@ -193,7 +191,6 @@ public class APITestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiTest createTest(SaveAPITestRequest request) {
|
private ApiTest createTest(SaveAPITestRequest request) {
|
||||||
checkNameExist(request);
|
|
||||||
final ApiTest test = new ApiTest();
|
final ApiTest test = new ApiTest();
|
||||||
test.setId(request.getId());
|
test.setId(request.getId());
|
||||||
test.setName(request.getName());
|
test.setName(request.getName());
|
||||||
|
@ -290,10 +287,6 @@ public class APITestService {
|
||||||
request.setName(name.substring(0, name.length() - suffix.length()));
|
request.setName(name.substring(0, name.length() - suffix.length()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNameExist(request)) {
|
|
||||||
request.setName(request.getName() + "_" + request.getId().substring(0, 5));
|
|
||||||
}
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class ApiTestEnvironmentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) {
|
public void update(ApiTestEnvironmentWithBLOBs apiTestEnvironment) {
|
||||||
apiTestEnvironmentMapper.updateByPrimaryKeySelective(apiTestEnvironment);
|
apiTestEnvironmentMapper.updateByPrimaryKey(apiTestEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String add(ApiTestEnvironmentWithBLOBs apiTestEnvironmentWithBLOBs) {
|
public String add(ApiTestEnvironmentWithBLOBs apiTestEnvironmentWithBLOBs) {
|
||||||
|
|
|
@ -111,7 +111,7 @@ public class DockerTestEngine extends AbstractEngine {
|
||||||
restTemplateWithTimeOut.getForObject(uri, String.class);
|
restTemplateWithTimeOut.getForObject(uri, String.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error("stop load test fail... " + testId);
|
LogUtil.error("stop load test fail... " + testId);
|
||||||
MSException.throwException(Translator.get("delete_fail"));
|
MSException.throwException(Translator.get("container_delete_fail"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ max_thread_insufficient=The number of concurrent users exceeds
|
||||||
related_case_del_fail_prefix=Connected to
|
related_case_del_fail_prefix=Connected to
|
||||||
related_case_del_fail_suffix=TestCase, please disassociate first
|
related_case_del_fail_suffix=TestCase, please disassociate first
|
||||||
jmx_content_valid=JMX content is invalid
|
jmx_content_valid=JMX content is invalid
|
||||||
|
container_delete_fail=The container failed to stop, please try again
|
||||||
#workspace
|
#workspace
|
||||||
workspace_name_is_null=Workspace name cannot be null
|
workspace_name_is_null=Workspace name cannot be null
|
||||||
workspace_name_already_exists=The workspace name already exists
|
workspace_name_already_exists=The workspace name already exists
|
||||||
|
|
|
@ -46,6 +46,7 @@ max_thread_insufficient=并发用户数超额
|
||||||
related_case_del_fail_prefix=已关联到
|
related_case_del_fail_prefix=已关联到
|
||||||
related_case_del_fail_suffix=测试用例,请先解除关联
|
related_case_del_fail_suffix=测试用例,请先解除关联
|
||||||
jmx_content_valid=JMX 内容无效,请检查
|
jmx_content_valid=JMX 内容无效,请检查
|
||||||
|
container_delete_fail=容器停止失败,请重试
|
||||||
#workspace
|
#workspace
|
||||||
workspace_name_is_null=工作空间名不能为空
|
workspace_name_is_null=工作空间名不能为空
|
||||||
workspace_name_already_exists=工作空间名已存在
|
workspace_name_already_exists=工作空间名已存在
|
||||||
|
|
|
@ -46,6 +46,7 @@ max_thread_insufficient=並發用戶數超額
|
||||||
related_case_del_fail_prefix=已關聯到
|
related_case_del_fail_prefix=已關聯到
|
||||||
related_case_del_fail_suffix=測試用例,請先解除關聯
|
related_case_del_fail_suffix=測試用例,請先解除關聯
|
||||||
jmx_content_valid=JMX 內容無效,請檢查
|
jmx_content_valid=JMX 內容無效,請檢查
|
||||||
|
container_delete_fail=容器停止失敗,請重試
|
||||||
#workspace
|
#workspace
|
||||||
workspace_name_is_null=工作空間名不能為空
|
workspace_name_is_null=工作空間名不能為空
|
||||||
workspace_name_already_exists=工作空間名已存在
|
workspace_name_already_exists=工作空間名已存在
|
||||||
|
|
|
@ -255,7 +255,7 @@
|
||||||
return this.test.isValid() && !this.change;
|
return this.test.isValid() && !this.change;
|
||||||
},
|
},
|
||||||
isDisabled() {
|
isDisabled() {
|
||||||
return !(this.test.isValid())
|
return !(this.test.isValid() && this.change);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -50,19 +50,34 @@
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
},
|
},
|
||||||
deleteEnvironment(environment) {
|
deleteEnvironment(environment) {
|
||||||
this.result = this.$get('/api/environment/delete/' + environment.id, response => {
|
if (environment.id) {
|
||||||
this.$success(this.$t('commons.delete_success'));
|
this.result = this.$get('/api/environment/delete/' + environment.id, () => {
|
||||||
this.getEnvironments();
|
this.$success(this.$t('commons.delete_success'));
|
||||||
});
|
this.getEnvironments();
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
copyEnvironment(environment) {
|
copyEnvironment(environment) {
|
||||||
let newEnvironment = {};
|
let newEnvironment = {};
|
||||||
Object.assign(newEnvironment, environment);
|
Object.assign(newEnvironment, environment);
|
||||||
newEnvironment.id = null;
|
newEnvironment.id = null;
|
||||||
|
newEnvironment.name = this.getNoRepeatName(newEnvironment.name);
|
||||||
|
this.$refs.environmentEdit._save(newEnvironment);
|
||||||
this.environments.push(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() {
|
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) {
|
environmentSelected(environment) {
|
||||||
this.getEnvironment(environment);
|
this.getEnvironment(environment);
|
||||||
|
@ -97,6 +112,7 @@
|
||||||
close() {
|
close() {
|
||||||
this.$emit('close');
|
this.$emit('close');
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
this.$refs.environmentEdit.clearValidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +132,4 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- <el-form-item :label="$t('api_test.scenario.base_url')" prop="url">-->
|
|
||||||
<!-- <el-input :placeholder="$t('api_test.scenario.base_url_description')" v-model="scenario.url" maxlength="200"/>-->
|
|
||||||
<!-- </el-form-item>-->
|
|
||||||
|
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane :label="$t('api_test.scenario.variables')" name="parameters">
|
<el-tab-pane :label="$t('api_test.scenario.variables')" name="parameters">
|
||||||
<ms-api-scenario-variables :is-read-only="isReadOnly" :items="scenario.variables" :description="$t('api_test.scenario.kv_description')"/>
|
<ms-api-scenario-variables :is-read-only="isReadOnly" :items="scenario.variables" :description="$t('api_test.scenario.kv_description')"/>
|
||||||
|
@ -86,6 +82,7 @@
|
||||||
for (let i in this.environments) {
|
for (let i in this.environments) {
|
||||||
if (this.environments[i].id === this.scenario.environmentId) {
|
if (this.environments[i].id === this.scenario.environmentId) {
|
||||||
this.scenario.environment = this.environments[i];
|
this.scenario.environment = this.environments[i];
|
||||||
|
this.setRequestEnvironments();
|
||||||
hasEnvironment = true;
|
hasEnvironment = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -104,9 +101,7 @@
|
||||||
for (let i in this.environments) {
|
for (let i in this.environments) {
|
||||||
if (this.environments[i].id === value) {
|
if (this.environments[i].id === value) {
|
||||||
this.scenario.environment = this.environments[i];
|
this.scenario.environment = this.environments[i];
|
||||||
this.scenario.requests.forEach(request => {
|
this.setRequestEnvironments();
|
||||||
request.environment = this.environments[i];
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +121,11 @@
|
||||||
},
|
},
|
||||||
environmentConfigClose() {
|
environmentConfigClose() {
|
||||||
this.getEnvironments();
|
this.getEnvironments();
|
||||||
|
},
|
||||||
|
setRequestEnvironments() {
|
||||||
|
this.scenario.requests.forEach(request => {
|
||||||
|
request.environment = this.scenario.environment;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,12 @@
|
||||||
<ms-api-scenario-variables :items="environment.variables"/>
|
<ms-api-scenario-variables :items="environment.variables"/>
|
||||||
|
|
||||||
<span>{{$t('api_test.request.headers')}}</span>
|
<span>{{$t('api_test.request.headers')}}</span>
|
||||||
<ms-api-key-value :items="environment.headers"/>
|
<ms-api-key-value :items="environment.headers" :suggestions="headerSuggestions"/>
|
||||||
|
|
||||||
<div class="environment-footer">
|
<div class="environment-footer">
|
||||||
<ms-dialog-footer
|
<ms-dialog-footer
|
||||||
@cancel="cancel"
|
@cancel="cancel"
|
||||||
@confirm="save()"/>
|
@confirm="save()"/>
|
||||||
<!-- <el-button type="primary" @click="save">{{this.$t('commons.save')}}</el-button>-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -42,6 +41,7 @@
|
||||||
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
import MsApiScenarioVariables from "../ApiScenarioVariables";
|
||||||
import MsApiKeyValue from "../ApiKeyValue";
|
import MsApiKeyValue from "../ApiKeyValue";
|
||||||
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
|
||||||
|
import {requestHeaders} from "../../../../../../common/js/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EnvironmentEdit",
|
name: "EnvironmentEdit",
|
||||||
|
@ -71,36 +71,37 @@
|
||||||
],
|
],
|
||||||
socket :[{required: true, validator: socketValidator, trigger: 'blur'}],
|
socket :[{required: true, validator: socketValidator, trigger: 'blur'}],
|
||||||
},
|
},
|
||||||
|
headerSuggestions: requestHeaders
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
save() {
|
save() {
|
||||||
this.$refs['from'].validate((valid) => {
|
this.$refs['from'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this._save();
|
this._save(this.environment);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_save() {
|
_save(environment) {
|
||||||
let param = this.buildParam();
|
let param = this.buildParam(environment);
|
||||||
let url = '/api/environment/add';
|
let url = '/api/environment/add';
|
||||||
if (param.id) {
|
if (param.id) {
|
||||||
url = '/api/environment/update';
|
url = '/api/environment/update';
|
||||||
}
|
}
|
||||||
this.result = this.$post(url, param, response => {
|
this.result = this.$post(url, param, response => {
|
||||||
if (!param.id) {
|
if (!param.id) {
|
||||||
this.environment.id = response.data;
|
environment.id = response.data;
|
||||||
}
|
}
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
buildParam() {
|
buildParam(environment) {
|
||||||
let param = {};
|
let param = {};
|
||||||
Object.assign(param, this.environment);
|
Object.assign(param, environment);
|
||||||
param.variables = JSON.stringify(this.environment.variables);
|
param.variables = JSON.stringify(environment.variables);
|
||||||
param.headers = JSON.stringify(this.environment.headers);
|
param.headers = JSON.stringify(environment.headers);
|
||||||
return param;
|
return param;
|
||||||
},
|
},
|
||||||
validateSocket(socket) {
|
validateSocket(socket) {
|
||||||
|
@ -134,6 +135,9 @@
|
||||||
},
|
},
|
||||||
cancel() {
|
cancel() {
|
||||||
this.$emit('close');
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
clearValidate() {
|
||||||
|
this.$refs["from"].clearValidate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,12 +400,12 @@ class JMXRequest {
|
||||||
this.pathname = decodeURIComponent(url.pathname);
|
this.pathname = decodeURIComponent(url.pathname);
|
||||||
this.port = url.port;
|
this.port = url.port;
|
||||||
this.protocol = url.protocol.split(":")[0];
|
this.protocol = url.protocol.split(":")[0];
|
||||||
this.pathname = this.getPostQueryParameters(request, this.pathname);
|
this.pathname = this.getPostQueryParameters(request, this.pathname);
|
||||||
} else {
|
} else {
|
||||||
this.environment = request.environment;
|
this.environment = request.environment;
|
||||||
this.port = request.environment.port;
|
this.port = request.environment.port;
|
||||||
this.path = decodeURIComponent(request.path);
|
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) {
|
addEnvironments(environments, target) {
|
||||||
let scenarioVariableKeys = new Set();
|
let keys = new Set();
|
||||||
scenario.variables.forEach(item => {
|
target.forEach(item => {
|
||||||
scenarioVariableKeys.add(item.name);
|
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;
|
let environment = scenario.environment;
|
||||||
if (environment) {
|
if (environment) {
|
||||||
let envVariables = environment.variables;
|
this.addEnvironments(environment.variables, scenario.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));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let args = this.filterKV(scenario.variables);
|
let args = this.filterKV(scenario.variables);
|
||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
|
@ -510,21 +514,9 @@ class JMXGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
addScenarioHeaders(threadGroup, scenario) {
|
addScenarioHeaders(threadGroup, scenario) {
|
||||||
let scenarioHeaderKeys = new Set();
|
|
||||||
scenario.headers.forEach(item => {
|
|
||||||
scenarioHeaderKeys.add(item.name);
|
|
||||||
});
|
|
||||||
let environment = scenario.environment;
|
let environment = scenario.environment;
|
||||||
if (environment) {
|
if (environment) {
|
||||||
let envHeaders = environment.headers;
|
this.addEnvironments(environment.headers, scenario.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));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let headers = this.filterKV(scenario.headers);
|
let headers = this.filterKV(scenario.headers);
|
||||||
if (headers.length > 0) {
|
if (headers.length > 0) {
|
||||||
|
|
|
@ -10,14 +10,10 @@
|
||||||
</span>
|
</span>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :style="{'height': itemBarHeight + 'px'}" v-for="(item, index) in data" :key="index" class="item-bar" @click="itemSelected(index, item)" :class="{'item-selected' : index == selectIndex}">
|
<div :style="{'height': itemBarHeight + 'px'}" v-for="(item, index) in data" :key="index" class="item-bar" @click="itemSelected(index, item)" :class="{'item-selected' : index == selectIndex}">
|
||||||
<!-- <span :style="{'line-height': itemBarHeight - 10 + 'px'}" class="item-left">-->
|
<input class="item-input" :style="{'height': itemBarHeight - 12 + 'px', 'line-height': itemBarHeight - 12 + 'px', 'width': width - 90 + 'px'}" v-model="item.name" :placeholder="$t('commons.input_content')"/>
|
||||||
<!--<!– {{item.name}}–>-->
|
|
||||||
<!-- </span>-->
|
|
||||||
<input class="item-input" :style="{'height': itemBarHeight - 12 + 'px', 'line-height': itemBarHeight - 12 + 'px', 'width': width - 90 + 'px'}" v-model="item.name" placeholder="请输入内容"/>
|
|
||||||
<span :style="{'line-height': itemBarHeight - 10 + 'px'}" class="item-right">
|
<span :style="{'line-height': itemBarHeight - 10 + 'px'}" class="item-right">
|
||||||
<i v-for="(operator, index) in itemOperators" :key="index" :class="operator.icon" @click="operator.func(item)"/>
|
<i v-for="(operator, index) in itemOperators" :key="index" :class="operator.icon" @click.stop="operator.func(item)"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</ms-aside-container>
|
</ms-aside-container>
|
||||||
|
|
|
@ -72,9 +72,13 @@
|
||||||
reset() {
|
reset() {
|
||||||
let source = this.condition.components;
|
let source = this.condition.components;
|
||||||
this.config.components.forEach((component, index) => {
|
this.config.components.forEach((component, index) => {
|
||||||
let operator = source[index].operator.value;
|
if (component.operator.value !== undefined) {
|
||||||
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
|
let operator = source[index].operator.value;
|
||||||
component.value = source[index].value;
|
component.operator.value = operator === undefined ? component.operator.options[0].value : operator;
|
||||||
|
}
|
||||||
|
if (component.value !== undefined) {
|
||||||
|
component.value = source[index].value;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
open() {
|
open() {
|
||||||
|
|
|
@ -215,8 +215,8 @@ export const MODULE = {
|
||||||
name: 'MsTableSearchInput',
|
name: 'MsTableSearchInput',
|
||||||
label: "test_track.case.module",
|
label: "test_track.case.module",
|
||||||
operator: {
|
operator: {
|
||||||
value: OPERATORS.LIKE.value, // 如果未设置value初始值,则value初始值为options[0]
|
value: OPERATORS.LIKE.value,
|
||||||
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE] // 运算符候选项
|
options: [OPERATORS.LIKE, OPERATORS.NOT_LIKE]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,13 @@
|
||||||
getRelatedTest() {
|
getRelatedTest() {
|
||||||
if (this.testCase.method == 'auto' && this.testCase.testId) {
|
if (this.testCase.method == 'auto' && this.testCase.testId) {
|
||||||
this.$get('/' + this.testCase.type + '/get/' + this.testCase.testId, response => {
|
this.$get('/' + this.testCase.type + '/get/' + this.testCase.testId, response => {
|
||||||
this.test = response.data;
|
let data = response.data;
|
||||||
|
if (data) {
|
||||||
|
this.test = data;
|
||||||
|
} else {
|
||||||
|
this.test = {};
|
||||||
|
this.$warning(this.$t("test_track.case.relate_test_not_find"));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,6 +70,8 @@
|
||||||
});
|
});
|
||||||
this.getProject(item.projectId);
|
this.getProject(item.projectId);
|
||||||
this.$refs.config.reset();
|
this.$refs.config.reset();
|
||||||
|
} else {
|
||||||
|
this.test = new Test();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -93,8 +93,12 @@
|
||||||
getTest() {
|
getTest() {
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
this.result = this.$get('/performance/get/' + this.id, response => {
|
this.result = this.$get('/performance/get/' + this.id, response => {
|
||||||
this.test = response.data;
|
if (response.data) {
|
||||||
this.getProject(this.test.projectId);
|
this.test = response.data;
|
||||||
|
this.getProject(this.test.projectId);
|
||||||
|
} else {
|
||||||
|
this.test = {};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -497,6 +497,7 @@ export default {
|
||||||
please_create_project: "No project available, please create the project first",
|
please_create_project: "No project available, please create the project first",
|
||||||
create_module_first: "Please create module first",
|
create_module_first: "Please create module first",
|
||||||
relate_test: "Relate test",
|
relate_test: "Relate test",
|
||||||
|
relate_test_not_find: 'The associated test does not exist, please check the test case',
|
||||||
import: {
|
import: {
|
||||||
import: "Import test case",
|
import: "Import test case",
|
||||||
case_import: "Import test case",
|
case_import: "Import test case",
|
||||||
|
|
|
@ -496,6 +496,7 @@ export default {
|
||||||
please_create_project: "暂无项目,请先创建项目",
|
please_create_project: "暂无项目,请先创建项目",
|
||||||
create_module_first: "请先新建模块",
|
create_module_first: "请先新建模块",
|
||||||
relate_test: "关联测试",
|
relate_test: "关联测试",
|
||||||
|
relate_test_not_find: '关联的测试不存在,请检查用例',
|
||||||
import: {
|
import: {
|
||||||
import: "导入用例",
|
import: "导入用例",
|
||||||
case_import: "导入测试用例",
|
case_import: "导入测试用例",
|
||||||
|
|
|
@ -496,6 +496,7 @@ export default {
|
||||||
please_create_project: "暫無項目,請先創建項目",
|
please_create_project: "暫無項目,請先創建項目",
|
||||||
create_module_first: "請先新建模塊",
|
create_module_first: "請先新建模塊",
|
||||||
relate_test: "關聯測試",
|
relate_test: "關聯測試",
|
||||||
|
relate_test_not_find: '關聯的測試不存在,請檢查用例',
|
||||||
import: {
|
import: {
|
||||||
import: "導入用例",
|
import: "導入用例",
|
||||||
case_import: "導入測試用例",
|
case_import: "導入測試用例",
|
||||||
|
|
Loading…
Reference in New Issue