diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourcePoolReturnDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourcePoolReturnDTO.java new file mode 100644 index 0000000000..fef9e4f645 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourcePoolReturnDTO.java @@ -0,0 +1,13 @@ +package io.metersphere.sdk.dto; + +import io.metersphere.system.domain.TestResourcePool; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class TestResourcePoolReturnDTO extends TestResourcePool { + private TestResourceReturnDTO testResourceReturnDTO; + + @Schema(title = "资源池是否在使用中") + private Boolean inUsed; +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourceReturnDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourceReturnDTO.java new file mode 100644 index 0000000000..1fa965bbc5 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/TestResourceReturnDTO.java @@ -0,0 +1,89 @@ +package io.metersphere.sdk.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; +import java.util.Map; + +/** + *用来返回TestResourceBlob的结构 + */ +@Getter +@Setter +public class TestResourceReturnDTO { + /** + * type为 node时, 性能测试的镜像 + */ + @Schema(title = "type为node时, 性能测试的镜像") + private String loadTestImage; + + /** + * type为 node时, 性能测试jvm配置 + */ + @Schema(title = "type为node时, 性能测试jvm配置") + private String loadTestHeap; + + /** + * type为 node时, 接口测试 性能测试 node 节点配置 + */ + @Schema(title = "type为node时, 接口测试,性能测试node节点配置") + private List nodesList; + + /** + * type为 k8s 时,接口测试,性能测试的ip + */ + @Schema(title = "type为k8s时,接口测试,性能测试的ip") + private String ip; + /** + * type为 k8s 时,接口测试,性能测试的token + */ + @Schema(title = "type为k8s时,接口测试,性能测试的token") + private String token; + /** + * type为 k8s 时,接口测试,性能测试的命名空间 + */ + @Schema(title = "type为k8s时,接口测试,性能测试的命名空间") + private String nameSpaces; + /** + * type为 k8s 时,接口测试,性能测试,UI测试的最大并发数 + */ + @Schema(title = "type为k8s时,接口测试,性能测试,UI测试的最大并发数") + private Integer concurrentNumber; + + /** + * type为 k8s 时,接口测试,性能测试的单pod 最大线程数 + */ + @Schema(title = "type为k8s时,接口测试,性能测试的单pod最大线程数") + private Integer podThreads; + + /** + * type为 k8s 时,性能测试自定义JOB模版 string + */ + @Schema(title = " type为k8s时,性能测试自定义JOB模版string") + private String jobDefinition; + /** + * type为 k8s 时,接口测试镜像 + */ + @Schema(title = "type为k8s时,接口测试镜像") + private String apiTestImage; + + /** + * type为 k8s 时,接口测试deployName + */ + @Schema(title = "type为k8s时,接口测试deployName") + private String deployName; + + /** + * UI测试的grid配置 + */ + @Schema(title = "UI测试的grid配置") + private String uiGrid; + + /** + * 关联的组织id集合 + */ + @Schema(title = "关联的组织id和名称map") + private Map orgIdNameMap; +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/NodeResourcePoolService.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/NodeResourcePoolService.java index 78a54783a8..ebbdb69660 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/NodeResourcePoolService.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/NodeResourcePoolService.java @@ -32,11 +32,29 @@ public class NodeResourcePoolService { restTemplateWithTimeOut.setRequestFactory(httpRequestFactory); } - public boolean validate(TestResourceDTO testResourceDTO) { + public boolean validate(TestResourceDTO testResourceDTO, Boolean usedApiType) { List nodesList = testResourceDTO.getNodesList(); if (CollectionUtils.isEmpty(nodesList)) { throw new MSException(Translator.get("no_nodes_message")); } + boolean isValid = true; + for (TestResourceNodeDTO testResourceNodeDTO : nodesList) { + if (StringUtils.isBlank(testResourceNodeDTO.getIp())) { + throw new MSException(Translator.get("ip_is_null")); + } + if (StringUtils.isBlank(testResourceNodeDTO.getPort())) { + throw new MSException(Translator.get("port_is_null")); + } + if (testResourceNodeDTO.getConcurrentNumber() == null) { + throw new MSException(Translator.get("concurrent_number_is_null")); + } + if (!usedApiType) { + if (StringUtils.isBlank(testResourceNodeDTO.getMonitor())) { + throw new MSException(Translator.get("monitor_number_is_null")); + } + } + isValid = validateNode(testResourceNodeDTO); + } //校验节点 List> ipPort = nodesList.stream() .map(resource -> { @@ -47,10 +65,6 @@ public class NodeResourcePoolService { if (ipPort.size() < nodesList.size()) { throw new MSException(Translator.get("duplicate_node_ip_port")); } - boolean isValid = true; - for (TestResourceNodeDTO testResourceNodeDTO : nodesList) { - isValid = validateNode(testResourceNodeDTO); - } return isValid; } diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/TestResourcePoolService.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/TestResourcePoolService.java index e7c6ec577b..ee12e3396a 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/TestResourcePoolService.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/service/TestResourcePoolService.java @@ -12,6 +12,7 @@ import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.*; +import io.metersphere.system.mapper.OrganizationMapper; import io.metersphere.system.mapper.TestResourcePoolBlobMapper; import io.metersphere.system.mapper.TestResourcePoolMapper; import io.metersphere.system.mapper.TestResourcePoolOrganizationMapper; @@ -25,9 +26,7 @@ import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; @Slf4j @Service @@ -117,7 +116,7 @@ public class TestResourcePoolService { if (StringUtils.equalsIgnoreCase(type, ResourcePoolTypeEnum.NODE.name())) { NodeResourcePoolService resourcePoolService = CommonBeanFactory.getBean(NodeResourcePoolService.class); if (resourcePoolService != null) { - return resourcePoolService.validate(testResourceDTO); + return resourcePoolService.validate(testResourceDTO, usedApiType); } else { return false; } @@ -234,23 +233,39 @@ public class TestResourcePoolService { } } - public TestResourcePoolDTO getTestResourcePoolDetail(String testResourcePoolId) { - TestResourcePoolDTO testResourcePoolDTO = new TestResourcePoolDTO(); + public TestResourcePoolReturnDTO getTestResourcePoolDetail(String testResourcePoolId) { + TestResourcePoolReturnDTO testResourcePoolReturnDTO = new TestResourcePoolReturnDTO(); TestResourcePool testResourcePool = testResourcePoolMapper.selectByPrimaryKey(testResourcePoolId); if (testResourcePool == null) { throw new MSException(Translator.get("test_resource_pool_not_exists")); } TestResourcePoolBlob testResourcePoolBlob = testResourcePoolBlobMapper.selectByPrimaryKey(testResourcePoolId); if (testResourcePoolBlob == null) { - BeanUtils.copyBean(testResourcePoolDTO, testResourcePool); - return testResourcePoolDTO; + BeanUtils.copyBean(testResourcePoolReturnDTO, testResourcePool); + return testResourcePoolReturnDTO; } byte[] configuration = testResourcePoolBlob.getConfiguration(); String testResourceDTOStr = new String(configuration); TestResourceDTO testResourceDTO = JSON.parseObject(testResourceDTOStr, TestResourceDTO.class); - BeanUtils.copyBean(testResourcePoolDTO, testResourcePool); - testResourcePoolDTO.setTestResourceDTO(testResourceDTO); - return testResourcePoolDTO; + TestResourceReturnDTO testResourceReturnDTO = new TestResourceReturnDTO(); + BeanUtils.copyBean(testResourceReturnDTO, testResourceDTO); + List orgIds = testResourceDTO.getOrgIds(); + Map orgIdNameMap = new HashMap<>(); + if (CollectionUtils.isNotEmpty(orgIds)) { + for (String orgId : orgIds) { + OrganizationMapper organizationMapper = CommonBeanFactory.getBean(OrganizationMapper.class); + Organization organization = organizationMapper.selectByPrimaryKey(orgId); + if (organization != null) { + orgIdNameMap.put(orgId,organization.getName()); + } else { + orgIdNameMap.put(orgId,Translator.get("organization_not_exists")); + } + } + } + testResourceReturnDTO.setOrgIdNameMap(orgIdNameMap); + BeanUtils.copyBean(testResourcePoolReturnDTO, testResourcePool); + testResourcePoolReturnDTO.setTestResourceReturnDTO(testResourceReturnDTO); + return testResourcePoolReturnDTO; } public LogDTO addLog(TestResourcePoolRequest request) { diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties index 963352d5bb..860c37c842 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties @@ -79,6 +79,9 @@ test_resource_pool_not_exists=Test resource pool not exists test_resource_pool_invalid=Test resource pool invalid selenium_grid_is_null=selenium_grid cannot be null ip_is_null=ip address/domain name cannot be null +port_is_null = Port cannot be null +concurrent_number_is_null = ConcurrentNumber cannot be null +monitor_is_null = Monitor cannot be null token_is_null = Token can not be null namespace_is_null=Namespaces can not be null deploy_name_is_null=Deploy Name cannot be null diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties index 489dd59c65..9710c35b3a 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties @@ -62,7 +62,7 @@ startTime_must_be_less_than_endTime=开始日期必须小于结束日期 start_time_is_null=开始日期不能为空 end_time_is_null=结束日期不能为空 -organization_not_exists=工作空间不存在 +organization_not_exists=组织不存在 #test resource pool test_resource_pool_id_is_null=资源池ID不能为空 test_resource_pool_name_is_null=资源池名称不能为空 @@ -77,6 +77,9 @@ test_resource_pool_not_exists=测试资源池不存在 test_resource_pool_invalid=当前测试使用的资源池处于禁用状态 selenium_grid_is_null=selenium_grid不能为空 ip_is_null=ip 地址/域名不能为空 +port_is_null = 节点端口不能为空 +concurrent_number_is_null = 节点最大线程数不能为空 +monitor_is_null = node节点监控器不能为空 token_is_null = Token 不能为空 namespace_is_null=命名空间不能为空 deploy_name_is_null=Deploy Name 不能为空 diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties index 2b043269a9..a7277a57ae 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties @@ -63,7 +63,7 @@ start_time_is_null=開始日期不能為空 end_time_is_null=結束日期不能為空 #organization -organization_not_exists=工作空間不存在 +organization_not_exists=組織不存在 #test resource pool test_resource_pool_id_is_null=資源池ID不能為空 test_resource_pool_name_is_null=資源池名稱不能為空 @@ -79,6 +79,9 @@ test_resource_pool_not_exists=測試資源池不存在 test_resource_pool_invalid=當前測試使用的資源池處於禁用狀態 selenium_grid_is_null=selenium_grid不能為空 ip_is_null=ip 地址/域名不能為空 +port_is_null = 節點端口不能為空 +concurrent_number_is_null = 節點最大線程數不能為空 +monitor_is_null = node節點監控器不能為空 token_is_null = Token 不能為空 namespace_is_null=命名空間不能為空 deploy_name_is_null=Deploy Name 不能為空 diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TestResourcePoolController.java b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TestResourcePoolController.java index 76a4f58888..fe22c9634f 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TestResourcePoolController.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/controller/TestResourcePoolController.java @@ -6,6 +6,7 @@ import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.dto.QueryResourcePoolRequest; import io.metersphere.sdk.dto.TestResourcePoolDTO; import io.metersphere.sdk.dto.TestResourcePoolRequest; +import io.metersphere.sdk.dto.TestResourcePoolReturnDTO; import io.metersphere.sdk.log.annotation.Log; import io.metersphere.sdk.log.constants.OperationLogType; import io.metersphere.sdk.service.TestResourcePoolService; @@ -78,7 +79,7 @@ public class TestResourcePoolController { @GetMapping("/detail/{poolId}") @Operation(summary = "查看资源池详细") @RequiresPermissions(PermissionConstants.SYSTEM_TEST_RESOURCE_POOL_READ) - public TestResourcePoolDTO getTestResourcePoolDetail(@PathVariable(value = "poolId") String testResourcePoolId) { + public TestResourcePoolReturnDTO getTestResourcePoolDetail(@PathVariable(value = "poolId") String testResourcePoolId) { return testResourcePoolService.getTestResourcePoolDetail(testResourcePoolId); } diff --git a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TestResourcePoolControllerTests.java b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TestResourcePoolControllerTests.java index c585d43029..edc27f04ff 100644 --- a/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TestResourcePoolControllerTests.java +++ b/backend/services/system-setting/src/test/java/io/metersphere/system/controller/TestResourcePoolControllerTests.java @@ -6,6 +6,7 @@ import io.metersphere.sdk.constants.ResourcePoolTypeEnum; import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.controller.handler.ResultHolder; import io.metersphere.sdk.dto.TestResourceDTO; +import io.metersphere.sdk.dto.TestResourceNodeDTO; import io.metersphere.sdk.dto.TestResourcePoolRequest; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.dto.QueryResourcePoolRequest; @@ -28,6 +29,7 @@ import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.List; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -69,6 +71,7 @@ class TestResourcePoolControllerTests extends BaseTest { "\"deployName\":\"hello\",\n" + "\"uiGrid\":\"localhost:4444\"\n" + "}"; + private static final String configuration = "{\n" + " \"loadTestImage\": \"123\",\n" + " \"loadTestHeap\": \"123\",\n" + @@ -344,19 +347,43 @@ class TestResourcePoolControllerTests extends BaseTest { url = TEST_RESOURCE_POOL_UPDATE; } - TestResourcePoolRequest testResourcePoolRequest = generatorDto(true, false, false, false); + TestResourcePoolRequest testResourcePoolRequest = generatorDto(true,true, false, false, false, false,false,false,false); this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); //资源池类型为空 - testResourcePoolRequest = generatorDto(false, true, false, false); + testResourcePoolRequest = generatorDto(true, false, true, false, false, false,false,false,false); this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); - //资源池节点集合为空 - testResourcePoolRequest = generatorDto(false, false, true, false); + //api 类型 资源池节点集合为空 + testResourcePoolRequest = generatorDto(true, false, false, true, false, false,false,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 ip 为空 + testResourcePoolRequest = generatorDto(true, false, false, true, false, true,false,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 port 为空 + testResourcePoolRequest = generatorDto(true, false, false, true, false, false,true,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 最大线程数 为空 + testResourcePoolRequest = generatorDto(true, false, false, true, false, false,false,false,true); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //性能测试类型 资源池节点集合为空 + testResourcePoolRequest = generatorDto(false, false, false, true, false, false,false,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空ip为空 + testResourcePoolRequest = generatorDto(false, false, false, true, false, true,false,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 port 为空 + testResourcePoolRequest = generatorDto(false, false, false, true, false, false,true,false,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 port 为空 + testResourcePoolRequest = generatorDto(false, false, false, true, false, false,false,true,false); + this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); + //资源池节点不为空,但是内容为空 最大线程数 为空 + testResourcePoolRequest = generatorDto(false, false, false, true, false, false,false,false,true); this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); //应用组织 - testResourcePoolRequest = generatorDto(false, false, false, true); + testResourcePoolRequest = generatorDto(true,false, false, false, true, false,false,false,false); this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); //部分组织 - testResourcePoolRequest = generatorDto(false, false, false, false); + testResourcePoolRequest = generatorDto(true,false, false, false, false, false, false,false,false); testResourcePoolRequest.setAllOrg(false); testResourcePoolRequest.setTestResourceDTO(JSON.parseObject(configurationWidthOutOrgIds, TestResourceDTO.class)); this.requestPost(url, testResourcePoolRequest, ERROR_REQUEST_MATCHER); @@ -398,7 +425,7 @@ class TestResourcePoolControllerTests extends BaseTest { .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } - private TestResourcePoolRequest generatorDto(boolean noName, boolean noType, boolean noResources, boolean noAllOrg) { + private TestResourcePoolRequest generatorDto(boolean useApiType, boolean noName, boolean noType, boolean noResources, boolean noAllOrg, boolean noIp, boolean noPort, boolean noMonitor, boolean noConcurrentNumber) { TestResourcePoolRequest testResourcePoolDTO = new TestResourcePoolRequest(); //没名字 if (!noName) { @@ -413,9 +440,38 @@ class TestResourcePoolControllerTests extends BaseTest { testResourcePoolDTO.setApiTest(true); setResources(testResourcePoolDTO,true); }else { - testResourcePoolDTO.setApiTest(true); + testResourcePoolDTO.setApiTest(useApiType); + testResourcePoolDTO.setLoadTest(!useApiType); TestResourceDTO testResourceDTO = JSON.parseObject(configuration, TestResourceDTO.class); - testResourceDTO.setNodesList(null); + //有资源池(用途为API 或者 性能测试的校验)但 IP port monitor ConcurrentNumber 为空 + TestResourceNodeDTO testResourceNodeDTO = new TestResourceNodeDTO(); + if (noIp) { + testResourceNodeDTO.setIp(""); + } else { + testResourceNodeDTO.setIp("172.2.130.1"); + } + if (noPort) { + testResourceNodeDTO.setPort(""); + } else { + testResourceNodeDTO.setPort("3306"); + } + if (noMonitor) { + testResourceNodeDTO.setMonitor(" "); + } else { + testResourceNodeDTO.setMonitor("11"); + } + if (noConcurrentNumber){ + testResourceNodeDTO.setConcurrentNumber(null); + } else { + testResourceNodeDTO.setConcurrentNumber(1); + } + if (!noIp && !noPort && !noMonitor && ! noConcurrentNumber) { + testResourceDTO.setNodesList(null); + } else { + ListtestResourceNodeDTOS = new ArrayList<>(); + testResourceNodeDTOS.add(testResourceNodeDTO); + testResourceDTO.setNodesList(testResourceNodeDTOS); + } testResourcePoolDTO.setTestResourceDTO(testResourceDTO); } //没选全部