diff --git a/backend/src/main/java/io/metersphere/base/domain/TestPlan.java b/backend/src/main/java/io/metersphere/base/domain/TestPlan.java index c20a28b949..e19aeba2b9 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestPlan.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlan.java @@ -7,12 +7,18 @@ public class TestPlan implements Serializable { private String projectId; + private String workspaceId; + private String name; private String description; private String status; + private String stage; + + private String principal; + private String testCaseMatchRule; private String executorMatchRule; @@ -41,6 +47,14 @@ public class TestPlan implements Serializable { this.projectId = projectId == null ? null : projectId.trim(); } + public String getWorkspaceId() { + return workspaceId; + } + + public void setWorkspaceId(String workspaceId) { + this.workspaceId = workspaceId == null ? null : workspaceId.trim(); + } + public String getName() { return name; } @@ -65,6 +79,22 @@ public class TestPlan implements Serializable { this.status = status == null ? null : status.trim(); } + public String getStage() { + return stage; + } + + public void setStage(String stage) { + this.stage = stage == null ? null : stage.trim(); + } + + public String getPrincipal() { + return principal; + } + + public void setPrincipal(String principal) { + this.principal = principal == null ? null : principal.trim(); + } + public String getTestCaseMatchRule() { return testCaseMatchRule; } diff --git a/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java b/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java index b5531b4ed8..a447f69dc1 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java @@ -244,6 +244,76 @@ public class TestPlanExample { return (Criteria) this; } + public Criteria andWorkspaceIdIsNull() { + addCriterion("workspace_id is null"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdIsNotNull() { + addCriterion("workspace_id is not null"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdEqualTo(String value) { + addCriterion("workspace_id =", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdNotEqualTo(String value) { + addCriterion("workspace_id <>", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdGreaterThan(String value) { + addCriterion("workspace_id >", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdGreaterThanOrEqualTo(String value) { + addCriterion("workspace_id >=", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdLessThan(String value) { + addCriterion("workspace_id <", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdLessThanOrEqualTo(String value) { + addCriterion("workspace_id <=", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdLike(String value) { + addCriterion("workspace_id like", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdNotLike(String value) { + addCriterion("workspace_id not like", value, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdIn(List values) { + addCriterion("workspace_id in", values, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdNotIn(List values) { + addCriterion("workspace_id not in", values, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdBetween(String value1, String value2) { + addCriterion("workspace_id between", value1, value2, "workspaceId"); + return (Criteria) this; + } + + public Criteria andWorkspaceIdNotBetween(String value1, String value2) { + addCriterion("workspace_id not between", value1, value2, "workspaceId"); + return (Criteria) this; + } + public Criteria andNameIsNull() { addCriterion("name is null"); return (Criteria) this; @@ -454,6 +524,146 @@ public class TestPlanExample { return (Criteria) this; } + public Criteria andStageIsNull() { + addCriterion("stage is null"); + return (Criteria) this; + } + + public Criteria andStageIsNotNull() { + addCriterion("stage is not null"); + return (Criteria) this; + } + + public Criteria andStageEqualTo(String value) { + addCriterion("stage =", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageNotEqualTo(String value) { + addCriterion("stage <>", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageGreaterThan(String value) { + addCriterion("stage >", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageGreaterThanOrEqualTo(String value) { + addCriterion("stage >=", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageLessThan(String value) { + addCriterion("stage <", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageLessThanOrEqualTo(String value) { + addCriterion("stage <=", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageLike(String value) { + addCriterion("stage like", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageNotLike(String value) { + addCriterion("stage not like", value, "stage"); + return (Criteria) this; + } + + public Criteria andStageIn(List values) { + addCriterion("stage in", values, "stage"); + return (Criteria) this; + } + + public Criteria andStageNotIn(List values) { + addCriterion("stage not in", values, "stage"); + return (Criteria) this; + } + + public Criteria andStageBetween(String value1, String value2) { + addCriterion("stage between", value1, value2, "stage"); + return (Criteria) this; + } + + public Criteria andStageNotBetween(String value1, String value2) { + addCriterion("stage not between", value1, value2, "stage"); + return (Criteria) this; + } + + public Criteria andPrincipalIsNull() { + addCriterion("principal is null"); + return (Criteria) this; + } + + public Criteria andPrincipalIsNotNull() { + addCriterion("principal is not null"); + return (Criteria) this; + } + + public Criteria andPrincipalEqualTo(String value) { + addCriterion("principal =", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalNotEqualTo(String value) { + addCriterion("principal <>", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalGreaterThan(String value) { + addCriterion("principal >", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalGreaterThanOrEqualTo(String value) { + addCriterion("principal >=", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalLessThan(String value) { + addCriterion("principal <", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalLessThanOrEqualTo(String value) { + addCriterion("principal <=", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalLike(String value) { + addCriterion("principal like", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalNotLike(String value) { + addCriterion("principal not like", value, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalIn(List values) { + addCriterion("principal in", values, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalNotIn(List values) { + addCriterion("principal not in", values, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalBetween(String value1, String value2) { + addCriterion("principal between", value1, value2, "principal"); + return (Criteria) this; + } + + public Criteria andPrincipalNotBetween(String value1, String value2) { + addCriterion("principal not between", value1, value2, "principal"); + return (Criteria) this; + } + public Criteria andTestCaseMatchRuleIsNull() { addCriterion("test_case_match_rule is null"); return (Criteria) this; diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml index 55398ba323..f91bb33a6c 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml @@ -4,9 +4,12 @@ + + + @@ -74,8 +77,8 @@ - id, project_id, name, description, status, test_case_match_rule, executor_match_rule, - create_time, update_time + id, project_id, workspace_id, name, description, status, stage, principal, test_case_match_rule, + executor_match_rule, create_time, update_time tags @@ -129,12 +132,14 @@ - insert into test_plan (id, project_id, name, - description, status, test_case_match_rule, + insert into test_plan (id, project_id, workspace_id, + name, description, status, + stage, principal, test_case_match_rule, executor_match_rule, create_time, update_time, tags) - values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, - #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{testCaseMatchRule,jdbcType=VARCHAR}, + values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, + #{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, + #{stage,jdbcType=VARCHAR}, #{principal,jdbcType=VARCHAR}, #{testCaseMatchRule,jdbcType=VARCHAR}, #{executorMatchRule,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{tags,jdbcType=LONGVARCHAR}) @@ -147,6 +152,9 @@ project_id, + + workspace_id, + name, @@ -156,6 +164,12 @@ status, + + stage, + + + principal, + test_case_match_rule, @@ -179,6 +193,9 @@ #{projectId,jdbcType=VARCHAR}, + + #{workspaceId,jdbcType=VARCHAR}, + #{name,jdbcType=VARCHAR}, @@ -188,6 +205,12 @@ #{status,jdbcType=VARCHAR}, + + #{stage,jdbcType=VARCHAR}, + + + #{principal,jdbcType=VARCHAR}, + #{testCaseMatchRule,jdbcType=VARCHAR}, @@ -220,6 +243,9 @@ project_id = #{record.projectId,jdbcType=VARCHAR}, + + workspace_id = #{record.workspaceId,jdbcType=VARCHAR}, + name = #{record.name,jdbcType=VARCHAR}, @@ -229,6 +255,12 @@ status = #{record.status,jdbcType=VARCHAR}, + + stage = #{record.stage,jdbcType=VARCHAR}, + + + principal = #{record.principal,jdbcType=VARCHAR}, + test_case_match_rule = #{record.testCaseMatchRule,jdbcType=VARCHAR}, @@ -253,9 +285,12 @@ update test_plan set id = #{record.id,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR}, + workspace_id = #{record.workspaceId,jdbcType=VARCHAR}, name = #{record.name,jdbcType=VARCHAR}, description = #{record.description,jdbcType=VARCHAR}, status = #{record.status,jdbcType=VARCHAR}, + stage = #{record.stage,jdbcType=VARCHAR}, + principal = #{record.principal,jdbcType=VARCHAR}, test_case_match_rule = #{record.testCaseMatchRule,jdbcType=VARCHAR}, executor_match_rule = #{record.executorMatchRule,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, @@ -269,9 +304,12 @@ update test_plan set id = #{record.id,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR}, + workspace_id = #{record.workspaceId,jdbcType=VARCHAR}, name = #{record.name,jdbcType=VARCHAR}, description = #{record.description,jdbcType=VARCHAR}, status = #{record.status,jdbcType=VARCHAR}, + stage = #{record.stage,jdbcType=VARCHAR}, + principal = #{record.principal,jdbcType=VARCHAR}, test_case_match_rule = #{record.testCaseMatchRule,jdbcType=VARCHAR}, executor_match_rule = #{record.executorMatchRule,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, @@ -286,6 +324,9 @@ project_id = #{projectId,jdbcType=VARCHAR}, + + workspace_id = #{workspaceId,jdbcType=VARCHAR}, + name = #{name,jdbcType=VARCHAR}, @@ -295,6 +336,12 @@ status = #{status,jdbcType=VARCHAR}, + + stage = #{stage,jdbcType=VARCHAR}, + + + principal = #{principal,jdbcType=VARCHAR}, + test_case_match_rule = #{testCaseMatchRule,jdbcType=VARCHAR}, @@ -316,9 +363,12 @@ update test_plan set project_id = #{projectId,jdbcType=VARCHAR}, + workspace_id = #{workspaceId,jdbcType=VARCHAR}, name = #{name,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, status = #{status,jdbcType=VARCHAR}, + stage = #{stage,jdbcType=VARCHAR}, + principal = #{principal,jdbcType=VARCHAR}, test_case_match_rule = #{testCaseMatchRule,jdbcType=VARCHAR}, executor_match_rule = #{executorMatchRule,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, @@ -329,9 +379,12 @@ update test_plan set project_id = #{projectId,jdbcType=VARCHAR}, + workspace_id = #{workspaceId,jdbcType=VARCHAR}, name = #{name,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, status = #{status,jdbcType=VARCHAR}, + stage = #{stage,jdbcType=VARCHAR}, + principal = #{principal,jdbcType=VARCHAR}, test_case_match_rule = #{testCaseMatchRule,jdbcType=VARCHAR}, executor_match_rule = #{executorMatchRule,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java new file mode 100644 index 0000000000..a97bdd1f08 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.java @@ -0,0 +1,11 @@ +package io.metersphere.base.mapper.ext; + +import io.metersphere.controller.request.testcase.QueryTestPlanRequest; +import io.metersphere.dto.TestPlanDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface ExtTestPlanMapper { + List list(@Param("request") QueryTestPlanRequest params); +} diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml new file mode 100644 index 0000000000..54e16d886d --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/constants/TestPlanStatus.java b/backend/src/main/java/io/metersphere/commons/constants/TestPlanStatus.java new file mode 100644 index 0000000000..eeced60689 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/constants/TestPlanStatus.java @@ -0,0 +1,5 @@ +package io.metersphere.commons.constants; + +public enum TestPlanStatus { + Prepare, Running, Completed +} diff --git a/backend/src/main/java/io/metersphere/controller/TestPlanController.java b/backend/src/main/java/io/metersphere/controller/TestPlanController.java new file mode 100644 index 0000000000..8010423357 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/TestPlanController.java @@ -0,0 +1,53 @@ +package io.metersphere.controller; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import io.metersphere.base.domain.TestCase; +import io.metersphere.base.domain.TestCaseWithBLOBs; +import io.metersphere.base.domain.TestPlan; +import io.metersphere.commons.utils.PageUtils; +import io.metersphere.commons.utils.Pager; +import io.metersphere.controller.request.testcase.QueryTestPlanRequest; +import io.metersphere.dto.TestPlanDTO; +import io.metersphere.service.TestCaseService; +import io.metersphere.service.TestPlanService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@RequestMapping("/test/plan") +@RestController +public class TestPlanController { + + @Resource + TestPlanService testPlanService; + + @PostMapping("/list/{goPage}/{pageSize}") + public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, testPlanService.listTestPlan(request)); + } + + @PostMapping("/get/{testPlanId}") + public List getTestPlan(@PathVariable String testPlanId){ + return testPlanService.getTestPlan(testPlanId); + } + + @PostMapping("/add") + public void addTestPlan(@RequestBody TestPlan testPlan){ + testPlanService.addTestPlan(testPlan); + } + + @PostMapping("/edit") + public void editTestPlan(@RequestBody TestPlan testPlan){ + testPlanService.editTestPlan(testPlan); + } + + @PostMapping("/delete/{testPlanId}") + public int deleteTestPlan(@PathVariable String testPlanId){ + return testPlanService.deleteTestPlan(testPlanId); + } + + +} diff --git a/backend/src/main/java/io/metersphere/controller/request/testcase/QueryTestPlanRequest.java b/backend/src/main/java/io/metersphere/controller/request/testcase/QueryTestPlanRequest.java new file mode 100644 index 0000000000..128eeca9f1 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/request/testcase/QueryTestPlanRequest.java @@ -0,0 +1,28 @@ +package io.metersphere.controller.request.testcase; + +import io.metersphere.base.domain.TestCase; +import io.metersphere.base.domain.TestPlan; + +import java.util.List; + +public class QueryTestPlanRequest extends TestPlan { + + private String workspaceId; + private boolean recent = false; + + public boolean isRecent() { + return recent; + } + + public void setRecent(boolean recent) { + this.recent = recent; + } + + public String getWorkspaceId() { + return workspaceId; + } + + public void setWorkspaceId(String workspaceId) { + this.workspaceId = workspaceId; + } +} diff --git a/backend/src/main/java/io/metersphere/dto/TestPlanDTO.java b/backend/src/main/java/io/metersphere/dto/TestPlanDTO.java new file mode 100644 index 0000000000..a7d6f3f205 --- /dev/null +++ b/backend/src/main/java/io/metersphere/dto/TestPlanDTO.java @@ -0,0 +1,15 @@ +package io.metersphere.dto; + +import io.metersphere.base.domain.TestPlan; + +public class TestPlanDTO extends TestPlan { + private String projectName; + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } +} diff --git a/backend/src/main/java/io/metersphere/report/JtlResolver.java b/backend/src/main/java/io/metersphere/report/JtlResolver.java index 30f631f045..d5e3a7a273 100644 --- a/backend/src/main/java/io/metersphere/report/JtlResolver.java +++ b/backend/src/main/java/io/metersphere/report/JtlResolver.java @@ -32,24 +32,25 @@ public class JtlResolver { return null; } - private static RequestStatisticsDTO getOneRpsResult(Map> map){ - RequestStatisticsDTO statisticsDTO = new RequestStatisticsDTO(); + public static RequestStatisticsDTO getRequestStatistics(String jtlString){ + List total = resolver(jtlString); + Map> map = total.stream().collect(Collectors.groupingBy(Metric::getLabel)); List requestStatisticsList = new ArrayList<>(); Iterator>> iterator = map.entrySet().iterator(); List allelapse = new ArrayList<>(); DecimalFormat df = new DecimalFormat("0.00"); int totalAverage = 0; + float allBytes = 0f; 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; int failSize = 0; + // 以list为单位 total bytes float totalBytes = 0f; List elapsedList = new ArrayList<>(); - for (int i = 0; i < list.size(); i++) { try { Metric row = list.get(i); @@ -64,24 +65,25 @@ public class JtlResolver { } String bytes = row.getBytes(); totalBytes += Float.parseFloat(bytes); + allBytes += Float.parseFloat(bytes); index++; }catch (Exception e){ System.out.println("exception i:"+i); } } - Collections.sort(elapsedList); 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)); + + list.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp()))); + long time = Long.parseLong(list.get(list.size()-1).getTimestamp()) - Long.parseLong(list.get(0).getTimestamp()) + Long.parseLong(list.get(list.size()-1).getElapsed()); RequestStatistics requestStatistics = new RequestStatistics(); requestStatistics.setRequestLabel(label); requestStatistics.setSamples(index); - String s = df.format((float)sumElapsed/index); requestStatistics.setAverage(s+""); @@ -92,23 +94,27 @@ public class JtlResolver { * 3,从序列A中找到第C个请求,它的响应时间,即为TP90的值 * 其余相似的指标还有TP95, TP99 */ + // todo tp90 requestStatistics.setTp90(elapsedList.get(tp90)+""); requestStatistics.setTp95(elapsedList.get(tp95)+""); requestStatistics.setTp99(elapsedList.get(tp99)+""); + double avgHits = (double)list.size() / (time * 1.0 / 1000); + requestStatistics.setAvgHits(df.format(avgHits)); + requestStatistics.setMin(elapsedList.get(0)+""); requestStatistics.setMax(elapsedList.get(index-1)+""); - requestStatistics.setErrors(String.format("%.2f",failSize*100.0/index)+"%"); + requestStatistics.setErrors(df.format(failSize * 100.0 / index)+"%"); requestStatistics.setKo(failSize); /** * 所有的相同请求的bytes总和 / 1024 / 请求持续运行的时间=sum(bytes)/1024/total time + * total time = 最大时间戳 - 最小时间戳 + 最后请求的响应时间 */ - // todo Avg Bandwidth(KBytes/s) 请求之间时间戳间隔l 可能为0 - requestStatistics.setKbPerSec(String.format("%.2f",totalBytes*1.0/1024/(l*1.0/1000))); + requestStatistics.setKbPerSec(df.format(totalBytes * 1.0 / 1024 / (time * 1.0 / 1000))); requestStatisticsList.add(requestStatistics); } - Collections.sort(allelapse); + Collections.sort(allelapse); int totalTP90 = allelapse.size()*90/100; int totalTP95 = allelapse.size()*95/100; int totalTP99 = allelapse.size()*99/100; @@ -118,11 +124,13 @@ public class JtlResolver { 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; String totalaverage = df.format(average); + RequestStatisticsDTO statisticsDTO = new RequestStatisticsDTO(); statisticsDTO.setRequestStatisticsList(requestStatisticsList); statisticsDTO.setTotalLabel("Total"); statisticsDTO.setTotalSamples(String.valueOf(allSamples)); @@ -133,16 +141,14 @@ public class JtlResolver { statisticsDTO.setTotalTP90(String.valueOf(allelapse.get(totalTP90))); statisticsDTO.setTotalTP95(String.valueOf(allelapse.get(totalTP95))); statisticsDTO.setTotalTP99(String.valueOf(allelapse.get(totalTP99))); - // todo -// statisticsDTO.setTotalAvgBandwidth(); - return statisticsDTO; - } - // 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); + total.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp()))); + long ms = Long.valueOf(total.get(total.size()-1).getTimestamp()) - Long.valueOf(total.get(0).getTimestamp()) + Long.parseLong(total.get(total.size()-1).getElapsed()); + double avgThroughput = (double)total.size() / (ms * 1.0 / 1000); + statisticsDTO.setTotalAvgHits(df.format(avgThroughput)); + + statisticsDTO.setTotalAvgBandwidth(df.format(allBytes * 1.0 / 1024 / (ms * 1.0 / 1000))); + return statisticsDTO; } // report - Errors @@ -259,8 +265,8 @@ public class JtlResolver { 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; + long time = timestamp2 - timestamp1 + Long.parseLong(total.get(total.size()-1).getElapsed()); + double avgThroughput = (double)total.size() / (time * 1.0 / 1000); testOverview.setAvgThroughput(df.format(avgThroughput)); List falseList = total.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList()); @@ -270,7 +276,7 @@ public class JtlResolver { double avg = totalElapsed * 1.0 / total.size() / 1000; // s testOverview.setAvgResponseTime(df.format(avg)); - double bandwidth = totalBytes * 1.0 / 1024 / seconds; + double bandwidth = totalBytes * 1.0 / time; testOverview.setAvgBandwidth(df.format(bandwidth)); return testOverview; diff --git a/backend/src/main/java/io/metersphere/report/base/RequestStatistics.java b/backend/src/main/java/io/metersphere/report/base/RequestStatistics.java index e5a0b0d269..1600cf342d 100644 --- a/backend/src/main/java/io/metersphere/report/base/RequestStatistics.java +++ b/backend/src/main/java/io/metersphere/report/base/RequestStatistics.java @@ -12,7 +12,7 @@ public class RequestStatistics { private String average; /**平均点击率*/ - private Double avgHits; + private String avgHits; /**90% Line*/ private String tp90; @@ -62,11 +62,11 @@ public class RequestStatistics { this.average = average; } - public Double getAvgHits() { + public String getAvgHits() { return avgHits; } - public void setAvgHits(Double avgHits) { + public void setAvgHits(String avgHits) { this.avgHits = avgHits; } diff --git a/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java b/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java index a92e235a89..1ea442e54f 100644 --- a/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java +++ b/backend/src/main/java/io/metersphere/report/dto/RequestStatisticsDTO.java @@ -28,6 +28,8 @@ public class RequestStatisticsDTO extends RequestStatistics { private String totalAvgBandwidth; + private String totalAvgHits; + public List getRequestStatisticsList() { return requestStatisticsList; } @@ -115,4 +117,12 @@ public class RequestStatisticsDTO extends RequestStatistics { public void setTotalAvgBandwidth(String totalAvgBandwidth) { this.totalAvgBandwidth = totalAvgBandwidth; } + + public String getTotalAvgHits() { + return totalAvgHits; + } + + public void setTotalAvgHits(String totalAvgHits) { + this.totalAvgHits = totalAvgHits; + } } diff --git a/backend/src/main/java/io/metersphere/service/TestPlanService.java b/backend/src/main/java/io/metersphere/service/TestPlanService.java new file mode 100644 index 0000000000..c9a9380829 --- /dev/null +++ b/backend/src/main/java/io/metersphere/service/TestPlanService.java @@ -0,0 +1,57 @@ +package io.metersphere.service; + + +import io.metersphere.base.domain.*; +import io.metersphere.base.mapper.TestCaseMapper; +import io.metersphere.base.mapper.TestPlanMapper; +import io.metersphere.base.mapper.ext.ExtTestPlanMapper; +import io.metersphere.commons.constants.TestPlanStatus; +import io.metersphere.controller.request.testcase.QueryTestCaseRequest; +import io.metersphere.controller.request.testcase.QueryTestPlanRequest; +import io.metersphere.dto.TestPlanDTO; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.UUID; + +@Service +@Transactional(rollbackFor = Exception.class) +public class TestPlanService { + + @Resource + TestPlanMapper testPlanMapper; + + @Resource + ExtTestPlanMapper extTestPlanMapper; + + public void addTestPlan(TestPlan testPlan) { + testPlan.setId(UUID.randomUUID().toString()); + testPlan.setStatus(TestPlanStatus.Prepare.name()); + testPlan.setCreateTime(System.currentTimeMillis()); + testPlan.setUpdateTime(System.currentTimeMillis()); + testPlanMapper.insert(testPlan); + } + + + public List getTestPlan(String testPlanId) { + TestPlanExample testPlanExample = new TestPlanExample(); + testPlanExample.createCriteria().andIdEqualTo(testPlanId); + return testPlanMapper.selectByExampleWithBLOBs(testPlanExample); + } + + public int editTestPlan(TestPlan testPlan) { + testPlan.setUpdateTime(System.currentTimeMillis()); + return testPlanMapper.updateByPrimaryKeySelective(testPlan); + } + + public int deleteTestPlan(String testPalnId) { + return testPlanMapper.deleteByPrimaryKey(testPalnId); + } + + public List listTestPlan(QueryTestPlanRequest request) { + return extTestPlanMapper.list(request); + } +} diff --git a/backend/src/main/resources/db/migration/V2__metersphere_ddl.sql b/backend/src/main/resources/db/migration/V2__metersphere_ddl.sql index e9b0fb7619..1f8a24766d 100644 --- a/backend/src/main/resources/db/migration/V2__metersphere_ddl.sql +++ b/backend/src/main/resources/db/migration/V2__metersphere_ddl.sql @@ -224,22 +224,23 @@ CREATE TABLE IF NOT EXISTS `fuc_test_report` ( -- funcional end - -- track start CREATE TABLE IF NOT EXISTS `test_plan` ( `id` varchar(50) NOT NULL COMMENT 'Test Plan ID', `project_id` varchar(50) NOT NULL COMMENT 'Project ID this plan belongs to', + `workspace_id` varchar(50) NOT NULL COMMENT 'Workspace ID this plan belongs to', `name` varchar(64) NOT NULL COMMENT 'Plan name', `description` varchar(255) DEFAULT NULL COMMENT 'Plan description', `status` varchar(20) NOT NULL COMMENT 'Plan status', + `stage` varchar(30) NOT NULL COMMENT 'Plan stage', + `principal` varchar(50) NOT NULL COMMENT 'Plan principal', `test_case_match_rule` varchar(255) DEFAULT NULL COMMENT 'Test case match rule', `executor_match_rule` varchar(255) DEFAULT NULL COMMENT 'Executor match rule)', `tags` text COMMENT 'Test plan tags (JSON format)', `create_time` bigint(13) NOT NULL COMMENT 'Create timestamp', - `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp', - PRIMARY KEY (`id`), - FOREIGN KEY (`project_id`) references project(`id`) + `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp' + PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 @@ -253,9 +254,7 @@ CREATE TABLE IF NOT EXISTS `test_case_node` ( `p_id` int(13) DEFAULT NULL COMMENT 'Parent node ID', `level` int(10) DEFAULT 1 COMMENT 'Node level', `create_time` bigint(13) NOT NULL COMMENT 'Create timestamp', - `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp', - FOREIGN KEY (`p_id`) references test_case_node(`id`) ON DELETE CASCADE, - FOREIGN KEY (`project_id`) references project(`id`) + `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp' ) AUTO_INCREMENT = 1 ENGINE = InnoDB @@ -276,10 +275,8 @@ CREATE TABLE IF NOT EXISTS `test_case` ( `remark` text DEFAULT NULL COMMENT 'Test case remark', `steps` text DEFAULT NULL COMMENT 'Test case steps (JSON format)', `create_time` bigint(13) NOT NULL COMMENT 'Create timestamp', - `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp', + `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp' PRIMARY KEY (`id`), - FOREIGN KEY (`project_id`) references project(`id`), - FOREIGN KEY (`node_id`) references test_case_node(`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 @@ -295,9 +292,7 @@ CREATE TABLE IF NOT EXISTS `test_plan_test_case` ( `results` longtext COMMENT 'Test case result', `remark` varchar(255) DEFAULT NULL COMMENT 'Test case remark', `create_time` bigint(13) NOT NULL COMMENT 'Create timestamp', - `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp', - FOREIGN KEY (`plan_id`) references test_plan(`id`), - FOREIGN KEY (`case_id`) references test_case(`id`) + `update_time` bigint(13) NOT NULL COMMENT 'Update timestamp' ) AUTO_INCREMENT = 1 ENGINE = InnoDB diff --git a/frontend/src/business/components/performance/report/components/RequestStatistics.vue b/frontend/src/business/components/performance/report/components/RequestStatistics.vue index 25103858dd..ba05dbbe5a 100644 --- a/frontend/src/business/components/performance/report/components/RequestStatistics.vue +++ b/frontend/src/business/components/performance/report/components/RequestStatistics.vue @@ -58,11 +58,11 @@ /> - - - - - + @@ -110,10 +110,10 @@ getCaseByNodeIds(data) { this.$refs.testCaseList.initTableData(data); }, - opentestCaseEditDialog(data) { + openTestCaseEditDialog(data) { this.setNodePathOption(this.$refs.nodeTree.treeNodes); this.setMaintainerOptions(); - this.$refs.testCaseEditDialog.opentestCaseEditDialog(data); + this.$refs.testCaseEditDialog.openTestCaseEditDialog(data); }, setNodePathOption(nodes) { let moduleOptions = []; diff --git a/frontend/src/business/components/track/case/components/TestCaseEdit.vue b/frontend/src/business/components/track/case/components/TestCaseEdit.vue index a8f765ad1e..573e44f552 100644 --- a/frontend/src/business/components/track/case/components/TestCaseEdit.vue +++ b/frontend/src/business/components/track/case/components/TestCaseEdit.vue @@ -181,7 +181,7 @@ diff --git a/frontend/src/business/components/track/plan/components/TestPlanEdit.vue b/frontend/src/business/components/track/plan/components/TestPlanEdit.vue new file mode 100644 index 0000000000..02c3f9bc45 --- /dev/null +++ b/frontend/src/business/components/track/plan/components/TestPlanEdit.vue @@ -0,0 +1,195 @@ + + + + + diff --git a/frontend/src/business/components/track/plan/components/TestPlanList.vue b/frontend/src/business/components/track/plan/components/TestPlanList.vue new file mode 100644 index 0000000000..34a82df17d --- /dev/null +++ b/frontend/src/business/components/track/plan/components/TestPlanList.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index d562bcbe60..a2721f7592 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -176,7 +176,6 @@ export default { 'case_list': 'Test Case List', 'create_case': 'Create Case', 'test_plan': 'Test Plan', - 'create_plan': 'Create Plan', 'no_project': 'There is no project in this workspace, please create the project first', 'priority': 'Priority', 'type': 'Type', @@ -205,7 +204,24 @@ export default { 'rename': 'rename', 'add_submodule': 'Add submodule', 'add_module': 'Add module', - 'module_name': 'Module name' + 'module_name': 'Module name', + 'create_plan': 'Create test plan', + 'plan_name': 'Test plan name', + 'plan_project': 'Related projects', + 'plan_stage': 'Testing phase', + 'plan_status': 'The current state', + 'smoke_test': 'Smoke test', + 'functional_test': 'Functional test', + 'integration_testing': 'Integration testing', + 'system_test': 'System test', + 'version_validation': 'Version validation', + 'plan_principal': 'principal', + 'input_plan_principal': 'Please select principal', + 'input_plan_project': 'Please select project', + 'input_plan_stage': 'Please select stage', + 'plan_status_prepare': ' Not started', + 'plan_status_running': 'Starting', + 'plan_status_completed': 'Completed', }, i18n: { 'home': 'Home' diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index cf4e22a395..2fe3753d3d 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -176,7 +176,6 @@ export default { 'case_list': '用例列表', 'create_case': '创建用例', 'test_plan': '测试计划', - 'create_plan': '创建计划', 'no_project': '该工作空间下无项目,请先创建项目', 'priority': '优先级', 'type': '类型', @@ -205,7 +204,25 @@ export default { 'rename': '重命名', 'add_submodule': '添加子模块', 'add_module': '添加模块', - 'module_name': '模块名称' + 'module_name': '模块名称', + + 'create_plan': '新建测试计划', + 'plan_name': '计划名称', + 'plan_project': '所属项目', + 'plan_stage': '测试阶段', + 'plan_status': '当前状态', + 'smoke_test': '冒烟测试', + 'functional_test': '功能测试', + 'integration_testing': '集成测试', + 'system_test': '系统测试', + 'version_validation': '版本验证', + 'plan_principal': '负责人', + 'input_plan_principal': '请选择负责人', + 'input_plan_project': '请选择所属项目', + 'input_plan_stage': '请选择测试阶段', + 'plan_status_prepare': '未开始', + 'plan_status_running': '进行中', + 'plan_status_completed': '已完成' }, i18n: { 'home': '首页'