Merge remote-tracking branch 'origin/master' into master
This commit is contained in:
commit
2183154d4d
|
@ -9,6 +9,7 @@ public class AssertionType {
|
||||||
public final static String JSON_PATH = "JSONPath";
|
public final static String JSON_PATH = "JSONPath";
|
||||||
public final static String JSR223 = "JSR223";
|
public final static String JSR223 = "JSR223";
|
||||||
public final static String TEXT = "Text";
|
public final static String TEXT = "Text";
|
||||||
|
public final static String XPATH2 = "XPath2";
|
||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package io.metersphere.api.dto.scenario.assertions;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class AssertionXPath2 extends AssertionType {
|
||||||
|
private String expression;
|
||||||
|
public AssertionXPath2() {
|
||||||
|
setType(AssertionType.XPATH2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,5 +9,6 @@ public class Assertions {
|
||||||
private List<AssertionRegex> regex;
|
private List<AssertionRegex> regex;
|
||||||
private List<AssertionJsonPath> jsonPath;
|
private List<AssertionJsonPath> jsonPath;
|
||||||
private List<AssertionJSR223> jsr223;
|
private List<AssertionJSR223> jsr223;
|
||||||
|
private List<AssertionXPath2> xpath2;
|
||||||
private AssertionDuration duration;
|
private AssertionDuration duration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,9 +305,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
private ResponseAssertionResult getResponseAssertionResult(AssertionResult assertionResult) {
|
private ResponseAssertionResult getResponseAssertionResult(AssertionResult assertionResult) {
|
||||||
ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult();
|
ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult();
|
||||||
responseAssertionResult.setMessage(assertionResult.getFailureMessage());
|
|
||||||
responseAssertionResult.setName(assertionResult.getName());
|
responseAssertionResult.setName(assertionResult.getName());
|
||||||
responseAssertionResult.setPass(!assertionResult.isFailure() && !assertionResult.isError());
|
responseAssertionResult.setPass(!assertionResult.isFailure() && !assertionResult.isError());
|
||||||
|
if (!responseAssertionResult.isPass()) {
|
||||||
|
responseAssertionResult.setMessage(assertionResult.getFailureMessage());
|
||||||
|
}
|
||||||
return responseAssertionResult;
|
return responseAssertionResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import org.apache.ibatis.annotations.Param;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ExtTestPlanMapper {
|
public interface ExtTestPlanMapper {
|
||||||
List<TestPlanDTO> list(@Param("request") QueryTestPlanRequest params);
|
List<TestPlanDTOWithMetric> list(@Param("request") QueryTestPlanRequest params);
|
||||||
|
|
||||||
List<TestPlanDTOWithMetric> listRelate(@Param("request") QueryTestPlanRequest params);
|
List<TestPlanDTOWithMetric> listRelate(@Param("request") QueryTestPlanRequest params);
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
</if>
|
</if>
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="list" resultMap="BaseResultMap"
|
<select id="list" resultType="io.metersphere.track.dto.TestPlanDTOWithMetric"
|
||||||
parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
|
parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
|
||||||
select DISTINCT test_plan.*, user.name as user_name from test_plan
|
select DISTINCT test_plan.*, user.name as user_name from test_plan
|
||||||
LEFT JOIN user ON user.id = test_plan.principal
|
LEFT JOIN user ON user.id = test_plan.principal
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package io.metersphere.notice.service;
|
package io.metersphere.notice.service;
|
||||||
|
|
||||||
import io.metersphere.base.domain.ApiTestReport;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
|
import io.metersphere.base.mapper.UserMapper;
|
||||||
import io.metersphere.base.domain.SystemParameter;
|
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
|
||||||
import io.metersphere.commons.constants.APITestStatus;
|
import io.metersphere.commons.constants.APITestStatus;
|
||||||
import io.metersphere.commons.constants.NoticeConstants;
|
import io.metersphere.commons.constants.NoticeConstants;
|
||||||
import io.metersphere.commons.constants.ParamConstants;
|
import io.metersphere.commons.constants.ParamConstants;
|
||||||
|
@ -46,6 +44,8 @@ public class MailService {
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
@Resource
|
@Resource
|
||||||
private SystemParameterService systemParameterService;
|
private SystemParameterService systemParameterService;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
//接口和性能测试
|
//接口和性能测试
|
||||||
public void sendLoadNotification(MessageDetail messageDetail, LoadTestReportWithBLOBs loadTestReport, String eventType) {
|
public void sendLoadNotification(MessageDetail messageDetail, LoadTestReportWithBLOBs loadTestReport, String eventType) {
|
||||||
|
@ -297,7 +297,8 @@ public class MailService {
|
||||||
Map<String, String> context = new HashMap<>();
|
Map<String, String> context = new HashMap<>();
|
||||||
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
|
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
|
||||||
context.put("url", baseSystemConfigDTO.getUrl());
|
context.put("url", baseSystemConfigDTO.getUrl());
|
||||||
context.put("creator", reviewRequest.getCreator());
|
User user = userMapper.selectByPrimaryKey(reviewRequest.getCreator());
|
||||||
|
context.put("creator", user.getName());
|
||||||
context.put("reviewName", reviewRequest.getName());
|
context.put("reviewName", reviewRequest.getName());
|
||||||
context.put("start", start);
|
context.put("start", start);
|
||||||
context.put("end", end);
|
context.put("end", end);
|
||||||
|
@ -328,6 +329,8 @@ public class MailService {
|
||||||
context.put("start", start);
|
context.put("start", start);
|
||||||
context.put("end", end);
|
context.put("end", end);
|
||||||
context.put("id", testPlan.getId());
|
context.put("id", testPlan.getId());
|
||||||
|
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
|
||||||
|
context.put("creator", user.getName());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,7 +229,6 @@ public class PerformanceTestService {
|
||||||
startEngine(loadTest, engine, request.getTriggerMode());
|
startEngine(loadTest, engine, request.getTriggerMode());
|
||||||
|
|
||||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(engine.getReportId());
|
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(engine.getReportId());
|
||||||
loadTestReport.setTriggerMode("API");
|
|
||||||
if (StringUtils.equals(NoticeConstants.API, loadTestReport.getTriggerMode()) || StringUtils.equals(NoticeConstants.SCHEDULE, loadTestReport.getTriggerMode())) {
|
if (StringUtils.equals(NoticeConstants.API, loadTestReport.getTriggerMode()) || StringUtils.equals(NoticeConstants.SCHEDULE, loadTestReport.getTriggerMode())) {
|
||||||
performanceNoticeTask.registerNoticeTask(loadTestReport);
|
performanceNoticeTask.registerNoticeTask(loadTestReport);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import io.metersphere.base.mapper.ext.*;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.dto.LoadTestDTO;
|
import io.metersphere.dto.LoadTestDTO;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.track.dto.TestPlanDTO;
|
import io.metersphere.track.dto.TestPlanDTOWithMetric;
|
||||||
import io.metersphere.track.request.testplan.QueryTestPlanRequest;
|
import io.metersphere.track.request.testplan.QueryTestPlanRequest;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -81,7 +81,7 @@ public class CheckOwnerService {
|
||||||
io.metersphere.track.request.testcase.QueryTestPlanRequest request = new io.metersphere.track.request.testcase.QueryTestPlanRequest();
|
io.metersphere.track.request.testcase.QueryTestPlanRequest request = new io.metersphere.track.request.testcase.QueryTestPlanRequest();
|
||||||
request.setWorkspaceId(workspaceId);
|
request.setWorkspaceId(workspaceId);
|
||||||
request.setId(planId);
|
request.setId(planId);
|
||||||
List<TestPlanDTO> list = extTestPlanMapper.list(request);
|
List<TestPlanDTOWithMetric> list = extTestPlanMapper.list(request);
|
||||||
if (CollectionUtils.size(list) != 1) {
|
if (CollectionUtils.size(list) != 1) {
|
||||||
throw new UnauthorizedException(Translator.get("check_owner_plan"));
|
throw new UnauthorizedException(Translator.get("check_owner_plan"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class TestPlanController {
|
||||||
CheckOwnerService checkOwnerService;
|
CheckOwnerService checkOwnerService;
|
||||||
|
|
||||||
@PostMapping("/list/{goPage}/{pageSize}")
|
@PostMapping("/list/{goPage}/{pageSize}")
|
||||||
public Pager<List<TestPlanDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) {
|
public Pager<List<TestPlanDTOWithMetric>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestPlanRequest request) {
|
||||||
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
||||||
request.setWorkspaceId(currentWorkspaceId);
|
request.setWorkspaceId(currentWorkspaceId);
|
||||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||||
|
|
|
@ -561,7 +561,9 @@ public class TestCaseReviewService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*编辑,新建,完成,删除通知内容*/
|
/*编辑,新建,完成,删除通知内容*/
|
||||||
private static String getReviewContext(SaveTestCaseReviewRequest reviewRequest, String type) {
|
private String getReviewContext(SaveTestCaseReviewRequest reviewRequest, String type) {
|
||||||
|
|
||||||
|
User user = userMapper.selectByPrimaryKey(reviewRequest.getCreator());
|
||||||
Long startTime = reviewRequest.getCreateTime();
|
Long startTime = reviewRequest.getCreateTime();
|
||||||
Long endTime = reviewRequest.getEndTime();
|
Long endTime = reviewRequest.getEndTime();
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
@ -577,11 +579,11 @@ public class TestCaseReviewService {
|
||||||
}
|
}
|
||||||
String context = "";
|
String context = "";
|
||||||
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
||||||
context = "测试评审任务通知:" + reviewRequest.getCreator() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
||||||
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
||||||
context = "测试评审任务通知:" + reviewRequest.getCreator() + "发起的" + "'" + reviewRequest.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
||||||
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
||||||
context = "测试评审任务通知:" + reviewRequest.getCreator() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
context = "测试评审任务通知:" + user.getName() + "发起的" + "'" + reviewRequest.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -457,7 +457,7 @@ public class TestCaseService {
|
||||||
if (t.getMethod().equals("manual")) {
|
if (t.getMethod().equals("manual")) {
|
||||||
String steps = t.getSteps();
|
String steps = t.getSteps();
|
||||||
String setp = "";
|
String setp = "";
|
||||||
if (steps.contains("null")) {
|
if (steps.contains("null") && !steps.contains("\"null\"")) {
|
||||||
setp = steps.replace("null", "\"\"");
|
setp = steps.replace("null", "\"\"");
|
||||||
} else {
|
} else {
|
||||||
setp = steps;
|
setp = steps;
|
||||||
|
|
|
@ -93,6 +93,8 @@ public class TestPlanService {
|
||||||
DingTaskService dingTaskService;
|
DingTaskService dingTaskService;
|
||||||
@Resource
|
@Resource
|
||||||
WxChatTaskService wxChatTaskService;
|
WxChatTaskService wxChatTaskService;
|
||||||
|
@Resource
|
||||||
|
UserMapper userMapper;
|
||||||
|
|
||||||
public void addTestPlan(AddTestPlanRequest testPlan) {
|
public void addTestPlan(AddTestPlanRequest testPlan) {
|
||||||
if (getTestPlanByName(testPlan.getName()).size() > 0) {
|
if (getTestPlanByName(testPlan.getName()).size() > 0) {
|
||||||
|
@ -279,9 +281,46 @@ public class TestPlanService {
|
||||||
testPlanTestCaseMapper.deleteByExample(testPlanTestCaseExample);
|
testPlanTestCaseMapper.deleteByExample(testPlanTestCaseExample);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestPlanDTO> listTestPlan(QueryTestPlanRequest request) {
|
private void calcTestPlanRate(List<TestPlanDTOWithMetric> testPlans) {
|
||||||
|
List<String> projectIds = extProjectMapper.getProjectIdByWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||||
|
Map<String, List<TestPlanCaseDTO>> testCaseMap = new HashMap<>();
|
||||||
|
listTestCaseByProjectIds(projectIds).forEach(testCase -> {
|
||||||
|
List<TestPlanCaseDTO> list = testCaseMap.get(testCase.getPlanId());
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<>();
|
||||||
|
list.add(testCase);
|
||||||
|
testCaseMap.put(testCase.getPlanId(), list);
|
||||||
|
} else {
|
||||||
|
list.add(testCase);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testPlans.forEach(testPlan -> {
|
||||||
|
List<TestPlanCaseDTO> testCases = testCaseMap.get(testPlan.getId());
|
||||||
|
testPlan.setTested(0);
|
||||||
|
testPlan.setPassed(0);
|
||||||
|
testPlan.setTotal(0);
|
||||||
|
if (testCases != null) {
|
||||||
|
testPlan.setTotal(testCases.size());
|
||||||
|
testCases.forEach(testCase -> {
|
||||||
|
if (!StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Prepare.name())
|
||||||
|
&& !StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Underway.name())) {
|
||||||
|
testPlan.setTested(testPlan.getTested() + 1);
|
||||||
|
if (StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Pass.name())) {
|
||||||
|
testPlan.setPassed(testPlan.getPassed() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
testPlan.setPassRate(MathUtils.getPercentWithDecimal(testPlan.getTested() == 0 ? 0 : testPlan.getPassed() * 1.0 / testPlan.getTested()));
|
||||||
|
testPlan.setTestRate(MathUtils.getPercentWithDecimal(testPlan.getTotal() == 0 ? 0 : testPlan.getTested() * 1.0 / testPlan.getTotal()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TestPlanDTOWithMetric> listTestPlan(QueryTestPlanRequest request) {
|
||||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||||
return extTestPlanMapper.list(request);
|
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.list(request);
|
||||||
|
calcTestPlanRate(testPlans);
|
||||||
|
return testPlans;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestPlanDTO> listTestPlanByProject(QueryTestPlanRequest request) {
|
public List<TestPlanDTO> listTestPlanByProject(QueryTestPlanRequest request) {
|
||||||
|
@ -359,49 +398,12 @@ public class TestPlanService {
|
||||||
|
|
||||||
public List<TestPlanDTOWithMetric> listRelateAllPlan() {
|
public List<TestPlanDTOWithMetric> listRelateAllPlan() {
|
||||||
SessionUser user = SessionUtils.getUser();
|
SessionUser user = SessionUtils.getUser();
|
||||||
|
|
||||||
QueryTestPlanRequest request = new QueryTestPlanRequest();
|
QueryTestPlanRequest request = new QueryTestPlanRequest();
|
||||||
request.setPrincipal(user.getId());
|
request.setPrincipal(user.getId());
|
||||||
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||||
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
|
request.setPlanIds(extTestPlanTestCaseMapper.findRelateTestPlanId(user.getId(), SessionUtils.getCurrentWorkspaceId()));
|
||||||
|
|
||||||
List<String> projectIds = extProjectMapper.getProjectIdByWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
|
||||||
|
|
||||||
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.listRelate(request);
|
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.listRelate(request);
|
||||||
|
calcTestPlanRate(testPlans);
|
||||||
Map<String, List<TestPlanCaseDTO>> testCaseMap = new HashMap<>();
|
|
||||||
listTestCaseByProjectIds(projectIds).forEach(testCase -> {
|
|
||||||
List<TestPlanCaseDTO> list = testCaseMap.get(testCase.getPlanId());
|
|
||||||
if (list == null) {
|
|
||||||
list = new ArrayList<>();
|
|
||||||
list.add(testCase);
|
|
||||||
testCaseMap.put(testCase.getPlanId(), list);
|
|
||||||
} else {
|
|
||||||
list.add(testCase);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
testPlans.forEach(testPlan -> {
|
|
||||||
List<TestPlanCaseDTO> testCases = testCaseMap.get(testPlan.getId());
|
|
||||||
testPlan.setTested(0);
|
|
||||||
testPlan.setPassed(0);
|
|
||||||
testPlan.setTotal(0);
|
|
||||||
if (testCases != null) {
|
|
||||||
testPlan.setTotal(testCases.size());
|
|
||||||
testCases.forEach(testCase -> {
|
|
||||||
if (!StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Prepare.name())
|
|
||||||
&& !StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Underway.name())) {
|
|
||||||
testPlan.setTested(testPlan.getTested() + 1);
|
|
||||||
if (StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Pass.name())) {
|
|
||||||
testPlan.setPassed(testPlan.getPassed() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
testPlan.setPassRate(MathUtils.getPercentWithDecimal(testPlan.getTested() == 0 ? 0 : testPlan.getPassed() * 1.0 / testPlan.getTested()));
|
|
||||||
testPlan.setTestRate(MathUtils.getPercentWithDecimal(testPlan.getTotal() == 0 ? 0 : testPlan.getTested() * 1.0 / testPlan.getTotal()));
|
|
||||||
});
|
|
||||||
|
|
||||||
return testPlans;
|
return testPlans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,13 +530,14 @@ public class TestPlanService {
|
||||||
for (Project project : projects) {
|
for (Project project : projects) {
|
||||||
stringBuilder.append(project.getName()).append("、");
|
stringBuilder.append(project.getName()).append("、");
|
||||||
}
|
}
|
||||||
projectName = stringBuilder.toString().substring(0, stringBuilder.length() - 1);
|
projectName = stringBuilder.substring(0, stringBuilder.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectName;
|
return projectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getTestPlanContext(AddTestPlanRequest testPlan, String type) {
|
private String getTestPlanContext(AddTestPlanRequest testPlan, String type) {
|
||||||
|
User user = userMapper.selectByPrimaryKey(testPlan.getCreator());
|
||||||
Long startTime = testPlan.getPlannedStartTime();
|
Long startTime = testPlan.getPlannedStartTime();
|
||||||
Long endTime = testPlan.getPlannedEndTime();
|
Long endTime = testPlan.getPlannedEndTime();
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
@ -554,11 +557,11 @@ public class TestPlanService {
|
||||||
}
|
}
|
||||||
String context = "";
|
String context = "";
|
||||||
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
if (StringUtils.equals(NoticeConstants.CREATE, type)) {
|
||||||
context = "测试计划任务通知:" + testPlan.getCreator() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
|
||||||
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
} else if (StringUtils.equals(NoticeConstants.UPDATE, type)) {
|
||||||
context = "测试计划任务通知:" + testPlan.getCreator() + "创建的" + "'" + testPlan.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
|
||||||
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
} else if (StringUtils.equals(NoticeConstants.DELETE, type)) {
|
||||||
context = "测试计划任务通知:" + testPlan.getCreator() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
context = "测试计划任务通知:" + user.getName() + "创建的" + "'" + testPlan.getName() + "'" + "计划开始时间是" + start + "计划结束时间为" + end + "已删除";
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
|
||||||
|
<el-col>
|
||||||
|
<el-input :disabled="isReadOnly" v-model="xPath2.expression" maxlength="200" size="small" show-word-limit
|
||||||
|
:placeholder="$t('api_test.request.extract.xpath_expression')"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col class="assertion-btn">
|
||||||
|
<el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove" v-if="edit"/>
|
||||||
|
<el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>
|
||||||
|
{{ $t('api_test.request.assertions.add') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {XPath2} from "../../model/ScenarioModel";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertionXPath2",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
xPath2: {
|
||||||
|
type: XPath2,
|
||||||
|
default: () => {
|
||||||
|
return new XPath2();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
index: Number,
|
||||||
|
list: Array,
|
||||||
|
callback: Function,
|
||||||
|
isReadOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.list.push(this.getXPath2());
|
||||||
|
this.callback();
|
||||||
|
},
|
||||||
|
remove: function () {
|
||||||
|
this.list.splice(this.index, 1);
|
||||||
|
},
|
||||||
|
getXPath2() {
|
||||||
|
return new XPath2(this.xPath2);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-select {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assertion-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assertion-btn {
|
||||||
|
text-align: center;
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,6 +8,7 @@
|
||||||
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
|
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
|
||||||
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
|
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
|
||||||
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
|
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
|
||||||
|
<el-option :label="'XPath'" :value="options.XPATH2"/>
|
||||||
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
|
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
|
||||||
<el-option :label="$t('api_test.request.assertions.jsr223')" :value="options.JSR223"/>
|
<el-option :label="$t('api_test.request.assertions.jsr223')" :value="options.JSR223"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT" :callback="after"/>
|
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT" :callback="after"/>
|
||||||
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX" :callback="after"/>
|
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX" :callback="after"/>
|
||||||
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :callback="after"/>
|
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :callback="after"/>
|
||||||
|
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2" :callback="after"/>
|
||||||
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
|
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
|
||||||
v-if="type === options.DURATION" :callback="after"/>
|
v-if="type === options.DURATION" :callback="after"/>
|
||||||
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223" :callback="after"/>
|
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223" :callback="after"/>
|
||||||
|
@ -52,11 +54,13 @@
|
||||||
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
|
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
|
||||||
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
|
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
|
||||||
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
|
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
|
||||||
|
import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiAssertions",
|
name: "MsApiAssertions",
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
MsApiAssertionXPath2,
|
||||||
MsApiAssertionJsr223,
|
MsApiAssertionJsr223,
|
||||||
MsApiJsonpathSuggestList,
|
MsApiJsonpathSuggestList,
|
||||||
MsApiAssertionJsonPath,
|
MsApiAssertionJsonPath,
|
||||||
|
|
|
@ -20,6 +20,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="assertion-item-editing x_path" v-if="assertions.xpath2.length > 0">
|
||||||
|
<div>
|
||||||
|
{{ 'XPath' }}
|
||||||
|
</div>
|
||||||
|
<div class="regex-item" v-for="(xPath, index) in assertions.xpath2" :key="index">
|
||||||
|
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2"
|
||||||
|
:x-path2="xPath" :edit="true" :index="index"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="assertion-item-editing jsr223" v-if="assertions.jsr223.length > 0">
|
<div class="assertion-item-editing jsr223" v-if="assertions.jsr223.length > 0">
|
||||||
<div>
|
<div>
|
||||||
{{ $t("api_test.request.assertions.script") }}
|
{{ $t("api_test.request.assertions.script") }}
|
||||||
|
@ -47,11 +57,14 @@ import MsApiAssertionDuration from "./ApiAssertionDuration";
|
||||||
import {Assertions} from "../../model/ScenarioModel";
|
import {Assertions} from "../../model/ScenarioModel";
|
||||||
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
|
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
|
||||||
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
|
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
|
||||||
|
import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiAssertionsEdit",
|
name: "MsApiAssertionsEdit",
|
||||||
|
|
||||||
components: {MsApiAssertionJsr223, MsApiAssertionJsonPath, MsApiAssertionDuration, MsApiAssertionRegex},
|
components: {
|
||||||
|
MsApiAssertionXPath2,
|
||||||
|
MsApiAssertionJsr223, MsApiAssertionJsonPath, MsApiAssertionDuration, MsApiAssertionRegex},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
assertions: Assertions,
|
assertions: Assertions,
|
||||||
|
@ -92,6 +105,10 @@ export default {
|
||||||
border-left: 2px solid #1FDD02;
|
border-left: 2px solid #1FDD02;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assertion-item-editing.x_path {
|
||||||
|
border-left: 2px solid #fca130;
|
||||||
|
}
|
||||||
|
|
||||||
.regex-item {
|
.regex-item {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -439,6 +439,16 @@ export class JSONPathAssertion extends DefaultTestElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class XPath2Assertion extends DefaultTestElement {
|
||||||
|
constructor(testName, xPath) {
|
||||||
|
super('XPath2Assertion', 'XPath2AssertionGui', 'XPath2Assertion', testName);
|
||||||
|
this.xPath = xPath || {};
|
||||||
|
this.stringProp('XPath.xpath', this.xPath.expression);
|
||||||
|
this.stringProp('XPath.namespace');
|
||||||
|
this.boolProp('XPath.negate', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ResponseCodeAssertion extends ResponseAssertion {
|
export class ResponseCodeAssertion extends ResponseAssertion {
|
||||||
constructor(testName, type, value, assumeSuccess, message) {
|
constructor(testName, type, value, assumeSuccess, message) {
|
||||||
let assertion = {
|
let assertion = {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {
|
||||||
ThreadGroup,
|
ThreadGroup,
|
||||||
XPath2Extractor,
|
XPath2Extractor,
|
||||||
IfController as JMXIfController,
|
IfController as JMXIfController,
|
||||||
ConstantTimer as JMXConstantTimer, TCPSampler, JSR223Assertion,
|
ConstantTimer as JMXConstantTimer, TCPSampler, JSR223Assertion, XPath2Assertion,
|
||||||
} from "./JMX";
|
} from "./JMX";
|
||||||
import Mock from "mockjs";
|
import Mock from "mockjs";
|
||||||
import {funcFilters} from "@/common/js/func-filter";
|
import {funcFilters} from "@/common/js/func-filter";
|
||||||
|
@ -96,6 +96,7 @@ export const ASSERTION_TYPE = {
|
||||||
JSON_PATH: "JSON",
|
JSON_PATH: "JSON",
|
||||||
DURATION: "Duration",
|
DURATION: "Duration",
|
||||||
JSR223: "JSR223",
|
JSR223: "JSR223",
|
||||||
|
XPATH2: "XPath2",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ASSERTION_REGEX_SUBJECT = {
|
export const ASSERTION_REGEX_SUBJECT = {
|
||||||
|
@ -741,10 +742,11 @@ export class Assertions extends BaseConfig {
|
||||||
this.regex = [];
|
this.regex = [];
|
||||||
this.jsonPath = [];
|
this.jsonPath = [];
|
||||||
this.jsr223 = [];
|
this.jsr223 = [];
|
||||||
|
this.xpath2 = [];
|
||||||
this.duration = undefined;
|
this.duration = undefined;
|
||||||
|
|
||||||
this.set(options);
|
this.set(options);
|
||||||
this.sets({text: Text, regex: Regex, jsonPath: JSONPath, jsr223: AssertionJSR223}, options);
|
this.sets({text: Text, regex: Regex, jsonPath: JSONPath, jsr223: AssertionJSR223, xpath2: XPath2}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
initOptions(options) {
|
initOptions(options) {
|
||||||
|
@ -826,6 +828,23 @@ export class JSONPath extends AssertionType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class XPath2 extends AssertionType {
|
||||||
|
constructor(options) {
|
||||||
|
super(ASSERTION_TYPE.XPATH2);
|
||||||
|
this.expression = undefined;
|
||||||
|
this.description = undefined;
|
||||||
|
this.set(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setJSONPathDescription() {
|
||||||
|
// this.description = this.expression + " expect: " + (this.expect ? this.expect : '');
|
||||||
|
// }
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return !!this.expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Duration extends AssertionType {
|
export class Duration extends AssertionType {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(ASSERTION_TYPE.DURATION);
|
super(ASSERTION_TYPE.DURATION);
|
||||||
|
@ -1001,7 +1020,8 @@ class JMXHttpRequest {
|
||||||
this.domain = environment.config.httpConfig.domain;
|
this.domain = environment.config.httpConfig.domain;
|
||||||
this.port = environment.config.httpConfig.port;
|
this.port = environment.config.httpConfig.port;
|
||||||
this.protocol = environment.config.httpConfig.protocol;
|
this.protocol = environment.config.httpConfig.protocol;
|
||||||
let envPath = environment.config.httpConfig.protocol + "://" + environment.config.httpConfig.socket;
|
let url = new URL(environment.config.httpConfig.protocol + "://" + environment.config.httpConfig.socket);
|
||||||
|
let envPath = url.pathname === '/' ? '' : url.pathname;
|
||||||
this.path = this.getPostQueryParameters(request, decodeURIComponent(envPath + (request.path ? request.path : '')));
|
this.path = this.getPostQueryParameters(request, decodeURIComponent(envPath + (request.path ? request.path : '')));
|
||||||
}
|
}
|
||||||
this.connectTimeout = request.connectTimeout;
|
this.connectTimeout = request.connectTimeout;
|
||||||
|
@ -1397,11 +1417,11 @@ class JMXGenerator {
|
||||||
body = this.filterKV(request.body.kvs);
|
body = this.filterKV(request.body.kvs);
|
||||||
this.addRequestBodyFile(httpSamplerProxy, request, testId);
|
this.addRequestBodyFile(httpSamplerProxy, request, testId);
|
||||||
} else {
|
} else {
|
||||||
httpSamplerProxy.boolProp('HTTPSampler.postBodyRaw', true);
|
|
||||||
body.push({name: '', value: request.body.raw, encode: false, enable: true});
|
body.push({name: '', value: request.body.raw, encode: false, enable: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method !== 'GET') {
|
if (request.method !== 'GET') {
|
||||||
|
httpSamplerProxy.boolProp('HTTPSampler.postBodyRaw', true);
|
||||||
httpSamplerProxy.add(new HTTPSamplerArguments(body));
|
httpSamplerProxy.add(new HTTPSamplerArguments(body));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1437,6 +1457,12 @@ class JMXGenerator {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (assertions.xpath2.length > 0) {
|
||||||
|
assertions.xpath2.filter(this.filter).forEach(item => {
|
||||||
|
httpSamplerProxy.put(this.getXpathAssertion(item));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (assertions.jsr223.length > 0) {
|
if (assertions.jsr223.length > 0) {
|
||||||
assertions.jsr223.filter(this.filter).forEach(item => {
|
assertions.jsr223.filter(this.filter).forEach(item => {
|
||||||
httpSamplerProxy.put(this.getJSR223Assertion(item));
|
httpSamplerProxy.put(this.getJSR223Assertion(item));
|
||||||
|
@ -1459,6 +1485,11 @@ class JMXGenerator {
|
||||||
return new JSR223Assertion(name, item);
|
return new JSR223Assertion(name, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getXpathAssertion(item) {
|
||||||
|
let name = item.expression;
|
||||||
|
return new XPath2Assertion(name, item);
|
||||||
|
}
|
||||||
|
|
||||||
getResponseAssertion(regex) {
|
getResponseAssertion(regex) {
|
||||||
let name = regex.description;
|
let name = regex.description;
|
||||||
let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match,自己写正则
|
let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match,自己写正则
|
||||||
|
|
|
@ -63,6 +63,15 @@
|
||||||
<plan-stage-table-item :stage="scope.row.stage"/>
|
<plan-stage-table-item :stage="scope.row.stage"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="projectName"
|
||||||
|
:label="$t('test_track.home.test_rate')"
|
||||||
|
min-width="100"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<el-progress :percentage="scope.row.testRate"></el-progress>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="projectName"
|
prop="projectName"
|
||||||
:label="$t('test_track.plan.plan_project')"
|
:label="$t('test_track.plan.plan_project')"
|
||||||
|
|
|
@ -286,12 +286,13 @@
|
||||||
},
|
},
|
||||||
getProject() {
|
getProject() {
|
||||||
if (this.planId) {
|
if (this.planId) {
|
||||||
this.$post("/test/plan/project/", {planId: this.planId}, res => {
|
this.result = this.$post("/test/plan/project/", {planId: this.planId}, res => {
|
||||||
let data = res.data;
|
let data = res.data;
|
||||||
if (data) {
|
if (data) {
|
||||||
this.projects = data;
|
this.projects = data;
|
||||||
this.projectId = data[0].id;
|
this.projectId = data[0].id;
|
||||||
this.projectName = data[0].name;
|
this.projectName = data[0].name;
|
||||||
|
this.search();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue