diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTest.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTest.java index 4143fa8230..75e65ad0dd 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTest.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTest.java @@ -30,6 +30,11 @@ public class FunctionalCaseTest implements Serializable { @Size(min = 1, max = 64, message = "{functional_case_test.source_type.length_range}", groups = {Created.class, Updated.class}) private String sourceType; + @Schema(description = "用例所属项目", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{functional_case_test.project_id.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 50, message = "{functional_case_test.project_id.length_range}", groups = {Created.class, Updated.class}) + private String projectId; + @Schema(description = "创建时间") private Long createTime; @@ -49,6 +54,7 @@ public class FunctionalCaseTest implements Serializable { caseId("case_id", "caseId", "VARCHAR", false), sourceId("source_id", "sourceId", "VARCHAR", false), sourceType("source_type", "sourceType", "VARCHAR", false), + projectId("project_id", "projectId", "VARCHAR", false), createTime("create_time", "createTime", "BIGINT", false), updateTime("update_time", "updateTime", "BIGINT", false), createUser("create_user", "createUser", "VARCHAR", false), diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTestExample.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTestExample.java index 75e8289bb1..5fa015ba01 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTestExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseTestExample.java @@ -384,6 +384,76 @@ public class FunctionalCaseTestExample { return (Criteria) this; } + public Criteria andProjectIdIsNull() { + addCriterion("project_id is null"); + return (Criteria) this; + } + + public Criteria andProjectIdIsNotNull() { + addCriterion("project_id is not null"); + return (Criteria) this; + } + + public Criteria andProjectIdEqualTo(String value) { + addCriterion("project_id =", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotEqualTo(String value) { + addCriterion("project_id <>", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThan(String value) { + addCriterion("project_id >", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThanOrEqualTo(String value) { + addCriterion("project_id >=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThan(String value) { + addCriterion("project_id <", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThanOrEqualTo(String value) { + addCriterion("project_id <=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLike(String value) { + addCriterion("project_id like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotLike(String value) { + addCriterion("project_id not like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdIn(List values) { + addCriterion("project_id in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotIn(List values) { + addCriterion("project_id not in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdBetween(String value1, String value2) { + addCriterion("project_id between", value1, value2, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotBetween(String value1, String value2) { + addCriterion("project_id not between", value1, value2, "projectId"); + return (Criteria) this; + } + public Criteria andCreateTimeIsNull() { addCriterion("create_time is null"); return (Criteria) this; diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseTestMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseTestMapper.xml index 1e9813c5ab..2c305ff60d 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseTestMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseTestMapper.xml @@ -6,6 +6,7 @@ + @@ -70,7 +71,8 @@ - id, case_id, source_id, source_type, create_time, update_time, create_user, update_user + id, case_id, source_id, source_type, project_id, create_time, update_time, create_user, + update_user - SELECT t1.id, t1.project_id, @@ -173,6 +173,17 @@ + + and a.protocol = #{request.protocol} 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 67f7468c67..a480dc4a00 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 @@ -3,14 +3,16 @@ package io.metersphere.api.provider; import io.metersphere.api.mapper.ExtApiDefinitionModuleMapper; import io.metersphere.api.mapper.ExtApiTestCaseMapper; import io.metersphere.api.service.definition.ApiDefinitionModuleService; -import io.metersphere.dto.ApiTestCaseProviderDTO; +import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.ApiTestCasePageProviderRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.request.AssociateOtherCaseRequest; 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; @@ -32,21 +34,34 @@ public class AssociateApiProvider implements BaseAssociateApiProvider { private static final String UNPLANNED_API = "api_unplanned_request"; @Override - public List getApiTestCaseList(String sourceType, String sourceName, String apiCaseColumnName, ApiTestCasePageProviderRequest apiTestCasePageProviderRequest) { - return extApiTestCaseMapper.listByProviderRequest(sourceType, sourceName, apiCaseColumnName, apiTestCasePageProviderRequest, false); + public List getApiTestCaseList(String sourceType, String sourceName, String apiCaseColumnName, TestCasePageProviderRequest testCasePageProviderRequest) { + return extApiTestCaseMapper.listByProviderRequest(sourceType, sourceName, apiCaseColumnName, testCasePageProviderRequest, false); } @Override public Map moduleCount(String sourceType, String sourceName, String apiCaseColumnName, ApiModuleProviderRequest request, boolean deleted) { request.setModuleIds(null); //查找根据moduleIds查找模块下的接口数量 查非delete状态的 - List moduleCountDTOList = extApiDefinitionModuleMapper.countModuleIdByProviderRequest(sourceType, sourceName, apiCaseColumnName,request, deleted); + List moduleCountDTOList = extApiDefinitionModuleMapper.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 getSelectIds(AssociateOtherCaseRequest request, Boolean deleted) { + if (request.isSelectAll()) { + List ids = extApiTestCaseMapper.getIdsByProvider(request, deleted); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + ids.removeAll(request.getExcludeIds()); + } + return ids; + } else { + return request.getSelectIds(); + } + } + public long getAllCount(List moduleCountDTOList) { long count = 0; for (ModuleCountDTO countDTO : moduleCountDTOList) { 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 3dddbaf965..9eefa4bb5e 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 @@ -1,16 +1,15 @@ package io.metersphere.api.controller; import io.metersphere.api.provider.AssociateApiProvider; -import io.metersphere.dto.ApiTestCaseProviderDTO; +import io.metersphere.dto.TestCaseProviderDTO; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.ApiTestCasePageProviderRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import jakarta.annotation.Resource; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; +import org.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; @@ -31,7 +30,8 @@ public class AssociateApiProviderTest extends BaseTest { @Order(1) @Sql(scripts = {"/dml/init_functional_case_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) public void getApiTestCaseListSuccess() throws Exception { - ApiTestCasePageProviderRequest request = new ApiTestCasePageProviderRequest(); + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setSourceType("API"); request.setSourceId("gyq_associate_case_id_1"); request.setProjectId("project-associate-case-test"); request.setCurrent(1); @@ -39,7 +39,7 @@ public class AssociateApiProviderTest extends BaseTest { request.setSort(new HashMap<>() {{ put("createTime", "desc"); }}); - List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); + List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); String jsonString = JSON.toJSONString(apiTestCaseList); System.out.println(jsonString); } @@ -57,5 +57,23 @@ public class AssociateApiProviderTest extends BaseTest { System.out.println(jsonString); } + @Test + @Order(3) + public void getSelectIdsSuccess() throws Exception { + AssociateOtherCaseRequest request = new AssociateOtherCaseRequest(); + request.setSourceType("API"); + 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")); + List selectIds = provider.getSelectIds(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds)); + request.setSelectAll(false); + request.setProjectId("project-associate-case-test"); + request.setSelectIds(List.of("gyq_associate_api_case_id_1")); + selectIds = provider.getSelectIds(request, false); + Assertions.assertTrue(CollectionUtils.isNotEmpty(selectIds)); + } + } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/constants/AssociateCaseType.java b/backend/services/case-management/src/main/java/io/metersphere/functional/constants/AssociateCaseType.java new file mode 100644 index 0000000000..2fdcdc051c --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/constants/AssociateCaseType.java @@ -0,0 +1,20 @@ +package io.metersphere.functional.constants; + +public class AssociateCaseType { + /** + * 接口用例 + */ + public static final String API = "API"; + /** + * 场景用例 + */ + public static final String SCENARIO = "SCENARIO"; + /** + * UI用例 + */ + public static final String UI = "UI"; + /** + * 性能用例 + */ + public static final String PERFORMANCE = "PERFORMANCE"; +} 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 09bc5406c4..4cd20c1bf9 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 @@ -2,14 +2,17 @@ package io.metersphere.functional.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; -import io.metersphere.dto.ApiTestCaseProviderDTO; +import io.metersphere.dto.TestCaseProviderDTO; +import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; import io.metersphere.functional.service.FunctionalTestCaseService; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.ApiTestCasePageProviderRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.request.AssociateOtherCaseRequest; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.system.security.CheckOwner; 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; @@ -37,20 +40,37 @@ public class FunctionalTestCaseController { @Operation(summary = "用例管理-功能用例-关联其他用例-获取接口用例列表") @RequiresPermissions(value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_DELETE}, logical = Logical.OR) @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") - public Pager> associateApiCaseList(@Validated @RequestBody ApiTestCasePageProviderRequest request) { + public Pager> associateApiCaseList(@Validated @RequestBody TestCasePageProviderRequest request) { Page page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc"); return PageUtils.setPageInfo(page, functionalTestCaseService.page(request)); } @PostMapping("/associate/api/module/count") - @Operation(summary = "接口测试-接口管理-模块-统计模块数量") + @Operation(summary = "用例管理-功能用例-关联其他用例-统计接口用例模块数量") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) @CheckOwner(resourceId = "#request.projectId", resourceType = "project") public Map moduleCount(@Validated @RequestBody ApiModuleProviderRequest request) { return functionalTestCaseService.moduleCount(request, false); } + @PostMapping("/associate/case") + @Operation(summary = "用例管理-功能用例-关联其他用例-关联用例") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) + @CheckOwner(resourceId = "#request.sourceId", resourceType = "functional_case") + public void associateCase(@Validated @RequestBody AssociateOtherCaseRequest request) { + functionalTestCaseService.associateCase(request, false, SessionUtils.getUserId()); + } + + @PostMapping("/disassociate/case") + @Operation(summary = "用例管理-功能用例-关联其他用例-取消关联用例") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) + @CheckOwner(resourceId = "#request.projectId", resourceType = "project") + public void disassociateCase(@Validated @RequestBody FunctionalTestCaseDisassociateRequest request) { + functionalTestCaseService.disassociateCase(request); + } + + diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.java b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.java new file mode 100644 index 0000000000..a4f66b56e7 --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.java @@ -0,0 +1,13 @@ +package io.metersphere.functional.mapper; + +import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface ExtFunctionalCaseTestMapper { + + List getIds(@Param("request") FunctionalTestCaseDisassociateRequest request); + + +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.xml b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.xml new file mode 100644 index 0000000000..23cf08228a --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtFunctionalCaseTestMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + functional_case_test.source_id not in + ( + select api_test_case.id from api_test_case where api_test_case.name like concat('%', #{request.keyword},'%') + ) + + + + + + functional_case_test.source_id not in + ( + select api_scenario.id from api_scenario where api_scenario.name like concat('%', #{request.keyword},'%') + ) + + + + + + + + + + + + + AND + + + OR + + + + + + + + + + + functional_case_test.project_id in + + + + + + + functional_case_test.source_type in + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalTestCaseDisassociateRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalTestCaseDisassociateRequest.java new file mode 100644 index 0000000000..a0f7e67e65 --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalTestCaseDisassociateRequest.java @@ -0,0 +1,20 @@ +package io.metersphere.functional.request; + +import io.metersphere.functional.dto.BaseFunctionalCaseBatchDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class FunctionalTestCaseDisassociateRequest extends BaseFunctionalCaseBatchDTO { + + @Schema(description = "功能用例选择的项目id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{functional_test_case_disassociate_request.case_id.not_blank}") + private String caseId; + + @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 43c65fa1e3..69e0bb1b98 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,10 +1,24 @@ package io.metersphere.functional.service; -import io.metersphere.dto.ApiTestCaseProviderDTO; +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.ExtFunctionalCaseTestMapper; +import io.metersphere.functional.mapper.FunctionalCaseTestMapper; +import io.metersphere.functional.request.FunctionalTestCaseDisassociateRequest; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.ApiTestCasePageProviderRequest; +import io.metersphere.request.TestCasePageProviderRequest; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.sdk.util.LogUtils; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionUtils; +import org.redisson.api.IdGenerator; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,12 +36,22 @@ public class FunctionalTestCaseService { @Resource private BaseAssociateApiProvider provider; + @Resource + SqlSessionFactory sqlSessionFactory; + + @Resource + private ExtFunctionalCaseTestMapper extFunctionalCaseTestMapper; + + @Resource + private FunctionalCaseTestMapper functionalCaseTestMapper; + /** * 获取功能用例未关联的接口用例列表 + * * @param request request * @return List */ - public List page(ApiTestCasePageProviderRequest request) { + public List page(TestCasePageProviderRequest request) { return provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); } @@ -42,4 +66,75 @@ public class FunctionalTestCaseService { return provider.moduleCount("functional_case_test", "case_id", "source_id", request, deleted); } + + /** + * 关联其他用例 + * + * @param request request + * @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); + } + + + } + + private void associateScenario(AssociateOtherCaseRequest request, boolean deleted, String userId) { + LogUtils.info("关联场景"); + } + + private void associateApi(AssociateOtherCaseRequest request, boolean deleted, String userId) { + List selectIds = provider.getSelectIds(request, deleted); + if (CollectionUtils.isEmpty(selectIds)) { + return; + } + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + FunctionalCaseTestMapper caseTestMapper = sqlSession.getMapper(FunctionalCaseTestMapper.class); + for (String selectId : selectIds) { + FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); + functionalCaseTest.setCaseId(request.getSourceId()); + functionalCaseTest.setProjectId(request.getProjectId()); + functionalCaseTest.setSourceId(selectId); + 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); + } + + /** + * 取消关联其他用例 + * + * @param request request + */ + public void disassociateCase(FunctionalTestCaseDisassociateRequest request) { + List functionalTestCaseIds = doSelectIds(request); + FunctionalCaseTestExample functionalCaseTestExample = new FunctionalCaseTestExample(); + if (CollectionUtils.isNotEmpty(functionalTestCaseIds)) { + functionalCaseTestExample.createCriteria().andIdIn(functionalTestCaseIds); + functionalCaseTestMapper.deleteByExample(functionalCaseTestExample); + } + } + + + public List doSelectIds(FunctionalTestCaseDisassociateRequest request) { + if (request.isSelectAll()) { + List ids = extFunctionalCaseTestMapper.getIds(request); + if (org.apache.commons.collections.CollectionUtils.isNotEmpty(request.getExcludeIds())) { + ids.removeAll(request.getExcludeIds()); + } + return ids; + } else { + return request.getSelectIds(); + } + } } 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 6682c2ed3d..98417cb492 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,14 @@ package io.metersphere.functional.controller; -import io.metersphere.dto.ApiTestCaseProviderDTO; +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.FunctionalTestCaseDisassociateRequest; import io.metersphere.provider.BaseAssociateApiProvider; import io.metersphere.request.ApiModuleProviderRequest; -import io.metersphere.request.ApiTestCasePageProviderRequest; +import io.metersphere.request.AssociateOtherCaseRequest; +import io.metersphere.request.TestCasePageProviderRequest; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; @@ -29,14 +34,24 @@ public class FunctionalTestCaseControllerTests extends BaseTest { private static final String URL_CASE_PAGE_MODULE_COUNT = "/functional/case/test/associate/api/module/count"; + private static final String URL_CASE_PAGE_ASSOCIATE = "/functional/case/test/associate/case"; + + private static final String URL_CASE_PAGE_DISASSOCIATE = "/functional/case/test/disassociate/case"; + + + @Resource BaseAssociateApiProvider provider; + @Resource + private FunctionalCaseTestMapper functionalCaseTestMapper; + @Test @Order(1) public void getPageSuccess() throws Exception { - ApiTestCasePageProviderRequest request = new ApiTestCasePageProviderRequest(); + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setSourceType(AssociateCaseType.API); request.setSourceId("gyq_associate_case_id_1"); request.setProjectId("project_gyq_associate_test"); request.setCurrent(1); @@ -44,17 +59,17 @@ public class FunctionalTestCaseControllerTests extends BaseTest { request.setSort(new HashMap<>() {{ put("createTime", "desc"); }}); - ApiTestCaseProviderDTO apiTestCaseProviderDTO = new ApiTestCaseProviderDTO(); - apiTestCaseProviderDTO.setName("第一个"); - List operations = new ArrayList<>(); - operations.add(apiTestCaseProviderDTO); + TestCaseProviderDTO testCaseProviderDTO = new TestCaseProviderDTO(); + testCaseProviderDTO.setName("第一个"); + List operations = new ArrayList<>(); + operations.add(testCaseProviderDTO); Mockito.when(provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request)).thenReturn(operations); - List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); + List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request); String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); - List apiTestCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), ApiTestCaseProviderDTO.class); - Assertions.assertNotNull(apiTestCaseProviderDTOS); + List testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class); + Assertions.assertNotNull(testCaseProviderDTOS); System.out.println(JSON.toJSONString(apiTestCaseList)); } @@ -62,17 +77,18 @@ public class FunctionalTestCaseControllerTests extends BaseTest { @Test @Order(2) public void getPageSuccessT() throws Exception { - ApiTestCasePageProviderRequest request = new ApiTestCasePageProviderRequest(); + TestCasePageProviderRequest request = new TestCasePageProviderRequest(); + request.setSourceType(AssociateCaseType.API); request.setSourceId("gyq_associate_case_id_1"); request.setProjectId("project_gyq_associate_test"); request.setCurrent(1); request.setPageSize(10); - List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); + List apiTestCaseList = provider.getApiTestCaseList("functional_case_test", "case_id", "source_id", request); MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE, request); String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); - List apiTestCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), ApiTestCaseProviderDTO.class); - Assertions.assertNotNull(apiTestCaseProviderDTOS); + List testCaseProviderDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestCaseProviderDTO.class); + Assertions.assertNotNull(testCaseProviderDTOS); System.out.println(JSON.toJSONString(apiTestCaseList)); } @@ -90,5 +106,78 @@ public class FunctionalTestCaseControllerTests extends BaseTest { Assertions.assertNotNull(resultHolder); } + @Test + @Order(4) + public void associateCaseSuccess() throws Exception { + AssociateOtherCaseRequest request = new AssociateOtherCaseRequest(); + request.setSourceType(AssociateCaseType.API); + 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 mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_ASSOCIATE, request); + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + request.setSelectAll(false); + request.setProjectId("project-associate-case-test"); + request.setSelectIds(List.of("gyq_associate_api_case_id_1")); + mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_ASSOCIATE, request); + returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + + } + + @Test + @Order(5) + public void disassociateCaseSuccess() throws Exception { + addFunctionalCaseTest(); + FunctionalTestCaseDisassociateRequest request = new FunctionalTestCaseDisassociateRequest(); + request.setSourceType(AssociateCaseType.API); + request.setCaseId("gyq_associate_functional_case_id_1"); + request.setSelectAll(true); + request.setExcludeIds(List.of("gyq_associate_api_case_id_2")); + MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_CASE_PAGE_DISASSOCIATE, request); + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + FunctionalCaseTest functionalCaseTest = functionalCaseTestMapper.selectByPrimaryKey("functionalCaseTestHasId"); + Assertions.assertNull(functionalCaseTest); + request = new FunctionalTestCaseDisassociateRequest(); + request.setSourceType(AssociateCaseType.API); + request.setCaseId("gyq_associate_case_id_1"); + request.setSelectAll(true); + request.setSelectIds(List.of("gyq_associate_api_case_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 FunctionalTestCaseDisassociateRequest(); + request.setSourceType(AssociateCaseType.API); + request.setCaseId("gyq_associate_case_id_1"); + request.setSelectAll(false); + request.setSelectIds(List.of("gyq_associate_api_case_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); + } + + private void addFunctionalCaseTest() { + FunctionalCaseTest functionalCaseTest = new FunctionalCaseTest(); + functionalCaseTest.setId("functionalCaseTestHasId"); + functionalCaseTest.setCaseId("gyq_associate_functional_case_id_1"); + functionalCaseTest.setSourceId("gyq_api_case_id_1"); + functionalCaseTest.setSourceType(AssociateCaseType.API); + functionalCaseTest.setProjectId("gyq-organization-associate-case-test"); + functionalCaseTest.setCreateUser("admin"); + functionalCaseTest.setCreateTime(System.currentTimeMillis()); + functionalCaseTest.setUpdateUser("admin"); + functionalCaseTest.setUpdateTime(System.currentTimeMillis()); + functionalCaseTestMapper.insert(functionalCaseTest); + } + } diff --git a/backend/services/case-management/src/test/resources/dml/init_associate_case_test.sql b/backend/services/case-management/src/test/resources/dml/init_associate_case_test.sql new file mode 100644 index 0000000000..0a6a6153b2 --- /dev/null +++ b/backend/services/case-management/src/test/resources/dml/init_associate_case_test.sql @@ -0,0 +1,33 @@ +INSERT INTO organization(id, num, name, description, create_time, update_time, create_user, update_user, deleted, + delete_user, delete_time) VALUE + ('gyq-organization-associate-case-test', null, 'gyq-organization-associate-case-test', 'gyq-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 ('gyq-project-associate-case-test', null, 'gyq-organization-associate-case-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_functional_case_id_1', 100, 'TEST_MODULE_ID', 'gyq-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_functional_case_id_1', 'STEP', '1111', '', '', 'TEST'); + +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 ('gyq_api_case_id_1','gyq_api_case_id_1','P0',1001, null, 'Underway', null, null, 100, 'gyq-project-associate-case-test', 'gyq_api_definition_id_1', 'gyq_version_id', 'gyq_associate_env_id', 1698058347559, 'admin',1698058347559,'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 ('gyq_api_case_id_2','测试查询模块用','P0',1002, null, 'Underway', null, null, 200, 'gyq-project-associate-case-test', 'gyq_api_definition_id_1', 'gyq_version_id', 'gyq_associate_env_id', 1698058347559, 'admin',1698058347559,'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 ('gyq_associate_api_definition_id_1', 'gyq_associate_api_definition_id_1', 'HTTP', 'POST','api/test','test-api-status', 1000001, null, 1, 'gyq-project-associate-case-test' , 'gyq_associate_test_module', true, 'v1.10','gyq_associate_api_definition_id_1', null, UNIX_TIMESTAMP() * 1000,'admin', UNIX_TIMESTAMP() * 1000,'admin', null,null,false); + + +INSERT INTO api_definition_module(id, name,parent_id, project_id, pos, create_time, update_time, update_user, create_user) +VALUES ('gyq_associate_test_module', 'gyq_associate_test_module', 'NONE', 'gyq-project-associate-case-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_version_id','gyq-project-associate-case-test','v1.0.0', null, 'open', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin');