diff --git a/backend/framework/provider/src/main/java/io/metersphere/context/AssociateCaseFactory.java b/backend/framework/provider/src/main/java/io/metersphere/context/AssociateCaseFactory.java new file mode 100644 index 0000000000..8ce53e8e32 --- /dev/null +++ b/backend/framework/provider/src/main/java/io/metersphere/context/AssociateCaseFactory.java @@ -0,0 +1,29 @@ +package io.metersphere.context; + +import io.metersphere.provider.BaseAssociateCaseProvider; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 关联用例接口Bean实例上下文 + */ +@Component +public class AssociateCaseFactory implements ApplicationContextAware { + + public static final Map PROVIDER_MAP = new HashMap<>(); + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map beanMap = applicationContext.getBeansOfType(BaseAssociateCaseProvider.class); + PROVIDER_MAP.putAll(beanMap); + } + + public static BaseAssociateCaseProvider getInstance(String serviceType) { + return PROVIDER_MAP.get(serviceType); + } +} diff --git a/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateCaseProvider.java b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateCaseProvider.java index e53734c37d..0fdbf112c5 100644 --- a/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateCaseProvider.java +++ b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateCaseProvider.java @@ -6,6 +6,9 @@ import io.metersphere.request.TestCasePageProviderRequest; import java.util.List; +/** + * 多个实现(关联用例基础接口) + */ public interface BaseAssociateCaseProvider { /** diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/CaseType.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/CaseType.java index c0008546eb..da0fa5b15f 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/CaseType.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/CaseType.java @@ -1,6 +1,5 @@ package io.metersphere.sdk.constants; -import io.metersphere.sdk.util.Translator; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @@ -10,41 +9,41 @@ public enum CaseType { /** * 功能用例 */ - FUNCTIONAL_CASE("FUNCTIONAL", "test_case"), + FUNCTIONAL_CASE("FUNCTIONAL", "test_case", PermissionConstants.FUNCTIONAL_CASE_READ, "functional_case", "functional_case_module", "functional_case.module.default.name"), /** * 接口用例 */ - API_CASE("API", "api_case"), + API_CASE("API", "api_case", PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, "api_test_case", "api_definition_module", "api_unplanned_request"), /** - * 性能用例 + * 场景用例 */ - SCENARIO_CASE("SCENARIO", "scenario_case"), - /** - * UI用例 - */ - UI_CASE("UI", "ui_case"), - /** - * 性能用例 - */ - PERFORMANCE_CASE("PERFORMANCE", "performance_case"); + SCENARIO_CASE("SCENARIO", "scenario_case", PermissionConstants.PROJECT_API_SCENARIO_READ, "api_scenario", "api_scenario_module", "api_unplanned_scenario"); private final String key; - private final String value; + private final String type; - CaseType(String key, String value) { + private final String usePermission; + + private final String caseTable; + + private final String moduleTable; + + private final String unPlanName; + + CaseType(String key, String type, String usePermission, String caseTable, String moduleTable, String unPlanName) { this.key = key; - this.value = value; + this.type = type; + this.usePermission = usePermission; + this.caseTable = caseTable; + this.moduleTable = moduleTable; + this.unPlanName = unPlanName; } - public String getValue() { - return Translator.get(value); - } - - public static String getValue(String key) { + public static CaseType getType(String key) { for (CaseType caseType : CaseType.values()) { if (StringUtils.equals(caseType.getKey(), key)) { - return caseType.getValue(); + return caseType; } } return null; diff --git a/backend/framework/sdk/src/main/resources/i18n/bug.properties b/backend/framework/sdk/src/main/resources/i18n/bug.properties index 01b820f185..8d1aa451a4 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug.properties @@ -94,6 +94,7 @@ bug_comment_not_exist=缺陷评论不存在 bug_comment_not_owner=非当前评论创建人, 无法操作! bug_relate_case_not_found=未查询到关联的用例 bug_relate_case_type_unknown=关联的用例类型未知, 无法查看 +unknown_case_type_of_relate_case=参数错误, 未知的用例类型 bug_relate_case_permission_error=无用例查看权限, 请联系管理员 bug_status_can_not_be_empty=缺陷状态不能为空 handle_user_can_not_be_empty=缺陷处理人不能为空 diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties index 339c92b044..0e2b3efbea 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties @@ -94,6 +94,7 @@ bug_comment_not_exist=Bug comment does not exist bug_comment_not_owner=Not owner of the bug comment! bug_relate_case_not_found=Bug related case not found bug_relate_case_type_unknown=Bug related case type unknown +unknown_case_type_of_relate_case=Parameter error, unknown case type bug_relate_case_permission_error=No permission to show the case bug_status_can_not_be_empty=Status cannot be empty handle_user_can_not_be_empty=Handle user cannot be empty diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties index 30982d6923..fd6221717b 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties @@ -94,6 +94,7 @@ bug_comment_not_exist=缺陷评论不存在 bug_comment_not_owner=非当前评论创建人, 无法操作! bug_relate_case_not_found=未查询到关联的用例 bug_relate_case_type_unknown=关联的用例类型未知, 无法查看 +unknown_case_type_of_relate_case=参数错误, 未知的用例类型 bug_relate_case_permission_error=无用例查看权限, 请联系管理员 bug_status_can_not_be_empty=缺陷状态不能为空 handle_user_can_not_be_empty=缺陷处理人不能为空 diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties index 64b6c16d84..1788585690 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties @@ -94,6 +94,7 @@ bug_comment_not_exist=缺陷評論不存在 bug_comment_not_owner=非當前評論創建人, 無法操作! bug_relate_case_not_found=未查詢到關聯的用例 bug_relate_case_type_unknown=關聯的用例類型未知, 無法查看 +unknown_case_type_of_relate_case=參數錯誤, 未知的用例類型 bug_relate_case_permission_error=無權限查看, 請聯繫管理員 bug_status_can_not_be_empty=缺陷狀態不能為空 handle_user_can_not_be_empty=缺陷處理人不能為空 diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.java index e7b43cfea8..dd4d887787 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.java @@ -59,4 +59,21 @@ public interface ExtApiScenarioMapper { List getScenarioExecuteInfoByIds(@Param("ids") List ids); List countModuleIdByRequest(@Param("request") ApiScenarioModuleRequest request, @Param("deleted") boolean deleted); + + /** + * 获取缺陷未关联的场景用例列表 + * @param request provider参数 + * @param deleted 是否删除状态 + * @param sort 排序 + * @return 通用的列表Case集合 + */ + List listUnRelatedCaseWithBug(@Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort); + + /** + * 根据关联条件获取关联的用例ID + * @param request 关联参数 + * @param deleted 是否删除状态 + * @return 关联的用例ID集合 + */ + List getSelectIdsByAssociateParam(@Param("request")AssociateOtherCaseRequest request, @Param("deleted") boolean deleted); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml index ad2640e975..468612d9a5 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml @@ -555,6 +555,49 @@ GROUP BY api_scenario.module_id + + + + @@ -577,4 +620,38 @@ + + + + + and ( + ao.num like concat('%', #{request.keyword}, '%') + or ao.name like concat('%', #{request.keyword}, '%') + or ao.tags like concat('%', #{request.keyword}, '%') + ) + + + and ao.module_id in + + #{moduleId} + + + + + + + + and ( + ao.num like concat('%', #{request.keyword}, '%') + or ao.name like concat('%', #{request.keyword}, '%') + or ao.tags like concat('%', #{request.keyword}, '%') + ) + + + and ao.module_id in + + #{moduleId} + + + diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java index e91525e247..e9a585d949 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java @@ -76,4 +76,21 @@ public interface ExtApiTestCaseMapper { DropNode selectNodeByPosOperator(NodeSortQueryParam nodeSortQueryParam); List getApiCaseExecuteInfoByIds(@Param("ids")List ids); + + /** + * 获取缺陷未关联的接口用例列表 + * @param request provider参数 + * @param deleted 是否删除状态 + * @param sort 排序 + * @return 通用的列表Case集合 + */ + List listUnRelatedCaseWithBug(@Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort); + + /** + * 根据关联条件获取关联的用例ID + * @param request 关联参数 + * @param deleted 是否删除状态 + * @return 关联的用例ID集合 + */ + List getSelectIdsByAssociateParam(@Param("request")AssociateOtherCaseRequest request, @Param("deleted") boolean deleted); } \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml index 4c069e1959..d434df0075 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml @@ -336,6 +336,52 @@ #{id} + + + + + @@ -484,4 +530,50 @@ AND a.latest = 1 + + + + + and ( + ac.num like concat('%', #{request.keyword}, '%') + or ac.name like concat('%', #{request.keyword}, '%') + or ac.tags like concat('%', #{request.keyword}, '%') + ) + + + and ac.module_id in + + #{moduleId} + + + + and ad.protocol = #{request.protocol} + + + and ac.api_definition_id = #{request.apiDefinitionId} + + + + + + + and ( + ac.num like concat('%', #{request.keyword}, '%') + or ac.name like concat('%', #{request.keyword}, '%') + or ac.tags like concat('%', #{request.keyword}, '%') + ) + + + and ac.module_id in + + #{moduleId} + + + + and ad.protocol = #{request.protocol} + + + and ac.api_definition_id = #{request.apiDefinitionId} + + \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateApiProvider.java b/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateApiProvider.java index 20e6292e28..e4733da80c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateApiProvider.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateApiProvider.java @@ -8,6 +8,7 @@ import io.metersphere.api.service.definition.ApiDefinitionModuleService; import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.provider.BaseAssociateApiProvider; +import io.metersphere.provider.BaseAssociateCaseProvider; import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.sdk.util.Translator; @@ -16,12 +17,13 @@ import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.List; import java.util.Map; -@Service -public class AssociateApiProvider implements BaseAssociateApiProvider { +@Service("API") +public class AssociateApiProvider implements BaseAssociateApiProvider, BaseAssociateCaseProvider { @Resource private ExtApiTestCaseMapper extApiTestCaseMapper; @@ -88,4 +90,26 @@ public class AssociateApiProvider implements BaseAssociateApiProvider { return moduleTreeService.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED_API)); } + + @Override + public List listUnRelatedTestCaseList(TestCasePageProviderRequest request) { + List apiCases = extApiTestCaseMapper.listUnRelatedCaseWithBug(request, false, request.getSortString()); + if (CollectionUtils.isEmpty(apiCases)) { + return new ArrayList<>(); + } + return apiCases; + } + + @Override + public List getRelatedIdsByParam(AssociateOtherCaseRequest request, boolean deleted) { + if (request.isSelectAll()) { + List relatedIds = extApiTestCaseMapper.getSelectIdsByAssociateParam(request, deleted); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + relatedIds = relatedIds.stream().filter(id -> !request.getExcludeIds().contains(id)).toList(); + } + return relatedIds; + } else { + return request.getSelectIds(); + } + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateScenarioProvider.java b/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateScenarioProvider.java index f2fb1b764d..62f3c0ca3b 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateScenarioProvider.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateScenarioProvider.java @@ -7,6 +7,7 @@ import io.metersphere.api.mapper.ExtApiScenarioMapper; import io.metersphere.api.service.scenario.ApiScenarioModuleService; import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.project.dto.ModuleCountDTO; +import io.metersphere.provider.BaseAssociateCaseProvider; import io.metersphere.provider.BaseAssociateScenarioProvider; import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.request.TestCasePageProviderRequest; @@ -16,11 +17,12 @@ import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.List; import java.util.Map; -@Service -public class AssociateScenarioProvider implements BaseAssociateScenarioProvider { +@Service("SCENARIO") +public class AssociateScenarioProvider implements BaseAssociateScenarioProvider, BaseAssociateCaseProvider { @Resource private ExtApiScenarioMapper extApiScenarioMapper; @@ -87,4 +89,26 @@ public class AssociateScenarioProvider implements BaseAssociateScenarioProvider List fileModuleList = extApiScenarioMapper.selectIdAndParentIdByProjectId(request.getProjectId()); return apiScenarioModuleService.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED_SCENARIO)); } + + @Override + public List listUnRelatedTestCaseList(TestCasePageProviderRequest request) { + List apiScenarios = extApiScenarioMapper.listUnRelatedCaseWithBug(request, false, request.getSortString()); + if (CollectionUtils.isEmpty(apiScenarios)) { + return new ArrayList<>(); + } + return apiScenarios; + } + + @Override + public List getRelatedIdsByParam(AssociateOtherCaseRequest request, boolean deleted) { + if (request.isSelectAll()) { + List relatedIds = extApiScenarioMapper.getSelectIdsByAssociateParam(request, deleted); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + relatedIds = relatedIds.stream().filter(id -> !request.getExcludeIds().contains(id)).toList(); + } + return relatedIds; + } else { + return request.getSelectIds(); + } + } } diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/service/AssociateCaseProviderTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/service/AssociateCaseProviderTests.java new file mode 100644 index 0000000000..a46b2f1e8f --- /dev/null +++ b/backend/services/api-test/src/test/java/io/metersphere/api/service/AssociateCaseProviderTests.java @@ -0,0 +1,76 @@ +package io.metersphere.api.service; + +import io.metersphere.api.provider.AssociateApiProvider; +import io.metersphere.api.provider.AssociateScenarioProvider; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; +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) +@AutoConfigureMockMvc +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class AssociateCaseProviderTests extends BaseTest { + + @Resource + AssociateApiProvider apiProvider; + @Resource + AssociateScenarioProvider scenarioProvider; + + @Test + @Order(1) + @Sql(scripts = {"/dml/init_associate_provider_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) + void coverApiProvider() { + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setProjectId("test-associate-pro"); + request.setSourceId("test-source-id"); + request.setSourceType("test-source-type"); + apiProvider.listUnRelatedTestCaseList(request); + request.setKeyword("api-case-associate-2"); + apiProvider.listUnRelatedTestCaseList(request); + AssociateOtherCaseRequest associateRequest = new AssociateOtherCaseRequest(); + associateRequest.setSelectAll(true); + associateRequest.setProjectId("test-associate-pro"); + associateRequest.setSourceId("test-source-id"); + associateRequest.setSourceType("test-source-type"); + apiProvider.getRelatedIdsByParam(associateRequest, false); + associateRequest.setExcludeIds(List.of("api-case-associate-1")); + apiProvider.getRelatedIdsByParam(associateRequest, false); + associateRequest.setSelectAll(false); + associateRequest.setSelectIds(List.of("api-case-associate-1")); + apiProvider.getRelatedIdsByParam(associateRequest, false); + } + + @Test + @Order(2) + void coverScenarioProvider() { + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setProjectId("test-associate-pro"); + request.setSourceId("test-source-id"); + request.setSourceType("test-source-type"); + scenarioProvider.listUnRelatedTestCaseList(request); + request.setKeyword("api-scenario-associate-2"); + scenarioProvider.listUnRelatedTestCaseList(request); + AssociateOtherCaseRequest associateRequest = new AssociateOtherCaseRequest(); + associateRequest.setSelectAll(true); + associateRequest.setProjectId("test-associate-pro"); + associateRequest.setSourceId("test-source-id"); + associateRequest.setSourceType("test-source-type"); + scenarioProvider.getRelatedIdsByParam(associateRequest, false); + associateRequest.setExcludeIds(List.of("api-case-scenario-1")); + scenarioProvider.getRelatedIdsByParam(associateRequest, false); + associateRequest.setSelectAll(false); + associateRequest.setSelectIds(List.of("api-case-scenario-1")); + scenarioProvider.getRelatedIdsByParam(associateRequest, false); + } +} diff --git a/backend/services/api-test/src/test/resources/dml/init_associate_provider_test.sql b/backend/services/api-test/src/test/resources/dml/init_associate_provider_test.sql new file mode 100644 index 0000000000..7873d0fe1d --- /dev/null +++ b/backend/services/api-test/src/test/resources/dml/init_associate_provider_test.sql @@ -0,0 +1,11 @@ +INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) +VALUES ('api-definition-tmp', 'test31931', 'HTTP', 'POST', '/api/test', 'PROCESSING', 1000001, '[\"test3\",\"te\"]', 1, 'test-associate-pro', 'root', b'1', '100570499574136985', '1001', NULL, UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', NULL, NULL, false); + +INSERT INTO `api_definition` (`id`, `name`, `protocol`, `method`, `path`, `status`, `num`, `tags`, `pos`, `project_id`, `module_id`, `latest`, `version_id`, `ref_id`, `description`, `create_time`, `create_user`, `update_time`, `update_user`, `delete_user`, `delete_time`, `deleted`) +VALUES ('api-definition-associate-1', 'test31931313', 'HTTP', 'POST', '/api/test', 'PROCESSING', 1000001, '[\"test3\",\"te\"]', 1, 'test-associate-pro', 'root', b'1', '100570499574136985', '1001', NULL, UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', NULL, NULL, false); + +INSERT INTO api_test_case(id, name, priority, num, tags, status, last_report_status, last_report_id, pos, project_id, api_definition_id, version_id, environment_id, create_time, create_user, update_time, update_user, delete_time, delete_user, deleted) +VALUES ('api-case-associate-1','test4938131', 'P0', 10000023131, null, 'Underway', 'PENDING', null, 1, 'test-associate-pro', 'api-definition-associate-1', '100570499574136985', 'test_associate_env_id', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', null, null, false); + +INSERT INTO api_scenario(id, name, priority, status, last_report_status, last_report_id, num, pos, version_id, ref_id, project_id, module_id, description, tags, create_user, create_time, delete_time, delete_user, update_user, update_time, deleted) +VALUES ('api-scenario-associate-1', 'test323131', 'p1', 'test-api-status', 'PENDING', null, 1000001, 1, 'v1.10', 'api-scenario-associate-rid', 'test-associate-pro', 'root', null, null, 'admin', UNIX_TIMESTAMP() * 1000, null, null, 'admin', UNIX_TIMESTAMP() * 1000, false); \ No newline at end of file diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugRelateCaseController.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugRelateCaseController.java index f1abd3778c..732685cfa2 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugRelateCaseController.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugRelateCaseController.java @@ -7,6 +7,7 @@ import io.metersphere.bug.dto.request.BugRelatedCasePageRequest; import io.metersphere.bug.dto.response.BugRelateCaseDTO; import io.metersphere.bug.service.BugRelateCaseCommonService; import io.metersphere.bug.service.BugRelateCaseLogService; +import io.metersphere.context.AssociateCaseFactory; import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.provider.BaseAssociateCaseProvider; import io.metersphere.request.AssociateCaseModuleRequest; @@ -37,23 +38,22 @@ public class BugRelateCaseController { @Resource private BugRelateCaseCommonService bugRelateCaseCommonService; - @Resource - private BaseAssociateCaseProvider functionalCaseProvider; @PostMapping("/un-relate/page") @Operation(description = "缺陷管理-关联用例-未关联用例-列表分页") @RequiresPermissions(PermissionConstants.PROJECT_BUG_READ) public Pager> unRelatedPage(@Validated @RequestBody TestCasePageProviderRequest request) { - // 目前只保留功能用例的Provider接口, 后续其他用例根据RelateCaseType扩展 + bugRelateCaseCommonService.checkCaseTypeParamIllegal(request.getSourceType()); + BaseAssociateCaseProvider associateCaseProvider = AssociateCaseFactory.getInstance(request.getSourceType()); Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize()); - return PageUtils.setPageInfo(page, functionalCaseProvider.listUnRelatedTestCaseList(request)); + return PageUtils.setPageInfo(page, associateCaseProvider.listUnRelatedTestCaseList(request)); } @PostMapping("/un-relate/module/count") @Operation(summary = "缺陷管理-关联用例-未关联用例-模块树数量") @RequiresPermissions(PermissionConstants.PROJECT_BUG_READ) @CheckOwner(resourceId = "#request.projectId", resourceType = "project") - public Map countTree(@RequestBody @Validated TestCasePageProviderRequest request) { + public Map countTree(@RequestBody @Validated AssociateCaseModuleRequest request) { return bugRelateCaseCommonService.countTree(request); } diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.java index 04598646d6..659fb6be6c 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.java @@ -7,7 +7,6 @@ import io.metersphere.dto.BugProviderDTO; import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.request.AssociateBugPageRequest; import io.metersphere.request.AssociateCaseModuleRequest; -import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.system.dto.sdk.BaseTreeNode; import org.apache.ibatis.annotations.Param; @@ -21,17 +20,20 @@ public interface ExtBugRelateCaseMapper { /** * 获取缺陷关联的用例模块树 * @param request 请求参数 + * @param caseTable 关联用例表 + * @param moduleTable 关联用例模块表 * @return 模块树集合 */ - List getRelateCaseModule(@Param("request") AssociateCaseModuleRequest request); + List getRelateCaseModule(@Param("request") AssociateCaseModuleRequest request, @Param("caseTable") String caseTable, @Param("moduleTable") String moduleTable); /** * 获取缺陷关联的用例模块树数量 * @param request 请求参数 * @param deleted 是否删除状态 + * @param caseTable 关联用例表 * @return 模块树数量 */ - List countRelateCaseModuleTree(@Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted); + List countRelateCaseModuleTree(@Param("request") AssociateCaseModuleRequest request, @Param("deleted") boolean deleted, @Param("caseTable") String caseTable); /** * 统计缺陷关联的用例数量 diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.xml b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.xml index 909547a6e1..685c366133 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.xml +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelateCaseMapper.xml @@ -3,34 +3,55 @@ select brc.id relateId, fc.id relateCaseId, fc.num relateCaseNum, fc.name relateCaseName, fc.project_id projectId, fc.version_id versionId, brc.case_type relateCaseType, 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} and fc.deleted = false + from bug_relation_case brc + left join functional_case fc on ((brc.case_id = fc.id or brc.test_plan_case_id = fc.id) and fc.deleted = false) + left join api_test_case atc on ((brc.case_id = atc.id or brc.test_plan_case_id = atc.id) and atc.deleted = false) + left join api_scenario ao on ((brc.case_id = ao.id or brc.test_plan_case_id = ao.id) and ao.deleted = false) + where brc.bug_id = #{request.bugId} and ( - fc.name like concat('%', #{request.keyword}, '%') - or fc.num like concat('%', #{request.keyword}, '%') + fc.name like concat('%', #{request.keyword}, '%') + or fc.num like concat('%', #{request.keyword}, '%') + or atc.name like concat('%', #{request.keyword}, '%') + or atc.num like concat('%', #{request.keyword}, '%') + or ao.name like concat('%', #{request.keyword}, '%') + or ao.num like concat('%', #{request.keyword}, '%') ) - order by brc.id desc + order by brc.create_time desc