diff --git a/backend/pom.xml b/backend/pom.xml
index 561fe81516..ab143b2730 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -110,7 +110,6 @@
commons-codec
commons-codec
- 1.12
junit
@@ -128,43 +127,12 @@
slf4j-simple
-
-
- org.apache.jmeter
- ApacheJMeter_http
- ${jmeter.version}
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
-
-
-
-
-
- kg.apc
- jmeter-plugins-tst
- 2.5
-
-
-
- kg.apc
- jmeter-plugins-casutg
- 2.9
-
-
com.opencsv
opencsv
5.1
-
- org.apache.httpcomponents
- httpclient
- 4.5.3
-
-
diff --git a/backend/src/main/java/io/metersphere/Application.java b/backend/src/main/java/io/metersphere/Application.java
index 20ac59d613..693b24040f 100644
--- a/backend/src/main/java/io/metersphere/Application.java
+++ b/backend/src/main/java/io/metersphere/Application.java
@@ -6,8 +6,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.context.annotation.Bean;
-import org.springframework.web.client.RestTemplate;
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
@ServletComponentScan
@@ -17,8 +15,5 @@ public class Application {
SpringApplication.run(Application.class, args);
}
- @Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
+
}
diff --git a/backend/src/main/java/io/metersphere/config/WebConfig.java b/backend/src/main/java/io/metersphere/config/WebConfig.java
index 35acc14672..1546184637 100644
--- a/backend/src/main/java/io/metersphere/config/WebConfig.java
+++ b/backend/src/main/java/io/metersphere/config/WebConfig.java
@@ -1,7 +1,9 @@
package io.metersphere.config;
import io.metersphere.interceptor.TestInterceptor;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -12,4 +14,9 @@ public class WebConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor());
}
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
}
diff --git a/backend/src/main/java/io/metersphere/controller/ReportController.java b/backend/src/main/java/io/metersphere/controller/ReportController.java
index 6167c9b8d4..57a62f5c32 100644
--- a/backend/src/main/java/io/metersphere/controller/ReportController.java
+++ b/backend/src/main/java/io/metersphere/controller/ReportController.java
@@ -9,8 +9,9 @@ import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ReportRequest;
import io.metersphere.dto.ReportDTO;
import io.metersphere.report.base.Errors;
-import io.metersphere.report.base.RequestStatistics;
-import io.metersphere.report.base.RequestStatisticsDTO;
+import io.metersphere.report.base.TestOverview;
+import io.metersphere.report.dto.ErrorsTop5DTO;
+import io.metersphere.report.dto.RequestStatisticsDTO;
import io.metersphere.service.ReportService;
import io.metersphere.user.SessionUtils;
import org.apache.shiro.authz.annotation.Logical;
@@ -65,5 +66,15 @@ public class ReportController {
return reportService.getReportErrors(reportId);
}
+ @GetMapping("/content/errors_top5/{reportId}")
+ public ErrorsTop5DTO getReportErrorsTop5(@PathVariable String reportId) {
+ return reportService.getReportErrorsTOP5(reportId);
+ }
+
+ @GetMapping("/content/testoverview/{reportId}")
+ public TestOverview getTestOverview(@PathVariable String reportId) {
+ return reportService.getTestOverview(reportId);
+ }
+
}
diff --git a/backend/src/main/java/io/metersphere/engine/docker/DockerTestEngine.java b/backend/src/main/java/io/metersphere/engine/docker/DockerTestEngine.java
index af7cb5b7f0..b08cb4676c 100644
--- a/backend/src/main/java/io/metersphere/engine/docker/DockerTestEngine.java
+++ b/backend/src/main/java/io/metersphere/engine/docker/DockerTestEngine.java
@@ -6,11 +6,12 @@ import io.metersphere.base.domain.TestResource;
import io.metersphere.commons.constants.ResourceStatusEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
-import io.metersphere.controller.request.TestRequest;
import io.metersphere.dto.NodeDTO;
import io.metersphere.engine.AbstractEngine;
import io.metersphere.engine.EngineContext;
import io.metersphere.engine.EngineFactory;
+import io.metersphere.engine.docker.request.DockerLoginRequest;
+import io.metersphere.engine.docker.request.TestRequest;
import io.metersphere.engine.kubernetes.registry.RegistryService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.client.RestTemplate;
@@ -85,10 +86,12 @@ public class DockerTestEngine extends AbstractEngine {
testRequest.setFileString(content);
testRequest.setImage(registryService.getRegistry() + JMETER_IMAGE);
testRequest.setTestData(context.getTestData());
-
+ testRequest.setRegistry(registryService.getRegistryUrl());
+ testRequest.setPassword(registryService.getRegistryPassword());
+ testRequest.setUsername(registryService.getRegistryUsername());
// todo 判断测试状态
String taskStatusUri = String.format(BASE_URL + "/jmeter/task/status/" + testId, nodeIp, port);
- List containerList = restTemplate.getForObject(taskStatusUri, List.class);
+ List containerList = restTemplate.postForObject(taskStatusUri, testRequest, List.class);
for (int i = 0; i < containerList.size(); i++) {
HashMap h = (HashMap) containerList.get(i);
if (StringUtils.equals((String) h.get("State"), "running")) {
@@ -103,13 +106,14 @@ public class DockerTestEngine extends AbstractEngine {
public void stop() {
// TODO 停止运行测试
String testId = loadTest.getId();
+ DockerLoginRequest request = new DockerLoginRequest();
this.resourceList.forEach(r -> {
NodeDTO node = JSON.parseObject(r.getConfiguration(), NodeDTO.class);
String ip = node.getIp();
Integer port = node.getPort();
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
- restTemplate.postForObject(uri, "", String.class);
+ restTemplate.postForObject(uri, request, String.class);
});
diff --git a/backend/src/main/java/io/metersphere/engine/docker/request/DockerLoginRequest.java b/backend/src/main/java/io/metersphere/engine/docker/request/DockerLoginRequest.java
new file mode 100644
index 0000000000..db6ab045a8
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/engine/docker/request/DockerLoginRequest.java
@@ -0,0 +1,31 @@
+package io.metersphere.engine.docker.request;
+
+public class DockerLoginRequest {
+ private String username;
+ private String password;
+ private String registry;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getRegistry() {
+ return registry;
+ }
+
+ public void setRegistry(String registry) {
+ this.registry = registry;
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/controller/request/TestRequest.java b/backend/src/main/java/io/metersphere/engine/docker/request/TestRequest.java
similarity index 90%
rename from backend/src/main/java/io/metersphere/controller/request/TestRequest.java
rename to backend/src/main/java/io/metersphere/engine/docker/request/TestRequest.java
index 22061bdaec..3f4131886b 100644
--- a/backend/src/main/java/io/metersphere/controller/request/TestRequest.java
+++ b/backend/src/main/java/io/metersphere/engine/docker/request/TestRequest.java
@@ -1,9 +1,9 @@
-package io.metersphere.controller.request;
+package io.metersphere.engine.docker.request;
import java.util.HashMap;
import java.util.Map;
-public class TestRequest {
+public class TestRequest extends DockerLoginRequest {
private int size;
private String fileString;
diff --git a/backend/src/main/java/io/metersphere/engine/kubernetes/KubernetesTestEngine.java b/backend/src/main/java/io/metersphere/engine/kubernetes/KubernetesTestEngine.java
index 69f154816a..dcfdef07a5 100644
--- a/backend/src/main/java/io/metersphere/engine/kubernetes/KubernetesTestEngine.java
+++ b/backend/src/main/java/io/metersphere/engine/kubernetes/KubernetesTestEngine.java
@@ -105,15 +105,14 @@ public class KubernetesTestEngine extends AbstractEngine {
public void stop() {
resourceList.forEach(r -> {
try {
- EngineContext context = EngineFactory.createContext(loadTest, threadNum);
String configuration = r.getConfiguration();
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
KubernetesProvider provider = new KubernetesProvider(JSON.toJSONString(clientCredential));
- provider.confirmNamespace(context.getNamespace());
+ provider.confirmNamespace(loadTest.getProjectId());
Jmeter jmeter = new Jmeter();
jmeter.setMetadata(new ObjectMeta() {{
- setName(context.getTestId());
- setNamespace(context.getNamespace());
+ setName(loadTest.getId());
+ setNamespace(loadTest.getProjectId());
}});
jmeter.setSpec(new JmeterSpec() {{
setReplicas(1);
diff --git a/backend/src/main/java/io/metersphere/parse/xml/reader/jmx/JmeterDocumentParser.java b/backend/src/main/java/io/metersphere/parse/xml/reader/jmx/JmeterDocumentParser.java
index 2f457f543d..cccc050a7a 100644
--- a/backend/src/main/java/io/metersphere/parse/xml/reader/jmx/JmeterDocumentParser.java
+++ b/backend/src/main/java/io/metersphere/parse/xml/reader/jmx/JmeterDocumentParser.java
@@ -422,7 +422,8 @@ public class JmeterDocumentParser implements DocumentParser {
stringPropCount++;
} else {
stringPropCount = 0;
- prop.getFirstChild().setNodeValue(context.getProperty("duration").toString());
+ Integer duration = (Integer) context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数
+ prop.getFirstChild().setNodeValue(String.valueOf(duration * 60));
continue;
}
prop.getFirstChild().setNodeValue(context.getProperty("rpsLimit").toString());
diff --git a/backend/src/main/java/io/metersphere/report/JtlResolver.java b/backend/src/main/java/io/metersphere/report/JtlResolver.java
index b5e07fa585..30f631f045 100644
--- a/backend/src/main/java/io/metersphere/report/JtlResolver.java
+++ b/backend/src/main/java/io/metersphere/report/JtlResolver.java
@@ -3,12 +3,10 @@ package io.metersphere.report;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
-import io.metersphere.report.base.Errors;
-import io.metersphere.report.base.Metric;
-import io.metersphere.report.base.RequestStatistics;
-import io.metersphere.report.base.RequestStatisticsDTO;
+import io.metersphere.report.base.*;
+import io.metersphere.report.dto.ErrorsTop5DTO;
+import io.metersphere.report.dto.RequestStatisticsDTO;
import org.apache.commons.lang3.StringUtils;
-
import java.io.Reader;
import java.io.StringReader;
import java.text.DecimalFormat;
@@ -21,7 +19,6 @@ public class JtlResolver {
HeaderColumnNameMappingStrategy ms = new HeaderColumnNameMappingStrategy<>();
ms.setType(Metric.class);
try (Reader reader = new StringReader(jtlString)) {
-
CsvToBean cb = new CsvToBeanBuilder(reader)
.withType(Metric.class)
.withSkipLines(0)
@@ -40,36 +37,33 @@ public class JtlResolver {
List requestStatisticsList = new ArrayList<>();
Iterator>> iterator = map.entrySet().iterator();
List allelapse = new ArrayList<>();
- Integer totalAverage = 0;
+ DecimalFormat df = new DecimalFormat("0.00");
+ int totalAverage = 0;
while (iterator.hasNext()) {
Map.Entry> entry = iterator.next();
String label = entry.getKey();
List list = entry.getValue();
List timestampList = list.stream().map(Metric::getTimestamp).collect(Collectors.toList());
int index=0;
- //总的响应时间
int sumElapsed=0;
- Integer failSize = 0;
- Float totalBytes = 0f;
+ int failSize = 0;
+ float totalBytes = 0f;
List elapsedList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
try {
Metric row = list.get(i);
- //响应时间
String elapsed = row.getElapsed();
- sumElapsed += Integer.valueOf(elapsed);
- totalAverage += Integer.valueOf(elapsed);
+ sumElapsed += Integer.parseInt(elapsed);
+ totalAverage += Integer.parseInt(elapsed);
elapsedList.add(Integer.valueOf(elapsed));
allelapse.add(Integer.valueOf(elapsed));
- //成功与否
String success = row.getSuccess();
if (!"true".equals(success)){
failSize++;
}
- //字节
String bytes = row.getBytes();
- totalBytes += Float.valueOf(bytes);
+ totalBytes += Float.parseFloat(bytes);
index++;
}catch (Exception e){
System.out.println("exception i:"+i);
@@ -78,17 +72,19 @@ public class JtlResolver {
Collections.sort(elapsedList);
- Integer tp90 = elapsedList.size()*90/100;
- Integer tp95 = elapsedList.size()*95/100;
- Integer tp99 = elapsedList.size()*99/100;
- Long l = Long.valueOf(timestampList.get(timestampList.size()-1)) - Long.valueOf(timestampList.get(0));
+ int tp90 = elapsedList.size()*90/100;
+ int tp95 = elapsedList.size()*95/100;
+ int tp99 = elapsedList.size()*99/100;
+ long l = Long.valueOf(timestampList.get(timestampList.size()-1)) - Long.valueOf(timestampList.get(0));
RequestStatistics requestStatistics = new RequestStatistics();
requestStatistics.setRequestLabel(label);
requestStatistics.setSamples(index);
- DecimalFormat df = new DecimalFormat("0.00");
+
+
String s = df.format((float)sumElapsed/index);
requestStatistics.setAverage(s+"");
+
/**
* TP90的计算
* 1,把一段时间内全部的请求的响应时间,从小到大排序,获得序列A
@@ -99,6 +95,7 @@ public class JtlResolver {
requestStatistics.setTp90(elapsedList.get(tp90)+"");
requestStatistics.setTp95(elapsedList.get(tp95)+"");
requestStatistics.setTp99(elapsedList.get(tp99)+"");
+
requestStatistics.setMin(elapsedList.get(0)+"");
requestStatistics.setMax(elapsedList.get(index-1)+"");
requestStatistics.setErrors(String.format("%.2f",failSize*100.0/index)+"%");
@@ -112,16 +109,15 @@ public class JtlResolver {
}
Collections.sort(allelapse);
- Integer totalTP90 = allelapse.size()*90/100;
- Integer totalTP95 = allelapse.size()*95/100;
- Integer totalTP99 = allelapse.size()*99/100;
+ int totalTP90 = allelapse.size()*90/100;
+ int totalTP95 = allelapse.size()*95/100;
+ int totalTP99 = allelapse.size()*99/100;
Integer min = allelapse.get(0);
Integer max = allelapse.get(allelapse.size() - 1);
- Integer allSamples = requestStatisticsList.stream().mapToInt(RequestStatistics::getSamples).sum();
- Integer failSize = requestStatisticsList.stream().mapToInt(RequestStatistics::getKo).sum();
- DecimalFormat df = new DecimalFormat("0.00");
+ int allSamples = requestStatisticsList.stream().mapToInt(RequestStatistics::getSamples).sum();
+ int failSize = requestStatisticsList.stream().mapToInt(RequestStatistics::getKo).sum();
double errors = (double)failSize / allSamples * 100;
String totalerrors = df.format(errors);
double average = (double)totalAverage / allSamples;
@@ -142,20 +138,21 @@ public class JtlResolver {
return statisticsDTO;
}
- // Aggregate Report
+ // report - Aggregate Report
public static RequestStatisticsDTO getRequestStatistics(String jtlString) {
List totalLines = resolver(jtlString);
Map> map = totalLines.stream().collect(Collectors.groupingBy(Metric::getLabel));
return getOneRpsResult(map);
}
- // Errors
+ // report - Errors
public static List getErrorsList(String jtlString) {
List totalLines = resolver(jtlString);
List falseList = totalLines.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList());
List errorsList = new ArrayList<>();
Map> collect = falseList.stream().collect(Collectors.groupingBy(JtlResolver::getResponseCodeAndFailureMessage));
Iterator>> iterator = collect.entrySet().iterator();
+ DecimalFormat df = new DecimalFormat("0.00");
while (iterator.hasNext()) {
Map.Entry> next = iterator.next();
String key = next.getKey();
@@ -163,10 +160,9 @@ public class JtlResolver {
Errors errors = new Errors();
errors.setErrorType(key);
errors.setErrorNumber(String.valueOf(value.size()));
- Integer errorSize = value.size();
- Integer errorAllSize = falseList.size();
- Integer allSamples = totalLines.size();
- DecimalFormat df = new DecimalFormat("0.00");
+ int errorSize = value.size();
+ int errorAllSize = falseList.size();
+ int allSamples = totalLines.size();
errors.setPrecentOfErrors(df.format((double)errorSize / errorAllSize * 100) + "%");
errors.setPrecentOfAllSamples(df.format((double)errorSize / allSamples * 100) + "%");
errorsList.add(errors);
@@ -178,4 +174,106 @@ public class JtlResolver {
return metric.getResponseCode() + "/" + metric.getResponseMessage();
}
+ // report - Errors Top 5
+ public static ErrorsTop5DTO getErrorsTop5DTO(String jtlString) {
+ List totalLines = resolver(jtlString);
+ ErrorsTop5DTO top5DTO = new ErrorsTop5DTO();
+ List falseList = totalLines.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList());
+ Map> collect = falseList.stream().collect(Collectors.groupingBy(JtlResolver::getResponseCodeAndFailureMessage));
+ Iterator>> iterator = collect.entrySet().iterator();
+ List errorsTop5s = new ArrayList<>();
+ while (iterator.hasNext()) {
+ Map.Entry> next = iterator.next();
+ String key = next.getKey();
+ List value = next.getValue();
+ ErrorsTop5 errorsTop5 = new ErrorsTop5();
+ List list = totalLines.stream()
+ .filter(metric -> StringUtils.equals(metric.getLabel(), value.get(0).getLabel())).collect(Collectors.toList());
+ errorsTop5.setSamples(String.valueOf(list.size()));
+ errorsTop5.setSample(value.get(0).getLabel());
+ errorsTop5.setErrors(String.valueOf(value.size()));
+ errorsTop5.setErrorsAllSize(value.size());
+ errorsTop5.setError(key);
+ errorsTop5s.add(errorsTop5);
+ }
+
+ errorsTop5s.sort((t0, t1) -> t1.getErrorsAllSize().compareTo(t0.getErrorsAllSize()));
+
+ if (errorsTop5s.size() >= 5) {
+ errorsTop5s = errorsTop5s.subList(0, 5);
+ }
+
+ top5DTO.setLabel("Total");
+ top5DTO.setErrorsTop5List(errorsTop5s);
+ top5DTO.setTotalSamples(String.valueOf(totalLines.size()));
+ top5DTO.setTotalErrors(String.valueOf(falseList.size()));
+ int size = errorsTop5s.size();
+ // Total行 信息
+ top5DTO.setError1(size > 0 ? errorsTop5s.get(0).getError() : null);
+ top5DTO.setError1Size(size > 0 ? errorsTop5s.get(0).getErrors() : null);
+ top5DTO.setError2(size > 1 ? errorsTop5s.get(1).getError() : null);
+ top5DTO.setError2Size(size > 1 ? errorsTop5s.get(1).getErrors() : null);
+ top5DTO.setError3(size > 2 ? errorsTop5s.get(2).getError() : null);
+ top5DTO.setError3Size(size > 2 ? errorsTop5s.get(2).getErrors() : null);
+ top5DTO.setError4(size > 3 ? errorsTop5s.get(3).getError() : null);
+ top5DTO.setError4Size(size > 3 ? errorsTop5s.get(3).getErrors() : null);
+ top5DTO.setError5(size > 4 ? errorsTop5s.get(4).getError() : null);
+ top5DTO.setError5Size(size > 4 ? errorsTop5s.get(4).getErrors() : null);
+
+ return top5DTO;
+ }
+
+ // report - TestOverview
+ public static TestOverview getTestOverview(String jtlString) {
+ TestOverview testOverview = new TestOverview();
+ List total = JtlResolver.resolver(jtlString);
+ Map> collect = total.stream().collect(Collectors.groupingBy(Metric::getTimestamp));
+ Iterator>> iterator = collect.entrySet().iterator();
+ int max = 0;
+ int totalElapsed = 0;
+ float totalBytes = 0f;
+ while (iterator.hasNext()) {
+ Map.Entry> entry = iterator.next();
+ List list = entry.getValue();
+ if (list.size() > max) {
+ max = list.size();
+ }
+ for (int i = 0; i < list.size(); i++) {
+ Metric metric = list.get(i);
+ String elapsed = metric.getElapsed();
+ totalElapsed += Integer.parseInt(elapsed);
+ String bytes = metric.getBytes();
+ totalBytes += Float.parseFloat(bytes);
+ }
+ }
+
+ total.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
+ DecimalFormat df = new DecimalFormat("0.00");
+
+ testOverview.setMaxUsers(String.valueOf(max));
+
+ List list90 = total.subList(0, total.size() * 9 / 10);
+ long sum = list90.stream().mapToLong(metric -> Long.parseLong(metric.getElapsed())).sum();
+ double avg90 = (double)sum / 1000 / list90.size();
+ testOverview.setResponseTime90(df.format(avg90));
+
+ Long timestamp1 = Long.valueOf(total.get(0).getTimestamp());
+ Long timestamp2 = Long.valueOf(total.get(total.size()-1).getTimestamp());
+ long seconds = (timestamp2 - timestamp1) / 1000;
+ double avgThroughput = (double)total.size() / seconds;
+ testOverview.setAvgThroughput(df.format(avgThroughput));
+
+ List falseList = total.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList());
+ double errors = falseList.size() * 1.0 / total.size() * 100;
+ testOverview.setErrors(df.format(errors));
+
+ double avg = totalElapsed * 1.0 / total.size() / 1000; // s
+ testOverview.setAvgResponseTime(df.format(avg));
+
+ double bandwidth = totalBytes * 1.0 / 1024 / seconds;
+ testOverview.setAvgBandwidth(df.format(bandwidth));
+
+ return testOverview;
+ }
+
}
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/report/base/ErrorsTop5.java b/backend/src/main/java/io/metersphere/report/base/ErrorsTop5.java
new file mode 100644
index 0000000000..311e1112fc
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/report/base/ErrorsTop5.java
@@ -0,0 +1,50 @@
+package io.metersphere.report.base;
+
+public class ErrorsTop5 {
+
+ private String sample;
+ private String samples;
+ private Integer errorsAllSize;
+ private String error;
+ private String errors;
+
+ public String getSample() {
+ return sample;
+ }
+
+ public void setSample(String sample) {
+ this.sample = sample;
+ }
+
+ public String getSamples() {
+ return samples;
+ }
+
+ public void setSamples(String samples) {
+ this.samples = samples;
+ }
+
+ public Integer getErrorsAllSize() {
+ return errorsAllSize;
+ }
+
+ public void setErrorsAllSize(Integer errorsAllSize) {
+ this.errorsAllSize = errorsAllSize;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+ public String getErrors() {
+ return errors;
+ }
+
+ public void setErrors(String errors) {
+ this.errors = errors;
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/report/base/TestOverview.java b/backend/src/main/java/io/metersphere/report/base/TestOverview.java
new file mode 100644
index 0000000000..9ef2b2c3dc
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/report/base/TestOverview.java
@@ -0,0 +1,59 @@
+package io.metersphere.report.base;
+
+public class TestOverview {
+
+ private String maxUsers;
+ private String avgThroughput; // Hits/s
+ private String errors;
+ private String avgResponseTime; // s
+ private String responseTime90;
+ private String avgBandwidth;
+
+ public String getMaxUsers() {
+ return maxUsers;
+ }
+
+ public void setMaxUsers(String maxUsers) {
+ this.maxUsers = maxUsers;
+ }
+
+ public String getAvgThroughput() {
+ return avgThroughput;
+ }
+
+ public void setAvgThroughput(String avgThroughput) {
+ this.avgThroughput = avgThroughput;
+ }
+
+ public String getErrors() {
+ return errors;
+ }
+
+ public void setErrors(String errors) {
+ this.errors = errors;
+ }
+
+ public String getAvgResponseTime() {
+ return avgResponseTime;
+ }
+
+ public void setAvgResponseTime(String avgResponseTime) {
+ this.avgResponseTime = avgResponseTime;
+ }
+
+ public String getResponseTime90() {
+ return responseTime90;
+ }
+
+ public void setResponseTime90(String responseTime90) {
+ this.responseTime90 = responseTime90;
+ }
+
+ public String getAvgBandwidth() {
+ return avgBandwidth;
+ }
+
+ public void setAvgBandwidth(String avgBandwidth) {
+ this.avgBandwidth = avgBandwidth;
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/report/dto/ErrorsTop5DTO.java b/backend/src/main/java/io/metersphere/report/dto/ErrorsTop5DTO.java
new file mode 100644
index 0000000000..7bcf200855
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/report/dto/ErrorsTop5DTO.java
@@ -0,0 +1,135 @@
+package io.metersphere.report.dto;
+
+import io.metersphere.report.base.ErrorsTop5;
+
+import java.util.List;
+
+public class ErrorsTop5DTO {
+
+ private List errorsTop5List;
+ private String label;
+ private String totalSamples;
+ private String totalErrors;
+ private String error1;
+ private String error1Size;
+ private String error2;
+ private String error2Size;
+ private String error3;
+ private String error3Size;
+ private String error4;
+ private String error4Size;
+ private String error5;
+ private String error5Size;
+
+ public List getErrorsTop5List() {
+ return errorsTop5List;
+ }
+
+ public void setErrorsTop5List(List errorsTop5List) {
+ this.errorsTop5List = errorsTop5List;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getTotalSamples() {
+ return totalSamples;
+ }
+
+ public void setTotalSamples(String totalSamples) {
+ this.totalSamples = totalSamples;
+ }
+
+ public String getTotalErrors() {
+ return totalErrors;
+ }
+
+ public void setTotalErrors(String totalErrors) {
+ this.totalErrors = totalErrors;
+ }
+
+ public String getError1() {
+ return error1;
+ }
+
+ public void setError1(String error1) {
+ this.error1 = error1;
+ }
+
+ public String getError1Size() {
+ return error1Size;
+ }
+
+ public void setError1Size(String error1Size) {
+ this.error1Size = error1Size;
+ }
+
+ public String getError2() {
+ return error2;
+ }
+
+ public void setError2(String error2) {
+ this.error2 = error2;
+ }
+
+ public String getError2Size() {
+ return error2Size;
+ }
+
+ public void setError2Size(String error2Size) {
+ this.error2Size = error2Size;
+ }
+
+ public String getError3() {
+ return error3;
+ }
+
+ public void setError3(String error3) {
+ this.error3 = error3;
+ }
+
+ public String getError3Size() {
+ return error3Size;
+ }
+
+ public void setError3Size(String error3Size) {
+ this.error3Size = error3Size;
+ }
+
+ public String getError4() {
+ return error4;
+ }
+
+ public void setError4(String error4) {
+ this.error4 = error4;
+ }
+
+ public String getError4Size() {
+ return error4Size;
+ }
+
+ public void setError4Size(String error4Size) {
+ this.error4Size = error4Size;
+ }
+
+ public String getError5() {
+ return error5;
+ }
+
+ public void setError5(String error5) {
+ this.error5 = error5;
+ }
+
+ public String getError5Size() {
+ return error5Size;
+ }
+
+ public void setError5Size(String error5Size) {
+ this.error5Size = error5Size;
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/report/base/RequestStatisticsDTO.java b/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java
similarity index 96%
rename from backend/src/main/java/io/metersphere/report/base/RequestStatisticsDTO.java
rename to backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java
index 3f93a5f8a2..a92e235a89 100644
--- a/backend/src/main/java/io/metersphere/report/base/RequestStatisticsDTO.java
+++ b/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java
@@ -1,4 +1,6 @@
-package io.metersphere.report.base;
+package io.metersphere.report.dto;
+
+import io.metersphere.report.base.RequestStatistics;
import java.util.List;
diff --git a/backend/src/main/java/io/metersphere/service/LoadTestService.java b/backend/src/main/java/io/metersphere/service/LoadTestService.java
index 1cdce5e7fb..a9396f4dd8 100644
--- a/backend/src/main/java/io/metersphere/service/LoadTestService.java
+++ b/backend/src/main/java/io/metersphere/service/LoadTestService.java
@@ -166,6 +166,9 @@ public class LoadTestService {
if (loadTest == null) {
MSException.throwException(Translator.get("run_load_test_not_found") + request.getId());
}
+ if (TestStatus.Running.name().equals(loadTest.getStatus())) {
+ MSException.throwException(Translator.get("load_test_is_running") + request.getId());
+ }
LogUtil.info("Load test started " + loadTest.getName());
// engine type (NODE|K8S)
diff --git a/backend/src/main/java/io/metersphere/service/ReportService.java b/backend/src/main/java/io/metersphere/service/ReportService.java
index a918b34516..76145cfced 100644
--- a/backend/src/main/java/io/metersphere/service/ReportService.java
+++ b/backend/src/main/java/io/metersphere/service/ReportService.java
@@ -8,8 +8,9 @@ import io.metersphere.controller.request.ReportRequest;
import io.metersphere.dto.ReportDTO;
import io.metersphere.report.JtlResolver;
import io.metersphere.report.base.Errors;
-import io.metersphere.report.base.RequestStatistics;
-import io.metersphere.report.base.RequestStatisticsDTO;
+import io.metersphere.report.base.TestOverview;
+import io.metersphere.report.dto.ErrorsTop5DTO;
+import io.metersphere.report.dto.RequestStatisticsDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -59,4 +60,18 @@ public class ReportService {
List errors = JtlResolver.getErrorsList(content);
return errors;
}
+
+ public ErrorsTop5DTO getReportErrorsTOP5(String id) {
+ LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
+ String content = loadTestReport.getContent();
+ ErrorsTop5DTO errors = JtlResolver.getErrorsTop5DTO(content);
+ return errors;
+ }
+
+ public TestOverview getTestOverview(String id) {
+ LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
+ String content = loadTestReport.getContent();
+ TestOverview testOverview = JtlResolver.getTestOverview(content);
+ return testOverview;
+ }
}
diff --git a/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java b/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java
index 058c555d34..e81cc22944 100644
--- a/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java
+++ b/backend/src/main/java/io/metersphere/service/TestResourcePoolService.java
@@ -16,7 +16,7 @@ import io.metersphere.dto.TestResourcePoolDTO;
import io.metersphere.engine.kubernetes.provider.KubernetesProvider;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpStatus;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -43,6 +43,8 @@ public class TestResourcePoolService {
private TestResourceMapper testResourceMapper;
@Resource
private ExtTestReourcePoolMapper extTestReourcePoolMapper;
+ @Resource
+ private RestTemplate restTemplate;
public TestResourcePoolDTO addTestResourcePool(TestResourcePoolDTO testResourcePool) {
testResourcePool.setId(UUID.randomUUID().toString());
@@ -100,9 +102,8 @@ public class TestResourcePoolService {
private boolean validateNode(NodeDTO node) {
try {
- RestTemplate restTemplate = new RestTemplate();
ResponseEntity entity = restTemplate.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class);
- return entity.getStatusCode().value() == HttpStatus.SC_OK;
+ return HttpStatus.OK.equals(entity.getStatusCode());
} catch (Exception e) {
return false;
}
diff --git a/backend/src/main/resources/i18n/en-US.json b/backend/src/main/resources/i18n/en-US.json
index 4d1a6251c1..04c61c9de6 100644
--- a/backend/src/main/resources/i18n/en-US.json
+++ b/backend/src/main/resources/i18n/en-US.json
@@ -12,5 +12,6 @@
"run_load_test_not_found": "Cannot run test, test not found:",
"run_load_test_file_not_found": "Unable to run test, unable to get test file meta information, test ID:",
"run_load_test_file_content_not_found": "Cannot run test, cannot get test file content, test ID:",
- "run_load_test_file_init_error": "Failed to run test, failed to initialize run environment, test ID:"
+ "run_load_test_file_init_error": "Failed to run test, failed to initialize run environment, test ID:",
+ "load_test_is_running": "Load test is running, please wait."
}
\ No newline at end of file
diff --git a/backend/src/main/resources/i18n/zh-CN.json b/backend/src/main/resources/i18n/zh-CN.json
index 85ca41c996..1d085f8813 100644
--- a/backend/src/main/resources/i18n/zh-CN.json
+++ b/backend/src/main/resources/i18n/zh-CN.json
@@ -12,5 +12,6 @@
"run_load_test_not_found": "无法运行测试,未找到测试:",
"run_load_test_file_not_found": "无法运行测试,无法获取测试文件元信息,测试ID:",
"run_load_test_file_content_not_found": "无法运行测试,无法获取测试文件内容,测试ID:",
- "run_load_test_file_init_error": "无法运行测试,初始化运行环境失败,测试ID:"
+ "run_load_test_file_init_error": "无法运行测试,初始化运行环境失败,测试ID:",
+ "load_test_is_running": "测试正在运行, 请等待"
}
\ No newline at end of file
diff --git a/frontend/src/business/components/performance/plan/EditPerformanceTestPlan.vue b/frontend/src/business/components/performance/plan/EditPerformanceTestPlan.vue
index a76ec27387..84d55c223a 100644
--- a/frontend/src/business/components/performance/plan/EditPerformanceTestPlan.vue
+++ b/frontend/src/business/components/performance/plan/EditPerformanceTestPlan.vue
@@ -82,6 +82,10 @@
return;
}
+ if (to.name !== 'editPerTest') {
+ return;
+ }
+
let testId = to.path.split('/')[4]; // find testId
if (testId) {
this.result = this.$get('/testplan/get/' + testId, response => {
diff --git a/frontend/src/business/components/performance/plan/components/PerformanceAdvancedConfig.vue b/frontend/src/business/components/performance/plan/components/PerformanceAdvancedConfig.vue
index 716b23fea9..fd0d714d1a 100644
--- a/frontend/src/business/components/performance/plan/components/PerformanceAdvancedConfig.vue
+++ b/frontend/src/business/components/performance/plan/components/PerformanceAdvancedConfig.vue
@@ -218,8 +218,8 @@
}
},
watch: {
- '$route'(to, from) {
- if (from.name !== 'createPerTest' && from.name !== 'editPerTest') {
+ '$route'(to) {
+ if (to.name !== 'createPerTest' && to.name !== 'editPerTest') {
return;
}
let testId = to.path.split('/')[4];
diff --git a/frontend/src/business/components/performance/plan/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/plan/components/PerformancePressureConfig.vue
index 07b08f2d8f..be8ffb0314 100644
--- a/frontend/src/business/components/performance/plan/components/PerformancePressureConfig.vue
+++ b/frontend/src/business/components/performance/plan/components/PerformancePressureConfig.vue
@@ -131,8 +131,8 @@
this.getResourcePools();
},
watch: {
- '$route'(to, from) {
- if (from.name !== 'createPerTest' && from.name !== 'editPerTest') {
+ '$route'(to) {
+ if (to.name !== 'createPerTest' && to.name !== 'editPerTest') {
return;
}
let testId = to.path.split('/')[4];
diff --git a/frontend/src/business/components/performance/report/PerformanceReportView.vue b/frontend/src/business/components/performance/report/PerformanceReportView.vue
index 522f861dce..c153d20254 100644
--- a/frontend/src/business/components/performance/report/PerformanceReportView.vue
+++ b/frontend/src/business/components/performance/report/PerformanceReportView.vue
@@ -35,7 +35,7 @@
-
+
@@ -44,7 +44,7 @@
-
+
diff --git a/frontend/src/business/components/performance/report/components/ErrorLog.vue b/frontend/src/business/components/performance/report/components/ErrorLog.vue
index eb13535c5b..aa885f8322 100644
--- a/frontend/src/business/components/performance/report/components/ErrorLog.vue
+++ b/frontend/src/business/components/performance/report/components/ErrorLog.vue
@@ -34,37 +34,39 @@
Top 5 Errors by sampler
@@ -126,7 +128,9 @@
name: "ErrorLog",
data() {
return {
- tableData: [{},{},{},{},{}]
+ tableData: [{},{},{},{},{}],
+ errorTotal: {},
+ errorTop5: []
}
},
methods: {
@@ -134,10 +138,32 @@
this.$get("/report/content/errors/" + this.id, res => {
this.tableData = res.data;
})
+ this.$get("/report/content/errors_top5/" + this.id, res => {
+ this.errorTotal = res.data
+ this.errorTop5 = res.data.errorsTop5List;
+ })
+ },
+ getSummaries () {
+ const sums = []
+ sums[0] = this.errorTotal.label;
+ sums[1] = this.errorTotal.totalSamples;
+ sums[2] = this.errorTotal.totalErrors;
+ sums[3] = this.errorTotal.error1;
+ sums[4] = this.errorTotal.error1Size;
+ sums[5] = this.errorTotal.error2;
+ sums[6] = this.errorTotal.error2Size;
+ sums[7] = this.errorTotal.error3;
+ sums[8] = this.errorTotal.error3Size;
+ sums[9] = this.errorTotal.error4;
+ sums[10] = this.errorTotal.error4Size;
+ sums[11] = this.errorTotal.error5;
+ sums[12] = this.errorTotal.error5Size;
+ return sums;
}
},
created() {
this.initTableData();
+ this.getSummaries()
},
props: ['id'],
watch: {
@@ -145,9 +171,13 @@
if (to.name === "perReportView") {
let reportId = to.path.split('/')[4];
if(reportId){
- this.$get("/report/content/errors/" + this.id, res => {
+ this.$get("/report/content/errors/" + reportId, res => {
this.tableData = res.data;
})
+ this.$get("/report/content/errors_top5/" + reportId, res => {
+ this.errorTop5 = res.data.errorsTop5List;
+ this.errorTotal = res.data
+ })
}
}
}
diff --git a/frontend/src/business/components/performance/report/components/TestOverview.vue b/frontend/src/business/components/performance/report/components/TestOverview.vue
index 1745b0bca7..54414663b8 100644
--- a/frontend/src/business/components/performance/report/components/TestOverview.vue
+++ b/frontend/src/business/components/performance/report/components/TestOverview.vue
@@ -4,7 +4,7 @@
- 40
+ {{maxUsers}}
VU
Max Users
@@ -13,7 +13,7 @@
- 5.4
+ {{avgThroughput}}
Hits/s
Avg.Throughput
@@ -22,7 +22,7 @@
- 0.41
+ {{errors}}
%
Errors
@@ -31,7 +31,7 @@
- 1.28
+ {{avgResponseTime}}
s
Avg.Response Time
@@ -40,7 +40,7 @@
- 1.41
+ {{responseTime90}}
s
90% Response Time
@@ -49,7 +49,7 @@
- 817.29
+ {{avgBandwidth}}
KiB/s
Avg.Bandwidth
@@ -73,6 +73,12 @@
name: "TestOverview",
data() {
return {
+ maxUsers: "0",
+ avgThroughput: "0",
+ errors: "0",
+ avgResponseTime: "0",
+ responseTime90: "0",
+ avgBandwidth: "0",
option1: {
legend: {
top: 20,
@@ -146,6 +152,41 @@
]
}
}
+ },
+ methods: {
+ initTableData() {
+ this.$get("/report/content/testoverview/" + this.id, res => {
+ let data = res.data;
+ this.maxUsers = data.maxUsers;
+ this.avgThroughput = data.avgThroughput;
+ this.errors = data.errors;
+ this.avgResponseTime = data.avgResponseTime;
+ this.responseTime90 = data.responseTime90;
+ this.avgBandwidth = data.avgBandwidth;
+ })
+ }
+ },
+ created() {
+ this.initTableData()
+ },
+ props: ['id'],
+ watch: {
+ '$route'(to) {
+ if (to.name === "perReportView") {
+ let reportId = to.path.split('/')[4];
+ if(reportId){
+ this.$get("/report/content/testoverview/" + reportId, res => {
+ let data = res.data;
+ this.maxUsers = data.maxUsers;
+ this.avgThroughput = data.avgThroughput;
+ this.errors = data.errors;
+ this.avgResponseTime = data.avgResponseTime;
+ this.responseTime90 = data.responseTime90;
+ this.avgBandwidth = data.avgBandwidth;
+ })
+ }
+ }
+ }
}
}
diff --git a/pom.xml b/pom.xml
index 14cce36261..7277be513f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.2.2.RELEASE
+ 2.2.6.RELEASE