feat(功能用例): 用例详情获取缺陷列表&关联缺陷&取消关联
This commit is contained in:
parent
a4e739eee8
commit
d076c43580
|
@ -0,0 +1,38 @@
|
|||
package io.metersphere.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
public class BugProviderDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "缺陷id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "缺陷名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "处理人")
|
||||
private String createUser;
|
||||
|
||||
@Schema(description = "处理人姓名")
|
||||
private String createUserName;
|
||||
|
||||
@Schema(description = "缺陷状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private String tags;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Long createTime;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package io.metersphere.provider;
|
||||
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.request.AssociateBugRequest;
|
||||
import io.metersphere.request.BugPageProviderRequest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
public interface BaseAssociateBugProvider {
|
||||
|
||||
/**
|
||||
* 获取尚未关联的缺陷列表
|
||||
*
|
||||
* @param sourceType 关联关系表表名
|
||||
* @param sourceName 关联关系表主动关联方字段名称
|
||||
* @param bugColumnName 缺陷id 在关联关系表的字段名称
|
||||
* @param bugPageProviderRequest 缺陷搜索条件
|
||||
* @return List<BugProviderDTO>
|
||||
*/
|
||||
List<BugProviderDTO> getBugList(String sourceType, String sourceName, String bugColumnName, BugPageProviderRequest bugPageProviderRequest);
|
||||
|
||||
|
||||
/**
|
||||
* 获取选中的缺陷id 列表
|
||||
*
|
||||
* @param request request
|
||||
* @param deleted deleted
|
||||
* @return
|
||||
*/
|
||||
List<String> getSelectBugs(AssociateBugRequest request, boolean deleted);
|
||||
|
||||
|
||||
/**
|
||||
* 关联用例处理
|
||||
*
|
||||
* @param ids 缺陷id集合
|
||||
* @param userId 用户id
|
||||
* @param caseId 用例id
|
||||
*/
|
||||
void handleAssociateBug(List<String> ids, String userId, String caseId);
|
||||
|
||||
/**
|
||||
* 取消关联缺陷
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void disassociateBug(String id);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package io.metersphere.request;
|
||||
|
||||
import io.metersphere.validation.groups.Created;
|
||||
import io.metersphere.validation.groups.Updated;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
public class AssociateBugRequest extends BaseProviderCondition {
|
||||
|
||||
@Schema(description = "不处理的ID")
|
||||
List<String> excludeIds;
|
||||
|
||||
@Schema(description = "选择的ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Valid
|
||||
private List<
|
||||
@NotBlank(message = "{id must not be blank}", groups = {Created.class, Updated.class})
|
||||
String
|
||||
> selectIds;
|
||||
|
||||
@Schema(description = "是否选择所有数据")
|
||||
private boolean selectAll;
|
||||
|
||||
|
||||
@Schema(description = "要关联的用例选择的项目id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.id.not_blank}")
|
||||
private String caseId;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package io.metersphere.request;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugPageProviderRequest implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Min(value = 1, message = "当前页码必须大于0")
|
||||
@Schema(description = "当前页码")
|
||||
private int current;
|
||||
|
||||
@Min(value = 5, message = "每页显示条数必须不小于5")
|
||||
@Max(value = 500, message = "每页显示条数不能大于500")
|
||||
@Schema(description = "每页显示条数")
|
||||
private int pageSize;
|
||||
|
||||
@Schema(description = "排序字段(model中的字段 : asc/desc)")
|
||||
private Map<@Valid @Pattern(regexp = "^[A-Za-z]+$") String, @Valid @NotBlank String> sort;
|
||||
|
||||
@Schema(description = "关键字")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "匹配模式 所有/任一", allowableValues = {"AND", "OR"})
|
||||
private String searchMode = "AND";
|
||||
|
||||
@Schema(description = "过滤字段")
|
||||
private Map<String, List<String>> filter;
|
||||
|
||||
@Schema(description = "高级搜索")
|
||||
private Map<String, Object> combine;
|
||||
|
||||
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "关联关系表里主ID eg:功能用例关联缺陷时为功能用例id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.id.not_blank}")
|
||||
private String sourceId;
|
||||
|
||||
public String getSortString() {
|
||||
if (sort == null || sort.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : sort.entrySet()) {
|
||||
String column = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey());
|
||||
sb.append(column)
|
||||
.append(StringUtils.SPACE)
|
||||
.append(StringUtils.equalsIgnoreCase(entry.getValue(), "DESC") ? "DESC" : "ASC")
|
||||
.append(",");
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,11 @@
|
|||
<artifactId>metersphere-sdk</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.metersphere</groupId>
|
||||
<artifactId>metersphere-provider</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.metersphere</groupId>
|
||||
<artifactId>metersphere-system-setting</artifactId>
|
||||
|
|
|
@ -4,6 +4,9 @@ import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
|||
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.bug.dto.response.BugTagEditDTO;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.request.AssociateBugRequest;
|
||||
import io.metersphere.request.BugPageProviderRequest;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -44,6 +47,7 @@ public interface ExtBugMapper {
|
|||
|
||||
/**
|
||||
* 获取缺陷标签列表
|
||||
*
|
||||
* @param ids 缺陷ID集合
|
||||
* @return 缺陷标签列表
|
||||
*/
|
||||
|
@ -51,8 +55,13 @@ public interface ExtBugMapper {
|
|||
|
||||
/**
|
||||
* 批量更新缺陷
|
||||
*
|
||||
* @param request 请求参数
|
||||
* @param ids 缺陷ID集合
|
||||
*/
|
||||
void batchUpdate(@Param("request") BugBatchUpdateRequest request, @Param("ids") List<String> ids);
|
||||
|
||||
List<BugProviderDTO> listByProviderRequest(@Param("table") String sourceType, @Param("sourceName") String sourceName, @Param("bugColumnName") String bugColumnName, @Param("request") BugPageProviderRequest bugPageProviderRequest, @Param("deleted") boolean deleted);
|
||||
|
||||
List<String> getIdsByProvider(@Param("request") AssociateBugRequest request, @Param("deleted") boolean deleted);
|
||||
}
|
||||
|
|
|
@ -188,5 +188,52 @@
|
|||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="listByProviderRequest" resultType="io.metersphere.dto.BugProviderDTO">
|
||||
SELECT
|
||||
b.id id,
|
||||
b.title title,
|
||||
b.create_user createUser,
|
||||
u.`name` name,
|
||||
b.`status` status,
|
||||
b.tag tag,
|
||||
b.create_time createTime
|
||||
FROM
|
||||
bug b
|
||||
LEFT JOIN `user` u ON b.create_user = u.id
|
||||
WHERE
|
||||
b.deleted = #{deleted}
|
||||
AND b.id NOT IN
|
||||
(
|
||||
select associate.${bugColumnName} from ${table} associate where associate.${sourceName} = #{request.sourceId}
|
||||
)
|
||||
<include refid="queryWhereConditionByProvider"/>
|
||||
</select>
|
||||
|
||||
|
||||
<select id="getIdsByProvider" resultType="java.lang.String">
|
||||
SELECT
|
||||
b.id
|
||||
FROM
|
||||
bug b
|
||||
WHERE b.deleted =#{deleted}
|
||||
<include refid="queryWhereConditionByProvider"/>
|
||||
</select>
|
||||
|
||||
<sql id="queryWhereConditionByProvider">
|
||||
<if test="request.projectId != null">
|
||||
and b.project_id = #{request.projectId}
|
||||
</if>
|
||||
<if test="request.keyword != null">
|
||||
and (
|
||||
b.title like concat('%', #{request.keyword},'%')
|
||||
or b.num like concat('%', #{request.keyword},'%')
|
||||
)
|
||||
</if>
|
||||
<include refid="filter"/>
|
||||
<include refid="combine">
|
||||
<property name="condition" value="request.combine"/>
|
||||
</include>
|
||||
</sql>
|
||||
</mapper>
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package io.metersphere.bug.provider;
|
||||
|
||||
|
||||
import io.metersphere.bug.domain.BugRelationCase;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.bug.mapper.ExtBugMapper;
|
||||
import io.metersphere.bug.service.BugRelateCaseService;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.provider.BaseAssociateBugProvider;
|
||||
import io.metersphere.request.AssociateBugRequest;
|
||||
import io.metersphere.request.BugPageProviderRequest;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Service
|
||||
public class AssociateBugProvider implements BaseAssociateBugProvider {
|
||||
@Resource
|
||||
private ExtBugMapper extBugMapper;
|
||||
@Resource
|
||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
||||
@Resource
|
||||
private BugRelateCaseService bugRelateCaseService;
|
||||
|
||||
|
||||
@Override
|
||||
public List<BugProviderDTO> getBugList(String sourceType, String sourceName, String bugColumnName, BugPageProviderRequest bugPageProviderRequest) {
|
||||
return extBugMapper.listByProviderRequest(sourceType, sourceName, bugColumnName, bugPageProviderRequest, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSelectBugs(AssociateBugRequest request, boolean deleted) {
|
||||
if (request.isSelectAll()) {
|
||||
List<String> ids = extBugMapper.getIdsByProvider(request, deleted);
|
||||
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
|
||||
ids.removeAll(request.getExcludeIds());
|
||||
}
|
||||
return ids;
|
||||
} else {
|
||||
return request.getSelectIds();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAssociateBug(List<String> ids, String userId, String caseId) {
|
||||
List<BugRelationCase> list = new ArrayList<>();
|
||||
ids.forEach(id -> {
|
||||
BugRelationCase bugRelationCase = new BugRelationCase();
|
||||
bugRelationCase.setId(IDGenerator.nextStr());
|
||||
bugRelationCase.setBugId(id);
|
||||
bugRelationCase.setCaseId(caseId);
|
||||
bugRelationCase.setCaseType("FUNCTIONAL");
|
||||
bugRelationCase.setCreateUser(userId);
|
||||
bugRelationCase.setCreateTime(System.currentTimeMillis());
|
||||
bugRelationCase.setUpdateTime(System.currentTimeMillis());
|
||||
list.add(bugRelationCase);
|
||||
});
|
||||
bugRelationCaseMapper.batchInsert(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disassociateBug(String id) {
|
||||
bugRelateCaseService.unRelate(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.provider.AssociateBugProvider;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.request.AssociateBugRequest;
|
||||
import io.metersphere.request.BugPageProviderRequest;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@AutoConfigureMockMvc
|
||||
public class AssociateBugProviderTests extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private AssociateBugProvider associateBugProvider;
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@Sql(scripts = {"/dml/init_bug_relation_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
public void getBugList() throws Exception {
|
||||
BugPageProviderRequest request = new BugPageProviderRequest();
|
||||
request.setSourceId("wx_associate_case_id_1");
|
||||
request.setProjectId("project_wx_associate_test");
|
||||
request.setCurrent(1);
|
||||
request.setPageSize(10);
|
||||
List<BugProviderDTO> bugList = associateBugProvider.getBugList("bug_relation_case", "case_id", "bug_id", request);
|
||||
String jsonString = JSON.toJSONString(bugList);
|
||||
System.out.println(jsonString);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void getSelectBugs() throws Exception {
|
||||
AssociateBugRequest request = new AssociateBugRequest();
|
||||
request.setCaseId("wx_associate_case_id_1");
|
||||
request.setProjectId("project_wx_associate_test");
|
||||
request.setSelectAll(true);
|
||||
List<String> list = associateBugProvider.getSelectBugs(request, false);
|
||||
String jsonString = JSON.toJSONString(list);
|
||||
System.out.println(jsonString);
|
||||
|
||||
request.setExcludeIds(List.of("bug_id_3"));
|
||||
List<String> list1 = associateBugProvider.getSelectBugs(request, false);
|
||||
String jsonString1 = JSON.toJSONString(list1);
|
||||
System.out.println(jsonString1);
|
||||
|
||||
request.setSelectAll(false);
|
||||
request.setSelectIds(List.of("bug_id_1", "bug_id_2"));
|
||||
List<String> list2 = associateBugProvider.getSelectBugs(request, false);
|
||||
String jsonString2 = JSON.toJSONString(list2);
|
||||
System.out.println(jsonString2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testAssociateBug() throws Exception {
|
||||
associateBugProvider.handleAssociateBug(List.of("bug_id_1", "bug_id_2"), "wx", "wx_associate_case_id_1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void testDisassociateBug() throws Exception {
|
||||
associateBugProvider.disassociateBug("wx_test_id_1");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, deleted) VALUES
|
||||
('bug_id_1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'project_wx_associate_test"', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||
('bug_id_2', 100001, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'project_wx_associate_test"', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0);
|
||||
|
||||
INSERT INTO bug_relation_case(id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time)
|
||||
VALUES ('wx_test_id_1', 'wx_1', 'bug_id_1', 'FUNCTIONAL', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('wx_test_id_2', 'wx_2', 'bug_id_1', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('wx_test_id_3', 'wx_3', 'bug_id_2', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case-1', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
|
@ -76,6 +76,9 @@ public class FunctionalCaseRelationshipController {
|
|||
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
@Operation(summary = "用例管理-功能用例-用例详情-前后置关系-取消关联")
|
||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE)
|
||||
@CheckOwner(resourceId = "#id", resourceType = "functional_case")
|
||||
public void delete(@PathVariable("id") String id) {
|
||||
functionalCaseRelationshipEdgeService.delete(id);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.functional.controller;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.dto.TestCaseProviderDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCaseTestDTO;
|
||||
import io.metersphere.functional.request.AssociateCaseModuleRequest;
|
||||
|
@ -9,9 +10,7 @@ import io.metersphere.functional.request.DisassociateOtherCaseRequest;
|
|||
import io.metersphere.functional.request.FunctionalCaseTestRequest;
|
||||
import io.metersphere.functional.service.FunctionalCaseLogService;
|
||||
import io.metersphere.functional.service.FunctionalTestCaseService;
|
||||
import io.metersphere.request.AssociateCaseModuleProviderRequest;
|
||||
import io.metersphere.request.AssociateOtherCaseRequest;
|
||||
import io.metersphere.request.TestCasePageProviderRequest;
|
||||
import io.metersphere.request.*;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||
import io.metersphere.system.log.annotation.Log;
|
||||
|
@ -27,10 +26,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -97,5 +93,31 @@ public class FunctionalTestCaseController {
|
|||
}
|
||||
|
||||
|
||||
@PostMapping("/associate/bug/page")
|
||||
@Operation(summary = "用例管理-功能用例-关联其他用例-获取缺陷列表")
|
||||
@RequiresPermissions(value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_DELETE}, logical = Logical.OR)
|
||||
@CheckOwner(resourceId = "#request.getProjectId", resourceType = "project")
|
||||
public Pager<List<BugProviderDTO>> associateBugList(@Validated @RequestBody BugPageProviderRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
|
||||
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc");
|
||||
return PageUtils.setPageInfo(page, functionalTestCaseService.bugPage(request));
|
||||
}
|
||||
|
||||
@PostMapping("/associate/bug")
|
||||
@Operation(summary = "用例管理-功能用例-关联其他用例-关联缺陷")
|
||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_ADD)
|
||||
@CheckOwner(resourceId = "#request.caseId", resourceType = "functional_case")
|
||||
public void associateBug(@Validated @RequestBody AssociateBugRequest request) {
|
||||
functionalTestCaseService.associateBug(request, false, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping("/disassociate/bug/{id}")
|
||||
@Operation(summary = "用例管理-功能用例-关联其他用例-取消关联缺陷")
|
||||
@Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disassociateBugLog(#id)", msClass = FunctionalCaseLogService.class)
|
||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_ADD)
|
||||
@CheckOwner(resourceId = "#id", resourceType = "functional_case")
|
||||
public void disassociateBug(@PathVariable String id) {
|
||||
functionalTestCaseService.disassociateBug(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,6 +69,15 @@
|
|||
|
||||
|
||||
<sql id="queryWhereCondition">
|
||||
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
|
||||
functional_case.module_id in
|
||||
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
|
||||
#{moduleId}
|
||||
</foreach>
|
||||
<include refid="queryType">
|
||||
<property name="searchMode" value="request.searchMode"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="request.keyword != null">
|
||||
(
|
||||
functional_case.name like concat('%', #{request.keyword},'%')
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
<select id="selectReviewers" resultType="io.metersphere.functional.dto.ReviewsDTO">
|
||||
SELECT
|
||||
case_id,
|
||||
GROUP_CONCAT( user_id ),
|
||||
GROUP_CONCAT( `user`.NAME )
|
||||
case_id caseId,
|
||||
GROUP_CONCAT( user_id ) userIds,
|
||||
GROUP_CONCAT( `user`.NAME ) userNames
|
||||
FROM
|
||||
case_review_functional_case_user crfcu
|
||||
LEFT JOIN `user` ON crfcu.user_id = `user`.id
|
||||
|
|
|
@ -7,6 +7,7 @@ import lombok.Data;
|
|||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
|
@ -23,4 +24,7 @@ public class ReviewFunctionalCasePageRequest extends BasePageRequest implements
|
|||
|
||||
@Schema(description = "是否只看我的", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Boolean viewFlag;
|
||||
|
||||
@Schema(description = "模块id")
|
||||
private List<String> moduleIds;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
import io.metersphere.api.mapper.ApiTestCaseMapper;
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.metersphere.bug.domain.BugRelationCase;
|
||||
import io.metersphere.bug.mapper.BugMapper;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.functional.domain.*;
|
||||
import io.metersphere.functional.dto.BaseFunctionalCaseBatchDTO;
|
||||
import io.metersphere.functional.dto.FunctionalCaseHistoryLogDTO;
|
||||
|
@ -48,7 +52,9 @@ public class FunctionalCaseLogService {
|
|||
private FileAssociationMapper fileAssociationMapper;
|
||||
|
||||
@Resource
|
||||
private ApiTestCaseMapper apiTestCaseMapper;
|
||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
||||
@Resource
|
||||
private BugMapper bugMapper;
|
||||
|
||||
|
||||
//TODO 日志(需要修改)
|
||||
|
@ -374,4 +380,25 @@ public class FunctionalCaseLogService {
|
|||
return request.getSelectIds();
|
||||
}
|
||||
}
|
||||
|
||||
public LogDTO disassociateBugLog(String id) {
|
||||
BugRelationCase bugRelationCase = bugRelationCaseMapper.selectByPrimaryKey(id);
|
||||
if (bugRelationCase != null) {
|
||||
Bug bug = bugMapper.selectByPrimaryKey(bugRelationCase.getBugId());
|
||||
LogDTO dto = new LogDTO(
|
||||
null,
|
||||
null,
|
||||
bugRelationCase.getBugId(),
|
||||
null,
|
||||
OperationLogType.DISASSOCIATE.name(),
|
||||
OperationLogModule.FUNCTIONAL_CASE,
|
||||
bug.getTitle()+"缺陷");
|
||||
|
||||
dto.setPath("/functional/case/test/disassociate/bug/"+id);
|
||||
dto.setMethod(HttpMethodConstants.GET.name());
|
||||
dto.setOriginalValue(JSON.toJSONBytes(bugRelationCase));
|
||||
return dto;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
import io.metersphere.api.domain.ApiTestCase;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.dto.TestCaseProviderDTO;
|
||||
import io.metersphere.functional.constants.AssociateCaseType;
|
||||
import io.metersphere.functional.domain.FunctionalCaseTest;
|
||||
|
@ -13,9 +15,8 @@ import io.metersphere.functional.request.AssociateCaseModuleRequest;
|
|||
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
|
||||
import io.metersphere.functional.request.FunctionalCaseTestRequest;
|
||||
import io.metersphere.provider.BaseAssociateApiProvider;
|
||||
import io.metersphere.request.AssociateCaseModuleProviderRequest;
|
||||
import io.metersphere.request.AssociateOtherCaseRequest;
|
||||
import io.metersphere.request.TestCasePageProviderRequest;
|
||||
import io.metersphere.provider.BaseAssociateBugProvider;
|
||||
import io.metersphere.request.*;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||
|
@ -60,6 +61,10 @@ public class FunctionalTestCaseService {
|
|||
|
||||
private static final String UNPLANNED_API = "api_unplanned_request";
|
||||
|
||||
@Resource
|
||||
private BaseAssociateBugProvider baseAssociateBugProvider;
|
||||
@Resource
|
||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
||||
|
||||
/**
|
||||
* 获取功能用例未关联的接口用例列表
|
||||
|
@ -164,4 +169,34 @@ public class FunctionalTestCaseService {
|
|||
public List<FunctionalCaseTestDTO> hasAssociatePage(FunctionalCaseTestRequest request) {
|
||||
return extFunctionalCaseTestMapper.getList(request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取功能用例未关联的缺陷列表
|
||||
*
|
||||
* @param request request
|
||||
* @return
|
||||
*/
|
||||
public List<BugProviderDTO> bugPage(BugPageProviderRequest request) {
|
||||
return baseAssociateBugProvider.getBugList("bug_relation_case", "case_id", "bug_id", request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关联缺陷
|
||||
*
|
||||
* @param request request
|
||||
* @param deleted 缺陷是否删除
|
||||
* @param userId 用户id
|
||||
*/
|
||||
public void associateBug(AssociateBugRequest request, boolean deleted, String userId) {
|
||||
List<String> ids = baseAssociateBugProvider.getSelectBugs(request, deleted);
|
||||
if (CollectionUtils.isNotEmpty(ids)) {
|
||||
baseAssociateBugProvider.handleAssociateBug(ids, userId, request.getCaseId());
|
||||
}
|
||||
}
|
||||
|
||||
public void disassociateBug(String id) {
|
||||
baseAssociateBugProvider.disassociateBug(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.functional.config;
|
||||
|
||||
import io.metersphere.provider.BaseAssociateApiProvider;
|
||||
import io.metersphere.provider.BaseAssociateBugProvider;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
|
||||
|
@ -10,4 +11,7 @@ public class CaseTestConfiguration {
|
|||
@MockBean
|
||||
BaseAssociateApiProvider provider;
|
||||
|
||||
@MockBean
|
||||
BaseAssociateBugProvider baseAssociateBugProvider;
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package io.metersphere.functional.controller;
|
|||
import io.metersphere.api.domain.ApiDefinitionModule;
|
||||
import io.metersphere.api.domain.ApiTestCase;
|
||||
import io.metersphere.api.mapper.ApiDefinitionModuleMapper;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.dto.BugProviderDTO;
|
||||
import io.metersphere.dto.TestCaseProviderDTO;
|
||||
import io.metersphere.functional.constants.AssociateCaseType;
|
||||
import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
|
||||
|
@ -15,9 +17,8 @@ import io.metersphere.functional.request.AssociateCaseModuleRequest;
|
|||
import io.metersphere.functional.request.DisassociateOtherCaseRequest;
|
||||
import io.metersphere.functional.request.FunctionalCaseTestRequest;
|
||||
import io.metersphere.provider.BaseAssociateApiProvider;
|
||||
import io.metersphere.request.AssociateCaseModuleProviderRequest;
|
||||
import io.metersphere.request.AssociateOtherCaseRequest;
|
||||
import io.metersphere.request.TestCasePageProviderRequest;
|
||||
import io.metersphere.provider.BaseAssociateBugProvider;
|
||||
import io.metersphere.request.*;
|
||||
import io.metersphere.sdk.constants.FunctionalCaseExecuteResult;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
|
@ -29,6 +30,8 @@ import org.junit.jupiter.api.*;
|
|||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -54,7 +57,9 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
|
|||
|
||||
private static final String URL_HAS_CASE_PAGE = "/functional/case/test/has/associate/case/page";
|
||||
|
||||
|
||||
private static final String URL_BUG_PAGE = "/functional/case/test/associate/bug/page";
|
||||
private static final String URL_ASSOCIATE_BUG = "/functional/case/test/associate/bug";
|
||||
private static final String URL_DISASSOCIATE_BUG = "/functional/case/test/disassociate/bug/";
|
||||
|
||||
|
||||
@Resource
|
||||
|
@ -68,6 +73,10 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
|
|||
|
||||
@Resource
|
||||
private ApiDefinitionModuleMapper apiDefinitionModuleMapper;
|
||||
@Resource
|
||||
BaseAssociateBugProvider baseAssociateBugProvider;
|
||||
@Resource
|
||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
||||
|
||||
|
||||
@Test
|
||||
|
@ -293,4 +302,55 @@ public class FunctionalTestCaseControllerTests extends BaseTest {
|
|||
functionalCaseMapper.insertSelective(functionalCase);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
public void getAssociateBugList() throws Exception {
|
||||
BugPageProviderRequest request = new BugPageProviderRequest();
|
||||
request.setSourceId("wx_associate_case_id_1");
|
||||
request.setProjectId("project_wx_associate_test");
|
||||
request.setCurrent(1);
|
||||
request.setPageSize(10);
|
||||
BugProviderDTO bugProviderDTO = new BugProviderDTO();
|
||||
bugProviderDTO.setName("第二个");
|
||||
List<BugProviderDTO> operations = new ArrayList<>();
|
||||
operations.add(bugProviderDTO);
|
||||
Mockito.when(baseAssociateBugProvider.getBugList("functional_case_test", "case_id", "bug_id", request)).thenReturn(operations);
|
||||
this.requestPostWithOkAndReturn(URL_BUG_PAGE, request);
|
||||
|
||||
request.setSort(new HashMap<>() {{
|
||||
put("createTime", "desc");
|
||||
}});
|
||||
|
||||
List<BugProviderDTO> bugList = baseAssociateBugProvider.getBugList("functional_case_test", "case_id", "bug_id", request);
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_BUG_PAGE, request);
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||
List<BugProviderDTO> bugProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BugProviderDTO.class);
|
||||
Assertions.assertNotNull(bugProviderDTOS);
|
||||
System.out.println(JSON.toJSONString(bugList));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
public void testAssociateBugs() throws Exception {
|
||||
AssociateBugRequest request = new AssociateBugRequest();
|
||||
request.setCaseId("test_1");
|
||||
request.setProjectId("project_wx_associate_test");
|
||||
List<String> ids = new ArrayList<>();
|
||||
ids.add("bug_id_1");
|
||||
Mockito.when(baseAssociateBugProvider.getSelectBugs(request, false)).thenReturn(ids);
|
||||
this.requestPostWithOkAndReturn(URL_ASSOCIATE_BUG, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
@Sql(scripts = {"/dml/init_bug_relation_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
public void testDisassociateBug() throws Exception {
|
||||
//增加日志覆盖率
|
||||
this.requestGetWithOkAndReturn(URL_DISASSOCIATE_BUG + "TEST");
|
||||
this.requestGetWithOkAndReturn(URL_DISASSOCIATE_BUG + "1234");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, deleted) VALUES
|
||||
('wx_bug_id_1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'project_wx_associate_test"', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||
('wx_bug_id_2', 100001, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'project_wx_associate_test"', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0);
|
||||
|
||||
INSERT INTO bug_relation_case(id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time)
|
||||
VALUES ('TEST', 'wx_1', 'wx_bug_id_1', 'FUNCTIONAL', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('wx_test_id_22', 'wx_2', 'wx_bug_id_1', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('wx_test_id_33', 'wx_3', 'wx_bug_id_2', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case-1', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
|
@ -55,6 +55,7 @@ VALUES ('wx_test_1', 'wx_review_id_1', 'wx_case_id_1', 'PASS', 1698058347559,'ad
|
|||
INSERT INTO case_review_functional_case_user(case_id, review_id, user_id)
|
||||
VALUES ('wx_case_id_1', 'wx_review_id_1', 'admin'),
|
||||
('wx_case_id_1', 'wx_review_id_1', 'gyq'),
|
||||
('wx_test_1', 'wx_review_id_1', 'admin'),
|
||||
('gyq_case_id_3', 'wx_review_id_1', 'gyq2'),
|
||||
('gyq_case_id_4', 'wx_review_id_1', 'gyq'),
|
||||
('wx_case_id_3', 'wx_review_id_3', 'admin'),
|
||||
|
|
Loading…
Reference in New Issue