Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(测试计划): 新增批量取消关联用例的接口 #30779

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package io.metersphere.plan.controller;

import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.functional.request.ReviewFunctionalCasePageRequest;
import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.ResourceSortRequest;
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
Expand Down Expand Up @@ -86,4 +85,13 @@ public List<BaseTreeNode> getTree(@PathVariable String testPlanId) {
public Map<String, Long> moduleCount(@Validated @RequestBody TestPlanCaseRequest request) {
return testPlanFunctionalCaseService.moduleCount(request);
}
@PostMapping("/batch/disassociate")
@Operation(summary = "测试计划-计划详情-列表-批量取消关联用例")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_ASSOCIATION)
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
public TestPlanAssociationResponse batchDisassociate(@Validated @RequestBody BasePlanCaseBatchRequest request) {
testPlanManagementService.checkModuleIsOpen(request.getTestPlanId(), TestPlanResourceConfig.CHECK_TYPE_TEST_PLAN, Collections.singletonList(TestPlanResourceConfig.CONFIG_TEST_PLAN_FUNCTIONAL_CASE));
return testPlanFunctionalCaseService.disassociate(request, new LogInsertModule(SessionUtils.getUserId(), "/test-plan/functional/case/association", HttpMethodConstants.POST.name()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.plan.dto.AssociationNode;
import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
import io.metersphere.plan.dto.response.TestPlanCasePageResponse;
import io.metersphere.project.dto.NodeSortQueryParam;
Expand Down Expand Up @@ -35,4 +36,6 @@ public interface ExtTestPlanFunctionalCaseMapper {
List<FunctionalCaseModuleCountDTO> countModuleIdByRequest(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted);

long caseCount(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted);

List<String> getIds(@Param("request") BasePlanCaseBatchRequest request, @Param("deleted") boolean deleted);
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@
ORDER BY #{orderString}
</if>
</select>

<select id="getIds" resultType="java.lang.String">
SELECT
tpfc.id as id
FROM
test_plan_functional_case tpfc
LEFT JOIN functional_case ON tpfc.functional_case_id = functional_case.id
WHERE
tpfc.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = #{deleted}
<include refid="queryWhereConditionByBatchQueryRequest"/>
</select>

<select id="selectDragInfoById" resultType="io.metersphere.plan.dto.AssociationNode">
SELECT id, pos
FROM test_plan_functional_case
Expand Down Expand Up @@ -138,6 +151,35 @@
</include>
</sql>

<sql id="queryWhereConditionByBatchQueryRequest">
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and functional_case.module_id in
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
#{moduleId}
</foreach>
</if>
<if test="request.condition.keyword != null">
and (
functional_case.name like concat('%', #{request.keyword},'%')
or functional_case.num like concat('%', #{request.keyword},'%')
or functional_case.tags like concat('%', #{request.keyword},'%')
)
</if>
<include refid="filters">
<property name="filter" value="request.condition.filter"/>
</include>
<choose>
<when test='request.condition.searchMode == "AND"'>
AND <include refid="batchQueryCombine"/>
</when>
<when test='request.condition.searchMode == "OR"'>
and (
<include refid="batchQueryCombine"/>
)
</when>
</choose>
</sql>

<sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">
Expand Down Expand Up @@ -202,6 +244,16 @@
</if>
</sql>

<sql id="batchQueryCombine">
<if test="request.condition.combine != null">
<include refid="combine">
<property name="condition" value="request.condition.combine"/>
<property name="searchMode" value="request.condition.searchMode"/>
</include>
</if>
1=1
</sql>

<sql id="queryCombine">
<if test="request.combine != null">
<include refid="combine">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

import io.metersphere.bug.dto.CaseRelateBugDTO;
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.functional.service.FunctionalCaseService;
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanFunctionalCase;
import io.metersphere.plan.domain.TestPlanFunctionalCaseExample;
import io.metersphere.plan.dto.AssociationNodeSortDTO;
import io.metersphere.plan.dto.ResourceLogInsertModule;
import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.ResourceSortRequest;
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
Expand Down Expand Up @@ -42,6 +44,7 @@
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -120,6 +123,13 @@ public TestPlanAssociationResponse association(TestPlanAssociationRequest reques
}


public void deleteTestPlanResource(@Validated TestPlanResourceAssociationParam associationParam) {
TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample();
testPlanFunctionalCaseExample.createCriteria().andIdIn(associationParam.getResourceIdList());
testPlanFunctionalCaseMapper.deleteByExample(testPlanFunctionalCaseExample);
//TODO:更新执行历史的删除状态为true
}

public TestPlanResourceSortResponse sortNode(ResourceSortRequest request, LogInsertModule logInsertModule) {
TestPlanFunctionalCase dragNode = testPlanFunctionalCaseMapper.selectByPrimaryKey(request.getDragNodeId());
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
Expand Down Expand Up @@ -255,4 +265,26 @@ public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(String projectId, Strin


}

public TestPlanAssociationResponse disassociate(BasePlanCaseBatchRequest request, LogInsertModule logInsertModule) {
List<String> selectIds = doSelectIds(request);
return super.disassociate(
TestPlanResourceConstants.RESOURCE_FUNCTIONAL_CASE,
request,
logInsertModule,
selectIds,
this::deleteTestPlanResource);
}

private List<String> doSelectIds(BasePlanCaseBatchRequest request) {
if (request.isSelectAll()) {
List<String> ids = extTestPlanFunctionalCaseMapper.getIds(request, false);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());
}
return ids;
} else {
return request.getSelectIds();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.dto.*;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.ResourceSortRequest;
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
Expand Down Expand Up @@ -86,6 +87,29 @@ public TestPlanAssociationResponse association(
return response;
}

/**
* 取消关联资源od
*
* @return TestPlanAssociationResponse
*/
public TestPlanAssociationResponse disassociate(
String resourceType,
BasePlanCaseBatchRequest request,
@Validated LogInsertModule logInsertModule,
List<String>associationIdList,
Consumer<TestPlanResourceAssociationParam> disassociate) {
TestPlanAssociationResponse response = new TestPlanAssociationResponse();
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
//获取有效ID
if (CollectionUtils.isNotEmpty(associationIdList)) {
TestPlanResourceAssociationParam associationParam = new TestPlanResourceAssociationParam(associationIdList, testPlan.getProjectId(), testPlan.getId(), testPlan.getNum(), logInsertModule.getOperator());
disassociate.accept(associationParam);
response.setAssociationCount(associationIdList.size());
testPlanResourceLogService.saveDeleteLog(testPlan, new ResourceLogInsertModule(resourceType, logInsertModule));
}
return response;
}

/**
* 构建节点排序的参数
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package io.metersphere.plan.controller;

import io.metersphere.plan.domain.TestPlanFunctionalCase;
import io.metersphere.plan.domain.TestPlanFunctionalCaseExample;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest;
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -13,6 +18,7 @@

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
Expand All @@ -23,6 +29,11 @@ public class TestPlanCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_TREE_URL = "/test-plan/functional/case/tree/";
public static final String FUNCTIONAL_CASE_TREE_COUNT_URL = "/test-plan/functional/case/module/count";

public static final String FUNCTIONAL_CASE_DISASSOCIATE_URL = "/test-plan/functional/case/batch/disassociate";

@Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;

@Test
@Order(1)
@Sql(scripts = {"/dml/init_test_plan_case_relate_bug.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
Expand Down Expand Up @@ -69,4 +80,25 @@ public void testGetFunctionalCaseTreeCount() throws Exception {
}



@Test
@Order(4)
public void disassociateBatch() throws Exception {
BasePlanCaseBatchRequest request = new BasePlanCaseBatchRequest();
request.setTestPlanId("plan_1");
request.setSelectAll(true);
request.setExcludeIds(List.of("relate_case_2"));
this.requestPostWithOk(FUNCTIONAL_CASE_DISASSOCIATE_URL, request);
TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample();
testPlanFunctionalCaseExample.createCriteria().andTestPlanIdEqualTo("plan_1");
List<TestPlanFunctionalCase> testPlanFunctionalCases = testPlanFunctionalCaseMapper.selectByExample(testPlanFunctionalCaseExample);
Assertions.assertEquals(1,testPlanFunctionalCases.size());
request = new BasePlanCaseBatchRequest();
request.setTestPlanId("plan_1");
request.setSelectAll(false);
request.setSelectIds(List.of("relate_case_2"));
this.requestPostWithOk(FUNCTIONAL_CASE_DISASSOCIATE_URL, request);
testPlanFunctionalCases = testPlanFunctionalCaseMapper.selectByExample(testPlanFunctionalCaseExample);
Assertions.assertEquals(0,testPlanFunctionalCases.size());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ VALUES
INSERT INTO project_version(id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user)
values ('v3.0.0','123','v3', null, 'open', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin');

INSERT INTO project(id, num, organization_id, name, description, create_time, update_time, update_user, create_user, delete_time, deleted, delete_user, enable, module_setting)
VALUE ('123', null, 'organization_plan_associate_case_project', 'test_plan_associate_case_name', null,
UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'admin', null, false, null, true, '["bugManagement","caseManagement","apiTest","testPlan"]');


INSERT INTO `test_plan_module`(`id`, `project_id`, `name`, `parent_id`, `pos`, `create_time`, `update_time`, `create_user`, `update_user`)
VALUES
Expand Down
Loading