diff --git a/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateApiProvider.java b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateApiProvider.java index 7ef5a997d9..29ea675f76 100644 --- a/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateApiProvider.java +++ b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateApiProvider.java @@ -13,13 +13,13 @@ import java.util.Map; */ public interface BaseAssociateApiProvider { /** - * 获取尚未关联的接口列表 + * 获取尚未关联的用例列表 * * @param sourceType 关联关系表表名 * @param sourceName 关联关系表主动关联方字段名称 * @param apiCaseColumnName 接口用例id 在关联关系表的字段名称 * @param testCasePageProviderRequest 接口用例高级搜索条件 - * @return List + * @return List 通用用例集合 */ List getApiTestCaseList(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest testCasePageProviderRequest); diff --git a/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateScenarioProvider.java b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateScenarioProvider.java new file mode 100644 index 0000000000..4cd597ffa2 --- /dev/null +++ b/backend/framework/provider/src/main/java/io/metersphere/provider/BaseAssociateScenarioProvider.java @@ -0,0 +1,45 @@ +package io.metersphere.provider; + +import io.metersphere.api.domain.ApiScenario; +import io.metersphere.dto.TestCaseProviderDTO; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; + +import java.util.List; +import java.util.Map; + +/** + * @author guoyuqi + */ +public interface BaseAssociateScenarioProvider { + /** + * 获取尚未关联的场景用例列表 + * + * @param sourceType 关联关系表表名 + * @param sourceName 关联关系表主动关联方字段名称 + * @param caseColumnName 场景用例id 在关联关系表的字段名称 + * @param testCasePageProviderRequest 用例高级搜索条件 + * @return List 通用用例集合 + */ + List getScenarioCaseList(String sourceType, String sourceName, String caseColumnName, TestCasePageProviderRequest testCasePageProviderRequest); + + /** + * 根据用例的搜索条件获取符合条件的接口定义的模块统计数量 + * + * @param request 接口用例高级搜索条件 + * @param deleted 接口定义是否删除 + * @return 接口模块统计数量 + */ + Map moduleCount(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest request, boolean deleted); + + /** + * 根据页面筛选条件获取批量操作的场景 + * + * @return 接口用例的ids + */ + List getSelectScenarioCases(AssociateOtherCaseRequest request, Boolean deleted); + + + + +} diff --git a/backend/framework/provider/src/main/java/io/metersphere/request/TestCasePageProviderRequest.java b/backend/framework/provider/src/main/java/io/metersphere/request/TestCasePageProviderRequest.java index 1a68846d13..0b03b0e381 100644 --- a/backend/framework/provider/src/main/java/io/metersphere/request/TestCasePageProviderRequest.java +++ b/backend/framework/provider/src/main/java/io/metersphere/request/TestCasePageProviderRequest.java @@ -53,7 +53,7 @@ public class TestCasePageProviderRequest implements Serializable { @Size(min = 1, max = 50, message = "{api_definition.project_id.length_range}") private String sourceId; - @Schema(description = "接口pk") + @Schema(description = "接口pk(只在关联接口的时候用)") private String apiDefinitionId; @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) 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 a92ab13720..465daa70af 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 @@ -4,6 +4,11 @@ import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest; import io.metersphere.api.dto.scenario.ApiScenarioDTO; import io.metersphere.api.dto.scenario.ApiScenarioPageRequest; +import io.metersphere.dto.TestCaseProviderDTO; +import io.metersphere.project.dto.ModuleCountDTO; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.system.dto.sdk.BaseTreeNode; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -17,4 +22,12 @@ public interface ExtApiScenarioMapper { List getTagsByIds(@Param("ids") List ids, @Param("deleted") boolean deleted); + List listByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted); + + List countModuleIdByProviderRequest(@Param("table") String resourceType, @Param("sourceName") String sourceName, @Param("apiCaseColumnName") String apiCaseColumnName, @Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted); + + List selectIdAndParentIdByProjectId(@Param("projectId") String projectId); + + List getTestCaseByProvider(@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 1ae2f53f0c..7d53bfd3db 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 @@ -9,6 +9,11 @@ + + + + + + + + + + + + @@ -109,6 +161,40 @@ + + + and ( + api_scenario.num like concat('%', #{request.keyword},'%') + or api_scenario.name like concat('%', #{request.keyword},'%') + or api_scenario.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]')) + ) + + + and api_scenario.project_id = #{request.projectId} + + + and api_scenario.module_id in + + #{nodeId} + + + + + + + + + + + + + + + + + + + @@ -253,6 +339,20 @@ AND ${versionTable}.latest = 1 + + + + + and ${versionTable}.version_id = #{request.versionId} + + + and ${versionTable}.ref_id = #{request.refId} + + + AND ${versionTable}.latest = 1 + + + and ${versionTable}.version_id = #{request.versionId} 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 new file mode 100644 index 0000000000..f2fb1b764d --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/provider/AssociateScenarioProvider.java @@ -0,0 +1,90 @@ +package io.metersphere.api.provider; + +import io.metersphere.api.domain.ApiScenario; +import io.metersphere.api.domain.ApiScenarioExample; +import io.metersphere.api.mapper.ApiScenarioMapper; +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.BaseAssociateScenarioProvider; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.sdk.util.Translator; +import io.metersphere.system.dto.sdk.BaseTreeNode; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class AssociateScenarioProvider implements BaseAssociateScenarioProvider { + + @Resource + private ExtApiScenarioMapper extApiScenarioMapper; + @Resource + private ApiScenarioModuleService apiScenarioModuleService; + @Resource + private ApiScenarioMapper apiScenarioMapper; + + private static final String DEBUG_MODULE_COUNT_ALL = "all"; + private static final String UNPLANNED_SCENARIO = "api_unplanned_scenario"; + + + @Override + public List getScenarioCaseList(String sourceType, String sourceName, String caseColumnName, TestCasePageProviderRequest testCasePageProviderRequest) { + return extApiScenarioMapper.listByProviderRequest(sourceType, sourceName, caseColumnName, testCasePageProviderRequest, false); + } + + @Override + public Map moduleCount(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest request, boolean deleted) { + request.setModuleIds(null); + //查找根据moduleIds查找模块下的接口数量 查非delete状态的 + List moduleCountDTOList = extApiScenarioMapper.countModuleIdByProviderRequest(sourceType, sourceName, apiCaseColumnName, request, deleted); + long allCount = getAllCount(moduleCountDTOList); + Map moduleCountMap = getModuleCountMap(request, moduleCountDTOList); + moduleCountMap.put(DEBUG_MODULE_COUNT_ALL, allCount); + return moduleCountMap; + } + + @Override + public List getSelectScenarioCases(AssociateOtherCaseRequest request, Boolean deleted) { + if (request.isSelectAll()) { + List cases = extApiScenarioMapper.getTestCaseByProvider(request, deleted); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + cases = cases.stream().filter(t -> !request.getExcludeIds().contains(t.getId())).toList(); + } + return cases; + } else { + ApiScenarioExample apiScenarioExample = new ApiScenarioExample(); + apiScenarioExample.createCriteria().andIdIn(request.getSelectIds()); + return apiScenarioMapper.selectByExample(apiScenarioExample); + } + } + + + public long getAllCount(List moduleCountDTOList) { + long count = 0; + for (ModuleCountDTO countDTO : moduleCountDTOList) { + count += countDTO.getDataCount(); + } + return count; + } + + /** + * 查找当前项目下模块每个节点对应的资源统计 + */ + public Map getModuleCountMap(TestCasePageProviderRequest request, List moduleCountDTOList) { + //构建模块树,并计算每个节点下的所有数量(包含子节点) + List treeNodeList = this.getTreeOnlyIdsAndResourceCount(request, moduleCountDTOList); + return apiScenarioModuleService.getIdCountMapByBreadth(treeNodeList); + } + + public List getTreeOnlyIdsAndResourceCount(TestCasePageProviderRequest request, List moduleCountDTOList) { + //节点内容只有Id和parentId + List fileModuleList = extApiScenarioMapper.selectIdAndParentIdByProjectId(request.getProjectId()); + return apiScenarioModuleService.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED_SCENARIO)); + } +} diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateScenarioProviderTest.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateScenarioProviderTest.java new file mode 100644 index 0000000000..8c1b614304 --- /dev/null +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/AssociateScenarioProviderTest.java @@ -0,0 +1,91 @@ +package io.metersphere.api.controller; + +import io.metersphere.api.domain.ApiScenario; +import io.metersphere.api.provider.AssociateScenarioProvider; +import io.metersphere.dto.TestCaseProviderDTO; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.sdk.util.JSON; +import io.metersphere.system.base.BaseTest; +import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +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 java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@AutoConfigureMockMvc +public class AssociateScenarioProviderTest extends BaseTest { + @Resource + private AssociateScenarioProvider provider; + + @Test + @Order(1) + @Sql(scripts = {"/dml/init_functional_scenario_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) + public void getScenarioCaseListSuccess() throws Exception { + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setSourceType("SCENARIO"); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setProjectId("project-associate-scenario-test"); + request.setCurrent(1); + request.setPageSize(10); + request.setSort(new HashMap<>() {{ + put("createTime", "desc"); + }}); + List apiScenarioList = provider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request); + String jsonString = JSON.toJSONString(apiScenarioList); + System.out.println(jsonString); + } + + @Test + @Order(2) + public void moduleCountSuccess() throws Exception { + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setSourceType("SCENARIO"); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setProjectId("project-associate-scenario-test"); + request.setCurrent(1); + request.setPageSize(10); + request.setSort(new HashMap<>() {{ + put("createTime", "desc"); + }}); + + Map stringLongMap = provider.moduleCount("functional_case_test", "case_id", "source_id", request, false); + String jsonString = JSON.toJSONString(stringLongMap); + System.out.println(jsonString); + } + + @Test + @Order(3) + public void getSelectIdsSuccess() throws Exception { + AssociateOtherCaseRequest request = new AssociateOtherCaseRequest(); + request.setSourceType("SCENARIO"); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setSelectAll(true); + request.setProjectId("project-associate-scenario-test"); + request.setExcludeIds(List.of("associate_gyq_api_scenario_two")); + List scenarioCases = provider.getSelectScenarioCases(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases)); + request.setSelectAll(false); + request.setProjectId("project-associate-scenario-test"); + request.setSelectIds(List.of("associate_gyq_api_scenario_one")); + scenarioCases = provider.getSelectScenarioCases(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases)); + request.setSourceType("SCENARIO"); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setSelectAll(true); + request.setProjectId("project-associate-scenario-test"); + scenarioCases = provider.getSelectScenarioCases(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(scenarioCases)); + + } + + +} diff --git a/backend/services/api-test/src/test/resources/dml/init_functional_scenario_test.sql b/backend/services/api-test/src/test/resources/dml/init_functional_scenario_test.sql new file mode 100644 index 0000000000..411186c5b6 --- /dev/null +++ b/backend/services/api-test/src/test/resources/dml/init_functional_scenario_test.sql @@ -0,0 +1,27 @@ +INSERT INTO organization(id, num, name, description, create_time, update_time, create_user, update_user, deleted, + delete_user, delete_time) VALUE + ('organization-associate-scenario-test', null, 'organization-associate-case-test', 'organization-associate-case-test', + UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'admin', 0, null, null); + +INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) +VALUES ('project-associate-scenario-test', null, 'organization-associate-scenario-test', '用例评论项目', '系统默认创建的项目', + 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000); + + +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 ('gyq_associate_scenario_id_1', 100, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'UN_EXECUTED', b'0', b'0', b'1', 'admin', 'admin', '', 1698058347559, 1698058347559, NULL); + +INSERT INTO functional_case_blob(id, steps, text_description, expected_result, prerequisite, description) VALUES ('gyq_associate_scenario_id_1', 'STEP', '1111', '', '', 'TEST'); + +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 ('associate_gyq_api_scenario_one', 'api_scenario', 'p1', 'test-api-status', null, null,1000001, 1,'v1.10', 'associate_gyq_api_scenario_one','project-associate-scenario-test', 'gyq_associate_test_scenario_module', null,null,'admin', UNIX_TIMESTAMP() * 1000,null,null,'admin', UNIX_TIMESTAMP() * 1000, false), + ('associate_gyq_api_scenario_two', 'api_scenario_two', 'p1', 'test-api-status', null, null,1000001, 1,'v1.10', 'associate_gyq_api_scenario_two','project-associate-scenario-test', 'gyq_associate_test_scenario_module', null,null,'admin', UNIX_TIMESTAMP() * 1000,null,null,'admin', UNIX_TIMESTAMP() * 1000, false); + + +INSERT INTO api_scenario_module(id, name,parent_id, project_id, pos, create_time, update_time, update_user, create_user) +VALUES ('gyq_associate_test_scenario_module', 'gyq_associate_test_module', 'NONE', 'project-associate-scenario-test', 100, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin','admin'); + +INSERT INTO project_version(id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user) +values ('gyq_associate_test_scenario_version_id','project-associate-scenario-test','v1.0.0', null, 'open', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin'); + + 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 92a185a78f..ce45d7e329 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 @@ -1,5 +1,6 @@ package io.metersphere.functional.service; +import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiTestCase; import io.metersphere.dto.BugProviderDTO; import io.metersphere.dto.TestCaseProviderDTO; @@ -17,6 +18,7 @@ import io.metersphere.functional.request.DisassociateOtherCaseRequest; import io.metersphere.functional.request.FunctionalCaseTestRequest; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateBugProvider; +import io.metersphere.provider.BaseAssociateScenarioProvider; import io.metersphere.request.*; import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.Translator; @@ -32,6 +34,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -44,7 +47,10 @@ import java.util.Map; public class FunctionalTestCaseService { @Resource - private BaseAssociateApiProvider provider; + private BaseAssociateApiProvider associateApiProvider; + + @Resource + private BaseAssociateScenarioProvider associateScenarioProvider; @Resource SqlSessionFactory sqlSessionFactory; @@ -68,13 +74,19 @@ public class FunctionalTestCaseService { /** - * 获取功能用例未关联的接口用例列表 + * 获取功能用例未关联的用例列表 * * @param request request * @return List */ public List page(TestCasePageProviderRequest request) { - return provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); + List testCaseProviderDTOS = new ArrayList<>(); + switch (request.getSourceType()) { + case AssociateCaseType.API -> testCaseProviderDTOS = associateApiProvider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); + case AssociateCaseType.SCENARIO -> testCaseProviderDTOS = associateScenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request); + default -> new ArrayList<>(); + } + return testCaseProviderDTOS; } /** @@ -85,7 +97,13 @@ public class FunctionalTestCaseService { * @return 接口模块统计数量 */ public Map moduleCount(TestCasePageProviderRequest request, boolean deleted) { - return provider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted); + Map moduleCount = new HashMap<>(); + switch (request.getSourceType()) { + case AssociateCaseType.API -> moduleCount = associateApiProvider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted); + case AssociateCaseType.SCENARIO -> moduleCount = associateScenarioProvider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted); + default -> new HashMap<>(); + } + return moduleCount; } @@ -96,22 +114,41 @@ public class FunctionalTestCaseService { * @param deleted 接口定义是否删除 */ public void associateCase(AssociateOtherCaseRequest request, boolean deleted, String userId) { - switch (request.getSourceType()) { case AssociateCaseType.API -> associateApi(request, deleted, userId); case AssociateCaseType.SCENARIO -> associateScenario(request, deleted, userId); default -> LogUtils.info("AssociateCaseType: " + request.getSourceType()); } - - } private void associateScenario(AssociateOtherCaseRequest request, boolean deleted, String userId) { + List scenarioCases = associateScenarioProvider.getSelectScenarioCases(request, deleted); + if (CollectionUtils.isEmpty(scenarioCases)) { + return; + } + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + FunctionalCaseTestMapper caseTestMapper = sqlSession.getMapper(FunctionalCaseTestMapper.class); + for (ApiScenario apiScenario : scenarioCases) { + FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); + functionalCaseTest.setCaseId(request.getSourceId()); + functionalCaseTest.setProjectId(request.getProjectId()); + functionalCaseTest.setSourceId(apiScenario.getId()); + functionalCaseTest.setVersionId(apiScenario.getVersionId()); + functionalCaseTest.setSourceType(request.getSourceType()); + functionalCaseTest.setId(IdGenerator.random().generateId()); + functionalCaseTest.setCreateUser(userId); + functionalCaseTest.setCreateTime(System.currentTimeMillis()); + functionalCaseTest.setUpdateUser(userId); + functionalCaseTest.setUpdateTime(System.currentTimeMillis()); + caseTestMapper.insert(functionalCaseTest); + } + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); LogUtils.info("关联场景"); } private void associateApi(AssociateOtherCaseRequest request, boolean deleted, String userId) { - List apiTestCases = provider.getSelectApiTestCases(request, deleted); + List apiTestCases = associateApiProvider.getSelectApiTestCases(request, deleted); if (CollectionUtils.isEmpty(apiTestCases)) { return; } diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/config/CaseTestConfiguration.java b/backend/services/case-management/src/test/java/io/metersphere/functional/config/CaseTestConfiguration.java index 278def0c08..9763a92dd6 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/config/CaseTestConfiguration.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/config/CaseTestConfiguration.java @@ -2,6 +2,7 @@ package io.metersphere.functional.config; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateBugProvider; +import io.metersphere.provider.BaseAssociateScenarioProvider; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; @@ -11,6 +12,9 @@ public class CaseTestConfiguration { @MockBean BaseAssociateApiProvider provider; + @MockBean + BaseAssociateScenarioProvider scenarioProvider; + @MockBean BaseAssociateBugProvider baseAssociateBugProvider; 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 b4ea05192c..17dfc4e656 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,8 +1,10 @@ package io.metersphere.functional.controller; import io.metersphere.api.domain.ApiDefinitionModule; +import io.metersphere.api.domain.ApiScenarioModule; import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.mapper.ApiDefinitionModuleMapper; +import io.metersphere.api.mapper.ApiScenarioModuleMapper; import io.metersphere.dto.BugProviderDTO; import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.functional.constants.AssociateCaseType; @@ -17,10 +19,9 @@ import io.metersphere.functional.request.AssociateCaseModuleRequest; import io.metersphere.functional.request.AssociatePlanPageRequest; import io.metersphere.functional.request.DisassociateOtherCaseRequest; import io.metersphere.functional.request.FunctionalCaseTestRequest; -import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper; -import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.provider.BaseAssociateBugProvider; +import io.metersphere.provider.BaseAssociateScenarioProvider; import io.metersphere.request.*; import io.metersphere.sdk.constants.FunctionalCaseExecuteResult; import io.metersphere.sdk.util.JSON; @@ -72,6 +73,9 @@ public class FunctionalTestCaseControllerTests extends BaseTest { @Resource BaseAssociateApiProvider provider; + @Resource + BaseAssociateScenarioProvider scenarioProvider; + @Resource private FunctionalCaseTestMapper functionalCaseTestMapper; @@ -80,17 +84,16 @@ public class FunctionalTestCaseControllerTests extends BaseTest { @Resource private ApiDefinitionModuleMapper apiDefinitionModuleMapper; + + @Resource + private ApiScenarioModuleMapper apiScenarioModuleMapper; + @Resource BaseAssociateBugProvider baseAssociateBugProvider; - @Resource - TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; - @Resource - TestPlanMapper testPlanMapper; @Test @Order(1) - @Sql(scripts = {"/dml/init_test_plan_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) public void getPageSuccess() throws Exception { TestCasePageProviderRequest request = new TestCasePageProviderRequest(); request.setSourceType(AssociateCaseType.API); @@ -114,6 +117,27 @@ public class FunctionalTestCaseControllerTests extends BaseTest { Assertions.assertNotNull(testCaseProviderDTOS); System.out.println(JSON.toJSONString(apiTestCaseList)); + request = new TestCasePageProviderRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setProjectId("project_gyq_associate_test"); + request.setCurrent(1); + request.setPageSize(10); + request.setSort(new HashMap<>() {{ + put("createTime", "desc"); + }}); + testCaseProviderDTO = new TestCaseProviderDTO(); + testCaseProviderDTO.setName("第一个场景"); + operations = new ArrayList<>(); + operations.add(testCaseProviderDTO); + Mockito.when(scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request)).thenReturn(operations); + List apiScenarioList = scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class); + Assertions.assertNotNull(testCaseProviderDTOS); + System.out.println(JSON.toJSONString(apiScenarioList)); } @Test @@ -133,6 +157,20 @@ public class FunctionalTestCaseControllerTests extends BaseTest { Assertions.assertNotNull(testCaseProviderDTOS); System.out.println(JSON.toJSONString(apiTestCaseList)); + request = new TestCasePageProviderRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setSourceId("gyq_associate_scenario_id_1"); + request.setProjectId("project_gyq_associate_test"); + request.setCurrent(1); + request.setPageSize(10); + List apiScenarioList = scenarioProvider.getScenarioCaseList("functional_case_test", "case_id", "source_id", request); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class); + Assertions.assertNotNull(testCaseProviderDTOS); + System.out.println(JSON.toJSONString(apiScenarioList)); + } @Test @@ -148,6 +186,17 @@ public class FunctionalTestCaseControllerTests extends BaseTest { String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); Assertions.assertNotNull(resultHolder); + + TestCasePageProviderRequest scenarioRequest = new TestCasePageProviderRequest(); + scenarioRequest.setSourceType(AssociateCaseType.SCENARIO); + scenarioRequest.setSourceId("gyq_associate_scenario_id_1"); + scenarioRequest.setProjectId("project_gyq_associate_test"); + scenarioRequest.setCurrent(1); + request.setPageSize(10); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_MODULE_COUNT, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); } @Test @@ -226,6 +275,38 @@ public class FunctionalTestCaseControllerTests extends BaseTest { returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); resultHolder = JSON.parseObject(returnData, ResultHolder.class); Assertions.assertNotNull(resultHolder); + + addFunctionalCaseScenarioTest(); + request = new DisassociateOtherCaseRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setCaseId("gyq_associate_functional_case_id_1"); + request.setSelectAll(true); + request.setExcludeIds(List.of("gyq_associate_api_scenario_id_2")); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + functionalCaseTest = functionalCaseTestMapper.selectByPrimaryKey("functionalCaseTestHasScenarioId"); + Assertions.assertNull(functionalCaseTest); + request = new DisassociateOtherCaseRequest(); + request.setSourceType(AssociateCaseType.API); + request.setCaseId("gyq_associate_case_id_1"); + request.setSelectAll(true); + request.setSelectIds(List.of("gyq_associate_api_scenario_id_1")); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + + request = new DisassociateOtherCaseRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setCaseId("gyq_associate_case_id_1"); + request.setSelectAll(false); + request.setSelectIds(List.of("gyq_associate_api_scenario_id_1")); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); } @Test @@ -244,6 +325,19 @@ public class FunctionalTestCaseControllerTests extends BaseTest { apiDefinitionModuleMapper.insert(apiDefinitionModule); List moduleTreeNode = this.getModuleTreeNode(); Assertions.assertNotNull(moduleTreeNode); + ApiScenarioModule apiScenarioModule = new ApiScenarioModule(); + apiScenarioModule.setId("scenario_module"); + apiScenarioModule.setPos(100L); + apiScenarioModule.setName("api_scenario_module"); + apiScenarioModule.setParentId("NONE"); + apiScenarioModule.setProjectId("project-associate-case-test"); + apiScenarioModule.setCreateUser("admin"); + apiScenarioModule.setCreateTime(System.currentTimeMillis()); + apiScenarioModule.setUpdateUser("admin"); + apiScenarioModule.setUpdateTime(System.currentTimeMillis()); + apiScenarioModuleMapper.insert(apiScenarioModule); + List moduleScenarioTreeNode = this.getModuleScenarioTreeNode(); + Assertions.assertNotNull(moduleScenarioTreeNode); } @Test @@ -262,6 +356,19 @@ public class FunctionalTestCaseControllerTests extends BaseTest { // 返回值中取出第一条ID最大的数据, 并判断是否是default-admin List functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class); Assertions.assertNotNull(functionalCaseTestDTOS); + addFunctionalCaseScenarioTest(); + request = new FunctionalCaseTestRequest(); + request.setSourceType(AssociateCaseType.SCENARIO); + request.setSourceId("gyq_associate_functional_case_id_1"); + request.setCurrent(1); + request.setPageSize(10); + mvcResult = this.requestPostWithOkAndReturn(URL_HAS_CASE_PAGE, request); + sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + sortHolder = JSON.parseObject(sortData, ResultHolder.class); + sortPageData = JSON.parseObject(JSON.toJSONString(sortHolder.getData()), Pager.class); + // 返回值中取出第一条ID最大的数据, 并判断是否是default-admin + functionalCaseTestDTOS = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), FunctionalCaseTestDTO.class); + Assertions.assertNotNull(functionalCaseTestDTOS); } @@ -276,6 +383,16 @@ public class FunctionalTestCaseControllerTests extends BaseTest { return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class); } + private List getModuleScenarioTreeNode() throws Exception { + MvcResult result = this.requestPostWithOkAndReturn(URL_CASE_MODULE_TREE, new AssociateCaseModuleRequest() {{ + this.setProjectId("project-associate-case-test"); + this.setSourceType(AssociateCaseType.SCENARIO); + }}); + 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"); @@ -291,6 +408,21 @@ public class FunctionalTestCaseControllerTests extends BaseTest { functionalCaseTestMapper.insert(functionalCaseTest); } + private void addFunctionalCaseScenarioTest() { + FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); + functionalCaseTest.setId("functionalCaseTestHasScenarioId"); + functionalCaseTest.setCaseId("gyq_associate_functional_case_id_1"); + functionalCaseTest.setVersionId("1.0"); + functionalCaseTest.setSourceId("gyq_api_scenario_id_1"); + functionalCaseTest.setSourceType(AssociateCaseType.SCENARIO); + functionalCaseTest.setProjectId("gyq-organization-associate-case-test"); + functionalCaseTest.setCreateUser("admin"); + functionalCaseTest.setCreateTime(System.currentTimeMillis()); + functionalCaseTest.setUpdateUser("admin"); + functionalCaseTest.setUpdateTime(System.currentTimeMillis()); + functionalCaseTestMapper.insert(functionalCaseTest); + } + private void addFunctionalCase() { FunctionalCase functionalCase = new FunctionalCase(); functionalCase.setName("测试关联"); @@ -401,6 +533,7 @@ public class FunctionalTestCaseControllerTests extends BaseTest { @Test @Order(12) + @Sql(scripts = {"/dml/init_test_plan_case.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) public void testAssociatePlanPage() throws Exception { AssociatePlanPageRequest request = new AssociatePlanPageRequest(); request.setCurrent(1);