fix (接口自动化): 接口自动化重构并发执行

This commit is contained in:
fit2-zhao 2021-08-27 21:07:14 +08:00 committed by fit2-zhao
parent f9eae5ce44
commit 1ad1f9a2b9
17 changed files with 273 additions and 131 deletions

View File

@ -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();

View File

@ -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;
/**
* 运行环境
*/

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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("执行内容存储结束");
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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");
}