feat(接口测试): 支持 k8s 执行

This commit is contained in:
fit2-zhao 2021-06-16 18:18:38 +08:00 committed by fit2-zhao
parent e30207a72f
commit 240cdbddf4
4 changed files with 94 additions and 36 deletions

View File

@ -8,6 +8,7 @@ import lombok.Setter;
@Setter @Setter
public class RunRequest { public class RunRequest {
private String testId; private String testId;
private String poolId;
// api / case 或有这个属性值 // api / case 或有这个属性值
private String reportId; private String reportId;
private String url; private String url;

View File

@ -7,13 +7,20 @@ import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.service.ApiScenarioReportService; import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.base.domain.JarConfig; import io.metersphere.base.domain.JarConfig;
import io.metersphere.base.domain.TestResource; import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.base.mapper.TestResourcePoolMapper;
import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.CompressUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.config.JmeterProperties; import io.metersphere.config.JmeterProperties;
import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.NodeDTO; import io.metersphere.dto.NodeDTO;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.performance.engine.Engine;
import io.metersphere.performance.engine.EngineFactory;
import io.metersphere.service.JarConfigService; import io.metersphere.service.JarConfigService;
import io.metersphere.service.SystemParameterService; import io.metersphere.service.SystemParameterService;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -54,6 +61,8 @@ public class JMeterService {
ResourcePoolCalculation resourcePoolCalculation; ResourcePoolCalculation resourcePoolCalculation;
@Resource @Resource
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Resource
private TestResourcePoolMapper testResourcePoolMapper;
@PostConstruct @PostConstruct
public void init() { public void init() {
@ -311,31 +320,36 @@ public class JMeterService {
public void runTest(String testId, String reportId, String runMode, String testPlanScenarioId, RunModeConfig config) { public void runTest(String testId, String reportId, String runMode, String testPlanScenarioId, RunModeConfig config) {
// 获取可以执行的资源池 // 获取可以执行的资源池
String resourcePoolId = config.getResourcePoolId(); String resourcePoolId = config.getResourcePoolId();
TestResource testResource = resourcePoolCalculation.getPool(resourcePoolId);
String configuration = testResource.getConfiguration();
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
String nodeIp = node.getIp();
Integer port = node.getPort();
BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo(); BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
// 占位符
String metersphereUrl = "http://localhost:8081";
if (baseInfo != null) {
metersphereUrl = baseInfo.getUrl();
}
try {
RunRequest runRequest = new RunRequest(); RunRequest runRequest = new RunRequest();
runRequest.setTestId(testId); runRequest.setTestId(testId);
if (ApiRunMode.API_PLAN.name().equals(runMode)) { if (ApiRunMode.API_PLAN.name().equals(runMode)) {
runRequest.setReportId(reportId); runRequest.setReportId(reportId);
} }
metersphereUrl += "/api/jmeter/download?testId=" + testId + "&reportId=" + reportId + "&testPlanScenarioId" + "&runMode=" + runMode; runRequest.setPoolId(resourcePoolId);
if (StringUtils.isNotEmpty(testPlanScenarioId)) { // 占位符
metersphereUrl += "=" + testPlanScenarioId; String platformUrl = "http://localhost:8081";
if (baseInfo != null) {
platformUrl = baseInfo.getUrl();
} }
runRequest.setUrl(metersphereUrl); platformUrl += "/api/jmeter/download?testId=" + testId + "&reportId=" + reportId + "&testPlanScenarioId" + "&runMode=" + runMode;
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
platformUrl += "=" + testPlanScenarioId;
}
runRequest.setUrl(platformUrl);
runRequest.setRunMode(runMode); runRequest.setRunMode(runMode);
// 如果是K8S调用
TestResourcePool pool = testResourcePoolMapper.selectByPrimaryKey(resourcePoolId);
if (pool != null && pool.getApi() && pool.getType().equals(ResourcePoolTypeEnum.K8S.name())) {
final Engine engine = EngineFactory.createApiEngine(runRequest);
engine.start();
} else {
TestResource testResource = resourcePoolCalculation.getPool(resourcePoolId);
String configuration = testResource.getConfiguration();
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
String nodeIp = node.getIp();
Integer port = node.getPort();
try {
String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port); String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port);
ResponseEntity<String> result = restTemplate.postForEntity(uri, runRequest, String.class); ResponseEntity<String> result = restTemplate.postForEntity(uri, runRequest, String.class);
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) { if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
@ -350,3 +364,4 @@ public class JMeterService {
} }
} }
} }
}

View File

@ -3,6 +3,7 @@ package io.metersphere.performance.engine;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.RunRequest;
import io.metersphere.base.domain.LoadTestWithBLOBs; import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.base.domain.TestResource; import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourcePool; import io.metersphere.base.domain.TestResourcePool;
@ -32,7 +33,6 @@ public abstract class AbstractEngine implements Engine {
protected PerformanceTestService performanceTestService; protected PerformanceTestService performanceTestService;
protected Integer threadNum; protected Integer threadNum;
protected List<TestResource> resourceList; protected List<TestResource> resourceList;
private final TestResourcePoolService testResourcePoolService; private final TestResourcePoolService testResourcePoolService;
private final TestResourceService testResourceService; private final TestResourceService testResourceService;
@ -45,7 +45,39 @@ public abstract class AbstractEngine implements Engine {
this.startTime = System.currentTimeMillis(); this.startTime = System.currentTimeMillis();
this.reportId = UUID.randomUUID().toString(); this.reportId = UUID.randomUUID().toString();
} }
protected void initApiConfig(RunRequest runRequest) {
String resourcePoolId = runRequest.getPoolId();
TestResourcePool resourcePool = testResourcePoolService.getResourcePool(resourcePoolId);
if (resourcePool == null || StringUtils.equals(resourcePool.getStatus(), ResourceStatusEnum.DELETE.name())) {
MSException.throwException("Resource Pool is empty");
}
if (!ResourcePoolTypeEnum.K8S.name().equals(resourcePool.getType())
&& !ResourcePoolTypeEnum.NODE.name().equals(resourcePool.getType())) {
MSException.throwException("Invalid Resource Pool type.");
}
if (!StringUtils.equals(resourcePool.getStatus(), ResourceStatusEnum.VALID.name())) {
MSException.throwException("Resource Pool Status is not VALID");
}
// image
String image = resourcePool.getImage();
if (StringUtils.isNotEmpty(image)) {
JMETER_IMAGE = image;
}
// heap
String heap = resourcePool.getHeap();
if (StringUtils.isNotEmpty(heap)) {
HEAP = heap;
}
// gc_algo
String gcAlgo = resourcePool.getGcAlgo();
if (StringUtils.isNotEmpty(gcAlgo)) {
GC_ALGO = gcAlgo;
}
this.resourceList = testResourceService.getResourcesByPoolId(resourcePool.getId());
if (CollectionUtils.isEmpty(this.resourceList)) {
MSException.throwException("Test Resource is empty");
}
}
protected void init(LoadTestWithBLOBs loadTest) { protected void init(LoadTestWithBLOBs loadTest) {
if (loadTest == null) { if (loadTest == null) {
MSException.throwException("LoadTest is null."); MSException.throwException("LoadTest is null.");

View File

@ -3,6 +3,7 @@ package io.metersphere.performance.engine;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.Application; import io.metersphere.Application;
import io.metersphere.api.dto.RunRequest;
import io.metersphere.base.domain.FileContent; import io.metersphere.base.domain.FileContent;
import io.metersphere.base.domain.FileMetadata; import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.LoadTestWithBLOBs; import io.metersphere.base.domain.LoadTestWithBLOBs;
@ -88,6 +89,15 @@ public class EngineFactory {
return null; return null;
} }
public static Engine createApiEngine(RunRequest runRequest) {
try {
return (Engine) ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, runRequest);
} catch (Exception e) {
LogUtil.error(e);
return null;
}
}
public static EngineContext createContext(LoadTestWithBLOBs loadTest, double[] ratios, String reportId, int resourceIndex) { public static EngineContext createContext(LoadTestWithBLOBs loadTest, double[] ratios, String reportId, int resourceIndex) {
final List<FileMetadata> fileMetadataList = performanceTestService.getFileMetadataByTestId(loadTest.getId()); final List<FileMetadata> fileMetadataList = performanceTestService.getFileMetadataByTestId(loadTest.getId());
if (org.springframework.util.CollectionUtils.isEmpty(fileMetadataList)) { if (org.springframework.util.CollectionUtils.isEmpty(fileMetadataList)) {