fix (接口自动化): 接口自动化重构并发执行
This commit is contained in:
parent
0757afee45
commit
82f43c5522
|
@ -1,15 +1,15 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.api.service.ApiJmeterFileService;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
|
@ -19,15 +19,23 @@ public class ApiJmeterFileController {
|
|||
@Resource
|
||||
private ApiJmeterFileService apiJmeterFileService;
|
||||
|
||||
@GetMapping("download")
|
||||
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("testPlanScenarioId") String testPlanScenarioId) {
|
||||
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode,testId, reportId, testPlanScenarioId);
|
||||
@PostMapping("download/files")
|
||||
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestBody List<BodyFile> bodyFileList) {
|
||||
byte[] bytes = new byte[10];
|
||||
if (CollectionUtils.isNotEmpty(bodyFileList)) {
|
||||
bytes = apiJmeterFileService.downloadJmeterFiles(bodyFileList);
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + testId + ".zip\"")
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + UUID.randomUUID().toString() + ".zip\"")
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
@GetMapping("download")
|
||||
public byte[] downloadJmx(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("testPlanScenarioId") String testPlanScenarioId) {
|
||||
return apiJmeterFileService.downloadJmx(runMode, testId, reportId, testPlanScenarioId);
|
||||
}
|
||||
|
||||
@GetMapping("download/jar")
|
||||
public ResponseEntity<byte[]> downloadJmeterFiles() {
|
||||
byte[] bytes = apiJmeterFileService.downloadJmeterJar();
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import io.metersphere.api.dto.JvmInfoDTO;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RunModeConfig {
|
||||
|
@ -12,7 +15,8 @@ public class RunModeConfig {
|
|||
private String reportId;
|
||||
private boolean onSampleError;
|
||||
private String resourcePoolId;
|
||||
|
||||
private BaseSystemConfigDTO baseInfo;
|
||||
private List<JvmInfoDTO> testResources;
|
||||
/**
|
||||
* 运行环境
|
||||
*/
|
||||
|
|
|
@ -7,8 +7,6 @@ import io.metersphere.api.service.MsResultService;
|
|||
import io.metersphere.api.service.TestResultService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
|
@ -20,8 +18,6 @@ import java.util.Map;
|
|||
* 获取结果和数据库操作分离
|
||||
* 减少占用的数据库连接
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class APIBackendListenerHandler {
|
||||
|
||||
@Resource
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.JvmInfoDTO;
|
||||
import io.metersphere.api.dto.RunRequest;
|
||||
import io.metersphere.api.dto.automation.ExecuteType;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
|
@ -10,9 +11,9 @@ import io.metersphere.base.domain.TestResourcePool;
|
|||
import io.metersphere.base.mapper.TestResourcePoolMapper;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
|
||||
import io.metersphere.commons.constants.TriggerMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.*;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.dto.NodeDTO;
|
||||
|
@ -20,7 +21,15 @@ import io.metersphere.i18n.Translator;
|
|||
import io.metersphere.performance.engine.Engine;
|
||||
import io.metersphere.performance.engine.EngineFactory;
|
||||
import io.metersphere.service.SystemParameterService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.jmeter.config.Arguments;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
|
@ -35,9 +44,9 @@ import org.springframework.web.client.RestTemplate;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -128,17 +137,21 @@ public class JMeterService {
|
|||
init();
|
||||
FixedTask.tasks.put(testId, System.currentTimeMillis());
|
||||
addBackendListener(testId, debugReportId, runMode, testPlan);
|
||||
if (ExecuteType.Debug.name().equals(debugReportId) || ApiRunMode.SCENARIO.name().equals(runMode)) {
|
||||
if (ExecuteType.Debug.name().equals(debugReportId) || (ApiRunMode.SCENARIO.name().equals(runMode) && !TriggerMode.BATCH.name().equals(debugReportId))) {
|
||||
addResultCollector(testId, testPlan);
|
||||
}
|
||||
LocalRunner runner = new LocalRunner(testPlan);
|
||||
runner.run(testId);
|
||||
}
|
||||
|
||||
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();
|
||||
BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
|
||||
BaseSystemConfigDTO baseInfo = config.getBaseInfo();
|
||||
if (baseInfo == null) {
|
||||
baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
|
||||
}
|
||||
RunRequest runRequest = new RunRequest();
|
||||
runRequest.setTestId(testId);
|
||||
runRequest.setReportId(reportId);
|
||||
|
@ -166,15 +179,24 @@ public class JMeterService {
|
|||
MSException.throwException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
TestResource testResource = resourcePoolCalculation.getPool(resourcePoolId);
|
||||
TestResource testResource = null;
|
||||
List<JvmInfoDTO> testResources = config.getTestResources();
|
||||
if (CollectionUtils.isEmpty(testResources)) {
|
||||
testResource = resourcePoolCalculation.getPool(resourcePoolId);
|
||||
} else {
|
||||
int index = (int) (Math.random() * testResources.size());
|
||||
JvmInfoDTO jvmInfoDTO = testResources.get(index);
|
||||
testResource = testResources.get(index).getTestResource();
|
||||
}
|
||||
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);
|
||||
ResponseEntity<String> result = restTemplate.postForEntity(uri, runRequest, String.class);
|
||||
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
|
||||
ResponseEntity<String> resultEntity = restTemplate.postForEntity(uri, runRequest, String.class);
|
||||
String result = resultEntity.getBody(); // this.send(uri, runRequest);
|
||||
if (StringUtils.isEmpty(result) || !StringUtils.equals("SUCCESS", result)) {
|
||||
// 清理零时报告
|
||||
ApiScenarioReportService apiScenarioReportService = CommonBeanFactory.getBean(ApiScenarioReportService.class);
|
||||
apiScenarioReportService.delete(reportId);
|
||||
|
@ -182,7 +204,31 @@ public class JMeterService {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
MSException.throwException(e.getMessage());
|
||||
MSException.throwException(runRequest.getReportId() + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String send(String webhook, RunRequest runRequest) {
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
// 创建Http Post请求
|
||||
HttpPost httpPost = new HttpPost(webhook);
|
||||
// 创建请求内容
|
||||
StringEntity entity = new StringEntity(JSON.toJSONString(runRequest), ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(entity);
|
||||
// 执行http请求
|
||||
response = httpClient.execute(httpPost);
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
return e.getMessage();
|
||||
} finally {
|
||||
try {
|
||||
response.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,12 +10,10 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
import org.springframework.kafka.annotation.KafkaListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class MsKafkaListener {
|
||||
public static final String TOPICS = "ms-api-exec-topic";
|
||||
public static final String CONSUME_ID = "ms-api-exec-consume";
|
||||
|
@ -23,7 +21,11 @@ public class MsKafkaListener {
|
|||
@KafkaListener(id = CONSUME_ID, topics = TOPICS, groupId = "${spring.kafka.consumer.group-id}")
|
||||
public void consume(ConsumerRecord<?, String> record) {
|
||||
LogUtil.info("接收到执行结果开始存储");
|
||||
try {
|
||||
this.save(record.value());
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage());
|
||||
}
|
||||
LogUtil.info("执行内容存储结束");
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -41,7 +42,7 @@ public class ResourcePoolCalculation {
|
|||
example.createCriteria().andStatusEqualTo("VALID").andTypeEqualTo("NODE").andIdEqualTo(resourcePoolId);
|
||||
List<TestResourcePool> pools = testResourcePoolMapper.selectByExample(example);
|
||||
// 按照NODE节点的可用内存空间大小排序
|
||||
JvmInfoDTO jvmInfoDTO = null;
|
||||
List<JvmInfoDTO> availableNodes = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(pools)) {
|
||||
List<String> poolIds = pools.stream().map(pool -> pool.getId()).collect(Collectors.toList());
|
||||
TestResourceExample resourceExample = new TestResourceExample();
|
||||
|
@ -57,19 +58,49 @@ public class ResourcePoolCalculation {
|
|||
if (nodeJvm == null) {
|
||||
continue;
|
||||
}
|
||||
// 优先取资源充足的节点,如果当前节点资源超过1G就不需要在排序了
|
||||
if (nodeJvm.getVmFree() > 1024) {
|
||||
return testResource;
|
||||
}
|
||||
if (jvmInfoDTO == null || jvmInfoDTO.getVmFree() < nodeJvm.getVmFree()) {
|
||||
jvmInfoDTO = nodeJvm;
|
||||
jvmInfoDTO.setTestResource(testResource);
|
||||
nodeJvm.setTestResource(testResource);
|
||||
availableNodes.add(nodeJvm);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jvmInfoDTO == null || jvmInfoDTO.getTestResource() == null) {
|
||||
if (CollectionUtils.isEmpty(availableNodes)) {
|
||||
MSException.throwException("未获取到资源池,请检查配置【系统设置-系统-测试资源池】");
|
||||
}
|
||||
int index = (int) (Math.random() * availableNodes.size());
|
||||
JvmInfoDTO jvmInfoDTO = availableNodes.get(index);
|
||||
return jvmInfoDTO.getTestResource();
|
||||
}
|
||||
|
||||
|
||||
public List<JvmInfoDTO> getPools(String resourcePoolId) {
|
||||
// 获取可以执行的资源池
|
||||
TestResourcePoolExample example = new TestResourcePoolExample();
|
||||
example.createCriteria().andStatusEqualTo("VALID").andTypeEqualTo("NODE").andIdEqualTo(resourcePoolId);
|
||||
List<TestResourcePool> pools = testResourcePoolMapper.selectByExample(example);
|
||||
|
||||
// 按照NODE节点的可用内存空间大小排序
|
||||
List<JvmInfoDTO> availableNodes = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(pools)) {
|
||||
List<String> poolIds = pools.stream().map(pool -> pool.getId()).collect(Collectors.toList());
|
||||
TestResourceExample resourceExample = new TestResourceExample();
|
||||
resourceExample.createCriteria().andTestResourcePoolIdIn(poolIds);
|
||||
List<TestResource> testResources = testResourceMapper.selectByExampleWithBLOBs(resourceExample);
|
||||
for (TestResource testResource : testResources) {
|
||||
String configuration = testResource.getConfiguration();
|
||||
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
|
||||
String nodeIp = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
String uri = String.format(BASE_URL + "/jmeter/getJvmInfo", nodeIp, port);
|
||||
JvmInfoDTO nodeJvm = this.getNodeJvmInfo(uri);
|
||||
if (nodeJvm == null) {
|
||||
continue;
|
||||
}
|
||||
nodeJvm.setTestResource(testResource);
|
||||
availableNodes.add(nodeJvm);
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isEmpty(availableNodes)) {
|
||||
MSException.throwException("未获取到资源池,请检查配置【系统设置-系统-测试资源池】");
|
||||
}
|
||||
return availableNodes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
|||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.api.jmeter.MessageCache;
|
||||
import io.metersphere.api.jmeter.ReportCounter;
|
||||
import io.metersphere.api.jmeter.ResourcePoolCalculation;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.api.service.task.ParallelScenarioExecTask;
|
||||
import io.metersphere.api.service.task.SerialScenarioExecTask;
|
||||
|
@ -129,6 +130,8 @@ public class ApiAutomationService {
|
|||
private TcpApiParamService tcpApiParamService;
|
||||
@Resource
|
||||
private ApiScenarioReferenceIdService apiScenarioReferenceIdService;
|
||||
@Resource
|
||||
private ResourcePoolCalculation resourcePoolCalculation;
|
||||
|
||||
public ApiScenarioWithBLOBs getDto(String id) {
|
||||
return apiScenarioMapper.selectByPrimaryKey(id);
|
||||
|
@ -989,6 +992,11 @@ public class ApiAutomationService {
|
|||
if (apiScenarios != null && apiScenarios.size() == 1 && (apiScenarios.get(0).getStepTotal() == null || apiScenarios.get(0).getStepTotal() == 0)) {
|
||||
MSException.throwException((apiScenarios.get(0).getName() + "," + Translator.get("automation_exec_info")));
|
||||
}
|
||||
// 资源池
|
||||
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
|
||||
List<JvmInfoDTO> testResources = resourcePoolCalculation.getPools(request.getConfig().getResourcePoolId());
|
||||
request.getConfig().setTestResources(testResources);
|
||||
}
|
||||
// 环境检查
|
||||
this.checkEnv(request, apiScenarios);
|
||||
// 集合报告设置
|
||||
|
@ -1087,7 +1095,7 @@ public class ApiAutomationService {
|
|||
private void run(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId) {
|
||||
// 开始选择执行模式
|
||||
if (executeQueue != null && executeQueue.size() > 0) {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(executeQueue.size());
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(6);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
||||
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
|
||||
|
@ -1175,9 +1183,11 @@ public class ApiAutomationService {
|
|||
//存储报告
|
||||
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
|
||||
batchMapper.insert(report);
|
||||
executorService.submit(new ParallelScenarioExecTask(jMeterService, executeQueue.get(reportId), request));
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
executorService.submit(new ParallelScenarioExecTask(jMeterService, executeQueue.get(reportId), request));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.api.dto.APIReportResult;
|
|||
import io.metersphere.api.dto.ApiTestImportRequest;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||
import io.metersphere.api.dto.automation.ReferenceDTO;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||
import io.metersphere.api.dto.definition.*;
|
||||
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
|
||||
|
@ -686,7 +687,9 @@ public class ApiDefinitionService {
|
|||
|
||||
// 调用执行方法
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(request.getId(), request.getId(), runMode, null, request.getConfig());
|
||||
RunModeConfig configs = request.getConfig();
|
||||
configs.setBaseInfo(CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo());
|
||||
jMeterService.runTest(request.getId(), request.getId(), runMode, null, configs);
|
||||
} else {
|
||||
jMeterService.runLocal(request.getId(), hashTree, request.getReportId(), runMode);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.metersphere.api.service;
|
|||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import io.metersphere.base.domain.JarConfig;
|
||||
import io.metersphere.base.domain.TestPlanApiScenario;
|
||||
|
@ -20,7 +19,6 @@ import org.apache.commons.collections.CollectionUtils;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
@ -31,7 +29,6 @@ import java.util.zip.ZipEntry;
|
|||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiJmeterFileService {
|
||||
|
||||
@Resource
|
||||
|
@ -42,10 +39,20 @@ public class ApiJmeterFileService {
|
|||
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
|
||||
@Resource
|
||||
private ApiScenarioMapper apiScenarioMapper;
|
||||
@Resource
|
||||
private JMeterService jMeterService;
|
||||
|
||||
public byte[] downloadJmeterFiles(String runMode, String testId, String reportId, String testPlanScenarioId) {
|
||||
public byte[] downloadJmeterFiles(List<BodyFile> bodyFileList) {
|
||||
Map<String, byte[]> files = new LinkedHashMap<>();
|
||||
Map<String, byte[]> multipartFiles = this.getMultipartFiles(bodyFileList);
|
||||
if (!com.alibaba.excel.util.CollectionUtils.isEmpty(multipartFiles)) {
|
||||
for (String k : multipartFiles.keySet()) {
|
||||
byte[] v = multipartFiles.get(k);
|
||||
files.put(k, v);
|
||||
}
|
||||
}
|
||||
return listBytesToZip(files);
|
||||
}
|
||||
|
||||
public byte[] downloadJmx(String runMode, String testId, String reportId, String testPlanScenarioId) {
|
||||
Map<String, String> planEnvMap = new HashMap<>();
|
||||
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
|
||||
// 获取场景用例单独的执行环境
|
||||
|
@ -66,7 +73,8 @@ public class ApiJmeterFileService {
|
|||
hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap);
|
||||
}
|
||||
//jMeterService.addBackendListener(reportId, hashTree);
|
||||
return zipFilesToByteArray(testId, hashTree);
|
||||
String jmx = new MsTestPlan().getJmx(hashTree);
|
||||
return jmx.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public byte[] downloadJmeterJar() {
|
||||
|
@ -124,6 +132,23 @@ public class ApiJmeterFileService {
|
|||
return multipartFiles;
|
||||
}
|
||||
|
||||
private Map<String, byte[]> getMultipartFiles(List<BodyFile> files) {
|
||||
Map<String, byte[]> multipartFiles = new LinkedHashMap<>();
|
||||
// 获取附件
|
||||
if (CollectionUtils.isNotEmpty(files)) {
|
||||
for (BodyFile bodyFile : files) {
|
||||
File file = new File(bodyFile.getName());
|
||||
if (file != null && !file.exists()) {
|
||||
byte[] fileByte = FileUtils.fileToByte(file);
|
||||
if (fileByte != null) {
|
||||
multipartFiles.put(file.getName(), fileByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return multipartFiles;
|
||||
}
|
||||
|
||||
private byte[] zipFilesToByteArray(String testId, HashTree hashTree) {
|
||||
String fileName = testId + ".jmx";
|
||||
String jmx = new MsTestPlan().getJmx(hashTree);
|
||||
|
@ -141,6 +166,11 @@ public class ApiJmeterFileService {
|
|||
return listBytesToZip(files);
|
||||
}
|
||||
|
||||
private byte[] fileToByteArray(HashTree hashTree) {
|
||||
String jmx = new MsTestPlan().getJmx(hashTree);
|
||||
return jmx.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private byte[] listBytesToZip(Map<String, byte[]> mapReport) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
|
|
@ -550,7 +550,6 @@ public class ApiScenarioReportService {
|
|||
public ApiScenarioReport updateScenario(TestResult result) {
|
||||
// 针对未正常返回结果的报告计数
|
||||
counter(result);
|
||||
|
||||
ApiScenarioReport lastReport = null;
|
||||
for (ScenarioResult item : result.getScenarios()) {
|
||||
// 更新报告状态
|
||||
|
@ -599,6 +598,7 @@ public class ApiScenarioReportService {
|
|||
if (obj != null) {
|
||||
ReportCounter counter = (ReportCounter) obj;
|
||||
counter.setNumber(counter.getNumber() + 1);
|
||||
System.out.println("得到统计数量:" + counter.getNumber());
|
||||
MessageCache.cache.put(report.getScenarioId(), counter);
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +623,9 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
|
||||
Map paramMap = new HashMap<>(beanMap);
|
||||
if (SessionUtils.getUser() != null) {
|
||||
paramMap.put("operator", SessionUtils.getUser().getName());
|
||||
}
|
||||
paramMap.put("status", result.getLastResult());
|
||||
String context = "${operator}执行接口自动化" + status + ": ${name}";
|
||||
NoticeModel noticeModel = NoticeModel.builder()
|
||||
|
|
|
@ -16,7 +16,6 @@ import io.metersphere.notice.service.NoticeSendService;
|
|||
import io.metersphere.service.SystemParameterService;
|
||||
import io.metersphere.track.request.testcase.TrackCount;
|
||||
import io.metersphere.track.service.TestPlanApiCaseService;
|
||||
import io.metersphere.track.service.TestPlanReportService;
|
||||
import io.metersphere.track.service.TestPlanScenarioCaseService;
|
||||
import io.metersphere.track.service.TestPlanTestCaseService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
@ -42,8 +41,6 @@ public class TestResultService {
|
|||
@Resource
|
||||
private ApiDefinitionExecResultService apiDefinitionExecResultService;
|
||||
@Resource
|
||||
private TestPlanReportService testPlanReportService;
|
||||
@Resource
|
||||
private ApiScenarioReportService apiScenarioReportService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
|
@ -158,6 +155,7 @@ public class TestResultService {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package io.metersphere.api.service.task;
|
|||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.commons.constants.TriggerMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -26,10 +27,10 @@ public class ParallelScenarioExecTask<T> implements Callable<T> {
|
|||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReport().getId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), request.getReportId(), request.getRunMode());
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.metersphere.api.jmeter.JMeterService;
|
|||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
||||
import io.metersphere.commons.constants.APITestStatus;
|
||||
import io.metersphere.commons.constants.TriggerMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -35,7 +36,7 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
|
|||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReport().getId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), request.getReportId(), request.getRunMode());
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
|
||||
}
|
||||
// 轮询查看报告状态,最多200次,防止死循环
|
||||
int index = 1;
|
||||
|
|
|
@ -38,6 +38,7 @@ public class ShiroUtils {
|
|||
filterChainDefinitionMap.put("/sso/callback", "anon");
|
||||
filterChainDefinitionMap.put("/license/valid", "anon");
|
||||
filterChainDefinitionMap.put("/api/jmeter/download", "anon");
|
||||
filterChainDefinitionMap.put("/api/jmeter/download/files", "anon");
|
||||
filterChainDefinitionMap.put("/api/jmeter/download/jar", "anon");
|
||||
|
||||
// for swagger
|
||||
|
|
|
@ -34,7 +34,7 @@ public class ParallelApiExecTask<T> implements Callable<T> {
|
|||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config);
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), null, runMode);
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null, runMode);
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -36,7 +36,7 @@ public class SerialApiExecTask<T> implements Callable<T> {
|
|||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config);
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), null, runMode);
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null, runMode);
|
||||
}
|
||||
// 轮询查看报告状态,最多200次,防止死循环
|
||||
ApiDefinitionExecResult report = null;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.jmeter.threads;
|
||||
|
||||
import io.metersphere.api.jmeter.MsResultCollector;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.jmeter.assertions.Assertion;
|
||||
import org.apache.jmeter.assertions.AssertionResult;
|
||||
import org.apache.jmeter.control.Controller;
|
||||
|
@ -67,7 +68,9 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
|
||||
private static final String TRUE = Boolean.toString(true); // i.e. "true"
|
||||
|
||||
/** How often to check for shutdown during ramp-up, default 1000ms */
|
||||
/**
|
||||
* How often to check for shutdown during ramp-up, default 1000ms
|
||||
*/
|
||||
private static final int RAMPUP_GRANULARITY =
|
||||
JMeterUtils.getPropDefault("jmeterthread.rampup.granularity", 1000); // $NON-NLS-1$
|
||||
|
||||
|
@ -169,8 +172,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Enable the scheduler for this JMeterThread.
|
||||
*
|
||||
* @param sche
|
||||
* flag whether the scheduler should be enabled
|
||||
* @param sche flag whether the scheduler should be enabled
|
||||
*/
|
||||
public void setScheduled(boolean sche) {
|
||||
this.scheduler = sche;
|
||||
|
@ -197,8 +199,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Set the EndTime for this Thread.
|
||||
*
|
||||
* @param etime
|
||||
* the EndTime value.
|
||||
* @param etime the EndTime value.
|
||||
*/
|
||||
public void setEndTime(long etime) {
|
||||
endTime = etime;
|
||||
|
@ -235,6 +236,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
public void setThreadName(String threadName) {
|
||||
this.threadName = threadName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// threadContext is not thread-safe, so keep within thread
|
||||
|
@ -278,8 +280,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
threadContext.setTestLogicalAction(TestLogicalAction.CONTINUE);
|
||||
sam = null;
|
||||
setLastSampleOk(threadContext.getVariables(), true);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sam = threadGroupLoopController.next();
|
||||
}
|
||||
}
|
||||
|
@ -297,8 +298,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
log.info("Stopping Test: {}", e.toString());
|
||||
}
|
||||
shutdownTest();
|
||||
}
|
||||
catch (JMeterStopTestNowException e) { // NOSONAR
|
||||
} catch (JMeterStopTestNowException e) { // NOSONAR
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Stopping Test Now: {}", e.toString());
|
||||
}
|
||||
|
@ -328,6 +328,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
|
||||
/**
|
||||
* Trigger break/continue/switch to next thread Loop depending on consumer implementation
|
||||
*
|
||||
* @param sampler Sampler Base sampler
|
||||
* @param threadContext
|
||||
* @param consumer Consumer that will process the tree of elements up to root node
|
||||
|
@ -364,6 +365,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Executes a continue of current loop, equivalent of "continue" in algorithm.
|
||||
* As a consequence it ends the first loop it finds on the path to root
|
||||
*
|
||||
* @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser}
|
||||
*/
|
||||
private static void continueOnCurrentLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) {
|
||||
|
@ -384,6 +386,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Executes a break of current loop, equivalent of "break" in algorithm.
|
||||
* As a consequence it ends the first loop it finds on the path to root
|
||||
*
|
||||
* @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser}
|
||||
*/
|
||||
private static void breakOnCurrentLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) {
|
||||
|
@ -404,6 +407,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Executes a restart of Thread loop, equivalent of "continue" in algorithm but on Thread Loop.
|
||||
* As a consequence it ends all loop on the path to root
|
||||
*
|
||||
* @param pathToRootTraverser {@link FindTestElementsUpToRootTraverser}
|
||||
*/
|
||||
private static void continueOnThreadLoop(FindTestElementsUpToRootTraverser pathToRootTraverser) {
|
||||
|
@ -424,6 +428,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
* if there are some other controllers (SimpleController or other implementations) between this TransactionSampler and the real sampler,
|
||||
* triggerEndOfLoop will not be called for those controllers leaving them in "ugly" state.
|
||||
* the following method will try to find the sampler that really generate an error
|
||||
*
|
||||
* @return {@link Sampler}
|
||||
*/
|
||||
private Sampler findRealSampler(Sampler sampler) {
|
||||
|
@ -548,12 +553,12 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
if (running) {
|
||||
Sampler sampler = pack.getSampler();
|
||||
// 执行前发给监听
|
||||
List<SampleListener> sampleListeners = getSampleListeners(pack, transactionPack, transactionSampler);
|
||||
SampleEvent event = new SampleEvent(null, current.getPropertyAsString("MS-RESOURCE-ID"), threadVars);
|
||||
List<SampleListener> sampleListeners = pack.getSampleListeners();
|
||||
if (CollectionUtils.isNotEmpty(sampleListeners)) {
|
||||
for (SampleListener sampleListener : sampleListeners) {
|
||||
try {
|
||||
if (sampleListener instanceof MsResultCollector) {
|
||||
TestBeanHelper.prepare((TestElement) sampleListener);
|
||||
SampleEvent event = new SampleEvent(null, current.getPropertyAsString("MS-RESOURCE-ID"), threadVars);
|
||||
sampleListener.sampleStarted(event);
|
||||
break;
|
||||
}
|
||||
|
@ -561,6 +566,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
log.error("自定义提前发送监听失败.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
//======
|
||||
result = doSampling(threadContext, sampler);
|
||||
}
|
||||
|
@ -622,6 +628,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
* <li>Playing SampleMonitor before and after sampling</li>
|
||||
* <li>resetting currentSamplerForInterruption</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param threadContext {@link JMeterContext}
|
||||
* @param sampler {@link Sampler}
|
||||
* @return {@link SampleResult}
|
||||
|
@ -826,7 +833,9 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
log.info("Stopping: {}", threadName);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean interrupt() {
|
||||
interruptLock.lock();
|
||||
|
|
Loading…
Reference in New Issue