feat(缺陷管理): 缺陷关联用例功能
This commit is contained in:
parent
04b8228808
commit
4eac5632f7
|
@ -0,0 +1,52 @@
|
|||
package io.metersphere.sdk.constants;
|
||||
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@Getter
|
||||
public enum CaseType {
|
||||
|
||||
/**
|
||||
* 功能用例
|
||||
*/
|
||||
FUNCTIONAL_CASE("FUNCTIONAL", "test_case"),
|
||||
/**
|
||||
* 接口用例
|
||||
*/
|
||||
API_CASE("API", "api_case"),
|
||||
/**
|
||||
* 性能用例
|
||||
*/
|
||||
SCENARIO_CASE("SCENARIO", "scenario_case"),
|
||||
/**
|
||||
* UI用例
|
||||
*/
|
||||
UI_CASE("UI", "ui_case"),
|
||||
/**
|
||||
* 性能用例
|
||||
*/
|
||||
PERFORMANCE_CASE("PERFORMANCE", "performance_case");
|
||||
|
||||
private final String key;
|
||||
|
||||
private final String value;
|
||||
|
||||
CaseType(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return Translator.get(value);
|
||||
}
|
||||
|
||||
public static String getValue(String key) {
|
||||
for (CaseType caseType : CaseType.values()) {
|
||||
if (StringUtils.equals(caseType.getKey(), key)) {
|
||||
return caseType.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -95,3 +95,6 @@ bug_comment.parent_id.not_blank=缺陷评论父级ID不能为空
|
|||
bug_comment.parent.not_exist=父级评论不存在
|
||||
bug_comment.reply_user.not_blank=缺陷回复人不能为空
|
||||
bug_comment_not_exist=缺陷评论不存在
|
||||
bug_relate_case_not_found=未查询到关联的用例
|
||||
bug_relate_case_type_unknown=关联的用例类型未知, 无法查看
|
||||
bug_relate_case_permission_error=无权限查看, 请联系管理员
|
|
@ -95,3 +95,6 @@ bug_comment.parent_id.not_blank=Bug comment parent-id cannot be empty
|
|||
bug_comment.parent.not_exist=Bug comment parent does not exist
|
||||
bug_comment.reply_user.not_blank=Bug comment reply-user cannot be empty
|
||||
bug_comment_not_exist=Bug comment does not exist
|
||||
bug_relate_case_not_found=Bug related case not found
|
||||
bug_relate_case_type_unknown=Bug related case type unknown
|
||||
bug_relate_case_permission_error=No permission to show the case
|
||||
|
|
|
@ -95,3 +95,6 @@ bug_comment.parent_id.not_blank=缺陷评论父级ID不能为空
|
|||
bug_comment.parent.not_exist=父级评论不存在
|
||||
bug_comment.reply_user.not_blank=缺陷回复人不能为空
|
||||
bug_comment_not_exist=缺陷评论不存在
|
||||
bug_relate_case_not_found=未查询到关联的用例
|
||||
bug_relate_case_type_unknown=关联的用例类型未知, 无法查看
|
||||
bug_relate_case_permission_error=无用例查看权限, 请联系管理员
|
|
@ -95,4 +95,6 @@ bug_comment.parent_id.not_blank=缺陷評論父級ID不能為空
|
|||
bug_comment.parent.not_exist=父級評論不存在
|
||||
bug_comment.reply_user.not_blank=缺陷回復人不能為空
|
||||
bug_comment_not_exist=缺陷評論不存在
|
||||
|
||||
bug_relate_case_not_found=未查詢到關聯的用例
|
||||
bug_relate_case_type_unknown=關聯的用例類型未知, 無法查看
|
||||
bug_relate_case_permission_error=無權限查看, 請聯繫管理員
|
||||
|
|
|
@ -314,6 +314,7 @@ connection_expired=The connection has expired, please get it again
|
|||
api_case=Api
|
||||
performance_case=Performance
|
||||
scenario_case=Scenario
|
||||
ui_case=UI
|
||||
scenario_name_is_null=Scenario name cannot be empty
|
||||
create_user=Create user
|
||||
test_case_status=Case status
|
||||
|
|
|
@ -310,6 +310,7 @@ connection_expired=连接已失效,请重新获取
|
|||
api_case=接口用例
|
||||
performance_case=性能用例
|
||||
scenario_case=场景用例
|
||||
ui_case=UI用例
|
||||
scenario_name_is_null=场景名称不能为空
|
||||
test_case_status_error=失败
|
||||
test_case_status_success=成功
|
||||
|
|
|
@ -309,6 +309,7 @@ connection_expired=連接已失效,請重新獲取
|
|||
api_case=接口用例
|
||||
performance_case=性能用例
|
||||
scenario_case=場景用例
|
||||
ui_case=UI用例
|
||||
scenario_name_is_null=場景名稱不能為空
|
||||
test_case_status_error=失敗
|
||||
test_case_status_success=成功
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package io.metersphere.bug.controller;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.service.BugRelateCaseService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.utils.PageUtils;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import io.metersphere.system.utils.SessionUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "缺陷管理-关联用例")
|
||||
@RestController
|
||||
@RequestMapping("/bug/relate/case")
|
||||
public class BugRelateCaseController {
|
||||
|
||||
@Resource
|
||||
private BugRelateCaseService bugRelateCaseService;
|
||||
|
||||
@PostMapping("/page")
|
||||
@Operation(description = "缺陷管理-关联用例-列表分页查询")
|
||||
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||
public Pager<List<BugRelateCaseDTO>> page(@Validated @RequestBody BugRelatedCasePageRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
|
||||
return PageUtils.setPageInfo(page, bugRelateCaseService.page(request));
|
||||
}
|
||||
|
||||
@GetMapping("/un-relate/{id}")
|
||||
@Operation(description = "缺陷管理-关联用例-取消关联用例")
|
||||
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||
public void unRelate(@PathVariable String id) {
|
||||
bugRelateCaseService.unRelate(id);
|
||||
}
|
||||
|
||||
@GetMapping("/check-permission/{projectId}/{caseType}")
|
||||
@Operation(description = "缺陷管理-关联用例-查看用例权限校验")
|
||||
public void checkPermission(@PathVariable String projectId, @PathVariable String caseType) {
|
||||
bugRelateCaseService.checkPermission(projectId, SessionUtils.getUserId(), caseType);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import lombok.Data;
|
|||
* @author song-cc-rock
|
||||
*/
|
||||
@Data
|
||||
public class BugRelationCaseCountDTO {
|
||||
public class BugRelateCaseCountDTO {
|
||||
|
||||
@Schema(description = "缺陷ID")
|
||||
private String bugId;
|
|
@ -0,0 +1,32 @@
|
|||
package io.metersphere.bug.dto;
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugRelateCaseDTO extends FunctionalCase {
|
||||
|
||||
@Schema(description = "关联ID")
|
||||
private String relateId;
|
||||
|
||||
@Schema(description = "关联类型")
|
||||
private String relateCaseType;
|
||||
|
||||
@Schema(description = "是否关联计划用例")
|
||||
private Boolean relatePlanCase;
|
||||
|
||||
@Schema(description = "是否关联用例")
|
||||
private Boolean relateCase;
|
||||
|
||||
@Schema(description = "关联用例类型名称")
|
||||
private String relateCaseTypeName;
|
||||
|
||||
@Schema(description = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Schema(description = "版本名称")
|
||||
private String versionName;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.system.dto.sdk.BasePageRequest;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugRelateCasePageRequest extends BasePageRequest {
|
||||
|
||||
@Schema(description = "所属项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "版本ID")
|
||||
private String versionId;
|
||||
|
||||
@Schema(description = "选中模块ID")
|
||||
private String selectModuleId;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugRelateCaseRequest extends BugRelateCasePageRequest{
|
||||
|
||||
@Schema(description = "是否全选", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean selectAll;
|
||||
|
||||
@Schema(description = "用例ID勾选列表")
|
||||
private List<String> includeCaseIds;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.system.dto.sdk.BasePageRequest;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugRelatedCasePageRequest extends BasePageRequest {
|
||||
|
||||
@Schema(description = "缺陷ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String bugId;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package io.metersphere.bug.mapper;
|
||||
|
||||
import io.metersphere.bug.dto.BugRelateCaseCountDTO;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author song-cc-rock
|
||||
*/
|
||||
public interface ExtBugRelateCaseMapper {
|
||||
|
||||
/**
|
||||
* 统计缺陷关联的用例数量
|
||||
* @param bugIds 缺陷ID集合
|
||||
* @return 缺陷关联DTO
|
||||
*/
|
||||
List<BugRelateCaseCountDTO> countRelationCases(@Param("ids") List<String> bugIds);
|
||||
|
||||
/**
|
||||
* 缺陷关联用例列表查询
|
||||
* @param request 请求参数
|
||||
* @return 缺陷关联用例列表
|
||||
*/
|
||||
List<BugRelateCaseDTO> list(@Param("request") BugRelatedCasePageRequest request);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.bug.mapper.ExtBugRelateCaseMapper">
|
||||
<select id="countRelationCases" resultType="io.metersphere.bug.dto.BugRelateCaseCountDTO">
|
||||
select count(id) as relationCaseCount, bug_id as bugId from bug_relation_case brc
|
||||
where brc.bug_id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
group by brc.bug_id
|
||||
</select>
|
||||
|
||||
<select id="list" resultType="io.metersphere.bug.dto.BugRelateCaseDTO">
|
||||
select fc.num, fc.name, fc.project_id, fc.version_id, brc.case_type relateCaseType, brc.id relateId,
|
||||
brc.test_plan_id is not null relatePlanCase, brc.case_id is not null relateCase
|
||||
from bug_relation_case brc join functional_case fc on (brc.case_id = fc.id or brc.test_plan_case_id = fc.id)
|
||||
where brc.bug_id = #{request.bugId}
|
||||
<if test="request.keyword != null and request.keyword != ''">
|
||||
and fc.name like concat('%', #{request.keyword}, '%')
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
|
@ -1,19 +0,0 @@
|
|||
package io.metersphere.bug.mapper;
|
||||
|
||||
import io.metersphere.bug.dto.BugRelationCaseCountDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author song-cc-rock
|
||||
*/
|
||||
public interface ExtBugRelationCaseMapper {
|
||||
|
||||
/**
|
||||
* 统计缺陷关联的用例数量
|
||||
* @param bugIds 缺陷ID集合
|
||||
* @return 缺陷关联DTO
|
||||
*/
|
||||
List<BugRelationCaseCountDTO> countRelationCases(@Param("ids") List<String> bugIds);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.bug.mapper.ExtBugRelationCaseMapper">
|
||||
<select id="countRelationCases" resultType="io.metersphere.bug.dto.BugRelationCaseCountDTO">
|
||||
select count(id) as relationCaseCount, bug_id as bugId from bug_relation_case brc
|
||||
where brc.bug_id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
group by brc.bug_id
|
||||
</select>
|
||||
</mapper>
|
|
@ -0,0 +1,136 @@
|
|||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.BugRelationCase;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.domain.ProjectExample;
|
||||
import io.metersphere.project.domain.ProjectVersion;
|
||||
import io.metersphere.project.domain.ProjectVersionExample;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.project.mapper.ProjectVersionMapper;
|
||||
import io.metersphere.project.service.PermissionCheckService;
|
||||
import io.metersphere.sdk.constants.CaseType;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BugRelateCaseService {
|
||||
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private ProjectVersionMapper projectVersionMapper;
|
||||
@Resource
|
||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
||||
@Resource
|
||||
private ExtBugRelateCaseMapper extBugRelateCaseMapper;
|
||||
@Resource
|
||||
private PermissionCheckService permissionCheckService;
|
||||
|
||||
/**
|
||||
* 分页查询关联用例列表
|
||||
* @param request 请求参数
|
||||
*/
|
||||
public List<BugRelateCaseDTO> page(BugRelatedCasePageRequest request) {
|
||||
List<BugRelateCaseDTO> relateCases = extBugRelateCaseMapper.list(request);
|
||||
if (CollectionUtils.isEmpty(relateCases)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Map<String, String> projectMap = getProjectMap(relateCases.stream().map(BugRelateCaseDTO::getProjectId).toList());
|
||||
Map<String, String> versionMap = getVersionMap(relateCases.stream().map(BugRelateCaseDTO::getVersionId).toList());
|
||||
relateCases.forEach(relateCase -> {
|
||||
relateCase.setProjectName(projectMap.get(relateCase.getProjectId()));
|
||||
relateCase.setVersionName(versionMap.get(relateCase.getVersionId()));
|
||||
relateCase.setRelateCaseTypeName(CaseType.getValue(relateCase.getRelateCaseType()));
|
||||
});
|
||||
return relateCases;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消关联用例
|
||||
* @param id 关联ID
|
||||
*/
|
||||
public void unRelate(String id) {
|
||||
// 只用取消关联直接关联的用例, 保留测试计划关联的用例
|
||||
BugRelationCase bugRelationCase = checkRelate(id);
|
||||
if (StringUtils.isEmpty(bugRelationCase.getTestPlanId())) {
|
||||
// 不包含测试计划关联的用例, 直接删除
|
||||
bugRelationCaseMapper.deleteByPrimaryKey(id);
|
||||
} else {
|
||||
// 包含测试计划关联的用例, 只需将直接关联CaseId置空即可
|
||||
bugRelationCase.setCaseId(null);
|
||||
bugRelationCaseMapper.updateByPrimaryKey(bugRelationCase);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前用户是否有关联用例的权限
|
||||
* @param projectId 项目ID
|
||||
* @param currentUser 当前用户
|
||||
* @param caseType 用例类型
|
||||
*/
|
||||
public void checkPermission(String projectId, String currentUser, String caseType) {
|
||||
// 校验关联用例的查看权限, 目前只支持功能用例的查看权限, 后续支持除功能用例外的其他类型用例
|
||||
if (!CaseType.FUNCTIONAL_CASE.getKey().equals(caseType)) {
|
||||
// 关联的用例类型未知
|
||||
throw new MSException(Translator.get("bug_relate_case_type_unknown"));
|
||||
}
|
||||
boolean hasPermission = permissionCheckService.userHasProjectPermission(currentUser, projectId, PermissionConstants.FUNCTIONAL_CASE_READ);
|
||||
if (!hasPermission) {
|
||||
// 没有该用例的访问权限
|
||||
throw new MSException(Translator.get("bug_relate_case_permission_error"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验关联用例
|
||||
* @param relateId 关联ID
|
||||
* @return 关联用例
|
||||
*/
|
||||
private BugRelationCase checkRelate(String relateId) {
|
||||
BugRelationCase bugRelationCase = bugRelationCaseMapper.selectByPrimaryKey(relateId);
|
||||
if (bugRelationCase == null) {
|
||||
throw new MSException(Translator.get("bug_relate_case_not_found"));
|
||||
}
|
||||
return bugRelationCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目Map
|
||||
* @param projectIds 项目ID集合
|
||||
* @return 获取项目Map
|
||||
*/
|
||||
private Map<String, String> getProjectMap(List<String> projectIds) {
|
||||
ProjectExample projectExample = new ProjectExample();
|
||||
projectExample.createCriteria().andIdIn(projectIds);
|
||||
List<Project> projects = projectMapper.selectByExample(projectExample);
|
||||
return projects.stream().collect(Collectors.toMap(Project::getId, Project::getName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本Map
|
||||
* @param versionIds 版本ID集合
|
||||
* @return 获取版本Map
|
||||
*/
|
||||
private Map<String, String> getVersionMap(List<String> versionIds) {
|
||||
ProjectVersionExample projectVersionExample = new ProjectVersionExample();
|
||||
projectVersionExample.createCriteria().andIdIn(versionIds);
|
||||
List<ProjectVersion> projectVersions = projectVersionMapper.selectByExample(projectVersionExample);
|
||||
return projectVersions.stream().collect(Collectors.toMap(ProjectVersion::getId, ProjectVersion::getName));
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package io.metersphere.bug.service;
|
|||
import io.metersphere.bug.domain.*;
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.dto.BugRelationCaseCountDTO;
|
||||
import io.metersphere.bug.dto.BugRelateCaseCountDTO;
|
||||
import io.metersphere.bug.dto.BugTagEditDTO;
|
||||
import io.metersphere.bug.dto.request.BugBatchRequest;
|
||||
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||
|
@ -76,7 +76,7 @@ public class BugService {
|
|||
@Resource
|
||||
private ExtBugCustomFieldMapper extBugCustomFieldMapper;
|
||||
@Resource
|
||||
private ExtBugRelationCaseMapper extBugRelationCaseMapper;
|
||||
private ExtBugRelateCaseMapper extBugRelateCaseMapper;
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
|
@ -561,8 +561,8 @@ public class BugService {
|
|||
Map<String, String> userMap = userOptions.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
|
||||
// 根据缺陷ID获取关联用例数
|
||||
List<String> ids = bugs.stream().map(BugDTO::getId).toList();
|
||||
List<BugRelationCaseCountDTO> relationCaseCount = extBugRelationCaseMapper.countRelationCases(ids);
|
||||
Map<String, Integer> countMap = relationCaseCount.stream().collect(Collectors.toMap(BugRelationCaseCountDTO::getBugId, BugRelationCaseCountDTO::getRelationCaseCount));
|
||||
List<BugRelateCaseCountDTO> relationCaseCount = extBugRelateCaseMapper.countRelationCases(ids);
|
||||
Map<String, Integer> countMap = relationCaseCount.stream().collect(Collectors.toMap(BugRelateCaseCountDTO::getBugId, BugRelateCaseCountDTO::getRelationCaseCount));
|
||||
bugs.forEach(bug -> {
|
||||
bug.setRelationCaseCount(countMap.get(bug.getId()));
|
||||
bug.setCreateUserName(userMap.get(bug.getCreateUser()));
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.sdk.constants.UserRoleType;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.*;
|
||||
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;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class BugRelateCaseControllerTests extends BaseTest {
|
||||
|
||||
public static final String BUG_CASE_RELATE_PAGE = "/bug/relate/case/page";
|
||||
public static final String BUG_CASE_UN_RELATE = "/bug/relate/case/un-relate";
|
||||
public static final String BUG_CASE_RELATE_CHECK = "/bug/relate/case/check-permission";
|
||||
|
||||
@Test
|
||||
@Order(0)
|
||||
@Sql(scripts = {"/dml/init_bug_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
void testBugRelatePageSuccess() throws Exception {
|
||||
BugRelatedCasePageRequest request = new BugRelatedCasePageRequest();
|
||||
request.setCurrent(1);
|
||||
request.setPageSize(10);
|
||||
request.setBugId("default-relate-bug-id");
|
||||
request.setKeyword("first");
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(BUG_CASE_RELATE_PAGE, request);
|
||||
// 获取返回值
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||
// 返回请求正常
|
||||
Assertions.assertNotNull(resultHolder);
|
||||
Pager<?> pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
||||
// 返回值不为空
|
||||
Assertions.assertNotNull(pageData);
|
||||
// 返回值的页码和当前页码相同
|
||||
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
|
||||
// 返回的数据量不超过规定要返回的数据量相同
|
||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
|
||||
// 返回值中取出第一条数据, 并判断是否包含关键字default
|
||||
BugRelateCaseDTO bugRelateCaseDTO = JSON.parseArray(JSON.toJSONString(pageData.getList()), BugRelateCaseDTO.class).get(0);
|
||||
Assertions.assertTrue(StringUtils.contains(bugRelateCaseDTO.getName(), request.getKeyword()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void testBugRelatePageEmpty() throws Exception {
|
||||
BugRelatedCasePageRequest request = new BugRelatedCasePageRequest();
|
||||
request.setCurrent(1);
|
||||
request.setPageSize(10);
|
||||
request.setBugId("default-relate-bug-id");
|
||||
request.setKeyword("keyword");
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(BUG_CASE_RELATE_PAGE, request);
|
||||
// 获取返回值
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||
// 返回请求正常
|
||||
Assertions.assertNotNull(resultHolder);
|
||||
Pager<?> pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
|
||||
// 返回值不为空
|
||||
Assertions.assertNotNull(pageData);
|
||||
// 返回值的页码和当前页码相同
|
||||
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
|
||||
// 返回的数据量为0条
|
||||
Assertions.assertEquals(0, pageData.getTotal());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void testBugRelatePageError() throws Exception {
|
||||
// 页码有误
|
||||
BugRelatedCasePageRequest request = new BugRelatedCasePageRequest();
|
||||
request.setCurrent(0);
|
||||
request.setPageSize(10);
|
||||
this.requestPost(BUG_CASE_RELATE_PAGE, request, status().isBadRequest());
|
||||
// 页数有误
|
||||
request = new BugRelatedCasePageRequest();
|
||||
request.setCurrent(1);
|
||||
request.setPageSize(1);
|
||||
this.requestPost(BUG_CASE_RELATE_PAGE, request, status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
void testBugUnRelateSuccess() throws Exception {
|
||||
this.requestGetWithOk(BUG_CASE_UN_RELATE + "/bug-relate-case-default-id");
|
||||
this.requestGetWithOk(BUG_CASE_UN_RELATE + "/bug-relate-case-default-id-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
void testBugUnRelateError() throws Exception {
|
||||
this.requestGet(BUG_CASE_UN_RELATE + "/bug-relate-case-default-id-x", status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
void testBugRelateCheckPermissionError() throws Exception {
|
||||
// 非功能用例类型参数
|
||||
this.requestGet(BUG_CASE_RELATE_CHECK + "/100001100001/API", status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
void testBugRelateCheckPermissionSuccess() throws Exception {
|
||||
// 默认项目ID且登录用户为admin
|
||||
this.requestGet(BUG_CASE_RELATE_CHECK + "/100001100001/FUNCTIONAL", status().isOk()).andReturn();
|
||||
// 切换登录用户为PROJECT, 权限校验失败
|
||||
this.requestGetWithNoAdmin(BUG_CASE_RELATE_CHECK + "/default-project-for-bug/FUNCTIONAL", UserRoleType.PROJECT.name(), status().is5xxServerError()).andReturn();
|
||||
}
|
||||
}
|
|
@ -26,7 +26,10 @@ spring.datasource.hikari.max-lifetime=1800000
|
|||
spring.datasource.hikari.connection-timeout=30000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
|
||||
#
|
||||
# 单元测试初始化权限 sql
|
||||
spring.sql.init.mode=always
|
||||
spring.sql.init.schema-locations=classpath*:dml/init_permission_test.sql
|
||||
|
||||
# spring.kafka
|
||||
spring.kafka.bootstrap-servers=${embedded.kafka.brokerList}
|
||||
spring.kafka.consumer.group-id=metersphere_group_id
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos,version_id, ref_id, last_execute_result,
|
||||
deleted, public_case, latest, create_user,update_user, delete_user, create_time, update_time, delete_time)
|
||||
VALUES ('bug_relate_case-tmp', 100100, 'init_module', 'default-project-for-bug', 'default_template', 'first_case', 'UN_REVIEWED', null, 'STEP',
|
||||
10001, '111', '111', 'UN_EXECUTED', 0, 0, true, 'admin', 'admin', null, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, null);
|
||||
|
||||
INSERT INTO project_version(id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user) VALUE
|
||||
('default_bug_version', 'default-project-for-bug', 'v1.2.8', 'This is a test version!', 'open', true, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
|
||||
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos,version_id, ref_id, last_execute_result,
|
||||
deleted, public_case, latest, create_user,update_user, delete_user, create_time, update_time, delete_time) VALUES
|
||||
('bug_relate_case', 100099, 'init_module', 'default-project-for-bug', 'default_template', 'first_case1', 'UN_REVIEWED', null, 'STEP',
|
||||
10001, '111', '111', 'UN_EXECUTED', 0, 0, true, 'admin', 'admin', null, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, null),
|
||||
('bug_relate_case-1', 100099, 'init_module', '100001100001', 'default_template', 'first_case2', 'UN_REVIEWED', null, 'STEP',
|
||||
10001, '111', '111', 'UN_EXECUTED', 0, 0, true, 'admin', 'admin', null, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, null);
|
||||
|
||||
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
|
||||
('default-relate-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||
('default-relate-bug-id-1', 100001, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', '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 ('bug-relate-case-default-id', 'bug_relate_case', 'default-relate-bug-id', 'FUNCTIONAL', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('bug-relate-case-default-id-1', 'bug_relate_case', 'default-relate-bug-id-1', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('bug-relate-case-default-id-2', 'bug_relate_case-1', 'default-relate-bug-id', 'FUNCTIONAL', 'test-plan-id', 'bug_relate_case-1', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
|
@ -0,0 +1,14 @@
|
|||
-- 初始化用于权限测试的组织用户
|
||||
INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source,
|
||||
last_project_id, create_user, update_user, deleted)
|
||||
VALUES ('PROJECT', 'PROJECT', 'PROJECT@fit2cloud.com', MD5('metersphere'),
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false);
|
||||
|
||||
-- 初始化一个用于权限测试的用户组,这里默认使用 PROJECT 作为ID,如果是组织和项目级别类似,便于根据权限的前缀找到对应测试的用户组
|
||||
INSERT INTO user_role (id, name, description, internal, type, create_time, update_time, create_user, scope_id)
|
||||
VALUES ('PROJECT', '项目级别权限校验', '', 1, 'PROJECT', 1620674220005, 1620674220000, 'admin', 'global');
|
||||
|
||||
-- 初始化用户和组的关系
|
||||
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user)
|
||||
SELECT 'PROJECT', 'PROJECT', 'PROJECT', id, organization_id, 1684747668375, 'admin' FROM project WHERE num = 100001;
|
|
@ -8,7 +8,6 @@ import io.metersphere.sdk.exception.IResultCode;
|
|||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.mapper.OperationLogMapper;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import io.metersphere.system.base.param.InvalidateParamInfo;
|
||||
import io.metersphere.system.base.param.ParamGeneratorFactory;
|
||||
import io.metersphere.system.domain.User;
|
||||
|
@ -18,6 +17,7 @@ import io.metersphere.system.log.constants.OperationLogType;
|
|||
import io.metersphere.system.mapper.UserMapper;
|
||||
import io.metersphere.system.mapper.UserRolePermissionMapper;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import io.metersphere.validation.groups.Created;
|
||||
import io.metersphere.validation.groups.Updated;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -133,6 +133,13 @@ public abstract class BaseTest {
|
|||
return setRequestBuilderHeader(requestBuilder, adminAuthInfo);
|
||||
}
|
||||
|
||||
protected MockHttpServletRequestBuilder getRequestBuilderByRole(String url, String userRoleType, Object... uriVariables) {
|
||||
// 使用对应的用户认证信息来请求, 非Admin
|
||||
AuthInfo authInfo = permissionAuthInfoMap.get(userRoleType);
|
||||
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(getBasePath() + url, uriVariables);
|
||||
return setRequestBuilderHeader(requestBuilder, authInfo == null ? adminAuthInfo : authInfo);
|
||||
}
|
||||
|
||||
protected ResultActions requestPost(String url, Object param, Object... uriVariables) throws Exception {
|
||||
return mockMvc.perform(getPostRequestBuilder(url, param, uriVariables))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
|
||||
|
@ -505,6 +512,11 @@ public abstract class BaseTest {
|
|||
requestPermissionsTest(permissionIds, url, () -> getPermissionMultipartRequestBuilder(permissionIds.get(0).split("_")[0], url, paramMap, uriVariables));
|
||||
}
|
||||
|
||||
protected ResultActions requestGetWithNoAdmin(String url, String userRoleType, Object... uriVariables) throws Exception {
|
||||
return mockMvc.perform(getRequestBuilderByRole(url, userRoleType, uriVariables))
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
/**
|
||||
* 给用户组绑定对应权限
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue