diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateApiProviderTest.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateApiProviderTest.java index 9eefa4bb5e..5fecd26cf2 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateApiProviderTest.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateApiProviderTest.java @@ -73,6 +73,13 @@ public class AssociateApiProviderTest extends BaseTest { request.setSelectIds(List.of("gyq_associate_api_case_id_1")); selectIds = provider.getSelectIds(request, false); Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds)); + request.setSourceType("API"); + request.setSourceId("gyq_associate_case_id_1"); + request.setSelectAll(true); + request.setProjectId("project-associate-case-test"); + selectIds = provider.getSelectIds(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds)); + } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalTestCaseController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalTestCaseController.java index 4cd20c1bf9..65394aba27 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalTestCaseController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalTestCaseController.java @@ -3,12 +3,14 @@ package io.metersphere.functional.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.dto.TestCaseProviderDTO; +import io.metersphere.functional.request.CaseApiModuleRequest; import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; import io.metersphere.functional.service.FunctionalTestCaseService; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.system.dto.sdk.BaseTreeNode; import io.metersphere.system.security.CheckOwner; import io.metersphere.system.utils.PageUtils; import io.metersphere.system.utils.Pager; @@ -54,6 +56,14 @@ public class FunctionalTestCaseController { return functionalTestCaseService.moduleCount(request, false); } + @PostMapping("/associate/api/module/tree") + @Operation(summary = "接口测试-接口管理-模块-查找模块") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) + @CheckOwner(resourceId = "#request.projectId", resourceType = "project") + public List getTree(@RequestBody @Validated CaseApiModuleRequest request) { + return functionalTestCaseService.getTree(request); + } + @PostMapping("/associate/case") @Operation(summary = "用例管理-功能用例-关联其他用例-关联用例") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.java b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.java index 70183f861c..70c04d4c2c 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.java @@ -1,5 +1,6 @@ package io.metersphere.functional.mapper; +import io.metersphere.functional.request.CaseApiModuleRequest; import io.metersphere.project.dto.NodeSortQueryParam; import io.metersphere.system.dto.sdk.BaseModule; import io.metersphere.system.dto.sdk.BaseTreeNode; @@ -24,4 +25,7 @@ public interface ExtFunctionalCaseModuleMapper { List selectIdAndParentIdByProjectId(String projectId); + List selectApiCaseModuleByRequest(@Param("request") CaseApiModuleRequest request); + + } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.xml b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.xml index 563bfd766b..de24e42711 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.xml +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseModuleMapper.xml @@ -61,4 +61,34 @@ FROM functional_case_module WHERE project_id = #{0} + + + + + + + AND m.project_id = #{request.projectId} + + + AND m.name like CONCAT('%', #{request.keyword},'%') + + + AND m.module_id IN + + #{item} + + + + + \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseApiModuleRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseApiModuleRequest.java new file mode 100644 index 0000000000..b1e7cc8dbf --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/CaseApiModuleRequest.java @@ -0,0 +1,38 @@ +package io.metersphere.functional.request; + +import io.metersphere.sdk.constants.ModuleConstants; +import io.metersphere.system.dto.sdk.BaseCondition; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +@Data +public class CaseApiModuleRequest extends BaseCondition { + @Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)") + private List<@NotBlank String> moduleIds; + + @Schema(description = "协议", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{api_definition_module.protocol.not_blank}") + @Size(min = 1, max = 20, message = "{api_definition_module.protocol.length_range}") + private String protocol = ModuleConstants.NODE_PROTOCOL_HTTP; + @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{api_definition_module.project_id.not_blank}") + @Size(min = 1, max = 50, message = "{api_definition_module.project_id.length_range}") + private String projectId; + + @Schema(description = "关键字") + private String keyword; + + @Schema(description = "版本fk") + private String versionId; + + @Schema(description = "版本引用fk") + private String refId; + + @Schema(description = "关联用例的类型(API,SCENARIO,UI,PERFORMANCE)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{functional_test_case_disassociate_request.type.not_blank}") + private String sourceType; +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalTestCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalTestCaseService.java index 69e0bb1b98..9e7d6f7fe9 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalTestCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalTestCaseService.java @@ -4,14 +4,18 @@ import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.functional.constants.AssociateCaseType; import io.metersphere.functional.domain.FunctionalCaseTest; import io.metersphere.functional.domain.FunctionalCaseTestExample; +import io.metersphere.functional.mapper.ExtFunctionalCaseModuleMapper; import io.metersphere.functional.mapper.ExtFunctionalCaseTestMapper; import io.metersphere.functional.mapper.FunctionalCaseTestMapper; +import io.metersphere.functional.request.CaseApiModuleRequest; import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.sdk.util.LogUtils; +import io.metersphere.sdk.util.Translator; +import io.metersphere.system.dto.sdk.BaseTreeNode; import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.ibatis.session.ExecutorType; @@ -45,6 +49,15 @@ public class FunctionalTestCaseService { @Resource private FunctionalCaseTestMapper functionalCaseTestMapper; + @Resource + private FunctionalCaseModuleService functionalCaseModuleService; + + @Resource + private ExtFunctionalCaseModuleMapper extFunctionalCaseModuleMapper; + + private static final String UNPLANNED_API = "api_unplanned_request"; + + /** * 获取功能用例未关联的接口用例列表 * @@ -78,6 +91,7 @@ public class FunctionalTestCaseService { switch (request.getSourceType()) { case AssociateCaseType.API -> associateApi(request, deleted, userId); case AssociateCaseType.SCENARIO -> associateScenario(request, deleted, userId); + default -> LogUtils.info("AssociateCaseType: " + request.getSourceType()); } @@ -137,4 +151,9 @@ public class FunctionalTestCaseService { return request.getSelectIds(); } } + + public List getTree(CaseApiModuleRequest request) { + List fileModuleList = extFunctionalCaseModuleMapper.selectApiCaseModuleByRequest(request); + return functionalCaseModuleService.buildTreeAndCountResource(fileModuleList, true, Translator.get(UNPLANNED_API)); + } } diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalTestCaseControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalTestCaseControllerTests.java index 98417cb492..536e1a8e01 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalTestCaseControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalTestCaseControllerTests.java @@ -1,9 +1,12 @@ package io.metersphere.functional.controller; +import io.metersphere.api.domain.ApiDefinitionModule; +import io.metersphere.api.mapper.ApiDefinitionModuleMapper; import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.functional.constants.AssociateCaseType; import io.metersphere.functional.domain.FunctionalCaseTest; import io.metersphere.functional.mapper.FunctionalCaseTestMapper; +import io.metersphere.functional.request.CaseApiModuleRequest; import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.request.ApiModuleProviderRequest; @@ -12,6 +15,7 @@ import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; +import io.metersphere.system.dto.sdk.BaseTreeNode; import jakarta.annotation.Resource; import org.junit.jupiter.api.*; import org.mockito.Mockito; @@ -38,6 +42,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest { private static final String URL_CASE_PAGE_DISASSOCIATE = "/functional/case/test/disassociate/case"; + private static final String URL_CASE_MODULE_TREE = "/functional/case/test/associate/api/module/tree"; @@ -47,6 +52,10 @@ public class FunctionalTestCaseControllerTests extends BaseTest { @Resource private FunctionalCaseTestMapper functionalCaseTestMapper; + @Resource + private ApiDefinitionModuleMapper apiDefinitionModuleMapper; + + @Test @Order(1) public void getPageSuccess() throws Exception { @@ -119,9 +128,24 @@ public class FunctionalTestCaseControllerTests extends BaseTest { String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); Assertions.assertNotNull(resultHolder); + Listoperations = new ArrayList<>(); + operations.add("gyq_associate_case_id_1"); + Mockito.when(provider.getSelectIds(request, false)).thenReturn(operations); + Assertions.assertNotNull(resultHolder); request.setSelectAll(false); request.setProjectId("project-associate-case-test"); - request.setSelectIds(List.of("gyq_associate_api_case_id_1")); + request.setSelectIds(operations); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_ASSOCIATE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + + request = new AssociateOtherCaseRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setSourceId("gyq_associate_case_id_1"); + request.setSelectAll(true); + request.setProjectId("project-associate-case-test"); + request.setExcludeIds(List.of("gyq_associate_api_case_id_2")); mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_ASSOCIATE, request); returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); resultHolder = JSON.parseObject(returnData, ResultHolder.class); @@ -165,6 +189,37 @@ public class FunctionalTestCaseControllerTests extends BaseTest { Assertions.assertNotNull(resultHolder); } + @Test + @Order(6) + public void getTreeSuccess() throws Exception { + ApiDefinitionModule apiDefinitionModule = new ApiDefinitionModule(); + apiDefinitionModule.setId("case_module"); + apiDefinitionModule.setPos(100L); + apiDefinitionModule.setName("api_case_module"); + apiDefinitionModule.setParentId("NONE"); + apiDefinitionModule.setProjectId("project-associate-case-test"); + apiDefinitionModule.setCreateUser("admin"); + apiDefinitionModule.setCreateTime(System.currentTimeMillis()); + apiDefinitionModule.setUpdateUser("admin"); + apiDefinitionModule.setUpdateTime(System.currentTimeMillis()); + apiDefinitionModuleMapper.insert(apiDefinitionModule); + List moduleTreeNode = this.getModuleTreeNode(); + Assertions.assertNotNull(moduleTreeNode); + System.out.println(JSON.toJSONString(moduleTreeNode)); + } + + + private List getModuleTreeNode() throws Exception { + MvcResult result = this.requestPostWithOkAndReturn(URL_CASE_MODULE_TREE, new CaseApiModuleRequest() {{ + this.setProtocol("HTTP"); + this.setProjectId("project-associate-case-test"); + this.setSourceType(AssociateCaseType.API); + }}); + String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class); + } + private void addFunctionalCaseTest() { FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); functionalCaseTest.setId("functionalCaseTestHasId");