From 0ed0330dfbc47b470859b580078f7ef15bb8c9a4 Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Wed, 16 Jun 2021 15:25:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=89=A7=E8=A1=8C=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E6=8E=A5=E5=8F=A3=E7=94=A8=E4=BE=8B=E5=90=8E?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=85=B3=E8=81=94=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/jmeter/APIBackendListenerClient.java | 37 ++++ .../api/service/ApiScenarioReportService.java | 2 + .../base/domain/ApiScenarioReport.java | 4 +- .../io/metersphere/base/domain/TestPlan.java | 9 +- .../base/domain/TestPlanExample.java | 180 ++++++++++++------ .../base/mapper/TestPlanMapper.xml | 73 ++++--- .../track/service/TestPlanApiCaseService.java | 12 ++ .../service/TestPlanLoadCaseService.java | 12 ++ .../service/TestPlanScenarioCaseService.java | 16 ++ .../service/TestPlanTestCaseService.java | 97 +++++++++- .../db/migration/V88__v1.10.3_release.sql | 2 + .../track/plan/components/TestPlanEdit.vue | 23 ++- 12 files changed, 364 insertions(+), 103 deletions(-) create mode 100644 backend/src/main/resources/db/migration/V88__v1.10.3_release.sql 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 786ffc536a..f81a9cbbfb 100644 --- a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java +++ b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java @@ -15,8 +15,10 @@ import io.metersphere.i18n.Translator; import io.metersphere.notice.sender.NoticeModel; import io.metersphere.notice.service.NoticeSendService; import io.metersphere.service.SystemParameterService; +import io.metersphere.track.request.testcase.TrackCount; import io.metersphere.track.service.TestPlanApiCaseService; import io.metersphere.track.service.TestPlanReportService; +import io.metersphere.track.service.TestPlanScenarioCaseService; import io.metersphere.track.service.TestPlanTestCaseService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -208,6 +210,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl ApiTestReport report = null; ApiTestReportVariable reportTask = null; String reportUrl = null; + String planScenarioId = null; // 这部分后续优化只留 DEFINITION 和 SCENARIO 两部分 if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) { report = apiReportService.get(debugReportId); @@ -335,6 +338,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo(); reportUrl = baseSystemConfigDTO.getUrl() + "/#/api/automation/report"; testResult.setTestId(scenarioReport.getScenarioId()); + planScenarioId = scenarioReport.getTestPlanScenarioId(); } else { apiTestService.changeStatus(testId, APITestStatus.Completed); report = apiReportService.getRunningReport(testResult.getTestId()); @@ -343,6 +347,8 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl queue.clear(); super.teardownTest(context); + updateTestCaseStates(testResult, planScenarioId); + List ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId()); if (ids.size() > 0) { try { @@ -363,6 +369,37 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl } + /** + * 更新测试计划关联接口测试的功能用例的状态 + * @param testResult + */ + private void updateTestCaseStates(TestResult testResult, String testPlanScenarioId) { + try { + if (StringUtils.equalsAny(this.runMode, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), + ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) { + testResult.getScenarios().forEach(scenarioResult -> { + if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) { + scenarioResult.getRequestResults().forEach(item -> { + if (StringUtils.equalsAny(this.runMode, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), + ApiRunMode.JENKINS_API_PLAN.name())) { + TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(item.getName()); + ApiTestCaseWithBLOBs apiTestCase = apiTestCaseService.get(testPlanApiCase.getApiCaseId()); + testPlanTestCaseService.updateTestCaseStates(apiTestCase.getId(), apiTestCase.getName(), testPlanApiCase.getTestPlanId(), TrackCount.TESTCASE); + } else { + TestPlanScenarioCaseService testPlanScenarioCaseService = CommonBeanFactory.getBean(TestPlanScenarioCaseService.class); + TestPlanApiScenario testPlanApiScenario = testPlanScenarioCaseService.get(testPlanScenarioId); + ApiScenarioWithBLOBs apiScenario = apiAutomationService.getApiScenario(testPlanApiScenario.getApiScenarioId()); + testPlanTestCaseService.updateTestCaseStates(apiScenario.getId(), apiScenario.getName(), testPlanApiScenario.getTestPlanId(), TrackCount.AUTOMATION); + } + }); + } + }); + } + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + } + } + private static void sendTask(ApiTestReportVariable report, String reportUrl, TestResult testResult) { if (report == null) { return; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java index 465275f94e..93056269e4 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioReportService.java @@ -233,6 +233,7 @@ public class ApiScenarioReportService { testPlanApiScenario.setPassRate(passRate); testPlanApiScenario.setReportId(report.getId()); testPlanApiScenario.setUpdateTime(report.getCreateTime()); + report.setTestPlanScenarioId(testPlanApiScenario.getId()); testPlanApiScenarioMapper.updateByPrimaryKeySelective(testPlanApiScenario); } returnReport = report; @@ -280,6 +281,7 @@ public class ApiScenarioReportService { } TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(planScenarioId); report.setScenarioId(testPlanApiScenario.getApiScenarioId()); + report.setTestPlanScenarioId(planScenarioId); apiScenarioReportMapper.updateByPrimaryKeySelective(report); if (scenarioResult.getError() > 0) { testPlanApiScenario.setLastResult(ScenarioStatus.Fail.name()); diff --git a/backend/src/main/java/io/metersphere/base/domain/ApiScenarioReport.java b/backend/src/main/java/io/metersphere/base/domain/ApiScenarioReport.java index e092062ac2..589b329176 100644 --- a/backend/src/main/java/io/metersphere/base/domain/ApiScenarioReport.java +++ b/backend/src/main/java/io/metersphere/base/domain/ApiScenarioReport.java @@ -31,5 +31,7 @@ public class ApiScenarioReport implements Serializable { private String description; + private String testPlanScenarioId; + private static final long serialVersionUID = 1L; -} \ No newline at end of file +} diff --git a/backend/src/main/java/io/metersphere/base/domain/TestPlan.java b/backend/src/main/java/io/metersphere/base/domain/TestPlan.java index 16cfa759c5..566e1350a9 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestPlan.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlan.java @@ -1,8 +1,7 @@ package io.metersphere.base.domain; -import lombok.Data; - import java.io.Serializable; +import lombok.Data; @Data public class TestPlan implements Serializable { @@ -30,20 +29,22 @@ public class TestPlan implements Serializable { private Long updateTime; - private Long actualEndTime; - private Long plannedStartTime; private Long plannedEndTime; private Long actualStartTime; + private Long actualEndTime; + private String creator; private String projectId; private Integer executionTimes; + private Boolean automaticStatusUpdate; + private String tags; private static final long serialVersionUID = 1L; diff --git a/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java b/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java index afe2e93584..34eb96ce0f 100644 --- a/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java +++ b/backend/src/main/java/io/metersphere/base/domain/TestPlanExample.java @@ -924,66 +924,6 @@ public class TestPlanExample { return (Criteria) this; } - public Criteria andActualEndTimeIsNull() { - addCriterion("actual_end_time is null"); - return (Criteria) this; - } - - public Criteria andActualEndTimeIsNotNull() { - addCriterion("actual_end_time is not null"); - return (Criteria) this; - } - - public Criteria andActualEndTimeEqualTo(Long value) { - addCriterion("actual_end_time =", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeNotEqualTo(Long value) { - addCriterion("actual_end_time <>", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeGreaterThan(Long value) { - addCriterion("actual_end_time >", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeGreaterThanOrEqualTo(Long value) { - addCriterion("actual_end_time >=", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeLessThan(Long value) { - addCriterion("actual_end_time <", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeLessThanOrEqualTo(Long value) { - addCriterion("actual_end_time <=", value, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeIn(List values) { - addCriterion("actual_end_time in", values, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeNotIn(List values) { - addCriterion("actual_end_time not in", values, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeBetween(Long value1, Long value2) { - addCriterion("actual_end_time between", value1, value2, "actualEndTime"); - return (Criteria) this; - } - - public Criteria andActualEndTimeNotBetween(Long value1, Long value2) { - addCriterion("actual_end_time not between", value1, value2, "actualEndTime"); - return (Criteria) this; - } - public Criteria andPlannedStartTimeIsNull() { addCriterion("planned_start_time is null"); return (Criteria) this; @@ -1164,6 +1104,66 @@ public class TestPlanExample { return (Criteria) this; } + public Criteria andActualEndTimeIsNull() { + addCriterion("actual_end_time is null"); + return (Criteria) this; + } + + public Criteria andActualEndTimeIsNotNull() { + addCriterion("actual_end_time is not null"); + return (Criteria) this; + } + + public Criteria andActualEndTimeEqualTo(Long value) { + addCriterion("actual_end_time =", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeNotEqualTo(Long value) { + addCriterion("actual_end_time <>", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeGreaterThan(Long value) { + addCriterion("actual_end_time >", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeGreaterThanOrEqualTo(Long value) { + addCriterion("actual_end_time >=", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeLessThan(Long value) { + addCriterion("actual_end_time <", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeLessThanOrEqualTo(Long value) { + addCriterion("actual_end_time <=", value, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeIn(List values) { + addCriterion("actual_end_time in", values, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeNotIn(List values) { + addCriterion("actual_end_time not in", values, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeBetween(Long value1, Long value2) { + addCriterion("actual_end_time between", value1, value2, "actualEndTime"); + return (Criteria) this; + } + + public Criteria andActualEndTimeNotBetween(Long value1, Long value2) { + addCriterion("actual_end_time not between", value1, value2, "actualEndTime"); + return (Criteria) this; + } + public Criteria andCreatorIsNull() { addCriterion("creator is null"); return (Criteria) this; @@ -1363,6 +1363,66 @@ public class TestPlanExample { addCriterion("execution_times not between", value1, value2, "executionTimes"); return (Criteria) this; } + + public Criteria andAutomaticStatusUpdateIsNull() { + addCriterion("automatic_status_update is null"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateIsNotNull() { + addCriterion("automatic_status_update is not null"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateEqualTo(Boolean value) { + addCriterion("automatic_status_update =", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateNotEqualTo(Boolean value) { + addCriterion("automatic_status_update <>", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateGreaterThan(Boolean value) { + addCriterion("automatic_status_update >", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateGreaterThanOrEqualTo(Boolean value) { + addCriterion("automatic_status_update >=", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateLessThan(Boolean value) { + addCriterion("automatic_status_update <", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateLessThanOrEqualTo(Boolean value) { + addCriterion("automatic_status_update <=", value, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateIn(List values) { + addCriterion("automatic_status_update in", values, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateNotIn(List values) { + addCriterion("automatic_status_update not in", values, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateBetween(Boolean value1, Boolean value2) { + addCriterion("automatic_status_update between", value1, value2, "automaticStatusUpdate"); + return (Criteria) this; + } + + public Criteria andAutomaticStatusUpdateNotBetween(Boolean value1, Boolean value2) { + addCriterion("automatic_status_update not between", value1, value2, "automaticStatusUpdate"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml index c3dd721c50..357a332f24 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/TestPlanMapper.xml @@ -14,13 +14,14 @@ - + + @@ -85,8 +86,8 @@ id, workspace_id, report_id, `name`, description, `status`, stage, principal, test_case_match_rule, - executor_match_rule, create_time, update_time, actual_end_time, planned_start_time, - planned_end_time, actual_start_time, creator, project_id, execution_times + executor_match_rule, create_time, update_time, planned_start_time, planned_end_time, + actual_start_time, actual_end_time, creator, project_id, execution_times, automatic_status_update tags @@ -144,16 +145,18 @@ `name`, description, `status`, stage, principal, test_case_match_rule, executor_match_rule, create_time, update_time, - actual_end_time, planned_start_time, planned_end_time, - actual_start_time, creator, project_id, - execution_times, tags) + planned_start_time, planned_end_time, actual_start_time, + actual_end_time, creator, project_id, + execution_times, automatic_status_update, tags + ) values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{stage,jdbcType=VARCHAR}, #{principal,jdbcType=VARCHAR}, #{testCaseMatchRule,jdbcType=VARCHAR}, #{executorMatchRule,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, - #{actualEndTime,jdbcType=BIGINT}, #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT}, - #{actualStartTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, - #{executionTimes,jdbcType=INTEGER}, #{tags,jdbcType=LONGVARCHAR}) + #{plannedStartTime,jdbcType=BIGINT}, #{plannedEndTime,jdbcType=BIGINT}, #{actualStartTime,jdbcType=BIGINT}, + #{actualEndTime,jdbcType=BIGINT}, #{creator,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, + #{executionTimes,jdbcType=INTEGER}, #{automaticStatusUpdate,jdbcType=BIT}, #{tags,jdbcType=LONGVARCHAR} + ) insert into test_plan @@ -194,9 +197,6 @@ update_time, - - actual_end_time, - planned_start_time, @@ -206,6 +206,9 @@ actual_start_time, + + actual_end_time, + creator, @@ -215,6 +218,9 @@ execution_times, + + automatic_status_update, + tags, @@ -256,9 +262,6 @@ #{updateTime,jdbcType=BIGINT}, - - #{actualEndTime,jdbcType=BIGINT}, - #{plannedStartTime,jdbcType=BIGINT}, @@ -268,6 +271,9 @@ #{actualStartTime,jdbcType=BIGINT}, + + #{actualEndTime,jdbcType=BIGINT}, + #{creator,jdbcType=VARCHAR}, @@ -277,6 +283,9 @@ #{executionTimes,jdbcType=INTEGER}, + + #{automaticStatusUpdate,jdbcType=BIT}, + #{tags,jdbcType=LONGVARCHAR}, @@ -327,9 +336,6 @@ update_time = #{record.updateTime,jdbcType=BIGINT}, - - actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, - planned_start_time = #{record.plannedStartTime,jdbcType=BIGINT}, @@ -339,6 +345,9 @@ actual_start_time = #{record.actualStartTime,jdbcType=BIGINT}, + + actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, + creator = #{record.creator,jdbcType=VARCHAR}, @@ -348,6 +357,9 @@ execution_times = #{record.executionTimes,jdbcType=INTEGER}, + + automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT}, + tags = #{record.tags,jdbcType=LONGVARCHAR}, @@ -370,13 +382,14 @@ executor_match_rule = #{record.executorMatchRule,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT}, - actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, planned_start_time = #{record.plannedStartTime,jdbcType=BIGINT}, planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT}, actual_start_time = #{record.actualStartTime,jdbcType=BIGINT}, + actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, creator = #{record.creator,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR}, execution_times = #{record.executionTimes,jdbcType=INTEGER}, + automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT}, tags = #{record.tags,jdbcType=LONGVARCHAR} @@ -396,13 +409,14 @@ executor_match_rule = #{record.executorMatchRule,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT}, - actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, planned_start_time = #{record.plannedStartTime,jdbcType=BIGINT}, planned_end_time = #{record.plannedEndTime,jdbcType=BIGINT}, actual_start_time = #{record.actualStartTime,jdbcType=BIGINT}, + actual_end_time = #{record.actualEndTime,jdbcType=BIGINT}, creator = #{record.creator,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR}, - execution_times = #{record.executionTimes,jdbcType=INTEGER} + execution_times = #{record.executionTimes,jdbcType=INTEGER}, + automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT} @@ -443,9 +457,6 @@ update_time = #{updateTime,jdbcType=BIGINT}, - - actual_end_time = #{actualEndTime,jdbcType=BIGINT}, - planned_start_time = #{plannedStartTime,jdbcType=BIGINT}, @@ -455,6 +466,9 @@ actual_start_time = #{actualStartTime,jdbcType=BIGINT}, + + actual_end_time = #{actualEndTime,jdbcType=BIGINT}, + creator = #{creator,jdbcType=VARCHAR}, @@ -464,6 +478,9 @@ execution_times = #{executionTimes,jdbcType=INTEGER}, + + automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT}, + tags = #{tags,jdbcType=LONGVARCHAR}, @@ -483,13 +500,14 @@ executor_match_rule = #{executorMatchRule,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, - actual_end_time = #{actualEndTime,jdbcType=BIGINT}, planned_start_time = #{plannedStartTime,jdbcType=BIGINT}, planned_end_time = #{plannedEndTime,jdbcType=BIGINT}, actual_start_time = #{actualStartTime,jdbcType=BIGINT}, + actual_end_time = #{actualEndTime,jdbcType=BIGINT}, creator = #{creator,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR}, execution_times = #{executionTimes,jdbcType=INTEGER}, + automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT}, tags = #{tags,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} @@ -506,13 +524,14 @@ executor_match_rule = #{executorMatchRule,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT}, - actual_end_time = #{actualEndTime,jdbcType=BIGINT}, planned_start_time = #{plannedStartTime,jdbcType=BIGINT}, planned_end_time = #{plannedEndTime,jdbcType=BIGINT}, actual_start_time = #{actualStartTime,jdbcType=BIGINT}, + actual_end_time = #{actualEndTime,jdbcType=BIGINT}, creator = #{creator,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR}, - execution_times = #{executionTimes,jdbcType=INTEGER} + execution_times = #{executionTimes,jdbcType=INTEGER}, + automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT} where id = #{id,jdbcType=VARCHAR} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java index 27f0afff5e..cdb6b2d286 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanApiCaseService.java @@ -219,4 +219,16 @@ public class TestPlanApiCaseService { } return null; } + + public Boolean hasFailCase(String planId, List apiCaseIds) { + if (CollectionUtils.isEmpty(apiCaseIds)) { + return false; + } + TestPlanApiCaseExample example = new TestPlanApiCaseExample(); + example.createCriteria() + .andTestPlanIdEqualTo(planId) + .andApiCaseIdIn(apiCaseIds) + .andStatusEqualTo("error"); + return testPlanApiCaseMapper.countByExample(example) > 0 ? true : false; + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java index fd681f499f..875f58c834 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanLoadCaseService.java @@ -326,4 +326,16 @@ public class TestPlanLoadCaseService { } return null; } + + public Boolean hasFailCase(String planId, List performanceIds) { + if (CollectionUtils.isEmpty(performanceIds)) { + return false; + } + TestPlanLoadCaseExample example = new TestPlanLoadCaseExample(); + example.createCriteria() + .andTestPlanIdEqualTo(planId) + .andLoadCaseIdIn(performanceIds) + .andStatusEqualTo("error"); + return testPlanLoadCaseMapper.countByExample(example) > 0 ? true : false; + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java index 5872c7e6fc..50b31ee0f9 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java @@ -236,4 +236,20 @@ public class TestPlanScenarioCaseService { } return null; } + + public TestPlanApiScenario get(String id) { + return testPlanApiScenarioMapper.selectByPrimaryKey(id); + } + + public Boolean hasFailCase(String planId, List automationIds) { + if (CollectionUtils.isEmpty(automationIds)) { + return false; + } + TestPlanApiScenarioExample example = new TestPlanApiScenarioExample(); + example.createCriteria() + .andTestPlanIdEqualTo(planId) + .andApiScenarioIdIn(automationIds) + .andLastResultEqualTo("Fail"); + return testPlanApiScenarioMapper.countByExample(example) > 0 ? true : false; + } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java index 357ceea970..5628e00ffe 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java @@ -8,6 +8,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.commons.constants.TestPlanTestCaseStatus; import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.BeanUtils; +import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.ServiceUtils; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.controller.request.member.QueryMemberRequest; @@ -17,19 +18,19 @@ import io.metersphere.service.UserService; import io.metersphere.track.dto.TestCaseTestDTO; import io.metersphere.track.dto.TestPlanCaseDTO; import io.metersphere.track.request.testcase.TestPlanCaseBatchRequest; +import io.metersphere.track.request.testcase.TrackCount; import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest; import io.metersphere.track.request.testplancase.TestPlanFuncCaseBatchRequest; import io.metersphere.track.request.testplancase.TestPlanFuncCaseConditions; +import io.metersphere.track.request.testreview.SaveCommentRequest; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Service @@ -38,13 +39,16 @@ public class TestPlanTestCaseService { @Resource TestPlanTestCaseMapper testPlanTestCaseMapper; - @Resource UserService userService; - @Resource TestPlanService testPlanService; - + @Resource + TestPlanApiCaseService testPlanApiCaseService; + @Resource + TestPlanLoadCaseService testPlanLoadCaseService; + @Resource + TestPlanScenarioCaseService testPlanScenarioCaseService; @Resource ExtTestPlanTestCaseMapper extTestPlanTestCaseMapper; @Resource @@ -57,6 +61,10 @@ public class TestPlanTestCaseService { private TestCaseMapper testCaseMapper; @Resource private TestPlanMapper testPlanMapper; + @Resource + private TestCaseTestMapper testCaseTestMapper; + @Resource + private TestCaseCommentService testCaseCommentService; public List list(QueryTestPlanCaseRequest request) { request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders())); @@ -206,6 +214,81 @@ public class TestPlanTestCaseService { return extTestPlanTestCaseMapper.updateTestCaseStates(ids, reportStatus); } + /** + * 更新测试计划关联接口测试的功能用例的状态 + * @param testId 接口测试id + */ + public void updateTestCaseStates(String testId, String testName, String planId, String testType) { + TestPlan testPlan = testPlanService.getTestPlan(planId); + if (BooleanUtils.isNotTrue(testPlan.getAutomaticStatusUpdate())) { + return; + } + TestCaseTestExample example = new TestCaseTestExample(); + example.createCriteria().andTestIdEqualTo(testId); + // 获取跟改接口测试有关联是功能用例id + List testCaseTests = testCaseTestMapper.selectByExample(example); + + testCaseTests.forEach(testCaseTest -> { + + TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample(); + testPlanTestCaseExample.createCriteria() + .andCaseIdEqualTo(testCaseTest.getTestCaseId()) + .andPlanIdEqualTo(planId); + // 获取该功能用例与测试计划关联的用例 + List testPlanTestCases = testPlanTestCaseMapper.selectByExample(testPlanTestCaseExample); + + try { + testPlanTestCases.forEach(testPlanTestCase -> { + // 获取跟该功能用例关联的所有自动化用例 + List relateTests = extTestPlanTestCaseMapper.listTestCaseTest(testPlanTestCase.getCaseId()); + List apiCaseIds = new ArrayList<>(); + List performanceIds = new ArrayList<>(); + List automationIds = new ArrayList<>(); + relateTests.forEach(item -> { + String type = item.getTestType(); + String id = item.getTestId(); + if (StringUtils.equals(TrackCount.TESTCASE, type)) { + apiCaseIds.add(id); + } else if (StringUtils.equals(TrackCount.AUTOMATION, type)) { + automationIds.add(id); + } else if (StringUtils.equals(TrackCount.PERFORMANCE, type)) { + performanceIds.add(id); + } + }); + Boolean hasApiFailCase = testPlanApiCaseService.hasFailCase(testPlanTestCase.getPlanId(), apiCaseIds); + Boolean hasScenarioFailCase = testPlanScenarioCaseService.hasFailCase(testPlanTestCase.getPlanId(), automationIds); + Boolean hasLoadFailCase = testPlanLoadCaseService.hasFailCase(testPlanTestCase.getPlanId(), performanceIds); + String status = TestPlanTestCaseStatus.Pass.name(); + if (hasApiFailCase || hasScenarioFailCase || hasLoadFailCase) { + status = TestPlanTestCaseStatus.Failure.name(); + } + + String tip = "执行成功"; + if (StringUtils.equals(TrackCount.TESTCASE, testType) && hasApiFailCase) { + tip = "执行失败"; + } else if (StringUtils.equals(TrackCount.AUTOMATION, testType) && hasScenarioFailCase) { + tip = "执行失败"; + } else if (StringUtils.equals(TrackCount.PERFORMANCE, testType) && hasLoadFailCase) { + tip = "执行失败"; + } + + TestPlanTestCaseWithBLOBs item = new TestPlanTestCaseWithBLOBs(); + item.setId(testPlanTestCase.getId()); + item.setStatus(status); + testPlanTestCaseMapper.updateByPrimaryKeySelective(item); + + SaveCommentRequest saveCommentRequest = new SaveCommentRequest(); + saveCommentRequest.setCaseId(testPlanTestCase.getCaseId()); + saveCommentRequest.setId(UUID.randomUUID().toString()); + saveCommentRequest.setDescription("关联的测试:[" + testName + "]" + tip); + testCaseCommentService.saveComment(saveCommentRequest); + }); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + } + }); + } + public List listForMinder(QueryTestPlanCaseRequest request) { return extTestPlanTestCaseMapper.listForMinder(request); } diff --git a/backend/src/main/resources/db/migration/V88__v1.10.3_release.sql b/backend/src/main/resources/db/migration/V88__v1.10.3_release.sql new file mode 100644 index 0000000000..a354712e7f --- /dev/null +++ b/backend/src/main/resources/db/migration/V88__v1.10.3_release.sql @@ -0,0 +1,2 @@ +-- 是否自定更新功能用例状态 +ALTER TABLE test_plan ADD automatic_status_update TINYINT(1) DEFAULT 0 NULL COMMENT '是否自定更新功能用例状态'; diff --git a/frontend/src/business/components/track/plan/components/TestPlanEdit.vue b/frontend/src/business/components/track/plan/components/TestPlanEdit.vue index 92e9d2b701..3427da7452 100644 --- a/frontend/src/business/components/track/plan/components/TestPlanEdit.vue +++ b/frontend/src/business/components/track/plan/components/TestPlanEdit.vue @@ -75,6 +75,18 @@ + + + + + + + + + @@ -123,14 +135,14 @@