diff --git a/backend/src/main/java/io/metersphere/api/controller/APITestController.java b/backend/src/main/java/io/metersphere/api/controller/APITestController.java index ce4a70f857..5cedaab099 100644 --- a/backend/src/main/java/io/metersphere/api/controller/APITestController.java +++ b/backend/src/main/java/io/metersphere/api/controller/APITestController.java @@ -20,6 +20,7 @@ import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.ScheduleDao; import io.metersphere.performance.service.PerformanceTestService; import io.metersphere.service.CheckPermissionService; @@ -104,7 +105,7 @@ public class APITestController { } @PostMapping(value = "/schedule/create") - public void createSchedule(@RequestBody Schedule request) { + public void createSchedule(@RequestBody ScheduleRequest request) { apiTestService.createSchedule(request); } diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index 586e45523a..2ceaf9f5b3 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -16,6 +16,7 @@ import io.metersphere.commons.constants.RoleConstants; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testplan.FileOperationRequest; import org.apache.shiro.authz.annotation.Logical; @@ -149,7 +150,7 @@ public class ApiAutomationController { } @PostMapping(value = "/schedule/create") - public void createSchedule(@RequestBody Schedule request) { + public void createSchedule(@RequestBody ScheduleRequest request) { apiAutomationService.createSchedule(request); } diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index c801121e83..11be08adc6 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -20,6 +20,7 @@ import io.metersphere.commons.utils.CronUtils; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.service.CheckPermissionService; import io.metersphere.service.ScheduleService; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; @@ -156,7 +157,7 @@ public class ApiDefinitionController { //定时任务创建 @PostMapping(value = "/schedule/create") - public void createSchedule(@RequestBody Schedule request) { + public void createSchedule(@RequestBody ScheduleRequest request) { apiDefinitionService.createSchedule(request); } @PostMapping(value = "/schedule/update") diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/assertions/MsAssertions.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/assertions/MsAssertions.java index 1a4de305d3..8197028c78 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/assertions/MsAssertions.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/assertions/MsAssertions.java @@ -63,7 +63,7 @@ public class MsAssertions extends MsTestElement { private ResponseAssertion responseAssertion(MsAssertionRegex assertionRegex) { ResponseAssertion assertion = new ResponseAssertion(); assertion.setEnabled(this.isEnable()); - assertion.setName(assertionRegex.getDescription()); + assertion.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : assertionRegex.getDescription()); assertion.setProperty(TestElement.TEST_CLASS, ResponseAssertion.class.getName()); assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("AssertionGui")); assertion.setAssumeSuccess(assertionRegex.isAssumeSuccess()); @@ -88,7 +88,7 @@ public class MsAssertions extends MsTestElement { private JSONPathAssertion jsonPathAssertion(MsAssertionJsonPath assertionJsonPath) { JSONPathAssertion assertion = new JSONPathAssertion(); assertion.setEnabled(this.isEnable()); - assertion.setName(StringUtils.isEmpty(assertionJsonPath.getDescription()) ? "JSONPathAssertion" : assertionJsonPath.getDescription()); + assertion.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "JSONPathAssertion"); assertion.setProperty(TestElement.TEST_CLASS, JSONPathAssertion.class.getName()); assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("JSONPathAssertionGui")); assertion.setJsonPath(assertionJsonPath.getExpression()); @@ -96,7 +96,7 @@ public class MsAssertions extends MsTestElement { assertion.setJsonValidationBool(true); assertion.setExpectNull(false); assertion.setInvert(false); - assertion.setProperty("ASS_OPTION",assertionJsonPath.getOption()); + assertion.setProperty("ASS_OPTION", assertionJsonPath.getOption()); if (StringUtils.isEmpty(assertionJsonPath.getOption()) || "REGEX".equals(assertionJsonPath.getOption())) { assertion.setIsRegex(true); } else { @@ -108,7 +108,7 @@ public class MsAssertions extends MsTestElement { private XPath2Assertion xPath2Assertion(MsAssertionXPath2 assertionXPath2) { XPath2Assertion assertion = new XPath2Assertion(); assertion.setEnabled(this.isEnable()); - assertion.setName(StringUtils.isEmpty(assertionXPath2.getExpression()) ? "XPath2Assertion" : assertionXPath2.getExpression()); + assertion.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "XPath2Assertion"); assertion.setProperty(TestElement.TEST_CLASS, XPath2Assertion.class.getName()); assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("XPath2AssertionGui")); assertion.setXPathString(assertionXPath2.getExpression()); @@ -119,7 +119,7 @@ public class MsAssertions extends MsTestElement { private DurationAssertion durationAssertion(MsAssertionDuration assertionDuration) { DurationAssertion assertion = new DurationAssertion(); assertion.setEnabled(this.isEnable()); - assertion.setName("Response In Time: " + assertionDuration.getValue()); + assertion.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "Response In Time: " + assertionDuration.getValue()); assertion.setProperty(TestElement.TEST_CLASS, DurationAssertion.class.getName()); assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DurationAssertionGui")); assertion.setAllowedDuration(assertionDuration.getValue()); @@ -129,7 +129,7 @@ public class MsAssertions extends MsTestElement { private JSR223Assertion jsr223Assertion(MsAssertionJSR223 assertionJSR223) { JSR223Assertion assertion = new JSR223Assertion(); assertion.setEnabled(this.isEnable()); - assertion.setName(StringUtils.isEmpty(assertionJSR223.getDesc()) ? "JSR223Assertion" : assertionJSR223.getDesc()); + assertion.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : "JSR223Assertion"); assertion.setProperty(TestElement.TEST_CLASS, JSR223Assertion.class.getName()); assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI")); assertion.setProperty("cacheKey", "true"); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/extract/MsExtract.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/extract/MsExtract.java index ab0336aa2a..45b6051347 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/extract/MsExtract.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/extract/MsExtract.java @@ -66,7 +66,7 @@ public class MsExtract extends MsTestElement { RegexExtractor extractor = new RegexExtractor(); extractor.setEnabled(this.isEnable()); - extractor.setName(extractRegex.getVariable() + " RegexExtractor"); + extractor.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : " RegexExtractor"); extractor.setProperty(TestElement.TEST_CLASS, RegexExtractor.class.getName()); extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("RegexExtractorGui")); extractor.setRefName(extractRegex.getVariable()); @@ -84,7 +84,7 @@ public class MsExtract extends MsTestElement { private XPath2Extractor xPath2Extractor(MsExtractXPath extractXPath, StringJoiner extract) { XPath2Extractor extractor = new XPath2Extractor(); extractor.setEnabled(this.isEnable()); - extractor.setName(extractXPath.getVariable() + " XPath2Extractor"); + extractor.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : " XPath2Extractor"); extractor.setProperty(TestElement.TEST_CLASS, XPath2Extractor.class.getName()); extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("XPath2ExtractorGui")); extractor.setRefName(extractXPath.getVariable()); @@ -99,7 +99,7 @@ public class MsExtract extends MsTestElement { private JSONPostProcessor jsonPostProcessor(MsExtractJSONPath extractJSONPath, StringJoiner extract) { JSONPostProcessor extractor = new JSONPostProcessor(); extractor.setEnabled(this.isEnable()); - extractor.setName(extractJSONPath.getVariable() + " JSONExtractor"); + extractor.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() : " JSONExtractor"); extractor.setProperty(TestElement.TEST_CLASS, JSONPostProcessor.class.getName()); extractor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("JSONPostProcessorGui")); extractor.setRefNames(extractJSONPath.getVariable()); diff --git a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java index 0a704845f9..b34067ab89 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java @@ -253,7 +253,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl String url2 = reportUrl; if (StringUtils.isEmpty(url)) { url = baseSystemConfigDTO.getUrl() + "/#/api/report/view/" + report.getId(); - url2 = baseSystemConfigDTO.getUrl() + "/#/api/automation/report"; + url2 = baseSystemConfigDTO.getUrl() + "/#/api/automation/report/view/" + report.getId(); } String successContext = ""; String failedContext = ""; diff --git a/backend/src/main/java/io/metersphere/api/service/APITestService.java b/backend/src/main/java/io/metersphere/api/service/APITestService.java index 102c3a2a80..e1534ac3ff 100644 --- a/backend/src/main/java/io/metersphere/api/service/APITestService.java +++ b/backend/src/main/java/io/metersphere/api/service/APITestService.java @@ -21,6 +21,7 @@ import io.metersphere.commons.constants.ScheduleType; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.ScheduleDao; import io.metersphere.i18n.Translator; import io.metersphere.job.sechedule.ApiTestJob; @@ -328,12 +329,12 @@ public class APITestService { addOrUpdateApiTestCronJob(request); } - public void createSchedule(Schedule request) { + public void createSchedule(ScheduleRequest request) { scheduleService.addSchedule(buildApiTestSchedule(request)); addOrUpdateApiTestCronJob(request); } - private Schedule buildApiTestSchedule(Schedule request) { + private Schedule buildApiTestSchedule(ScheduleRequest request) { Schedule schedule = scheduleService.buildApiTestSchedule(request); schedule.setJob(ApiTestJob.class.getName()); schedule.setGroup(ScheduleGroup.API_TEST.name()); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 4846a2b422..a620aef449 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -31,6 +31,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper; import io.metersphere.commons.constants.*; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.i18n.Translator; import io.metersphere.job.sechedule.ApiScenarioTestJob; import io.metersphere.job.sechedule.TestPlanTestJob; @@ -717,7 +718,7 @@ public class ApiAutomationService { return apiScenarioMapper.selectByExampleWithBLOBs(example); } - public void createSchedule(Schedule request) { + public void createSchedule(ScheduleRequest request) { Schedule schedule = scheduleService.buildApiTestSchedule(request); schedule.setJob(ApiScenarioTestJob.class.getName()); schedule.setGroup(ScheduleGroup.API_SCENARIO_TEST.name()); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index d580c154af..a73d6f1c6c 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -28,6 +28,7 @@ import io.metersphere.base.mapper.ext.*; import io.metersphere.commons.constants.*; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.i18n.Translator; import io.metersphere.job.sechedule.SwaggerUrlImportJob; import io.metersphere.service.FileService; @@ -197,7 +198,7 @@ public class ApiDefinitionService { .andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath()) .andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); - if (apiDefinitionMapper.countByExample(example) > 0 && (project.getRepeatable() == null || !project.getRepeatable())) { + if (apiDefinitionMapper.countByExample(example) > 0 && (project == null || project.getRepeatable() == null || !project.getRepeatable())) { MSException.throwException(Translator.get("api_definition_url_not_repeating")); } } else { @@ -702,7 +703,7 @@ public class ApiDefinitionService { } /*swagger定时导入*/ - public void createSchedule(Schedule request) { + public void createSchedule(ScheduleRequest request) { /*保存swaggerUrl*/ SwaggerUrlProject swaggerUrlProject = new SwaggerUrlProject(); swaggerUrlProject.setId(UUID.randomUUID().toString()); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java index a81b53f786..63bcec8ef0 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java @@ -126,8 +126,14 @@ public class ApiTestCaseService { if (!CollectionUtils.isEmpty(userIds)) { Map userMap = userService.queryNameByIds(userIds); apiTestCases.forEach(caseResult -> { - caseResult.setCreateUser(userMap.get(caseResult.getCreateUserId()).getName()); - caseResult.setUpdateUser(userMap.get(caseResult.getUpdateUserId()).getName()); + User createUser = userMap.get(caseResult.getCreateUserId()); + if (createUser != null) { + caseResult.setCreateUser(createUser.getName()); + } + User updateUser = userMap.get(caseResult.getUpdateUserId()); + if (updateUser != null) { + caseResult.setUpdateUser(updateUser.getName()); + } }); } } diff --git a/backend/src/main/java/io/metersphere/base/domain/Schedule.java b/backend/src/main/java/io/metersphere/base/domain/Schedule.java index 8033b6f759..c92c80d081 100644 --- a/backend/src/main/java/io/metersphere/base/domain/Schedule.java +++ b/backend/src/main/java/io/metersphere/base/domain/Schedule.java @@ -33,15 +33,4 @@ public class Schedule implements Serializable { private String customData; private static final long serialVersionUID = 1L; - - //定时任务来源: 测试计划/测试场景 - private String scheduleFrom; - - private String projectId; - - private String moduleId; - - private String modulePath; - - private String modeId; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/TestCase.java b/backend/src/main/java/io/metersphere/base/domain/TestCase.java index b57a8b7649..0ad81ca190 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestCase.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestCase.java @@ -46,5 +46,9 @@ public class TestCase implements Serializable { private String demandName; + private String followPeople; + + private String status; + private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/TestCaseExample.java b/backend/src/main/java/io/metersphere/base/domain/TestCaseExample.java index 2d88c502a7..96daffcbf2 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestCaseExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestCaseExample.java @@ -1463,6 +1463,146 @@ public class TestCaseExample { addCriterion("demand_name not between", value1, value2, "demandName"); return (Criteria) this; } + + public Criteria andFollowPeopleIsNull() { + addCriterion("follow_people is null"); + return (Criteria) this; + } + + public Criteria andFollowPeopleIsNotNull() { + addCriterion("follow_people is not null"); + return (Criteria) this; + } + + public Criteria andFollowPeopleEqualTo(String value) { + addCriterion("follow_people =", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleNotEqualTo(String value) { + addCriterion("follow_people <>", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleGreaterThan(String value) { + addCriterion("follow_people >", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleGreaterThanOrEqualTo(String value) { + addCriterion("follow_people >=", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleLessThan(String value) { + addCriterion("follow_people <", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleLessThanOrEqualTo(String value) { + addCriterion("follow_people <=", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleLike(String value) { + addCriterion("follow_people like", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleNotLike(String value) { + addCriterion("follow_people not like", value, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleIn(List values) { + addCriterion("follow_people in", values, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleNotIn(List values) { + addCriterion("follow_people not in", values, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleBetween(String value1, String value2) { + addCriterion("follow_people between", value1, value2, "followPeople"); + return (Criteria) this; + } + + public Criteria andFollowPeopleNotBetween(String value1, String value2) { + addCriterion("follow_people not between", value1, value2, "followPeople"); + return (Criteria) this; + } + + public Criteria andStatusIsNull() { + addCriterion("`status` is null"); + return (Criteria) this; + } + + public Criteria andStatusIsNotNull() { + addCriterion("`status` is not null"); + return (Criteria) this; + } + + public Criteria andStatusEqualTo(String value) { + addCriterion("`status` =", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotEqualTo(String value) { + addCriterion("`status` <>", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThan(String value) { + addCriterion("`status` >", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThanOrEqualTo(String value) { + addCriterion("`status` >=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThan(String value) { + addCriterion("`status` <", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThanOrEqualTo(String value) { + addCriterion("`status` <=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLike(String value) { + addCriterion("`status` like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotLike(String value) { + addCriterion("`status` not like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusIn(List values) { + addCriterion("`status` in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotIn(List values) { + addCriterion("`status` not in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusBetween(String value1, String value2) { + addCriterion("`status` between", value1, value2, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotBetween(String value1, String value2) { + addCriterion("`status` not between", value1, value2, "status"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/TestCaseMapper.xml index 3f738911f0..59d8833db3 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/TestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/TestCaseMapper.xml @@ -2,14 +2,14 @@ - - - - - - - - + + + + + + + + @@ -22,6 +22,8 @@ + + @@ -88,7 +90,7 @@ id, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`, prerequisite, create_time, update_time, test_id, sort, num, other_test_name, review_status, - tags, demand_id, demand_name + tags, demand_id, demand_name, follow_people, `status` remark, steps @@ -148,16 +150,16 @@ prerequisite, create_time, update_time, test_id, sort, num, other_test_name, review_status, tags, - demand_id, demand_name, remark, - steps) + demand_id, demand_name, follow_people, + `status`, remark, steps) values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{maintainer,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR}, #{prerequisite,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{testId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{num,jdbcType=INTEGER}, #{otherTestName,jdbcType=VARCHAR}, #{reviewStatus,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR}, - #{demandId,jdbcType=VARCHAR}, #{demandName,jdbcType=VARCHAR}, #{remark,jdbcType=LONGVARCHAR}, - #{steps,jdbcType=LONGVARCHAR}) + #{demandId,jdbcType=VARCHAR}, #{demandName,jdbcType=VARCHAR}, #{followPeople,jdbcType=VARCHAR}, + #{status,jdbcType=VARCHAR}, #{remark,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR}) insert into test_case @@ -222,6 +224,12 @@ demand_name, + + follow_people, + + + `status`, + remark, @@ -290,6 +298,12 @@ #{demandName,jdbcType=VARCHAR}, + + #{followPeople,jdbcType=VARCHAR}, + + + #{status,jdbcType=VARCHAR}, + #{remark,jdbcType=LONGVARCHAR}, @@ -367,6 +381,12 @@ demand_name = #{record.demandName,jdbcType=VARCHAR}, + + follow_people = #{record.followPeople,jdbcType=VARCHAR}, + + + `status` = #{record.status,jdbcType=VARCHAR}, + remark = #{record.remark,jdbcType=LONGVARCHAR}, @@ -381,40 +401,12 @@ update test_case set id = #{record.id,jdbcType=VARCHAR}, - node_id = #{record.nodeId,jdbcType=VARCHAR}, - node_path = #{record.nodePath,jdbcType=VARCHAR}, - project_id = #{record.projectId,jdbcType=VARCHAR}, - `name` = #{record.name,jdbcType=VARCHAR}, - `type` = #{record.type,jdbcType=VARCHAR}, - maintainer = #{record.maintainer,jdbcType=VARCHAR}, - priority = #{record.priority,jdbcType=VARCHAR}, - `method` = #{record.method,jdbcType=VARCHAR}, - prerequisite = #{record.prerequisite,jdbcType=VARCHAR}, - create_time = #{record.createTime,jdbcType=BIGINT}, - update_time = #{record.updateTime,jdbcType=BIGINT}, - test_id = #{record.testId,jdbcType=VARCHAR}, - sort = #{record.sort,jdbcType=INTEGER}, - num = #{record.num,jdbcType=INTEGER}, - other_test_name = #{record.otherTestName,jdbcType=VARCHAR}, - review_status = #{record.reviewStatus,jdbcType=VARCHAR}, - tags = #{record.tags,jdbcType=VARCHAR}, - demand_id = #{record.demandId,jdbcType=VARCHAR}, - demand_name = #{record.demandName,jdbcType=VARCHAR}, - remark = #{record.remark,jdbcType=LONGVARCHAR}, - steps = #{record.steps,jdbcType=LONGVARCHAR} - - - - - - update test_case - set id = #{record.id,jdbcType=VARCHAR}, - node_id = #{record.nodeId,jdbcType=VARCHAR}, - node_path = #{record.nodePath,jdbcType=VARCHAR}, - project_id = #{record.projectId,jdbcType=VARCHAR}, - `name` = #{record.name,jdbcType=VARCHAR}, - `type` = #{record.type,jdbcType=VARCHAR}, - maintainer = #{record.maintainer,jdbcType=VARCHAR}, + node_id = #{record.nodeId,jdbcType=VARCHAR}, + node_path = #{record.nodePath,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR}, + `name` = #{record.name,jdbcType=VARCHAR}, + `type` = #{record.type,jdbcType=VARCHAR}, + maintainer = #{record.maintainer,jdbcType=VARCHAR}, priority = #{record.priority,jdbcType=VARCHAR}, `method` = #{record.method,jdbcType=VARCHAR}, prerequisite = #{record.prerequisite,jdbcType=VARCHAR}, @@ -427,7 +419,39 @@ review_status = #{record.reviewStatus,jdbcType=VARCHAR}, tags = #{record.tags,jdbcType=VARCHAR}, demand_id = #{record.demandId,jdbcType=VARCHAR}, - demand_name = #{record.demandName,jdbcType=VARCHAR} + demand_name = #{record.demandName,jdbcType=VARCHAR}, + follow_people = #{record.followPeople,jdbcType=VARCHAR}, + `status` = #{record.status,jdbcType=VARCHAR}, + remark = #{record.remark,jdbcType=LONGVARCHAR}, + steps = #{record.steps,jdbcType=LONGVARCHAR} + + + + + + update test_case + set id = #{record.id,jdbcType=VARCHAR}, + node_id = #{record.nodeId,jdbcType=VARCHAR}, + node_path = #{record.nodePath,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR}, + `name` = #{record.name,jdbcType=VARCHAR}, + `type` = #{record.type,jdbcType=VARCHAR}, + maintainer = #{record.maintainer,jdbcType=VARCHAR}, + priority = #{record.priority,jdbcType=VARCHAR}, + `method` = #{record.method,jdbcType=VARCHAR}, + prerequisite = #{record.prerequisite,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT}, + update_time = #{record.updateTime,jdbcType=BIGINT}, + test_id = #{record.testId,jdbcType=VARCHAR}, + sort = #{record.sort,jdbcType=INTEGER}, + num = #{record.num,jdbcType=INTEGER}, + other_test_name = #{record.otherTestName,jdbcType=VARCHAR}, + review_status = #{record.reviewStatus,jdbcType=VARCHAR}, + tags = #{record.tags,jdbcType=VARCHAR}, + demand_id = #{record.demandId,jdbcType=VARCHAR}, + demand_name = #{record.demandName,jdbcType=VARCHAR}, + follow_people = #{record.followPeople,jdbcType=VARCHAR}, + `status` = #{record.status,jdbcType=VARCHAR} @@ -492,6 +516,12 @@ demand_name = #{demandName,jdbcType=VARCHAR}, + + follow_people = #{followPeople,jdbcType=VARCHAR}, + + + `status` = #{status,jdbcType=VARCHAR}, + remark = #{remark,jdbcType=LONGVARCHAR}, @@ -522,6 +552,8 @@ tags = #{tags,jdbcType=VARCHAR}, demand_id = #{demandId,jdbcType=VARCHAR}, demand_name = #{demandName,jdbcType=VARCHAR}, + follow_people = #{followPeople,jdbcType=VARCHAR}, + `status` = #{status,jdbcType=VARCHAR}, remark = #{remark,jdbcType=LONGVARCHAR}, steps = #{steps,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} @@ -546,7 +578,9 @@ review_status = #{reviewStatus,jdbcType=VARCHAR}, tags = #{tags,jdbcType=VARCHAR}, demand_id = #{demandId,jdbcType=VARCHAR}, - demand_name = #{demandName,jdbcType=VARCHAR} + demand_name = #{demandName,jdbcType=VARCHAR}, + follow_people = #{followPeople,jdbcType=VARCHAR}, + `status` = #{status,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/RsaKey.java b/backend/src/main/java/io/metersphere/commons/utils/RsaKey.java new file mode 100644 index 0000000000..9da3834c02 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/utils/RsaKey.java @@ -0,0 +1,16 @@ +package io.metersphere.commons.utils; + +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +public class RsaKey { + + //公钥 + private String publicKey; + + //私钥 + private String privateKey; + +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/RsaUtil.java b/backend/src/main/java/io/metersphere/commons/utils/RsaUtil.java new file mode 100644 index 0000000000..43de7ad70a --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/utils/RsaUtil.java @@ -0,0 +1,224 @@ +package io.metersphere.commons.utils; + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RsaUtil { + + public static final String CHARSET = "UTF-8"; + public static final String RSA_ALGORITHM = "RSA"; + + + /** + * 创建RSA 公钥-私钥 + */ + public static RsaKey createKeys() throws NoSuchAlgorithmException { + return createKeys(1024); + } + + /** + * 创建RSA 公钥-私钥 + */ + public static RsaKey createKeys(int keySize) throws NoSuchAlgorithmException { + //为RSA算法创建一个KeyPairGenerator对象 + KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); + + //初始化KeyPairGenerator对象,密钥长度 + kpg.initialize(keySize); + //生成密匙对 + KeyPair keyPair = kpg.generateKeyPair(); + + //得到公钥 + Key publicKey = keyPair.getPublic(); + + String publicKeyStr = new String(Base64.encodeBase64(publicKey.getEncoded())); + + //得到私钥 + Key privateKey = keyPair.getPrivate(); + String privateKeyStr = new String(Base64.encodeBase64(privateKey.getEncoded())); + + RsaKey rsaKey = new RsaKey(); + rsaKey.setPublicKey(publicKeyStr); + rsaKey.setPrivateKey(privateKeyStr); + + return rsaKey; + } + + + /** + * 公钥加密 + * + * @param originalText 原文 + * @param publicKey 公钥 + */ + public static String publicEncrypt(String originalText, String publicKey) throws NoSuchAlgorithmException { + RSAPublicKey rsaPublicKey = getPublicKey(publicKey); + return publicEncrypt(originalText, rsaPublicKey); + } + + /** + * 公钥解密 + * + * @param cipherText 密文 + * @param publicKey 公钥 + */ + public static String publicDecrypt(String cipherText, String publicKey) throws NoSuchAlgorithmException { + RSAPublicKey rsaPublicKey = getPublicKey(publicKey); + return publicDecrypt(cipherText, rsaPublicKey); + } + + /** + * 私钥加密 + * + * @param originalText 原文 + * @param privateKey 私钥 + */ + public static String privateEncrypt(String originalText, String privateKey) throws NoSuchAlgorithmException { + RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKey); + return privateEncrypt(originalText, rsaPrivateKey); + } + + + /** + * 私钥解密 + * + * @param cipherText 密文 + * @param privateKey 私钥 + */ + public static String privateDecrypt(String cipherText, String privateKey) throws NoSuchAlgorithmException { + RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKey); + return privateDecrypt(cipherText, rsaPrivateKey); + } + + + /** + * 得到公钥 + * + * @param publicKey 密钥字符串(经过base64编码) + */ + private static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException { + //通过X509编码的Key指令获得公钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); + RSAPublicKey key = null; + try { + key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + } + return key; + } + + /** + * 公钥加密 + * + * @param originalText 原文 + * @param publicKey 公钥 + */ + private static String publicEncrypt(String originalText, RSAPublicKey publicKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, originalText.getBytes(CHARSET), publicKey.getModulus().bitLength())); + } catch (Exception e) { + throw new RuntimeException("加密字符串[" + originalText + "]时遇到异常", e); + } + } + + /** + * 得到私钥 + * + * @param privateKey 密钥字符串(经过base64编码) + */ + private static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException { + //通过PKCS#8编码的Key指令获得私钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); + + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); + RSAPrivateKey key = null; + try { + key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); + } catch (InvalidKeySpecException e) { + e.printStackTrace(); + } + return key; + } + + + /** + * 私钥解密 + * + * @param cipherText 密文 + * @param privateKey 私钥 + */ + + private static String privateDecrypt(String cipherText, RSAPrivateKey privateKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(cipherText), privateKey.getModulus().bitLength()), CHARSET); + } catch (Exception e) { + throw new RuntimeException("解密字符串[" + cipherText + "]时遇到异常", e); + } + } + + private static String privateEncrypt(String originalText, RSAPrivateKey privateKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, originalText.getBytes(CHARSET), privateKey.getModulus().bitLength())); + } catch (Exception e) { + throw new RuntimeException("加密字符串[" + originalText + "]时遇到异常", e); + } + } + + + private static String publicDecrypt(String cipherText, RSAPublicKey publicKey) { + try { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(cipherText), publicKey.getModulus().bitLength()), CHARSET); + } catch (Exception e) { + throw new RuntimeException("解密字符串[" + cipherText + "]时遇到异常", e); + } + } + + private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) { + int maxBlock; + if (opmode == Cipher.DECRYPT_MODE) { + maxBlock = keySize / 8; + } else { + maxBlock = keySize / 8 - 11; + } + int offSet = 0; + byte[] buff; + int i = 0; + try ( + ByteArrayOutputStream out = new ByteArrayOutputStream() + ) { + while (datas.length > offSet) { + if (datas.length - offSet > maxBlock) { + buff = cipher.doFinal(datas, offSet, maxBlock); + } else { + buff = cipher.doFinal(datas, offSet, datas.length - offSet); + } + out.write(buff, 0, buff.length); + i++; + offSet = i * maxBlock; + } + return out.toByteArray(); + } catch (Exception e) { + throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e); + } + } + +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java index 18c222d1ba..90c4e26e92 100644 --- a/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java +++ b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java @@ -46,6 +46,7 @@ public class ShiroUtils { public static void ignoreCsrfFilter(Map filterChainDefinitionMap) { filterChainDefinitionMap.put("/", "apikey, authc"); // 跳转到 / 不用校验 csrf + filterChainDefinitionMap.put("/document", "apikey, authc"); // 跳转到 /document 不用校验 csrf } public static Cookie getSessionIdCookie(){ diff --git a/backend/src/main/java/io/metersphere/config/RsaConfig.java b/backend/src/main/java/io/metersphere/config/RsaConfig.java new file mode 100644 index 0000000000..945ae94a7e --- /dev/null +++ b/backend/src/main/java/io/metersphere/config/RsaConfig.java @@ -0,0 +1,16 @@ +package io.metersphere.config; + +import io.metersphere.commons.utils.RsaKey; +import io.metersphere.commons.utils.RsaUtil; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.security.NoSuchAlgorithmException; + +@Configuration +public class RsaConfig { + @Bean + public RsaKey rsaKey() throws NoSuchAlgorithmException { + return RsaUtil.createKeys(); + } +} diff --git a/backend/src/main/java/io/metersphere/controller/LoginController.java b/backend/src/main/java/io/metersphere/controller/LoginController.java index 75a2f8455d..c040c0710f 100644 --- a/backend/src/main/java/io/metersphere/controller/LoginController.java +++ b/backend/src/main/java/io/metersphere/controller/LoginController.java @@ -2,6 +2,8 @@ package io.metersphere.controller; import io.metersphere.commons.constants.UserSource; import io.metersphere.commons.user.SessionUser; +import io.metersphere.commons.utils.RsaKey; +import io.metersphere.commons.utils.RsaUtil; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.LoginRequest; import io.metersphere.service.BaseDisplayService; @@ -23,6 +25,8 @@ public class LoginController { private UserService userService; @Resource private BaseDisplayService baseDisplayService; + @Resource + private RsaKey rsaKey; @GetMapping(value = "/isLogin") public ResultHolder isLogin() { @@ -33,7 +37,7 @@ public class LoginController { } return ResultHolder.success(user); } - return ResultHolder.error(""); + return ResultHolder.error(rsaKey.getPublicKey()); } @PostMapping(value = "/signin") diff --git a/backend/src/main/java/io/metersphere/controller/ScheduleController.java b/backend/src/main/java/io/metersphere/controller/ScheduleController.java index 23ae6a9c4d..0b93ea15a1 100644 --- a/backend/src/main/java/io/metersphere/controller/ScheduleController.java +++ b/backend/src/main/java/io/metersphere/controller/ScheduleController.java @@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper; import io.metersphere.api.service.ApiAutomationService; import io.metersphere.base.domain.Schedule; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.ScheduleDao; import io.metersphere.service.ScheduleService; import org.springframework.web.bind.annotation.*; @@ -38,7 +39,7 @@ public class ScheduleController { } @PostMapping(value = "/create") - public void createSchedule(@RequestBody Schedule request) { + public void createSchedule(@RequestBody ScheduleRequest request) { scheduleService.createSchedule(request); } diff --git a/backend/src/main/java/io/metersphere/controller/request/LoginRequest.java b/backend/src/main/java/io/metersphere/controller/request/LoginRequest.java index db6cb22e65..20c2ab2dd9 100644 --- a/backend/src/main/java/io/metersphere/controller/request/LoginRequest.java +++ b/backend/src/main/java/io/metersphere/controller/request/LoginRequest.java @@ -1,12 +1,36 @@ package io.metersphere.controller.request; +import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.commons.utils.RsaKey; +import io.metersphere.commons.utils.RsaUtil; import lombok.Getter; import lombok.Setter; +import java.security.NoSuchAlgorithmException; + @Getter @Setter public class LoginRequest { private String username; private String password; private String authenticate; + + + public String getUsername() { + try { + RsaKey rsaKey = CommonBeanFactory.getBean(RsaKey.class); + return RsaUtil.privateDecrypt(username, rsaKey.getPrivateKey()); + } catch (NoSuchAlgorithmException e) { + return username; + } + } + + public String getPassword() { + try { + RsaKey rsaKey = CommonBeanFactory.getBean(RsaKey.class); + return RsaUtil.privateDecrypt(password, rsaKey.getPrivateKey()); + } catch (NoSuchAlgorithmException e) { + return password; + } + } } diff --git a/backend/src/main/java/io/metersphere/controller/request/ScheduleRequest.java b/backend/src/main/java/io/metersphere/controller/request/ScheduleRequest.java new file mode 100644 index 0000000000..057f499903 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/request/ScheduleRequest.java @@ -0,0 +1,27 @@ +package io.metersphere.controller.request; + +import io.metersphere.base.domain.Schedule; +import lombok.Getter; +import lombok.Setter; + +/** + * @author song.tianyang + * @Date 2021/3/12 12:57 下午 + * @Description + */ +@Getter +@Setter +public class ScheduleRequest extends Schedule { + + //定时任务来源: 测试计划/测试场景 + private String scheduleFrom; + + private String projectId; + + private String moduleId; + + private String modulePath; + + private String modeId; + +} diff --git a/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java b/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java index e9f370bfb2..213f4b43d9 100644 --- a/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java +++ b/backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java @@ -10,6 +10,7 @@ import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.DashboardTestDTO; import io.metersphere.dto.LoadTestDTO; import io.metersphere.dto.ScheduleDao; @@ -175,7 +176,7 @@ public class PerformanceTestController { } @PostMapping(value = "/schedule/create") - public void createSchedule(@RequestBody Schedule request) { + public void createSchedule(@RequestBody ScheduleRequest request) { performanceTestService.createSchedule(request); } diff --git a/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java b/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java index 2e357a04d0..e7f6fa41e3 100644 --- a/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java +++ b/backend/src/main/java/io/metersphere/performance/engine/docker/DockerTestEngine.java @@ -103,12 +103,18 @@ public class DockerTestEngine extends AbstractEngine { startTestRequest.setEnv(env); String uri = String.format(BASE_URL + "/jmeter/container/start", nodeIp, port); - ResultHolder result = restTemplate.postForObject(uri, startTestRequest, ResultHolder.class); - if (result == null) { - MSException.throwException(Translator.get("start_engine_fail")); - } - if (!result.isSuccess()) { - MSException.throwException(result.getMessage()); + try { + ResultHolder result = restTemplate.postForObject(uri, startTestRequest, ResultHolder.class); + if (result == null) { + MSException.throwException(Translator.get("start_engine_fail")); + } + if (!result.isSuccess()) { + MSException.throwException(result.getMessage()); + } + } catch (MSException e) { + throw e; + } catch (Exception e) { + MSException.throwException("Please check node-controller status."); } } diff --git a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java index 2422f4afef..b5e2209e5c 100644 --- a/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java +++ b/backend/src/main/java/io/metersphere/performance/service/PerformanceTestService.java @@ -14,6 +14,7 @@ import io.metersphere.commons.utils.SessionUtils; import io.metersphere.config.KafkaProperties; import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.DashboardTestDTO; import io.metersphere.dto.LoadTestDTO; import io.metersphere.dto.ScheduleDao; @@ -465,12 +466,12 @@ public class PerformanceTestService { addOrUpdatePerformanceTestCronJob(request); } - public void createSchedule(Schedule request) { + public void createSchedule(ScheduleRequest request) { scheduleService.addSchedule(buildPerformanceTestSchedule(request)); addOrUpdatePerformanceTestCronJob(request); } - private Schedule buildPerformanceTestSchedule(Schedule request) { + private Schedule buildPerformanceTestSchedule(ScheduleRequest request) { Schedule schedule = scheduleService.buildApiTestSchedule(request); schedule.setJob(PerformanceTestJob.class.getName()); schedule.setGroup(ScheduleGroup.PERFORMANCE_TEST.name()); diff --git a/backend/src/main/java/io/metersphere/service/ScheduleService.java b/backend/src/main/java/io/metersphere/service/ScheduleService.java index cc30924d46..279568b785 100644 --- a/backend/src/main/java/io/metersphere/service/ScheduleService.java +++ b/backend/src/main/java/io/metersphere/service/ScheduleService.java @@ -17,6 +17,7 @@ import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.QueryScheduleRequest; +import io.metersphere.controller.request.ScheduleRequest; import io.metersphere.dto.ScheduleDao; import io.metersphere.job.sechedule.*; import org.apache.commons.lang3.StringUtils; @@ -143,7 +144,7 @@ public class ScheduleService { }); } - public Schedule buildApiTestSchedule(Schedule request) { + public Schedule buildApiTestSchedule(ScheduleRequest request) { Schedule schedule = new Schedule(); schedule.setResourceId(request.getResourceId()); schedule.setEnable(true); @@ -218,7 +219,7 @@ public class ScheduleService { return runningTaskInfoList; } - public void createSchedule(Schedule request) { + public void createSchedule(ScheduleRequest request) { Schedule schedule = this.buildApiTestSchedule(request); schedule.setJob(ApiScenarioTestJob.class.getName()); diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java index 6308f89b33..51f40d68a6 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java @@ -190,4 +190,9 @@ public class TestCaseController { .body(bytes); } + @PostMapping("/save") + public TestCaseWithBLOBs saveTestCase(@RequestBody TestCaseWithBLOBs testCaseWithBLOBs) { + return testCaseService.addTestCase(testCaseWithBLOBs); + } + } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java index b8ae792fe4..4ae0ae598a 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java @@ -92,7 +92,7 @@ public class TestCaseService { @Resource TestCaseFileMapper testCaseFileMapper; - private TestCaseWithBLOBs addTestCase(TestCaseWithBLOBs testCase) { + public TestCaseWithBLOBs addTestCase(TestCaseWithBLOBs testCase) { testCase.setName(testCase.getName()); checkTestCaseExist(testCase); testCase.setId(UUID.randomUUID().toString()); @@ -102,6 +102,7 @@ public class TestCaseService { testCase.setReviewStatus(TestCaseReviewStatus.Prepare.name()); testCase.setDemandId(testCase.getDemandId()); testCase.setDemandName(testCase.getDemandName()); + testCaseMapper.insert(testCase); return testCase; } @@ -703,4 +704,5 @@ public class TestCaseService { request.setSelectFields(selectFields); return extTestCaseMapper.list(request); } + } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index d2fc4b4211..efd6af73b7 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit d2fc4b42117be97c679b4d15d6f979923e598f7f +Subproject commit efd6af73b7c5cc53cd4515772000bc1436c49837 diff --git a/backend/src/main/resources/db/migration/V78__v1.8_release.sql b/backend/src/main/resources/db/migration/V78__v1.8_release.sql index 48db340305..9c3112ba2a 100644 --- a/backend/src/main/resources/db/migration/V78__v1.8_release.sql +++ b/backend/src/main/resources/db/migration/V78__v1.8_release.sql @@ -9,7 +9,48 @@ CREATE TABLE IF NOT EXISTS `user_header` primary key (id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; - +-- create table test_case_review_api_case +create table test_case_review_api_case +( + id varchar(50) not null, + test_case_review_id varchar(50) null, + api_case_id varchar(50) null, + status varchar(50) null, + environment_id varchar(50) null, + create_time bigint(13) null, + update_time bigint(13) null, + primary key (id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; +-- create table test_case_review_scenario +create table test_case_review_scenario +( + id varchar(50) not null, + test_case_review_id varchar(50) null, + api_scenario_id varchar(50) null, + status varchar(50) null, + environment varchar(50) null, + create_time bigint(13) null, + update_time bigint(13) null, + pass_rate varchar(100) null, + last_result varchar(100) null, + report_id varchar(50) null, + primary key (id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; +-- create table test_case_review_load +create table test_case_review_load +( + id varchar(50) not null, + test_case_review_id varchar(50) null, + load_case_id varchar(50) null, + status varchar(50) null, + create_time bigint(13) null, + update_time bigint(13) null, + load_report_id varchar(50) null, + primary key (id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4; -- test_resource_pool add column ALTER TABLE test_resource_pool ADD heap VARCHAR(200) NULL; ALTER TABLE test_resource_pool ADD gc_algo VARCHAR(200) NULL; @@ -37,14 +78,19 @@ alter table test_case alter table test_case add demand_name varchar(999) null; +alter table test_case + add follow_people varchar(100) null; -- test_case_review add column -ALTER TABLE test_case_review ADD tags VARCHAR(2000) NULL; +ALTER TABLE test_case_review + ADD tags VARCHAR(2000) NULL; -- alter test_plan_api_scenario -alter table test_plan_api_scenario change environment_id environment longtext null comment 'Relevance environment'; +alter table test_plan_api_scenario + change environment_id environment longtext null comment 'Relevance environment'; -- file add sort column -alter table file_metadata add sort int default 0; +alter table file_metadata + add sort int default 0; -- add Original state alter table api_definition add original_state varchar(64); diff --git a/frontend/package.json b/frontend/package.json index eecd89e847..ee6fce3649 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,8 @@ "xml-js": "^1.6.11", "yan-progress": "^1.0.3", "jsonpath": "^1.1.0", - "vue-minder-editor-plus": "^1.0.14" + "vue-minder-editor-plus": "^1.0.16", + "jsencrypt": "^3.1.0" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.1.0", diff --git a/frontend/src/business/components/api/automation/report/ApiReportList.vue b/frontend/src/business/components/api/automation/report/ApiReportList.vue index 4d0d6cb1c7..f26eda2ed4 100644 --- a/frontend/src/business/components/api/automation/report/ApiReportList.vue +++ b/frontend/src/business/components/api/automation/report/ApiReportList.vue @@ -68,12 +68,6 @@ :total="total"/> - - - - @@ -89,14 +83,13 @@ import ReportTriggerModeItem from "../../../common/tableItem/ReportTriggerModeIt import {REPORT_CONFIGS} from "../../../common/components/search/search-components"; import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent"; import ShowMoreBtn from "../../../track/case/components/ShowMoreBtn"; -import MsApiReportDetail from "./ApiReportDetail"; import {_filter, _sort} from "@/common/js/tableUtils"; export default { components: { ReportTriggerModeItem, MsTableOperatorButton, - MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn, MsApiReportDetail + MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn }, data() { return { @@ -167,7 +160,10 @@ export default { handleView(report) { this.reportId = report.id; this.currentProjectId = report.projectId; - this.debugVisible = true; + this.$router.push({ + path: 'report/view/' + report.id, + }) + }, handleDelete(report) { this.$alert(this.$t('api_report.delete_confirm') + report.name + "?", '', { diff --git a/frontend/src/business/components/api/automation/report/ApiReportView.vue b/frontend/src/business/components/api/automation/report/ApiReportView.vue new file mode 100644 index 0000000000..03533b7c52 --- /dev/null +++ b/frontend/src/business/components/api/automation/report/ApiReportView.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue b/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue index 624aeef9b4..1090ac3b5b 100644 --- a/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue +++ b/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue @@ -31,10 +31,10 @@ - + - + diff --git a/frontend/src/business/components/api/automation/scenario/component/ApiComponent.vue b/frontend/src/business/components/api/automation/scenario/component/ApiComponent.vue index 81103b6beb..368ef166ae 100644 --- a/frontend/src/business/components/api/automation/scenario/component/ApiComponent.vue +++ b/frontend/src/business/components/api/automation/scenario/component/ApiComponent.vue @@ -12,10 +12,10 @@ :title="displayTitle"> @@ -26,6 +26,7 @@ diff --git a/frontend/src/business/components/api/automation/scenario/component/LoopController.vue b/frontend/src/business/components/api/automation/scenario/component/LoopController.vue index b52464f9ce..99cf8699fd 100644 --- a/frontend/src/business/components/api/automation/scenario/component/LoopController.vue +++ b/frontend/src/business/components/api/automation/scenario/component/LoopController.vue @@ -69,7 +69,6 @@
- @@ -79,18 +78,6 @@ ms
- - - - - - - - - - - - @@ -344,14 +331,6 @@ export default { font-weight: normal; } - .tip { - padding: 3px 5px; - font-size: 16px; - border-radius: 4px; - border-left: 4px solid #783887; - margin: 20px 0; - } - .icon.is-active { transform: rotate(90deg); } diff --git a/frontend/src/business/components/api/definition/components/list/ApiList.vue b/frontend/src/business/components/api/definition/components/list/ApiList.vue index 80b323b0b6..3ae913db9d 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiList.vue @@ -325,7 +325,7 @@ export default { currentPage: 1, pageSize: 10, total: 0, - screenHeight: document.documentElement.clientHeight - 270,//屏幕高度, + screenHeight: document.documentElement.clientHeight - 310,//屏幕高度, environmentId: undefined, selectDataCounts: 0, } diff --git a/frontend/src/business/components/api/router.js b/frontend/src/business/components/api/router.js index 4f1fd3a90c..20a0108078 100644 --- a/frontend/src/business/components/api/router.js +++ b/frontend/src/business/components/api/router.js @@ -63,6 +63,12 @@ export default { name: "ApiReportList", component: () => import('@/business/components/api/automation/report/ApiReportList'), }, + { + path:"automation/report/view/:reportId", + name:"ApiReportView", + component: () => import('@/business/components/api/automation/report/ApiReportView'), + + }, { path: 'monitor/view', name: 'ApiMonitor', diff --git a/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue index 2a372d5e09..2157353b8d 100644 --- a/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue +++ b/frontend/src/business/components/performance/report/components/PerformancePressureConfig.vue @@ -132,6 +132,7 @@ import MsChart from "@/business/components/common/chart/MsChart"; import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup"; const HANDLER = "handler"; +const THREAD_GROUP_TYPE = "tgType"; const TARGET_LEVEL = "TargetLevel"; const RAMP_UP = "RampUp"; const STEPS = "Steps"; @@ -225,6 +226,9 @@ export default { case HANDLER: this.threadGroups[i].handler = item.value; break; + case THREAD_GROUP_TYPE: + this.threadGroups[i].tgType = item.value; + break; default: break; } @@ -360,7 +364,7 @@ export default { if (j === 0) { seriesData.data.push([0, 0]); } - if (j > tg.rampUpTime) { + if (j >= tg.rampUpTime) { xAxis.push(tg.duration); seriesData.data.push([j, tg.threadNumber]); @@ -471,7 +475,7 @@ export default { if (i === 0) { handler.options.series[0].data.push([0, 0]); } - if (i > handler.rampUpTime) { + if (i >= handler.rampUpTime) { handler.options.xAxis.data.push(handler.duration); handler.options.series[0].data.push([i, handler.threadNumber]); diff --git a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue index f7c3e121ee..c800972a24 100644 --- a/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue +++ b/frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue @@ -92,6 +92,7 @@ :disabled="isReadOnly" :min="1" v-model="threadGroup.rampUpTime" + @change="calculateChart(threadGroup)" size="mini"/> @@ -402,7 +403,7 @@ export default { if (j === 0) { seriesData.data.push([0, 0]); } - if (j > tg.rampUpTime) { + if (j >= tg.rampUpTime) { xAxis.push(tg.duration); seriesData.data.push([j, tg.threadNumber]); @@ -519,7 +520,7 @@ export default { if (i === 0) { handler.options.series[0].data.push([0, 0]); } - if (i > handler.rampUpTime) { + if (i >= handler.rampUpTime) { handler.options.xAxis.data.push(handler.duration); handler.options.series[0].data.push([i, handler.threadNumber]); diff --git a/frontend/src/business/components/track/case/TestCase.vue b/frontend/src/business/components/track/case/TestCase.vue index 6b32fdec2d..97ac158146 100644 --- a/frontend/src/business/components/track/case/TestCase.vue +++ b/frontend/src/business/components/track/case/TestCase.vue @@ -7,8 +7,10 @@ @refreshTable="refresh" @setTreeNodes="setTreeNodes" @exportTestCase="exportTestCase" + @saveAsEdit="editTestCase" :type="'edit'" - ref="nodeTree"/> + ref="nodeTree" + /> @@ -161,7 +163,6 @@ export default { }, isRedirectEdit: function () { let redirectParam = this.$route.params.dataSelectRange; - this.checkRedirectEditPage(redirectParam); return redirectParam; } }, @@ -191,29 +192,6 @@ export default { this.redirectFlag = "none"; } }, - checkRedirectEditPage(redirectParam) { - if (redirectParam != null) { - let selectParamArr = redirectParam.split("edit:"); - if (selectParamArr.length == 2) { - let scenarioId = selectParamArr[1]; - let projectId = getCurrentProjectID(); - //查找单条数据,跳转修改页面 - /* let url = "/api/automation/list/" + 1 + "/" + 1; - this.$post(url, {id: scenarioId, projectId: projectId}, response => { - let data = response.data; - if (data != null) { - //如果树未加载 - if (JSON.stringify(this.moduleOptions) === '{}') { - this.$refs.nodeTree.list(); - } - let row = data.listObject[0]; - row.tags = JSON.parse(row.tags); - this.editScenario(row); - } - });*/ - } - } - }, addTab(tab) { if (!getCurrentProjectID()) { this.$warning(this.$t('commons.check_project_tip')); @@ -301,25 +279,17 @@ export default { return; } this.addTab({name: 'edit', testCaseInfo: testCase}); - - }, + copyTestCase(testCase) { this.type="copy" this.testCaseReadOnly = false; let item = {}; testCase.isCopy = true; this.addTab({name: 'edit', testCaseInfo: testCase}); - -/* - this.$refs.testCaseEditDialog.open(item); -*/ }, showTestCaseDetail(testCase) { this.testCaseReadOnly = true; -/* - this.$refs.testCaseEditDialog.open(testCase); -*/ }, refresh() { this.selectNodeIds = []; diff --git a/frontend/src/business/components/track/case/components/TestCaseCreate.vue b/frontend/src/business/components/track/case/components/TestCaseCreate.vue index 8180b0685a..e132bdfc4e 100644 --- a/frontend/src/business/components/track/case/components/TestCaseCreate.vue +++ b/frontend/src/business/components/track/case/components/TestCaseCreate.vue @@ -8,7 +8,7 @@ - + @@ -61,59 +61,87 @@ import {getCurrentProjectID, getCurrentUser, getUUID} from "@/common/js/utils"; import {WORKSPACE_ID} from "@/common/js/constants"; import MsDialogFooter from "@/business/components/common/components/MsDialogFooter"; +import {buildNodePath} from "@/business/components/api/definition/model/NodeTree"; export default { -name: "TestCaseCreate", + name: "TestCaseCreate", components: {MsDialogFooter}, - data(){ - return{ - testCaseForm:{}, - visible: false, - currentModule: {}, - userOptions: [], - rule: { - name: [ - {required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'}, - {max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'} - ], - principal: [{ - required: true, - message: this.$t('api_test.automation.scenario.select_principal'), - trigger: 'change' - }], - }, - } + data() { + return { + testCaseForm: {}, + visible: false, + currentModule: {}, + userOptions: [], + rule: { + name: [ + {required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'}, + {max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'} + ], + maintainer: [{ + required: true, + message: this.$t('api_test.automation.scenario.select_principal'), + trigger: 'change' + }], + + + }, + } }, - methods:{ - saveTestCase(){ + props: { + treeNodes: { + type: Array + }, + }, + watch: { + treeNodes() { + this.getModuleOptions(); + }, + }, + methods: { + saveTestCase(saveAs) { this.$refs['testCaseForm'].validate((valid) => { if (valid) { - let path = "/api/automation/create"; - this.setParameter(); - /* this.$fileUpload(path, null, [], this.scenarioForm, () => { + let path = "/test/case/save"; + this.testCaseForm.projectId = getCurrentProjectID(); + this.testCaseForm.type = ""; + this.testCaseForm.priority = "P0"; + this.testCaseForm.method = "manual"; + if(this.currentModule!==undefined){ + this.testCaseForm.nodePath = this.currentModule.path; + this.testCaseForm.nodeId = this.currentModule.id; + }else{ + this.testCaseForm.nodePath="/全部用例" + this.testCaseForm.nodeId="root" + } + this.result = this.$post(path, this.testCaseForm, response => { + this.testCaseForm.id=response.data.id + this.$success(this.$t('commons.save_success')); this.visible = false; if (saveAs) { - this.scenarioForm.request = JSON.stringify(this.scenarioForm.request); - this.$emit('saveAsEdit', this.scenarioForm); + this.$emit('saveAsEdit', this.testCaseForm); } else { this.$emit('refresh'); } - });*/ + }) } else { return false; } }) }, - setParameter() { - this.scenarioForm.projectId = getCurrentProjectID(); - this.scenarioForm.id = getUUID().substring(0, 8); - this.scenarioForm.protocol = this.currentProtocol; - - if (this.currentModule && this.currentModule.id != "root") { - this.scenarioForm.modulePath = this.currentModule.method !== undefined ? this.currentModule.method : null; - this.scenarioForm.apiScenarioModuleId = this.currentModule.id; + getModuleOptions() { + let moduleOptions = []; + this.treeNodes.forEach(node => { + buildNodePath(node, {path: ''}, moduleOptions); + }); + if(this.currentModule!==undefined){ + moduleOptions.forEach(item => { + if (this.currentModule.id === item.id) { + this.currentModule.path = item.path; + } + }); } }, + getMaintainerOptions() { let workspaceId = localStorage.getItem(WORKSPACE_ID); this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => { @@ -121,10 +149,11 @@ name: "TestCaseCreate", }); }, open(currentModule) { - this.scenarioForm = {principal: getCurrentUser().id}; + this.testCaseForm = {maintainer: getCurrentUser().id}; this.currentModule = currentModule; this.getMaintainerOptions(); this.visible = true; + this.getModuleOptions() } } } diff --git a/frontend/src/business/components/track/case/components/TestCaseEdit.vue b/frontend/src/business/components/track/case/components/TestCaseEdit.vue index b7278ab371..f9a18890b6 100644 --- a/frontend/src/business/components/track/case/components/TestCaseEdit.vue +++ b/frontend/src/business/components/track/case/components/TestCaseEdit.vue @@ -48,15 +48,24 @@ - - - + + + + + + + + + + + + @@ -76,7 +85,8 @@ - + + - - + + + + + + diff --git a/frontend/src/business/components/track/case/components/minder/TestcaseMinder.vue b/frontend/src/business/components/track/case/components/minder/TestcaseMinder.vue deleted file mode 100644 index 42a6419b18..0000000000 --- a/frontend/src/business/components/track/case/components/minder/TestcaseMinder.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/frontend/src/business/components/track/common/TestCaseNodeTree.vue b/frontend/src/business/components/track/common/TestCaseNodeTree.vue index e3d268daab..ed31d2c7df 100644 --- a/frontend/src/business/components/track/common/TestCaseNodeTree.vue +++ b/frontend/src/business/components/track/common/TestCaseNodeTree.vue @@ -33,6 +33,7 @@