Merge pull request #7423 from metersphere/pr@v1.14@feat_测试计划支持允许重复关联用例

feat: 测试计划支持允许重复关联用例
This commit is contained in:
jianxing 2021-11-02 16:10:59 +08:00 committed by GitHub
commit f8078a4a06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 435 additions and 183 deletions

View File

@ -70,8 +70,7 @@ public class ApiDefinitionController {
@PostMapping("/list/relevance/{goPage}/{pageSize}")
public Pager<List<ApiDefinitionResult>> listRelevance(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, apiDefinitionService.listRelevance(request));
return apiDefinitionService.listRelevance(request, goPage, pageSize);
}
@PostMapping("/list/relevance/review/{goPage}/{pageSize}")

View File

@ -21,4 +21,7 @@ public class ApiDefinitionRequest extends BaseQueryRequest {
private String status;
private String apiCaseCoverage;
private String reviewId;
// 测试计划是否允许重复
private boolean repeatCase;
}

View File

@ -52,12 +52,14 @@ import io.metersphere.service.ScheduleService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.service.TestPlanService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
@ -125,6 +127,9 @@ public class ApiDefinitionService {
private RelationshipEdgeService relationshipEdgeService;
@Resource
private ApiDefinitionFollowMapper apiDefinitionFollowMapper;
@Resource
@Lazy
private TestPlanService testPlanService;
private static Cache cache = Cache.newHardMemoryCache(0, 3600);
@ -1247,13 +1252,18 @@ public class ApiDefinitionService {
// extApiDefinitionMapper.removeToGcByExample(example);
}
public List<ApiDefinitionResult> listRelevance(ApiDefinitionRequest request) {
public Pager<List<ApiDefinitionResult>> listRelevance(ApiDefinitionRequest request, int goPage, int pageSize) {
request.setOrders(ServiceUtils.getDefaultSortOrder(request.getOrders()));
if (testPlanService.isAllowedRepeatCase(request.getPlanId())) {
request.setRepeatCase(true);
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
List<ApiDefinitionResult> resList = extApiDefinitionMapper.listRelevance(request);
calculateResult(resList, request.getProjectId());
return resList;
return PageUtils.setPageInfo(page, resList);
}
public List<ApiDefinitionResult> listRelevanceReview(ApiDefinitionRequest request) {
request.setOrders(ServiceUtils.getDefaultSortOrder(request.getOrders()));
List<ApiDefinitionResult> resList = extApiDefinitionMapper.listRelevanceReview(request);

View File

@ -37,6 +37,7 @@ import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
import io.metersphere.service.UserService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import io.metersphere.track.service.TestPlanService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
@ -96,6 +97,9 @@ public class ApiTestCaseService {
@Lazy
private APITestService apiTestService;
@Resource
@Lazy
private TestPlanService testPlanService;
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@Resource
private ApiTestEnvironmentMapper apiTestEnvironmentMapper;
@ -544,6 +548,7 @@ public class ApiTestCaseService {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtTestPlanApiCaseMapper batchMapper = sqlSession.getMapper(ExtTestPlanApiCaseMapper.class);
TestPlanApiCaseMapper batchBaseMapper = sqlSession.getMapper(TestPlanApiCaseMapper.class);
Long nextOrder = ServiceUtils.getNextOrder(request.getPlanId(), extTestPlanApiCaseMapper::getLastOrder);
for (ApiTestCase apiTestCase : apiTestCases) {
@ -557,7 +562,11 @@ public class ApiTestCaseService {
testPlanApiCase.setUpdateTime(System.currentTimeMillis());
testPlanApiCase.setOrder(nextOrder);
nextOrder += 5000;
batchMapper.insertIfNotExists(testPlanApiCase);
if (testPlanService.isAllowedRepeatCase(request.getPlanId())) {
batchBaseMapper.insert(testPlanApiCase);
} else {
batchMapper.insertIfNotExists(testPlanApiCase);
}
}
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());

View File

@ -27,14 +27,14 @@ 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;
@ -43,5 +43,9 @@ public class TestPlan implements Serializable {
private Boolean automaticStatusUpdate;
private String followPeople;
private Boolean repeatCase;
private static final long serialVersionUID = 1L;
}

View File

@ -854,66 +854,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<Long> values) {
addCriterion("actual_end_time in", values, "actualEndTime");
return (Criteria) this;
}
public Criteria andActualEndTimeNotIn(List<Long> 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;
@ -1094,6 +1034,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<Long> values) {
addCriterion("actual_end_time in", values, "actualEndTime");
return (Criteria) this;
}
public Criteria andActualEndTimeNotIn(List<Long> 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;
@ -1353,6 +1353,136 @@ public class TestPlanExample {
addCriterion("automatic_status_update not between", value1, value2, "automaticStatusUpdate");
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<String> values) {
addCriterion("follow_people in", values, "followPeople");
return (Criteria) this;
}
public Criteria andFollowPeopleNotIn(List<String> 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 andRepeatCaseIsNull() {
addCriterion("repeat_case is null");
return (Criteria) this;
}
public Criteria andRepeatCaseIsNotNull() {
addCriterion("repeat_case is not null");
return (Criteria) this;
}
public Criteria andRepeatCaseEqualTo(Boolean value) {
addCriterion("repeat_case =", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseNotEqualTo(Boolean value) {
addCriterion("repeat_case <>", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseGreaterThan(Boolean value) {
addCriterion("repeat_case >", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseGreaterThanOrEqualTo(Boolean value) {
addCriterion("repeat_case >=", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseLessThan(Boolean value) {
addCriterion("repeat_case <", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseLessThanOrEqualTo(Boolean value) {
addCriterion("repeat_case <=", value, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseIn(List<Boolean> values) {
addCriterion("repeat_case in", values, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseNotIn(List<Boolean> values) {
addCriterion("repeat_case not in", values, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseBetween(Boolean value1, Boolean value2) {
addCriterion("repeat_case between", value1, value2, "repeatCase");
return (Criteria) this;
}
public Criteria andRepeatCaseNotBetween(Boolean value1, Boolean value2) {
addCriterion("repeat_case not between", value1, value2, "repeatCase");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -13,14 +13,16 @@
<result column="executor_match_rule" jdbcType="VARCHAR" property="executorMatchRule" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="actual_end_time" jdbcType="BIGINT" property="actualEndTime" />
<result column="planned_start_time" jdbcType="BIGINT" property="plannedStartTime" />
<result column="planned_end_time" jdbcType="BIGINT" property="plannedEndTime" />
<result column="actual_start_time" jdbcType="BIGINT" property="actualStartTime" />
<result column="actual_end_time" jdbcType="BIGINT" property="actualEndTime" />
<result column="creator" jdbcType="VARCHAR" property="creator" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="execution_times" jdbcType="INTEGER" property="executionTimes" />
<result column="automatic_status_update" jdbcType="BIT" property="automaticStatusUpdate" />
<result column="follow_people" jdbcType="VARCHAR" property="followPeople" />
<result column="repeat_case" jdbcType="BIT" property="repeatCase" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanWithBLOBs">
<result column="tags" jdbcType="LONGVARCHAR" property="tags" />
@ -86,10 +88,10 @@
</where>
</sql>
<sql id="Base_Column_List">
id
, workspace_id, report_id, `name`, description, `status`, stage, 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, automatic_status_update
id, workspace_id, report_id, `name`, description, `status`, stage, test_case_match_rule,
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,
follow_people, repeat_case
</sql>
<sql id="Blob_Column_List">
tags, report_summary, report_config
@ -143,22 +145,24 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanWithBLOBs">
insert into test_plan (id, workspace_id, report_id,
`name`, description, `status`,
stage, 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,
automatic_status_update, tags, report_summary,
report_config)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{stage,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},
#{automaticStatusUpdate,jdbcType=BIT}, #{tags,jdbcType=LONGVARCHAR}, #{reportSummary,jdbcType=LONGVARCHAR},
#{reportConfig,jdbcType=LONGVARCHAR})
insert into test_plan (id, workspace_id, report_id,
`name`, description, `status`,
stage, test_case_match_rule, 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, follow_people, repeat_case,
tags, report_summary, report_config
)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{stage,jdbcType=VARCHAR}, #{testCaseMatchRule,jdbcType=VARCHAR}, #{executorMatchRule,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{plannedStartTime,jdbcType=BIGINT},
#{plannedEndTime,jdbcType=BIGINT}, #{actualStartTime,jdbcType=BIGINT}, #{actualEndTime,jdbcType=BIGINT},
#{creator,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{executionTimes,jdbcType=INTEGER},
#{automaticStatusUpdate,jdbcType=BIT}, #{followPeople,jdbcType=VARCHAR}, #{repeatCase,jdbcType=BIT},
#{tags,jdbcType=LONGVARCHAR}, #{reportSummary,jdbcType=LONGVARCHAR}, #{reportConfig,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanWithBLOBs">
insert into test_plan
@ -196,9 +200,6 @@
<if test="updateTime != null">
update_time,
</if>
<if test="actualEndTime != null">
actual_end_time,
</if>
<if test="plannedStartTime != null">
planned_start_time,
</if>
@ -208,6 +209,9 @@
<if test="actualStartTime != null">
actual_start_time,
</if>
<if test="actualEndTime != null">
actual_end_time,
</if>
<if test="creator != null">
creator,
</if>
@ -220,6 +224,12 @@
<if test="automaticStatusUpdate != null">
automatic_status_update,
</if>
<if test="followPeople != null">
follow_people,
</if>
<if test="repeatCase != null">
repeat_case,
</if>
<if test="tags != null">
tags,
</if>
@ -264,9 +274,6 @@
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="actualEndTime != null">
#{actualEndTime,jdbcType=BIGINT},
</if>
<if test="plannedStartTime != null">
#{plannedStartTime,jdbcType=BIGINT},
</if>
@ -276,6 +283,9 @@
<if test="actualStartTime != null">
#{actualStartTime,jdbcType=BIGINT},
</if>
<if test="actualEndTime != null">
#{actualEndTime,jdbcType=BIGINT},
</if>
<if test="creator != null">
#{creator,jdbcType=VARCHAR},
</if>
@ -288,6 +298,12 @@
<if test="automaticStatusUpdate != null">
#{automaticStatusUpdate,jdbcType=BIT},
</if>
<if test="followPeople != null">
#{followPeople,jdbcType=VARCHAR},
</if>
<if test="repeatCase != null">
#{repeatCase,jdbcType=BIT},
</if>
<if test="tags != null">
#{tags,jdbcType=LONGVARCHAR},
</if>
@ -341,9 +357,6 @@
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.actualEndTime != null">
actual_end_time = #{record.actualEndTime,jdbcType=BIGINT},
</if>
<if test="record.plannedStartTime != null">
planned_start_time = #{record.plannedStartTime,jdbcType=BIGINT},
</if>
@ -353,6 +366,9 @@
<if test="record.actualStartTime != null">
actual_start_time = #{record.actualStartTime,jdbcType=BIGINT},
</if>
<if test="record.actualEndTime != null">
actual_end_time = #{record.actualEndTime,jdbcType=BIGINT},
</if>
<if test="record.creator != null">
creator = #{record.creator,jdbcType=VARCHAR},
</if>
@ -365,6 +381,12 @@
<if test="record.automaticStatusUpdate != null">
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT},
</if>
<if test="record.followPeople != null">
follow_people = #{record.followPeople,jdbcType=VARCHAR},
</if>
<if test="record.repeatCase != null">
repeat_case = #{record.repeatCase,jdbcType=BIT},
</if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=LONGVARCHAR},
</if>
@ -392,14 +414,16 @@
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},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
repeat_case = #{record.repeatCase,jdbcType=BIT},
tags = #{record.tags,jdbcType=LONGVARCHAR},
report_summary = #{record.reportSummary,jdbcType=LONGVARCHAR},
report_config = #{record.reportConfig,jdbcType=LONGVARCHAR}
@ -410,24 +434,26 @@
<update id="updateByExample" parameterType="map">
update test_plan
set id = #{record.id,jdbcType=VARCHAR},
workspace_id = #{record.workspaceId,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
stage = #{record.stage,jdbcType=VARCHAR},
test_case_match_rule = #{record.testCaseMatchRule,jdbcType=VARCHAR},
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},
creator = #{record.creator,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
execution_times = #{record.executionTimes,jdbcType=INTEGER},
automatic_status_update = #{record.automaticStatusUpdate,jdbcType=BIT}
workspace_id = #{record.workspaceId,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
stage = #{record.stage,jdbcType=VARCHAR},
test_case_match_rule = #{record.testCaseMatchRule,jdbcType=VARCHAR},
executor_match_rule = #{record.executorMatchRule,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,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},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
repeat_case = #{record.repeatCase,jdbcType=BIT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -465,9 +491,6 @@
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="actualEndTime != null">
actual_end_time = #{actualEndTime,jdbcType=BIGINT},
</if>
<if test="plannedStartTime != null">
planned_start_time = #{plannedStartTime,jdbcType=BIGINT},
</if>
@ -477,6 +500,9 @@
<if test="actualStartTime != null">
actual_start_time = #{actualStartTime,jdbcType=BIGINT},
</if>
<if test="actualEndTime != null">
actual_end_time = #{actualEndTime,jdbcType=BIGINT},
</if>
<if test="creator != null">
creator = #{creator,jdbcType=VARCHAR},
</if>
@ -489,6 +515,12 @@
<if test="automaticStatusUpdate != null">
automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT},
</if>
<if test="followPeople != null">
follow_people = #{followPeople,jdbcType=VARCHAR},
</if>
<if test="repeatCase != null">
repeat_case = #{repeatCase,jdbcType=BIT},
</if>
<if test="tags != null">
tags = #{tags,jdbcType=LONGVARCHAR},
</if>
@ -513,14 +545,16 @@
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},
follow_people = #{followPeople,jdbcType=VARCHAR},
repeat_case = #{repeatCase,jdbcType=BIT},
tags = #{tags,jdbcType=LONGVARCHAR},
report_summary = #{reportSummary,jdbcType=LONGVARCHAR},
report_config = #{reportConfig,jdbcType=LONGVARCHAR}
@ -528,24 +562,26 @@
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlan">
update test_plan
set workspace_id = #{workspaceId,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
stage = #{stage,jdbcType=VARCHAR},
test_case_match_rule = #{testCaseMatchRule,jdbcType=VARCHAR},
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},
creator = #{creator,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
execution_times = #{executionTimes,jdbcType=INTEGER},
automatic_status_update = #{automaticStatusUpdate,jdbcType=BIT}
set workspace_id = #{workspaceId,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
stage = #{stage,jdbcType=VARCHAR},
test_case_match_rule = #{testCaseMatchRule,jdbcType=VARCHAR},
executor_match_rule = #{executorMatchRule,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,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},
follow_people = #{followPeople,jdbcType=VARCHAR},
repeat_case = #{repeatCase,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -427,17 +427,19 @@
</if>
</foreach>
</if>
and exists (
select id
from api_test_case c
where c.api_definition_id = api_definition.id
and not exists (
select id
from test_plan_api_case t
where t.api_case_id = c.id
and t.test_plan_id = #{request.planId}
)
)
<if test="!request.repeatCase">
and exists (
select id
from api_test_case c
where c.api_definition_id = api_definition.id
and not exists (
select id
from test_plan_api_case t
where t.api_case_id = c.id
and t.test_plan_id = #{request.planId}
)
)
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by

View File

@ -296,7 +296,7 @@
<if test="request.executeStatus == 'executePass'">
and api_scenario.last_result = 'Success'
</if>
<if test="request.notInTestPlan == true ">
<if test="request.notInTestPlan">
and api_scenario.id not in (
select pc.api_scenario_id
from test_plan_api_scenario pc

View File

@ -127,9 +127,13 @@
select test_case.id, test_case.name, test_case.priority, test_case.type, test_case.review_status,
test_case.num, test_case.custom_num, test_case.priority, test_case.tags, test_case.create_time, test_case.update_time
from test_case as test_case
left join test_plan_test_case as T2 on test_case.id=T2.case_id and T2.plan_id =#{request.planId}
<include refid="notInQueryWhereCondition"></include>
and T2.case_id is null
<if test="!request.repeatCase">
left join test_plan_test_case as T2 on test_case.id=T2.case_id and T2.plan_id =#{request.planId}
</if>
<include refid="notInQueryWhereCondition"/>
<if test="!request.repeatCase">
and T2.case_id is null
</if>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>

View File

@ -17,9 +17,11 @@
select load_test.id
from load_test
where load_test.project_id = #{request.projectId}
and load_test.id not in (
select tplc.load_case_id from test_plan_load_case tplc where tplc.test_plan_id = #{request.testPlanId}
)
<if test="!request.repeatCase">
and load_test.id not in (
select tplc.load_case_id from test_plan_load_case tplc where tplc.test_plan_id = #{request.testPlanId}
)
</if>
<if test="request.name != null and request.name != ''">
and load_test.name like CONCAT('%', #{request.name},'%')
</if>

View File

@ -121,8 +121,8 @@ public class TestCaseController {
@PostMapping("/relate/{goPage}/{pageSize}")
public Pager<List<TestCase>> getTestCaseRelateList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryTestCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testCaseService.getTestCaseRelateList(request));
// Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return testCaseService.getTestCaseRelateList(request, goPage, pageSize);
}
@PostMapping("/relationship/relate/{goPage}/{pageSize}")

View File

@ -31,8 +31,7 @@ public class TestPlanLoadCaseController {
@PostMapping("/relevance/list/{goPage}/{pageSize}")
public Pager<List<LoadTest>> relevanceList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody LoadCaseRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testPlanLoadCaseService.relevanceList(request));
return testPlanLoadCaseService.relevanceList(request, goPage, pageSize);
}
@PostMapping("/relevance")

View File

@ -49,8 +49,7 @@ public class TestPlanScenarioCaseController {
@PostMapping("/relevance/list/{goPage}/{pageSize}")
public Pager<List<ApiScenarioDTO>> relevanceList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiScenarioRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testPlanScenarioCaseService.relevanceList(request));
return testPlanScenarioCaseService.relevanceList(request, goPage, pageSize);
}
@GetMapping("/delete/{id}")

View File

@ -18,6 +18,9 @@ public class QueryTestCaseRequest extends BaseQueryRequest {
private List<String> testCaseIds;
// 测试计划是否允许重复
private boolean repeatCase;
private String planId;
private String issuesId;

View File

@ -19,4 +19,7 @@ public class LoadCaseRequest extends TestPlanLoadCase {
private Map<String, List<String>> filters;
private List<OrderRequest> orders;
private Map<String, Object> combine;
// 测试计划是否允许重复
private boolean repeatCase;
}

View File

@ -142,6 +142,9 @@ public class TestCaseService {
private PerformanceTestService performanceTestService;
@Resource
private TestCaseFollowMapper testCaseFollowMapper;
@Resource
@Lazy
private TestPlanService testPlanService;
private void setNode(TestCaseWithBLOBs testCase) {
if (StringUtils.isEmpty(testCase.getNodeId()) || "default-module".equals(testCase.getNodeId())) {
@ -452,12 +455,16 @@ public class TestCaseService {
* @param request
* @return
*/
public List<TestCase> getTestCaseRelateList(QueryTestCaseRequest request) {
public Pager<List<TestCase>> getTestCaseRelateList(QueryTestCaseRequest request, int goPage, int pageSize) {
setDefaultOrder(request);
request.getOrders().forEach(order -> {
order.setPrefix("test_case");
});
return getTestCaseByNotInPlan(request);
if (testPlanService.isAllowedRepeatCase(request.getPlanId())) {
request.setRepeatCase(true);
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, getTestCaseByNotInPlan(request));
}
public List<TestCase> getTestCaseByNotInPlan(QueryTestCaseRequest request) {

View File

@ -90,7 +90,8 @@ public class TestPlanApiCaseService {
@Resource
private ResourcePoolCalculation resourcePoolCalculation;
@Resource
private NodeKafkaService nodeKafkaService;
@Lazy
private TestPlanService testPlanService;
@Resource
private TestResourcePoolMapper testResourcePoolMapper;
@ -138,12 +139,14 @@ public class TestPlanApiCaseService {
}
public Pager<List<ApiTestCaseDTO>> relevanceList(int goPage, int pageSize, ApiTestCaseRequest request) {
List<String> ids = apiTestCaseService.selectIdsNotExistsInPlan(request.getProjectId(), request.getPlanId());
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
if (CollectionUtils.isEmpty(ids)) {
return PageUtils.setPageInfo(page, new ArrayList<>());
if (!testPlanService.isAllowedRepeatCase(request.getPlanId())) { // 不允许重复关联
List<String> ids = apiTestCaseService.selectIdsNotExistsInPlan(request.getProjectId(), request.getPlanId());
if (CollectionUtils.isEmpty(ids)) {
return PageUtils.setPageInfo(PageHelper.startPage(goPage, pageSize, true), new ArrayList<>());
}
request.setIds(ids);
}
request.setIds(ids);
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, apiTestCaseService.listSimple(request));
}

View File

@ -1,6 +1,8 @@
package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
@ -10,9 +12,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanLoadCaseMapper;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.commons.utils.TestPlanUtils;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.log.vo.OperatingLogDetails;
@ -30,6 +30,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -57,16 +58,23 @@ public class TestPlanLoadCaseService {
private LoadTestReportMapper loadTestReportMapper;
@Resource
private LoadTestMapper loadTestMapper;
@Resource
@Lazy
private TestPlanService testPlanService;
public List<LoadTest> relevanceList(LoadCaseRequest request) {
public Pager<List<LoadTest>> relevanceList(LoadCaseRequest request, int goPage, int pageSize) {
List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders());
orders.forEach(i -> i.setPrefix("load_test"));
request.setOrders(orders);
if (testPlanService.isAllowedRepeatCase(request.getTestPlanId())) {
request.setRepeatCase(true);
}
List<String> ids = extTestPlanLoadCaseMapper.selectIdsNotInPlan(request);
if (CollectionUtils.isEmpty(ids)) {
return new ArrayList<>();
return PageUtils.setPageInfo(PageHelper.startPage(goPage, pageSize, true), new ArrayList<>());
}
return performanceTestService.getLoadTestListByIds(ids);
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, performanceTestService.getLoadTestListByIds(ids));
}
public List<TestPlanLoadCaseDTO> list(LoadCaseRequest request) {

View File

@ -2,6 +2,8 @@ package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiScenarioReportService;
@ -14,6 +16,8 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.TestPlanUtils;
import io.metersphere.controller.request.ResetOrderRequest;
@ -26,6 +30,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -55,6 +60,9 @@ public class TestPlanScenarioCaseService {
private ApiTestEnvironmentMapper apiTestEnvironmentMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
@Lazy
private TestPlanService testPlanService;
public List<ApiScenarioDTO> list(TestPlanScenarioRequest request) {
request.setProjectId(null);
@ -107,10 +115,13 @@ public class TestPlanScenarioCaseService {
return idList;
}
public List<ApiScenarioDTO> relevanceList(ApiScenarioRequest request) {
public Pager<List<ApiScenarioDTO>> relevanceList(ApiScenarioRequest request, int goPage, int pageSize) {
request.setNotInTestPlan(true);
List<ApiScenarioDTO> list = apiAutomationService.list(request);
return list;
if (testPlanService.isAllowedRepeatCase(request.getPlanId())) {
request.setNotInTestPlan(false);
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, apiAutomationService.list(request));
}
public int delete(String id) {

View File

@ -26,7 +26,6 @@ import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.IssueTemplateDao;
@ -36,7 +35,6 @@ import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestPlanReference;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.performance.base.*;
import io.metersphere.performance.dto.LoadTestExportJmx;
@ -2072,4 +2070,8 @@ public class TestPlanService {
userExample.createCriteria().andIdIn(userIds);
return userMapper.selectByExample(userExample);
}
public boolean isAllowedRepeatCase(String planId) {
return testPlanMapper.selectByPrimaryKey(planId).getRepeatCase();
}
}

View File

@ -356,7 +356,7 @@ public class TestReviewTestCaseService {
}
public void initOrderField() {
ServiceUtils.initOrderField(TestCaseReviewTestCase.class, TestCaseReviewMapper.class,
ServiceUtils.initOrderField(TestCaseReviewTestCase.class, TestCaseReviewTestCaseMapper.class,
extTestReviewCaseMapper::selectReviewIds,
extTestReviewCaseMapper::getIdsOrderByUpdateTime);
}

View File

@ -1,6 +1,11 @@
ALTER TABLE mock_expect_config ADD COLUMN expect_num varchar(50);
ALTER TABLE test_plan ADD COLUMN repeat_case TINYINT(1) DEFAULT 0 COMMENT '是否允许重复添加用例';
ALTER TABLE test_plan_api_case DROP KEY plan_id_case_id;
ALTER TABLE test_plan_load_case DROP KEY plan_load_case_id;
ALTER TABLE test_plan_api_scenario DROP KEY plan_id_scenario_id;
insert into user_group_permission (id, group_id, permission_id, module_id)
values (UUID(), 'ws_admin', 'WORKSPACE_PROJECT_MANAGER:READ+UPLOAD_JAR', 'WORKSPACE_PROJECT_MANAGER');
insert into user_group_permission (id, group_id, permission_id, module_id)
values (UUID(), 'ws_member', 'WORKSPACE_PROJECT_MANAGER:READ+UPLOAD_JAR', 'WORKSPACE_PROJECT_MANAGER');
values (UUID(), 'ws_member', 'WORKSPACE_PROJECT_MANAGER:READ+UPLOAD_JAR', 'WORKSPACE_PROJECT_MANAGER');

View File

@ -88,6 +88,18 @@
<ms-instructions-icon :content="'当功能用例关联的接口或性能用例在测试计划执行后,自动更新功能用例的状态'"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
:label="$t('允许关联重复用例')"
label-width="140px"
prop="automaticStatusUpdate">
<el-switch v-model="form.repeatCase"/>
<ms-instructions-icon :content="'是否允许同一个测试计划中多次关联相同用例'"/>
</el-form-item>
</el-col>
</el-row>
<el-row type="flex" justify="left" :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('test_track.plan.follow_people')" :label-width="formLabelWidth"
prop="follows">
@ -175,6 +187,7 @@ export default {
plannedStartTime: '',
plannedEndTime: '',
automaticStatusUpdate: false,
repeatCase: false,
follows: []
},
rules: {