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("接收到执行结果开始存储");
|
||||
this.save(record.value());
|
||||
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);
|
||||
|
@ -813,7 +816,7 @@ public class ApiAutomationService {
|
|||
return null;
|
||||
}
|
||||
|
||||
public APIScenarioReportResult createScenarioReport(String id, String scenarioId, String scenarioName, String triggerMode, String execType, String projectId, String userID, RunModeConfig config,String desc) {
|
||||
public APIScenarioReportResult createScenarioReport(String id, String scenarioId, String scenarioName, String triggerMode, String execType, String projectId, String userID, RunModeConfig config, String desc) {
|
||||
APIScenarioReportResult report = new APIScenarioReportResult();
|
||||
if (triggerMode.equals(ApiRunMode.SCENARIO.name()) || triggerMode.equals(ApiRunMode.DEFINITION.name())) {
|
||||
triggerMode = ReportTriggerMode.MANUAL.name();
|
||||
|
@ -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);
|
||||
// 集合报告设置
|
||||
|
@ -1026,21 +1034,21 @@ public class ApiAutomationService {
|
|||
planEnvMap = JSON.parseObject(environment, Map.class);
|
||||
}
|
||||
}
|
||||
String projectId = testPlanScenarioCaseService.getProjectIdById(testPlanScenarioId);
|
||||
if(StringUtils.isEmpty(projectId)){
|
||||
String projectId = testPlanScenarioCaseService.getProjectIdById(testPlanScenarioId);
|
||||
if (StringUtils.isEmpty(projectId)) {
|
||||
projectId = item.getProjectId();
|
||||
}
|
||||
if (request.isTestPlanScheduleJob()) {
|
||||
String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId();
|
||||
report = createScenarioReport(reportId, savedScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(), item.getId());
|
||||
} else {
|
||||
report = createScenarioReport(reportId, testPlanScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(), item.getId());
|
||||
}
|
||||
} else {
|
||||
report = createScenarioReport(reportId, ExecuteType.Marge.name().equals(request.getExecuteType()) ? serialReportId : item.getId(), item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig(), item.getId());
|
||||
}
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
|
@ -1064,7 +1072,7 @@ public class ApiAutomationService {
|
|||
APIScenarioReportResult report = createScenarioReport(request.getConfig().getReportId(),
|
||||
JSON.toJSONString(CollectionUtils.isNotEmpty(scenarioIds) && scenarioIds.size() > 50 ? scenarioIds.subList(0, 50) : scenarioIds),
|
||||
scenarioNames.length() >= 3000 ? scenarioNames.substring(0, 2000) : scenarioNames.deleteCharAt(scenarioNames.toString().length() - 1).toString(),
|
||||
ReportTriggerMode.MANUAL.name(), ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig(),JSON.toJSONString(scenarioIds));
|
||||
ReportTriggerMode.MANUAL.name(), ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig(), JSON.toJSONString(scenarioIds));
|
||||
|
||||
report.setName(request.getConfig().getReportName());
|
||||
report.setId(serialReportId);
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1256,22 +1266,22 @@ public class ApiAutomationService {
|
|||
}
|
||||
}
|
||||
|
||||
String projectId = testPlanScenarioCaseService.getProjectIdById(testPlanScenarioId);
|
||||
if(StringUtils.isEmpty(projectId)){
|
||||
String projectId = testPlanScenarioCaseService.getProjectIdById(testPlanScenarioId);
|
||||
if (StringUtils.isEmpty(projectId)) {
|
||||
projectId = item.getProjectId();
|
||||
}
|
||||
|
||||
if (request.isTestPlanScheduleJob()) {
|
||||
String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId();
|
||||
report = createScenarioReport(group.getName(), savedScenarioId, item.getName(), request.getTriggerMode(),
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(), item.getId());
|
||||
} else {
|
||||
report = createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(), item.getId());
|
||||
}
|
||||
} else {
|
||||
report = createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig(),item.getId());
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig(), item.getId());
|
||||
}
|
||||
batchMapper.insert(report);
|
||||
reportIds.add(group.getName());
|
||||
|
@ -1380,7 +1390,7 @@ public class ApiAutomationService {
|
|||
String runMode = ApiRunMode.SCENARIO.name();
|
||||
if (StringUtils.isNotBlank(request.getRunMode()) && StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
|
||||
runMode = ApiRunMode.SCENARIO_PLAN.name();
|
||||
}else if (StringUtils.isNotBlank(request.getRunMode()) && StringUtils.equals(request.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO.name())) {
|
||||
} else if (StringUtils.isNotBlank(request.getRunMode()) && StringUtils.equals(request.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO.name())) {
|
||||
runMode = ApiRunMode.SCHEDULE_SCENARIO.name();
|
||||
}
|
||||
if (StringUtils.isNotBlank(request.getRunMode()) && StringUtils.equals(request.getRunMode(), ApiRunMode.DEFINITION.name())) {
|
||||
|
@ -1490,7 +1500,7 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
APIScenarioReportResult report = createScenarioReport(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
|
||||
SessionUtils.getUserId(), request.getConfig(),request.getId());
|
||||
SessionUtils.getUserId(), request.getConfig(), request.getId());
|
||||
apiScenarioReportMapper.insert(report);
|
||||
|
||||
uploadBodyFiles(request.getBodyFileRequestIds(), bodyFiles);
|
||||
|
@ -2393,7 +2403,7 @@ public class ApiAutomationService {
|
|||
example.createCriteria().andNameEqualTo(newModel.getName()).
|
||||
andProjectIdEqualTo(newModel.getProjectId()).andStatusNotEqualTo("Trash").andIdNotEqualTo(newModel.getId());
|
||||
if (apiScenarioMapper.countByExample(example) > 0) {
|
||||
stringBuffer.append(newModel.getName()+";");
|
||||
stringBuffer.append(newModel.getName() + ";");
|
||||
continue;
|
||||
} else {
|
||||
boolean insertFlag = true;
|
||||
|
@ -2426,11 +2436,11 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
BatchOperaResponse result = new BatchOperaResponse();
|
||||
if(stringBuffer.length() == 0){
|
||||
if (stringBuffer.length() == 0) {
|
||||
result.result = true;
|
||||
}else {
|
||||
} else {
|
||||
result.result = false;
|
||||
result.errorMsg = stringBuffer.substring(0,stringBuffer.length()-1);
|
||||
result.errorMsg = stringBuffer.substring(0, stringBuffer.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -2497,16 +2507,16 @@ public class ApiAutomationService {
|
|||
|
||||
public void initExecuteTimes() {
|
||||
List<String> apiScenarioIds = extApiScenarioMapper.selectIdsByExecuteTimeIsNull();
|
||||
Map<String,Long> scenarioIdMap = new HashMap<>();
|
||||
Map<String, Long> scenarioIdMap = new HashMap<>();
|
||||
List<ApiReportCountDTO> reportCount = apiScenarioReportService.countByApiScenarioId();
|
||||
for (ApiReportCountDTO dto : reportCount) {
|
||||
scenarioIdMap.put(dto.getId(),dto.getCountNum());
|
||||
scenarioIdMap.put(dto.getId(), dto.getCountNum());
|
||||
}
|
||||
for (String id:apiScenarioIds) {
|
||||
for (String id : apiScenarioIds) {
|
||||
int count = 0;
|
||||
if(scenarioIdMap.containsKey(id)){
|
||||
if (scenarioIdMap.containsKey(id)) {
|
||||
Long countNum = scenarioIdMap.get(id);
|
||||
if(countNum != null){
|
||||
if (countNum != null) {
|
||||
count = countNum.intValue();
|
||||
}
|
||||
}
|
||||
|
@ -2519,9 +2529,9 @@ public class ApiAutomationService {
|
|||
|
||||
public long countExecuteTimesByProjectID(String projectId) {
|
||||
Long result = extApiScenarioMapper.countExecuteTimesByProjectID(projectId);
|
||||
if(result == null){
|
||||
if (result == null) {
|
||||
return 0;
|
||||
}else {
|
||||
} else {
|
||||
return result.longValue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -296,7 +296,7 @@ public class ApiScenarioReportService {
|
|||
List<String> reportIds = new ArrayList<>();
|
||||
List<String> scenarioIdList = new ArrayList<>();
|
||||
Map<String, String> scenarioAndErrorMap = new HashMap<>();
|
||||
Map<String,APIScenarioReportResult> caseReportMap = new HashMap<>();
|
||||
Map<String, APIScenarioReportResult> caseReportMap = new HashMap<>();
|
||||
for (ScenarioResult scenarioResult : scenarioResultList) {
|
||||
|
||||
// 存储场景报告
|
||||
|
@ -387,7 +387,7 @@ public class ApiScenarioReportService {
|
|||
lastReport = report;
|
||||
|
||||
APIScenarioReportResult reportResult = this.get(report.getId());
|
||||
caseReportMap.put(testPlanApiScenario.getApiScenarioId(),reportResult);
|
||||
caseReportMap.put(testPlanApiScenario.getApiScenarioId(), reportResult);
|
||||
reportIds.add(report.getId());
|
||||
}
|
||||
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||
|
@ -395,8 +395,8 @@ public class ApiScenarioReportService {
|
|||
testPlanLog.info("TestPlanReportId" + JSONArray.toJSONString(testPlanReportIdList) + " EXECUTE OVER. SCENARIO STATUS : " + JSONObject.toJSONString(scenarioAndErrorMap));
|
||||
|
||||
for (String reportId : testPlanReportIdList) {
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(reportId,null,scenarioAndErrorMap,null);
|
||||
TestPlanReportExecuteCatch.updateTestPlanExecuteResultInfo(reportId,null,caseReportMap,null);
|
||||
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(reportId, null, scenarioAndErrorMap, null);
|
||||
TestPlanReportExecuteCatch.updateTestPlanExecuteResultInfo(reportId, null, caseReportMap, null);
|
||||
}
|
||||
|
||||
return lastReport;
|
||||
|
@ -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);
|
||||
paramMap.put("operator", SessionUtils.getUser().getName());
|
||||
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$
|
||||
|
||||
|
@ -77,7 +80,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
|
||||
private static final float ONE_AS_FLOAT = 1.0f;
|
||||
|
||||
private static final boolean APPLY_TIMER_FACTOR = Float.compare(TIMER_FACTOR,ONE_AS_FLOAT) != 0;
|
||||
private static final boolean APPLY_TIMER_FACTOR = Float.compare(TIMER_FACTOR, ONE_AS_FLOAT) != 0;
|
||||
|
||||
private final Controller threadGroupLoopController;
|
||||
|
||||
|
@ -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
|
||||
|
@ -258,7 +260,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
&& threadContext.getTestLogicalAction() != TestLogicalAction.CONTINUE) {
|
||||
log.debug("Start Next Thread Loop option is on, Last sample failed, starting next thread loop");
|
||||
}
|
||||
if(onErrorStartNextLoop && !lastSampleOk){
|
||||
if (onErrorStartNextLoop && !lastSampleOk) {
|
||||
triggerLoopLogicalActionOnParentControllers(sam, threadContext, JMeterThread::continueOnThreadLoop);
|
||||
} else {
|
||||
switch (threadContext.getTestLogicalAction()) {
|
||||
|
@ -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,12 +328,13 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
|
||||
/**
|
||||
* Trigger break/continue/switch to next thread Loop depending on consumer implementation
|
||||
* @param sampler Sampler Base sampler
|
||||
*
|
||||
* @param sampler Sampler Base sampler
|
||||
* @param threadContext
|
||||
* @param consumer Consumer that will process the tree of elements up to root node
|
||||
* @param consumer Consumer that will process the tree of elements up to root node
|
||||
*/
|
||||
private void triggerLoopLogicalActionOnParentControllers(Sampler sampler, JMeterContext threadContext,
|
||||
Consumer<FindTestElementsUpToRootTraverser> consumer) {
|
||||
Consumer<FindTestElementsUpToRootTraverser> consumer) {
|
||||
TransactionSampler transactionSampler = null;
|
||||
if (sampler instanceof TransactionSampler) {
|
||||
transactionSampler = (TransactionSampler) sampler;
|
||||
|
@ -343,7 +344,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
if (realSampler == null) {
|
||||
throw new IllegalStateException(
|
||||
"Got null subSampler calling findRealSampler for:" +
|
||||
(sampler != null ? sampler.getName() : "null") + ", sampler:" + sampler);
|
||||
(sampler != null ? sampler.getName() : "null") + ", sampler:" + sampler);
|
||||
}
|
||||
// Find parent controllers of current sampler
|
||||
FindTestElementsUpToRootTraverser pathToRootTraverser = new FindTestElementsUpToRootTraverser(realSampler);
|
||||
|
@ -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) {
|
||||
|
@ -437,8 +442,8 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
/**
|
||||
* Process the current sampler, handling transaction samplers.
|
||||
*
|
||||
* @param current sampler
|
||||
* @param parent sampler
|
||||
* @param current sampler
|
||||
* @param parent sampler
|
||||
* @param threadContext
|
||||
* @return SampleResult if a transaction was processed
|
||||
*/
|
||||
|
@ -519,8 +524,8 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
}
|
||||
|
||||
private void fillThreadInformation(SampleResult result,
|
||||
int nbActiveThreadsInThreadGroup,
|
||||
int nbTotalActiveThreads) {
|
||||
int nbActiveThreadsInThreadGroup,
|
||||
int nbTotalActiveThreads) {
|
||||
result.setGroupThreads(nbActiveThreadsInThreadGroup);
|
||||
result.setAllThreads(nbTotalActiveThreads);
|
||||
result.setThreadName(threadName);
|
||||
|
@ -531,9 +536,9 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
* Broadcast the result to the sample listeners
|
||||
*/
|
||||
private void executeSamplePackage(Sampler current,
|
||||
TransactionSampler transactionSampler,
|
||||
SamplePackage transactionPack,
|
||||
JMeterContext threadContext) {
|
||||
TransactionSampler transactionSampler,
|
||||
SamplePackage transactionPack,
|
||||
JMeterContext threadContext) {
|
||||
|
||||
threadContext.setCurrentSampler(current);
|
||||
// Get the sampler ready to sample
|
||||
|
@ -548,17 +553,18 @@ 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);
|
||||
for (SampleListener sampleListener : sampleListeners) {
|
||||
try {
|
||||
if(sampleListener instanceof MsResultCollector) {
|
||||
TestBeanHelper.prepare((TestElement) sampleListener);
|
||||
sampleListener.sampleStarted(event);
|
||||
break;
|
||||
List<SampleListener> sampleListeners = pack.getSampleListeners();
|
||||
if (CollectionUtils.isNotEmpty(sampleListeners)) {
|
||||
for (SampleListener sampleListener : sampleListeners) {
|
||||
try {
|
||||
if (sampleListener instanceof MsResultCollector) {
|
||||
SampleEvent event = new SampleEvent(null, current.getPropertyAsString("MS-RESOURCE-ID"), threadVars);
|
||||
sampleListener.sampleStarted(event);
|
||||
break;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
log.error("自定义提前发送监听失败.", e);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
log.error("自定义提前发送监听失败.", e);
|
||||
}
|
||||
}
|
||||
//======
|
||||
|
@ -622,8 +628,9 @@ 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}
|
||||
* @param sampler {@link Sampler}
|
||||
* @return {@link SampleResult}
|
||||
*/
|
||||
private SampleResult doSampling(JMeterContext threadContext, Sampler sampler) {
|
||||
|
@ -635,7 +642,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
currentSamplerForInterruption = sampler;
|
||||
if (!sampleMonitors.isEmpty()) {
|
||||
for (SampleMonitor sampleMonitor : sampleMonitors) {
|
||||
if(sampleMonitor instanceof TestElement) {
|
||||
if (sampleMonitor instanceof TestElement) {
|
||||
TestBeanHelper.prepare((TestElement) sampleMonitor);
|
||||
}
|
||||
sampleMonitor.sampleStarting(sampler);
|
||||
|
@ -682,20 +689,20 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
private List<SampleListener> getSampleListeners(SamplePackage samplePack, SamplePackage transactionPack, TransactionSampler transactionSampler) {
|
||||
List<SampleListener> sampleListeners = samplePack.getSampleListeners();
|
||||
// Do not send subsamples to listeners which receive the transaction sample
|
||||
if(transactionSampler != null) {
|
||||
if (transactionSampler != null) {
|
||||
List<SampleListener> onlySubSamplerListeners = new ArrayList<>();
|
||||
List<SampleListener> transListeners = transactionPack.getSampleListeners();
|
||||
for(SampleListener listener : sampleListeners) {
|
||||
for (SampleListener listener : sampleListeners) {
|
||||
// Check if this instance is present in transaction listener list
|
||||
boolean found = false;
|
||||
for(SampleListener trans : transListeners) {
|
||||
for (SampleListener trans : transListeners) {
|
||||
// Check for the same instance
|
||||
if(trans == listener) {
|
||||
if (trans == listener) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
if (!found) {
|
||||
onlySubSamplerListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
@ -751,7 +758,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
private void threadStarted() {
|
||||
JMeterContextService.incrNumberOfThreads();
|
||||
threadGroup.incrNumberOfThreads();
|
||||
GuiPackage gp =GuiPackage.getInstance();
|
||||
GuiPackage gp = GuiPackage.getInstance();
|
||||
if (gp != null) {// check there is a GUI
|
||||
gp.getMainFrame().updateCounts();
|
||||
}
|
||||
|
@ -765,7 +772,7 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
JMeterContextService.decrNumberOfThreads();
|
||||
threadGroup.decrNumberOfThreads();
|
||||
GuiPackage gp = GuiPackage.getInstance();
|
||||
if (gp != null){// check there is a GUI
|
||||
if (gp != null) {// check there is a GUI
|
||||
gp.getMainFrame().updateCounts();
|
||||
}
|
||||
if (iterationListener != null) { // probably not possible, but check anyway
|
||||
|
@ -826,18 +833,20 @@ public class JMeterThread implements Runnable, Interruptible {
|
|||
log.info("Stopping: {}", threadName);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean interrupt(){
|
||||
public boolean interrupt() {
|
||||
interruptLock.lock();
|
||||
try {
|
||||
Sampler samp = currentSamplerForInterruption; // fetch once; must be done under lock
|
||||
if (samp instanceof Interruptible){ // (also protects against null)
|
||||
if (samp instanceof Interruptible) { // (also protects against null)
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("Interrupting: {} sampler: {}", threadName, samp.getName());
|
||||
}
|
||||
try {
|
||||
boolean found = ((Interruptible)samp).interrupt();
|
||||
boolean found = ((Interruptible) samp).interrupt();
|
||||
if (!found) {
|
||||
log.warn("No operation pending");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue