This commit is contained in:
chenjianxing 2020-07-22 17:00:31 +08:00
commit af03676879
11 changed files with 215 additions and 15 deletions

2
README.md Normal file → Executable file
View File

@ -3,6 +3,8 @@
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/metersphere/metersphere)](https://github.com/metersphere/metersphere/releases/latest)
[![GitHub All Releases](https://img.shields.io/github/downloads/metersphere/metersphere/total)](https://github.com/metersphere/metersphere/releases)
> [English](README_EN.md) | 中文
MeterSphere 是一站式的开源企业级持续测试平台涵盖测试跟踪、接口测试、性能测试、团队协作等功能兼容JMeter 等开源标准,有效助力开发和测试团队充分利用云弹性进行高度可扩展的自动化测试,加速高质量软件的交付。
- 测试跟踪: 远超 TestLink 的使用体验;

170
README_EN.md Executable file
View File

@ -0,0 +1,170 @@
# MeterSphere : Open-source Continuous Testing Platform
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/metersphere/metersphere)](https://github.com/metersphere/metersphere/releases/latest)
[![GitHub All Releases](https://img.shields.io/github/downloads/metersphere/metersphere/total)](https://github.com/metersphere/metersphere/releases)
> [中文](README.md) | English
MeterSphere is a one-stop open-source enterprise-class continuous testing platform. It covers functions such as tests tracking, interface testing, performance testing, team collaboration and is compatible with open-source standards such as JMeter. It helps development and testing teams to conduct highly scalable automated testing, making full use of elasticity of the cloud, and accelerating the delivery process of high-quality software.
- Test Tracking: Far beyond the user experience of TestLink.
- API Testing: Similar to Postman's experience.
- Performance Testing: Compatible with JMeter. Support Kubernetes and Cloud Environment. High concurrency, distributed performance testing with ease.
- Team Collaboration: duo-levels tenants system, naturally support team co-op.
## Quick Start
Only need two steps to install MeterSphere
What you need:
1. Prepare a 64-bit Linux host with no less than 8 G RAM
2. Log into root user and execute the command down below to install MeterSphere
```sh
curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh
```
## Technical advantages
- Full Life Cycle: Full coverage over all STLC phases. Starting from the Test Plan to the Report Creation phase.
- Automation & Scalable: Automation for interface and performance testings. Fully adopt the elasticity of Cloud to produce a large scale of performance testing.
- Continuous Testing: Seamlessly integrated with the CI tools. Supporting enterprises for "Shift left" testing.
- Team Collaboration: Support different proportions of teams. Capable from a group of five to a testing center of several hundred people.
## Features List
<table>
<tbody>
<tr>
<td rowspan="10">Test Tracking</td>
<td>Project management</td>
<td>Multi-project support, test cases, test plan, and project association</td>
</tr>
<tr>
<td rowspan="4">Test Cases Management</td>
<td>Online editing test case</td>
</tr>
<tr>
<td>tree structure display project module and its test cases</td>
</tr>
<tr>
<td>Custom test case attributes</td>
</tr>
<tr>
<td>Quickly import test cases into the system</td>
</tr>
<tr>
<td rowspan="5">Test Plan Tracking</td>
<td>Initiate a test plan based on existing test cases</td>
</tr>
<tr>
<td>Online update of test case execution results</td>
</tr>
<tr>
<td>Flexible test case allocation</td>
</tr>
<tr>
<td>Generate test reports online, support custom test report templates</td>
</tr>
<tr>
<td>Combine with the interface test and performance test functions in the platform to automatically update the results of associated test cases</td>
</tr>
<tr>
<td rowspan="7">Interface Testing</td>
<td rowspan="5">Test Script</td>
<td>Online editing interface testing content</td>
</tr>
<tr>
<td>Support parameterized testing</td>
</tr>
<tr>
<td>Pliable assertion support</td>
</tr>
<tr>
<td>Support multi-interface scenario testing</td>
</tr>
<tr>
<td>Quickly record test script via brower plug-in</td>
</tr>
<tr>
<td rowspan="2">Test Report</td>
<td>Automatically generate test report after test execution</td>
</tr>
<tr>
<td>Exportable Test report</td>
</tr>
<tr>
<td rowspan="9">Performance Testing</td>
<td rowspan="5">Test Script</td>
<td>Fully compatible with JMeter script</td>
</tr>
<tr>
<td>Adjust pressure parameter online</td>
</tr>
<tr>
<td>Distributed pressure testing</td>
</tr>
<tr>
<td>Support parameterized testing</td>
</tr>
<tr>
<td>Quickly record test script via brower plug-in</td>
</tr>
<tr>
<td rowspan="4">Test Report</td>
<td>Automatically generate test report after test execution</td>
</tr>
<tr>
<td>Rich test report display form</td>
</tr>
<tr>
<td>Exportable test report</td>
</tr>
<tr>
<td>View test log details</td>
</tr>
<tr>
<td rowspan="6">System Management</td>
<td rowspan="2">Tenant management</td>
<td>Support multi-level tenant system</td>
</tr>
<tr>
<td>Support multiple tenant roles</td>
</tr>
<tr>
<td rowspan="2">Test resource management</td>
<td>Performance test resource pool management</td>
</tr>
<tr>
<td>Email notification configuration</td>
</tr>
<tr>
<td rowspan="2">Integration and expansion</td>
<td>Complete&nbsp;API&nbsp;list</td>
</tr>
<tr>
<td>Supports continuous integration tools such as&nbsp;Jenkins&nbsp;</td>
</tr>
</tbody>
</table>
## Technology stack
- Backend: [Spring Boot](https://www.tutorialspoint.com/spring_boot/spring_boot_introduction.htm)
- Frontend: [Vue.js](https://vuejs.org/)
- Middleware: [MySQL](https://www.mysql.com/), [Kafka](https://kafka.apache.org/)
- Basic infrastructure: [Docker](https://www.docker.com/), [Kubernetes](https://kubernetes.io/)
- Test engine: [JMeter](https://jmeter.apache.org/)
## License & Copyright
Copyright (c) 2014-2020 飞致云 FIT2CLOUD, All rights reserved.
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/gpl-2.0.html
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.

View File

@ -27,6 +27,7 @@ import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.service.TestCaseService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -264,7 +265,7 @@ public class APITestService {
ApiImportParser apiImportParser = ApiImportParserFactory.getApiImportParser(request.getPlatform());
ApiImport apiImport = null;
try {
apiImport = apiImportParser.parse(file == null ? null : file.getInputStream(), request);
apiImport = Objects.requireNonNull(apiImportParser).parse(file.getInputStream(), request);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("parse_data_error"));
@ -291,21 +292,26 @@ public class APITestService {
}
public List<DubboProvider> getProviders(RegistryCenter registry) {
ProviderService providerService = ProviderService.get("provider");
ProviderService providerService = ProviderService.get(registry.getAddress());
List<String> providers = providerService.getProviders(registry.getProtocol(), registry.getAddress(), registry.getGroup());
List<DubboProvider> providerList = new ArrayList<>();
List<DubboProvider> list = new ArrayList<>();
providers.forEach(p -> {
DubboProvider provider = new DubboProvider();
String[] info = p.split(":");
if (info.length > 1) {
provider.setVersion(info[1]);
}
provider.setService(info[0]);
provider.setServiceInterface(p);
Map<String, URL> services = providerService.findByService(p);
services.forEach((k, v) -> {
DubboProvider provider = new DubboProvider();
provider.setVersion(v.getParameter("version"));
provider.setService(v.getServiceKey());
provider.setServiceInterface(v.getServiceInterface());
String[] methods = v.getParameter("methods").split(",");
if (services != null && !services.isEmpty()) {
String[] methods = services.values().stream().findFirst().get().getParameter(CommonConstants.METHODS_KEY).split(",");
provider.setMethods(Arrays.asList(methods));
providerList.add(provider);
});
} else {
provider.setMethods(new ArrayList<>());
}
list.add(provider);
});
return providerList;
return list;
}
}

View File

@ -213,6 +213,7 @@ public class ReportService {
public byte[] downloadLog(String reportId, String resourceId) {
LoadTestReportLogExample example = new LoadTestReportLogExample();
example.createCriteria().andReportIdEqualTo(reportId).andResourceIdEqualTo(resourceId);
example.setOrderByClause("part desc");
List<LoadTestReportLog> loadTestReportLogs = loadTestReportLogMapper.selectByExampleWithBLOBs(example);
String content = loadTestReportLogs.stream().map(LoadTestReportLog::getContent).reduce("", (a, b) -> a + b);

View File

@ -82,7 +82,7 @@
}
.metric .code {
width: 120px;
min-width: 120px;
}
.metric .code .value {
@ -98,4 +98,9 @@
border-left: 1px solid #EBEEF5;
margin-right: 20px;
}
.metric .message {
max-height: 114px;
overflow-y: auto;
}
</style>

View File

@ -96,6 +96,7 @@
this.methods = this.methodMap[this.request.interface].methods;
}
this.loading = false;
this.$success(this.$t('api_test.request.dubbo.get_provider_success'));
}).catch(() => {
this.loading = false;
this.$warning(this.$t('api_test.request.dubbo.check_registry_center'));

View File

@ -194,6 +194,18 @@ class DubboConfig extends BaseConfig {
super();
this.configCenter = new ConfigCenter(options.configCenter)
this.registryCenter = new RegistryCenter(options.registryCenter)
if (options.consumerAndService === undefined) {
options.consumerAndService = {
timeout: undefined,
version: undefined,
retries: undefined,
cluster: undefined,
group: undefined,
connections: undefined,
async: undefined,
loadBalance: undefined
}
}
this.consumerAndService = new ConsumerAndService(options.consumerAndService)
}
}
@ -259,7 +271,7 @@ export class HttpRequest extends Request {
}
isValid(environmentId) {
if (this.useEnvironment){
if (this.useEnvironment) {
if (!environmentId) {
return {
isValid: false,

View File

@ -297,7 +297,7 @@
responseType: 'blob'
};
this.result = this.$request(config).then(response => {
const filename = '测试用例.xlsx'
const filename = this.$t('test_track.case.test_case') + ".xlsx";
const blob = new Blob([response.data]);
if ("download" in document.createElement("a")) {
let aTag = document.createElement('a');

View File

@ -417,6 +417,7 @@ export default {
input_interface: "Please enter the interface",
input_method: "Please enter the method",
input_config_center: "Please enter the config center",
get_provider_success: "get provider list to finish",
input_registry_center: "Please enter the registry center",
input_consumer_service: "Please enter the consumer & service",
check_registry_center: "Can't get interface list, please check the registry center",

View File

@ -418,6 +418,7 @@ export default {
input_config_center: "请输入Config Center",
input_registry_center: "请输入Registry Center",
input_consumer_service: "请输入Consumer & Service",
get_provider_success: "获取成功",
check_registry_center: "获取失败请检查Registry Center",
form_description: "如果当前配置项无值,则取场景配置项的值",
}

View File

@ -416,6 +416,7 @@ export default {
input_interface: "請輸入Interface",
input_method: "請輸入Method",
input_config_center: "請輸入Config Center",
get_provider_success: "獲取成功",
input_registry_center: "請輸入Registry Center",
input_consumer_service: "請輸入Consumer & Service",
check_registry_center: "獲取失敗請檢查Registry Center",