merge: 合并dev最新修改

This commit is contained in:
BugKing 2021-12-22 11:35:05 +08:00
commit 3448c90c10
577 changed files with 22506 additions and 16694 deletions

View File

@ -16,10 +16,11 @@ COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
RUN mv /app/lib/ms-jmeter-core-*.jar /app/lib/ms-jmeter-core.jar
RUN mv /app/jmeter /opt/
RUN mkdir -p /opt/jmeter/lib/junit
ENV JAVA_CLASSPATH=/app:/app/lib/*
ENV JAVA_CLASSPATH=/app:/app/lib/ms-jmeter-core.jar:/app/lib/*
ENV JAVA_MAIN_CLASS=io.metersphere.Application
ENV AB_OFF=true
ENV MS_VERSION=${MS_VERSION}

View File

@ -17,11 +17,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<shiro.version>1.6.0</shiro.version>
<java.version>1.8</java.version>
<jmeter.version>5.4.1</jmeter.version>
<nacos.version>1.1.3</nacos.version>
<dubbo.version>2.7.8</dubbo.version>
<groovy.version>3.0.8</groovy.version>
<metersphere-jmeter-functions.version>1.4</metersphere-jmeter-functions.version>
<flyway.version>7.15.0</flyway.version>
</properties>
<dependencies>
@ -120,11 +116,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
@ -154,23 +145,12 @@
<artifactId>spring-boot-starter-rsocket</artifactId>
</dependency>
<!-- jmeter -->
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_http</artifactId>
<version>${jmeter.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</exclusion>
<exclusion>
<artifactId>xstream</artifactId>
<groupId>com.thoughtworks.xstream</groupId>
</exclusion>
</exclusions>
<groupId>io.metersphere</groupId>
<artifactId>ms-jmeter-core</artifactId>
<version>1.0.2</version>
</dependency>
<!-- 排除jmeter中的 xstream 解决bug -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
@ -178,103 +158,6 @@
<version>1.4.18</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_functions</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_jdbc</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_tcp</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-jmeter-functions</artifactId>
<version>${metersphere-jmeter-functions.version}</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.4.1.jre8</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.14</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.7.0.0</version>
</dependency>
<!-- Zookeeper -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!-- nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-api</artifactId>
<version>${nacos.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos.version}</version>
</dependency>
<!-- easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
@ -285,14 +168,9 @@
<dependency>
<groupId>com.fit2cloud</groupId>
<artifactId>quartz-spring-boot-starter</artifactId>
<version>0.0.7</version>
<version>0.0.9</version>
</dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>jmeter-plugins-dubbo</artifactId>
<version>2.7.13</version>
</dependency>
<!-- LDAP Module -->
<dependency>
@ -307,11 +185,6 @@
<version>2.0.24</version>
</dependency>
<!-- ApacheJMeter_core scope 是 runtime这里去掉scope -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-jsr223</artifactId>
</dependency>
<!-- 执行 js 代码依赖 -->
<dependency>
@ -355,17 +228,6 @@
<version>2.24</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20171018</version>
</dependency>
<!--钉钉sdk-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
@ -382,53 +244,7 @@
<artifactId>kubernetes-client</artifactId>
<version>4.13.0</version>
</dependency>
<!-- 添加jmeter包支持导入的jmx能正常执行 -->
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_bolt</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_jms</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_ftp</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_junit</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_ldap</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_mail</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_components</artifactId>
<version>${jmeter.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_native</artifactId>
<version>${jmeter.version}</version>
</dependency>
<!-- 添加jmeter包支持导入的jmx能正常执行 -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
@ -440,11 +256,22 @@
<artifactId>xmindjbehaveplugin</artifactId>
<version>0.8</version>
</dependency>
<!-- selenium包 -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
</dependency>
<!-- 基础包 -->
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-plugin-core</artifactId>
<version>1.0.1</version>
<exclusions>
<exclusion>
<artifactId>log4j-slf4j-impl</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--随机数据生成API-->
<dependency>
@ -464,6 +291,12 @@
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
<version>31.0.1-jre</version>
</dependency>
</dependencies>
<build>
@ -597,7 +430,7 @@
<artifactItem>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_functions</artifactId>
<version>${jmeter.version}</version>
<version>5.4.2</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>src/main/resources/jmeter/lib/ext</outputDirectory>
@ -606,7 +439,7 @@
<artifactItem>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-jmeter-functions</artifactId>
<version>${metersphere-jmeter-functions.version}</version>
<version>1.4</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>src/main/resources/jmeter/lib/ext</outputDirectory>

View File

@ -1,14 +1,15 @@
package io.metersphere.api.cache;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.jmeter.JmeterThreadUtils;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.base.domain.ApiScenarioReportExample;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
import io.metersphere.commons.constants.TestPlanResourceType;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.utils.LoggerUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
@ -88,13 +89,16 @@ public class TestPlanExecuteInfo {
this.isApiCaseAllExecuted = true;
this.isScenarioAllExecuted = true;
this.isLoadCaseAllExecuted = true;
boolean isQueue = false;
for (String result : apiCaseExecInfo.values()) {
if (StringUtils.equalsIgnoreCase(result, TestPlanApiExecuteStatus.RUNNING.name())) {
unFinishedCount++;
if (this.isApiCaseAllExecuted) {
this.isApiCaseAllExecuted = false;
}
if (!isQueue) {
isQueue = CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).check(apiCaseExecuteThreadMap.get(result));
}
}
}
for (String result : apiScenarioCaseExecInfo.values()) {
@ -103,6 +107,9 @@ public class TestPlanExecuteInfo {
if (this.isScenarioAllExecuted) {
isScenarioAllExecuted = false;
}
if (!isQueue) {
isQueue = CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).check(apiScenarioThreadMap.get(result));
}
}
}
for (String result : loadCaseExecInfo.values()) {
@ -117,6 +124,12 @@ public class TestPlanExecuteInfo {
lastUnFinishedNumCount = unFinishedCount;
lastFinishedNumCountTime = System.currentTimeMillis();
}
if (lastUnFinishedNumCount == unFinishedCount && isQueue) {
LoggerUtil.info("执行的报告还在队列中,重置超时时间");
lastUnFinishedNumCount = unFinishedCount;
lastFinishedNumCountTime = System.currentTimeMillis();
}
return unFinishedCount;
}
@ -178,10 +191,6 @@ public class TestPlanExecuteInfo {
JmeterThreadUtils.stop(apiCaseExecuteThreadMap.get(resourceId));
}
}
if (apiCaseExecuteThreadMap.containsKey(resourceId)) {
MessageCache.executionQueue.remove(apiCaseExecuteThreadMap.get(resourceId));
}
}
List<String> updateScenarioReportList = new ArrayList<>();
@ -195,10 +204,6 @@ public class TestPlanExecuteInfo {
JmeterThreadUtils.stop(apiScenarioThreadMap.get(resourceId));
}
}
if (apiScenarioThreadMap.containsKey(resourceId)) {
MessageCache.executionQueue.remove(apiScenarioThreadMap.get(resourceId));
}
}
if (CollectionUtils.isNotEmpty(updateScenarioReportList)) {
ApiScenarioReportMapper apiScenarioReportMapper = CommonBeanFactory.getBean(ApiScenarioReportMapper.class);
@ -218,10 +223,6 @@ public class TestPlanExecuteInfo {
}
loadCaseExecInfo.put(resourceId, TestPlanApiExecuteStatus.FAILD.name());
}
if (loadCaseReportIdMap.containsKey(resourceId)) {
MessageCache.executionQueue.remove(loadCaseReportIdMap.get(resourceId));
}
}
this.countUnFinishedNum();

View File

@ -1,6 +1,11 @@
package io.metersphere.api.cache;
import io.metersphere.commons.constants.TestPlanApiExecuteStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -8,6 +13,7 @@ import java.util.Map;
* @Date 2021/8/20 3:29 下午
*/
public class TestPlanReportExecuteCatch {
private static Logger testPlanLog = LoggerFactory.getLogger("testPlanExecuteLog");
private static Map<String, TestPlanExecuteInfo> testPlanReportMap = new HashMap<>();
private TestPlanReportExecuteCatch() {
@ -69,7 +75,6 @@ public class TestPlanReportExecuteCatch {
}
public static TestPlanExecuteInfo getTestPlanExecuteInfo(String reportId) {
return testPlanReportMap.get(reportId);
}
@ -88,8 +93,21 @@ public class TestPlanReportExecuteCatch {
}
public static void finishAllTask(String planReportId) {
testPlanLog.info("ReportId[" + planReportId + "] finish task!");
if (testPlanReportMap.containsKey(planReportId)) {
testPlanReportMap.get(planReportId).finishAllTask();
}
}
public static void set(String planReportId, List<String> executeErrorList) {
if (TestPlanReportExecuteCatch.containsReport(planReportId)) {
if (!executeErrorList.isEmpty()) {
Map<String, String> executeErrorMap = new HashMap<>();
for (String id : executeErrorList) {
executeErrorMap.put(id, TestPlanApiExecuteStatus.FAILD.name());
}
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(planReportId, executeErrorMap, null, null);
}
}
}
}

View File

@ -7,9 +7,7 @@ import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.MsResultService;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
@ -27,8 +25,6 @@ public class APIScenarioReportController {
@Resource
private ApiScenarioReportService apiReportService;
@Resource
private MsResultService resultService;
@GetMapping("/get/{reportId}")
public APIScenarioReportResult get(@PathVariable String reportId) {
@ -63,14 +59,4 @@ public class APIScenarioReportController {
apiReportService.deleteAPIReportBatch(request);
}
@GetMapping("/get/real/{reportId}")
public TestResult getRealReport(@PathVariable String reportId) {
return resultService.getResult(reportId);
}
@GetMapping("/remove/real/{reportId}")
public void removeRealReport(@PathVariable String reportId) {
resultService.delete(reportId);
}
}

View File

@ -340,7 +340,7 @@ public class APITestController {
@GetMapping("/faliureCaseAboutTestPlan/{projectId}/{limitNumber}")
public List<ExecutedCaseInfoDTO> faliureCaseAboutTestPlan(@PathVariable String projectId, @PathVariable int limitNumber) {
List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId, limitNumber);
List<ExecutedCaseInfoResult> selectDataList = apiDefinitionExecResultService.findFailureCaseInfoByProjectIDAndLimitNumberInSevenDays(projectId, limitNumber);
List<ExecutedCaseInfoDTO> returnList = new ArrayList<>(limitNumber);

View File

@ -6,8 +6,7 @@ import io.metersphere.api.dto.*;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.automation.parse.ScenarioImport;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.jmeter.LocalRunner;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.ApiScenario;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
@ -17,6 +16,8 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.jmeter.LocalRunner;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.task.service.TaskService;
@ -42,6 +43,8 @@ public class ApiAutomationController {
private ApiAutomationService apiAutomationService;
@Resource
private TaskService taskService;
@Resource
private ExecThreadPoolExecutor execThreadPoolExecutor;
@PostMapping("/list/{goPage}/{pageSize}")
@RequiresPermissions("PROJECT_API_SCENARIO:READ")
@ -208,7 +211,7 @@ public class ApiAutomationController {
@PostMapping(value = "/run")
@MsAuditLog(module = "api_automation", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.ids)", msClass = ApiAutomationService.class)
public String run(@RequestBody RunScenarioRequest request) {
public List<MsExecResponseDTO> run(@RequestBody RunScenarioRequest request) {
if (!StringUtils.equals(request.getExecuteType(), ExecuteType.Saved.name())) {
request.setExecuteType(ExecuteType.Completed.name());
}
@ -219,7 +222,7 @@ public class ApiAutomationController {
@PostMapping(value = "/run/jenkins")
@MsAuditLog(module = "api_automation", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.id)", msClass = ApiAutomationService.class)
public String runByJenkins(@RequestBody RunScenarioRequest request) {
public List<MsExecResponseDTO> runByJenkins(@RequestBody RunScenarioRequest request) {
request.setExecuteType(ExecuteType.Saved.name());
request.setTriggerMode(TriggerMode.API.name());
request.setRunMode(ApiRunMode.SCENARIO.name()); // 回退
@ -228,7 +231,7 @@ public class ApiAutomationController {
@PostMapping(value = "/run/batch")
@MsAuditLog(module = "api_automation", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.ids)", msClass = ApiAutomationService.class)
public String runBatch(@RequestBody RunScenarioRequest request) {
public List<MsExecResponseDTO> runBatch(@RequestBody RunScenarioRequest request) {
request.setExecuteType(ExecuteType.Saved.name());
request.setTriggerMode(TriggerMode.BATCH.name());
request.setRunMode(ApiRunMode.SCENARIO.name());
@ -283,7 +286,7 @@ public class ApiAutomationController {
}
@PostMapping(value = "/genPerformanceTestJmx")
public JmxInfoDTO genPerformanceTestJmx(@RequestBody RunScenarioRequest runRequest) throws Exception {
public JmxInfoDTO genPerformanceTestJmx(@RequestBody GenScenarioRequest runRequest) throws Exception {
runRequest.setExecuteType(ExecuteType.Completed.name());
return apiAutomationService.genPerformanceTestJmx(runRequest);
}
@ -326,7 +329,7 @@ public class ApiAutomationController {
@GetMapping(value = "/stop/{reportId}")
public void stop(@PathVariable String reportId) {
if (StringUtils.isNotEmpty(reportId)) {
MessageCache.caseExecResourceLock.remove(reportId);
execThreadPoolExecutor.removeQueue(reportId);
new LocalRunner().stop(reportId);
}
}
@ -364,10 +367,16 @@ public class ApiAutomationController {
return apiAutomationService.checkScenarioEnv(request);
}
@GetMapping(value = "/checkScenarioEnv/{scenarioId}")
public boolean checkScenarioEnvByScenarioId(@PathVariable String scenarioId) {
return apiAutomationService.checkScenarioEnv(scenarioId);
}
@GetMapping("/follow/{scenarioId}")
public List<String> getFollows(@PathVariable String scenarioId) {
return apiAutomationService.getFollows(scenarioId);
}
@PostMapping("/update/follows/{scenarioId}")
public void saveFollows(@PathVariable String scenarioId, @RequestBody List<String> follows) {
apiAutomationService.saveFollows(scenarioId, follows);

View File

@ -12,6 +12,7 @@ import io.metersphere.api.dto.definition.request.assertions.document.DocumentEle
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.EsbApiParamService;
@ -28,6 +29,7 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.RelationshipEdgeDTO;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
@ -57,6 +59,8 @@ public class ApiDefinitionController {
private EsbImportService esbImportService;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
@Resource
private ExecThreadPoolExecutor execThreadPoolExecutor;
@PostMapping("/list/{goPage}/{pageSize}")
@RequiresPermissions("PROJECT_API_DEFINITION:READ")
@ -174,22 +178,18 @@ public class ApiDefinitionController {
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
@MsAuditLog(module = "api_definition", type = OperLogConstants.DEBUG, title = "#request.name", project = "#request.projectId")
public String runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
public MsExecResponseDTO runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
request.setDebug(true);
return apiDefinitionService.run(request, bodyFiles);
}
@PostMapping(value = "/run", consumes = {"multipart/form-data"})
@MsAuditLog(module = "api_definition", type = OperLogConstants.EXECUTE, sourceId = "#request.id", title = "#request.name", project = "#request.projectId")
public String run(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
public MsExecResponseDTO run(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {
request.setReportId(null);
return apiDefinitionService.run(request, bodyFiles);
}
@GetMapping("/report/get/{testId}/{test}")
public APIReportResult getResult(@PathVariable String testId, @PathVariable String test) {
return apiDefinitionService.getResult(testId, test);
}
@GetMapping("/report/getReport/{testId}")
public APIReportResult getReport(@PathVariable String testId) {
return apiDefinitionService.getDbResult(testId);
@ -347,4 +347,9 @@ public class ApiDefinitionController {
apiDefinitionService.saveFollows(definitionId, follows);
}
@GetMapping("/getWorkerQueue")
public String getWorkerQueue() {
return execThreadPoolExecutor.getWorkerQueue();
}
}

View File

@ -47,11 +47,11 @@ public class ApiJmeterFileController {
}
@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);
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("reportType") String reportType) {
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode, testId, reportId, reportType);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + testId + ".zip\"")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + "_" + testId + ".zip\"")
.body(bytes);
}

View File

@ -2,7 +2,8 @@ package io.metersphere.api.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.ApiCaseBatchRequest;
import io.metersphere.api.dto.ApiCaseEditRequest;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.DeleteCheckResult;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.service.ApiTestCaseService;
@ -14,6 +15,7 @@ import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
@ -128,7 +130,7 @@ public class ApiTestCaseController {
}
@PostMapping("/batch/edit")
public void editApiBath(@RequestBody ApiCaseBatchRequest request) {
public void editApiBath(@RequestBody ApiCaseEditRequest request) {
apiTestCaseService.editApiBath(request);
}
@ -189,13 +191,13 @@ public class ApiTestCaseController {
@PostMapping(value = "/batch/run")
@MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public void batchRun(@RequestBody ApiCaseBatchRequest request) {
public void batchRun(@RequestBody ApiCaseRunRequest request) {
apiTestCaseService.batchRun(request);
}
@PostMapping(value = "/jenkins/run")
@MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public String jenkinsRun(@RequestBody RunCaseRequest request) {
public MsExecResponseDTO jenkinsRun(@RequestBody RunCaseRequest request) {
return apiTestCaseService.jenkinsRun(request);
}

View File

@ -12,7 +12,6 @@ import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.controller.request.EnvironmentRequest;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.service.CheckPermissionService;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -26,13 +25,10 @@ public class ApiTestEnvironmentController {
@Resource
ApiTestEnvironmentService apiTestEnvironmentService;
@Resource
private CheckPermissionService checkPermissionService;
@Resource
private CommandService commandService;
@GetMapping("/list/{projectId}")
public List<ApiTestEnvironmentWithBLOBs> list(@PathVariable String projectId) {
// checkPermissionService.checkProjectOwner(projectId);
return apiTestEnvironmentService.list(projectId);
}
@ -46,10 +42,6 @@ public class ApiTestEnvironmentController {
*/
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<ApiTestEnvironmentWithBLOBs>> listByCondition(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EnvironmentRequest environmentRequest) {
// List<String> projectIds = environmentRequest.getProjectIds();
// for (String projectId : projectIds) {
// checkPermissionService.checkProjectOwner(projectId);
// }
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, apiTestEnvironmentService.listByConditions(environmentRequest));
}

View File

@ -7,8 +7,11 @@ import io.metersphere.api.dto.share.ShareInfoDTO;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ShareInfoService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ReportStatisticsWithBLOBs;
import io.metersphere.base.domain.ShareInfo;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.reportstatistics.dto.ReportStatisticsSaveRequest;
import io.metersphere.reportstatistics.service.ReportStatisticsService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -29,6 +32,8 @@ public class ShareInfoController {
ShareInfoService shareInfoService;
@Resource
ApiDefinitionService apiDefinitionService;
@Resource
ReportStatisticsService reportStatisticsService;
@PostMapping("/selectApiSimpleInfo")
public List<ApiDocumentInfoDTO> list(@RequestBody ApiDocumentRequest request) {
@ -88,4 +93,9 @@ public class ShareInfoController {
ShareInfoDTO returnDTO = shareInfoService.conversionShareInfoToDTO(apiShare);
return returnDTO;
}
@PostMapping("/selectHistoryReportById")
public ReportStatisticsWithBLOBs selectById(@RequestBody ReportStatisticsSaveRequest request) {
return reportStatisticsService.selectById(request.getId());
}
}

View File

@ -2,7 +2,6 @@ package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
@ -11,7 +10,7 @@ import java.util.List;
@Getter
@Setter
public class ApiCaseBatchRequest extends ApiTestCaseWithBLOBs {
public class ApiCaseEditRequest extends ApiTestCaseWithBLOBs {
private List<String> ids;
private List<OrderRequest> orders;
private String projectId;

View File

@ -0,0 +1,20 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ApiCaseRunRequest {
private String reportId;
private String id;
private List<String> ids;
private List<OrderRequest> orders;
private String projectId;
private String environmentId;
private ApiTestCaseRequest condition;
}

View File

@ -0,0 +1,28 @@
package io.metersphere.api.dto;
import lombok.Data;
import java.util.List;
@Data
public class ApiScenarioReportDTO {
private List<StepTreeDTO> steps;
private String console;
private long totalTime;
private long total;
private long error;
private long scenarioTotal;
private long scenarioError;
private long scenarioSuccess;
private long scenarioStepTotal;
private long scenarioStepError;
private long scenarioStepSuccess;
private long totalAssertions = 0;
private long passAssertions = 0;
}

View File

@ -1,7 +1,10 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.scenario.KeyValue;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
@ -24,4 +27,9 @@ public class ApiTestImportRequest {
private String type;
// 是否开启自定义ID
private Boolean openCustomNum = false;
// 鉴权相关
private List<KeyValue> headers;
private List<KeyValue> arguments;
private MsAuthManager authManager;
}

View File

@ -1,38 +0,0 @@
package io.metersphere.api.dto;
import io.metersphere.base.domain.TestResource;
import lombok.Data;
@Data
public class JvmInfoDTO {
/**
* JVM内存的空闲空间为
*/
private long vmFree;
/**
* JVM内存已用的空间为
*/
private long vmUse;
private long vmTotal;
/**
* JVM总内存空间为
*/
private long vmMax;
private int totalThread;
private TestResource testResource;
public JvmInfoDTO() {
}
public JvmInfoDTO(long vmTotal, long vmFree, long vmMax, long vmUse, int totalThread) {
this.vmFree = vmFree;
this.vmTotal = vmTotal;
this.vmMax = vmMax;
this.vmUse = vmUse;
this.totalThread = totalThread;
}
}

View File

@ -14,6 +14,8 @@ public class RunModeDataDTO {
private HashTree hashTree;
// 测试场景/测试用例
private String testId;
private String reportId;
// 初始化报告
private APIScenarioReportResult report;
//
@ -21,28 +23,12 @@ public class RunModeDataDTO {
private Map<String, String> planEnvMap;
private String debugReportId;
public RunModeDataDTO() {
}
public RunModeDataDTO(String testId, String apiCaseId) {
this.testId = testId;
this.apiCaseId = apiCaseId;
}
public RunModeDataDTO(HashTree hashTree, String apiCaseId) {
this.hashTree = hashTree;
this.apiCaseId = apiCaseId;
}
public RunModeDataDTO(String testId, APIScenarioReportResult report) {
this.testId = testId;
this.report = report;
}
public RunModeDataDTO(HashTree hashTree, APIScenarioReportResult report) {
this.hashTree = hashTree;
public RunModeDataDTO(APIScenarioReportResult report, String testId) {
this.report = report;
this.testId = testId;
}
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
@ -20,7 +20,7 @@ public class RunRequest {
private String jmx;
// 集成报告ID
private String amassReport;
private RunModeConfig config;
private RunModeConfigDTO config;
private Map<String, Object> kafka;
}

View File

@ -0,0 +1,31 @@
package io.metersphere.api.dto;
import io.metersphere.dto.RequestResult;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import java.util.LinkedList;
import java.util.List;
@Data
public class StepTreeDTO {
private String type;
private int index;
private String resourceId;
private String label;
private RequestResult value;
private List<StepTreeDTO> children;
public StepTreeDTO() {
}
public StepTreeDTO(String name, String resourceId, String type, int index) {
this.label = StringUtils.isNotEmpty(name) ? name : type;
this.resourceId = resourceId;
this.type = type;
this.index = index;
this.children = new LinkedList<>();
}
}

View File

@ -30,4 +30,5 @@ public class ApiScenarioDTO extends ApiScenarioWithBLOBs {
*/
private String env;
private Map<String, String> environmentMap;
private String creator;
}

View File

@ -0,0 +1,45 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Setter
@Getter
public class GenScenarioRequest extends ApiScenarioWithBLOBs {
private String reportId;
private String environmentId;
private String triggerMode;
private String executeType;
private String runMode;
/**测试情景和测试计划的关联ID*/
private String planScenarioId;
private List<String> planCaseIds;
private List<String> ids;
private String reportUserID;
private Map<String, String> scenarioTestPlanIdMap;
private ApiScenarioRequest condition;
private RunModeConfigDTO config;
private boolean isTestPlanScheduleJob = false;
//生成测试报告当isTestPlanScheduleJob为ture时使用
private String testPlanReportId;
private String requestOriginator;
}

View File

@ -1,27 +0,0 @@
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 {
private String mode;
private String reportType;
private String reportName;
private String reportId;
private String amassReport;
private boolean onSampleError;
private String resourcePoolId;
private BaseSystemConfigDTO baseInfo;
private List<JvmInfoDTO> testResources;
/**
* 运行环境
*/
private Map<String, String> envMap;
private String environmentType;
private String environmentGroupId;
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
@ -9,19 +9,24 @@ import java.util.Map;
@Setter
@Getter
public class RunScenarioRequest extends ApiScenarioWithBLOBs {
public class RunScenarioRequest {
private String id;
private String reportId;
private String environmentId;
private String projectId;
private String triggerMode;
private String executeType;
private String runMode;
/**测试情景和测试计划的关联ID*/
/**
* 测试情景和测试计划的关联ID
*/
private String planScenarioId;
private List<String> planCaseIds;
@ -34,9 +39,10 @@ public class RunScenarioRequest extends ApiScenarioWithBLOBs {
private ApiScenarioRequest condition;
private RunModeConfig config;
private RunModeConfigDTO config;
private boolean isTestPlanScheduleJob = false;
//生成测试报告当isTestPlanScheduleJob为ture时使用
private String testPlanReportId;

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
@ -36,5 +37,5 @@ public class RunTestPlanScenarioRequest extends ApiScenarioWithBLOBs {
private TestPlanScenarioRequest condition;
private RunModeConfig config;
private RunModeConfigDTO config;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.automation;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
@ -36,5 +37,5 @@ public class SchedulePlanScenarioExecuteRequest {
private String testPlanReportId;
private RunModeConfig config;
private RunModeConfigDTO config;
}

View File

@ -5,16 +5,16 @@ import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.definition.parse.har.HarUtils;
import io.metersphere.api.dto.definition.parse.har.model.*;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.jmeter.RequestResult;
import io.metersphere.api.jmeter.ResponseResult;
import io.metersphere.api.parse.HarScenarioAbstractParser;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.ResponseResult;
import io.metersphere.plugin.core.MsTestElement;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

View File

@ -175,7 +175,6 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
if (!path.startsWith("http://") && !path.startsWith("https://")) {
String domain = source.getDomain();
String protocol = source.getProtocol();
String method = source.getMethod();
StringBuilder pathAndQuery = new StringBuilder(100);
if ("file".equalsIgnoreCase(protocol)) {
domain = null;
@ -184,18 +183,6 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
}
pathAndQuery.append(path);
if ("GET".equals(method) || "DELETE".equals(method) || "OPTIONS".equals(method)) {
String queryString = source.getQueryString(source.getContentEncoding());
if (queryString.length() > 0) {
if (path.contains("?")) {
pathAndQuery.append("&");
} else {
pathAndQuery.append("?");
}
pathAndQuery.append(queryString);
}
}
String portAsString = source.getPropertyAsString("HTTPSampler.port");
return this.isProtocolDefaultPort(source) ? new URL(protocol, domain, pathAndQuery.toString()).toExternalForm() : this.url(protocol, domain, portAsString, pathAndQuery.toString());
} else {
@ -213,6 +200,44 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
return null;
}
private static String truncateUrlPage(String strURL) {
String strAllParam = null;
if (StringUtils.isNotEmpty(strURL)) {
String[] arrSplit = strURL.split("[?]");
if (strURL.length() > 1) {
if (arrSplit.length > 1) {
if (arrSplit[1] != null) {
strAllParam = arrSplit[1];
}
}
}
}
return strAllParam;
}
public static Map<String, String> parseURLParam(String URL) {
Map<String, String> mapRequest = new LinkedHashMap<>();
String strUrlParam = truncateUrlPage(URL);
if (StringUtils.isEmpty(strUrlParam)) {
return mapRequest;
}
//每个键值为一组
String[] arrSplit = strUrlParam.split("[&]");
for (String strSplit : arrSplit) {
String[] arrSplitEqual = strSplit.split("[=]");
//解析出键值
if (arrSplitEqual.length > 1) {
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
} else {
if (StringUtils.isNotEmpty(arrSplitEqual[0])) {
//只有参数没有值不加入
mapRequest.put(arrSplitEqual[0], "");
}
}
}
return mapRequest;
}
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) {
try {
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
@ -303,9 +328,9 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
}
samplerProxy.getBody().initBinary();
}
// samplerProxy.setPath(source.getPath());
samplerProxy.setMethod(source.getMethod());
if (this.getUrl(source) != null) {
URL url = source.getUrl();
if (url != null) {
samplerProxy.setUrl(this.getUrl(source));
samplerProxy.setPath(null);
}
@ -530,9 +555,11 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
RegexExtractor regexExtractor = (RegexExtractor) key;
if (regexExtractor.useRequestHeaders()) {
regex.setUseHeaders("request_headers");
}if (regexExtractor.useHeaders()) {
}
if (regexExtractor.useHeaders()) {
regex.setUseHeaders("true");
} if (regexExtractor.useBody()) {
}
if (regexExtractor.useBody()) {
regex.setUseHeaders("false");
} else if (regexExtractor.useUnescapedBody()) {
regex.setUseHeaders("unescaped");

View File

@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.plugin.core.MsTestElement;
@ -108,6 +109,9 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
if (environmentMap != null) {
scenarioDefinition.put("environmentMap", new HashMap<>());
}
item.setEnvironmentType(EnvironmentType.JSON.name());
item.setEnvironmentJson(null);
item.setEnvironmentGroupId(null);
item.setScenarioDefinition(JSONObject.toJSONString(scenarioDefinition));
}
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
@ -15,7 +15,7 @@ public class BatchRunDefinitionRequest {
private String triggerMode;
private RunModeConfig config;
private RunModeConfigDTO config;
//测试计划报告ID 测试计划执行时使用
private String planReportId;

View File

@ -8,11 +8,12 @@ import lombok.Setter;
@Setter
@Getter
public class RunCaseRequest {
private String reportId;
private String id;
private String caseId;
private String reportId;
private String runMode;
private String environmentId;

View File

@ -1,22 +1,21 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.api.dto.definition.response.Response;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Setter
@Getter
@Data
public class RunDefinitionRequest {
private String id;
private String reportId;
private boolean isDebug;
private boolean saved;
private String requestId;
@ -43,7 +42,7 @@ public class RunDefinitionRequest {
List<String> scenarioFileIds;
private RunModeConfig config;
private RunModeConfigDTO config;
private Map<String, String> environmentMap;

View File

@ -0,0 +1,92 @@
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.GlobalScriptConfig;
import io.metersphere.plugin.core.MsTestElement;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
import org.springframework.util.CollectionUtils;
import java.util.List;
public class JMeterScriptUtil {
/**
* 判断脚本是否被过滤
*
* @param filterProtocals 要过滤掉的请求类型
* @param protocal 当前请求类型
* @return
*/
public static boolean isScriptFilter(List<String> filterProtocals, String protocal) {
if (!CollectionUtils.isEmpty(filterProtocals)) {
return filterProtocals.contains(protocal);
} else {
return false;
}
}
public static MsJSR223PreProcessor getPreScript(EnvironmentConfig envConfig) {
if (envConfig != null && envConfig.getPreProcessor() != null && StringUtils.isNotEmpty(envConfig.getPreProcessor().getScript())) {
return envConfig.getPreProcessor();
} else {
return null;
}
}
public static MsJSR223PostProcessor getPostScript(EnvironmentConfig envConfig) {
if (envConfig != null && envConfig.getPostProcessor() != null && StringUtils.isNotEmpty(envConfig.getPostProcessor().getScript())) {
return envConfig.getPostProcessor();
} else {
return null;
}
}
/**
* Samper中放置脚本
*
* @param envConfig 环境配置信息
* @param samplerHashTree sampler的hashtree
* @param isAfterPrivateScript 是否将脚本放置在sampler的私有脚本之后
* @param protocal 请求类型
* @param environmentId 环境ID
* @param config 参数配置
*/
public static void setScript(EnvironmentConfig envConfig, HashTree samplerHashTree, String protocal, String environmentId, ParameterConfig config, boolean isAfterPrivateScript) {
GlobalScriptConfig globalScriptConfig = envConfig != null ? envConfig.getGlobalScriptConfig() : null;
boolean isPreScriptExecAfterPrivateScript = globalScriptConfig == null ? false : globalScriptConfig.isPreScriptExecAfterPrivateScript();
boolean isPostScriptExecAfterPrivateScript = globalScriptConfig == null ? false : globalScriptConfig.isPostScriptExecAfterPrivateScript();
List<String> preFilterProtocal = globalScriptConfig == null ? null : globalScriptConfig.getFilterRequestPreScript();
List<String> postFilterProtocal = globalScriptConfig == null ? null : globalScriptConfig.getFilterRequestPostScript();
MsJSR223PreProcessor preProcessor = JMeterScriptUtil.getPreScript(envConfig);
MsJSR223PostProcessor postProcessor = JMeterScriptUtil.getPostScript(envConfig);
boolean globalPreScriptIsFilter = JMeterScriptUtil.isScriptFilter(preFilterProtocal, protocal);
boolean globalPostScriptIsFilter = JMeterScriptUtil.isScriptFilter(postFilterProtocal, protocal);
if (isAfterPrivateScript) {
if (isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter) {
addItemHashTree(preProcessor, samplerHashTree, config, environmentId);
}
if (isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter) {
addItemHashTree(postProcessor, samplerHashTree, config, environmentId);
}
} else {
if (!isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter) {
addItemHashTree(preProcessor, samplerHashTree, config, environmentId);
}
if (!isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter) {
addItemHashTree(postProcessor, samplerHashTree, config, environmentId);
}
}
}
private static void addItemHashTree(MsTestElement element, HashTree samplerHashTree, ParameterConfig config, String enviromentId) {
if (element != null && element.getEnvironmentId() == null) {
element.setEnvironmentId(enviromentId);
element.toHashTree(samplerHashTree, element.getHashTree(), config);
}
}
}

View File

@ -14,13 +14,13 @@ import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.constants.SwaggerParameterType;
import io.swagger.models.*;
import io.swagger.models.auth.AuthorizationValue;
import io.swagger.models.parameters.*;
import io.swagger.models.properties.*;
import io.swagger.parser.SwaggerParser;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.*;
@ -32,24 +32,69 @@ public class Swagger2Parser extends SwaggerAbstractParser {
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
Swagger swagger;
String sourceStr = "";
List<AuthorizationValue> auths = setAuths(request);
if (StringUtils.isNotBlank(request.getSwaggerUrl())) { // 使用 url 导入 swagger
swagger = new SwaggerParser().read(request.getSwaggerUrl());
swagger = new SwaggerParser().read(request.getSwaggerUrl(), auths, true);
} else {
sourceStr = getApiTestStr(source); // 导入的二进制文件转换为 String
swagger = new SwaggerParser().readWithInfo(sourceStr).getSwagger();
swagger = new SwaggerParser().readWithInfo(sourceStr, auths, true).getSwagger();
}
if (swagger == null || swagger.getSwagger() == null) { // 不是 2.0 版本则尝试转换 3.0
Swagger3Parser swagger3Parser = new Swagger3Parser();
return swagger3Parser.parse(sourceStr, request);
}
ApiDefinitionImport definitionImport = new ApiDefinitionImport();
this.projectId = request.getProjectId();
definitionImport.setData(parseRequests(swagger, request));
return definitionImport;
}
// 鉴权设置
private List<AuthorizationValue> setAuths(ApiTestImportRequest request) {
List<AuthorizationValue> auths = new ArrayList<>();
// 如果有 BaseAuth 参数base64 编码后转换成 headers
if(request.getAuthManager() != null
&& StringUtils.isNotBlank(request.getAuthManager().getUsername())
&& StringUtils.isNotBlank(request.getAuthManager().getPassword())
&& request.getAuthManager().getVerification().equals("Basic Auth")){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("header");
authorizationValue.setKeyName("Authorization");
String authValue = "Basic " + Base64.getUrlEncoder().encodeToString((request.getAuthManager().getUsername()
+ ":" + request.getAuthManager().getPassword()).getBytes());
authorizationValue.setValue(authValue);
auths.add(authorizationValue);
}
// 设置 headers
if(!CollectionUtils.isEmpty(request.getHeaders())){
for(KeyValue keyValue : request.getHeaders()){
// 当有 key 时才进行设置
if(StringUtils.isNotBlank(keyValue.getName())){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("header");
authorizationValue.setKeyName(keyValue.getName());
authorizationValue.setValue(keyValue.getValue());
auths.add(authorizationValue);
}
}
}
// 设置 query 参数
if(!CollectionUtils.isEmpty(request.getArguments())){
for(KeyValue keyValue : request.getArguments()){
if(StringUtils.isNotBlank(keyValue.getName())){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("query");
authorizationValue.setKeyName(keyValue.getName());
authorizationValue.setValue(keyValue.getValue());
auths.add(authorizationValue);
}
}
}
return CollectionUtils.size(auths) == 0 ? null : auths;
}
private List<ApiDefinitionWithBLOBs> parseRequests(Swagger swagger, ApiTestImportRequest importRequest) {
Map<String, Path> paths = swagger.getPaths();
Set<String> pathNames = paths.keySet();

View File

@ -27,12 +27,12 @@ import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import java.io.InputStream;
import java.util.*;
@ -51,29 +51,74 @@ public class Swagger3Parser extends SwaggerAbstractParser {
}
public ApiDefinitionImport parse(String sourceStr, ApiTestImportRequest request) {
List<AuthorizationValue> auths = setAuths(request);
SwaggerParseResult result;
if (StringUtils.isNotBlank(request.getSwaggerUrl())) {
result = new OpenAPIParser().readLocation(request.getSwaggerUrl(), null, null);
result = new OpenAPIParser().readLocation(request.getSwaggerUrl(), auths, null);
} else {
result = new OpenAPIParser().readContents(sourceStr, null, null);
result = new OpenAPIParser().readContents(sourceStr, auths, null);
}
if (result == null) {
MSException.throwException("解析失败,请确认选择的是 swagger 格式!");
}
OpenAPI openAPI = result.getOpenAPI();
if (result.getMessages() != null) {
result.getMessages().forEach(msg -> LogUtil.error(msg)); // validation errors and warnings
}
ApiDefinitionImport definitionImport = new ApiDefinitionImport();
this.projectId = request.getProjectId();
definitionImport.setData(parseRequests(openAPI, request));
return definitionImport;
}
// 鉴权设置
private List<AuthorizationValue> setAuths(ApiTestImportRequest request) {
List<AuthorizationValue> auths = new ArrayList<>();
// 如果有 BaseAuth 参数base64 编码后转换成 headers
if(request.getAuthManager() != null
&& StringUtils.isNotBlank(request.getAuthManager().getUsername())
&& StringUtils.isNotBlank(request.getAuthManager().getPassword())
&& request.getAuthManager().getVerification().equals("Basic Auth")){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("header");
authorizationValue.setKeyName("Authorization");
String authValue = "Basic " + Base64.getUrlEncoder().encodeToString((request.getAuthManager().getUsername()
+ ":" + request.getAuthManager().getPassword()).getBytes());
authorizationValue.setValue(authValue);
auths.add(authorizationValue);
}
// 设置 headers
if(!CollectionUtils.isEmpty(request.getHeaders())){
for(KeyValue keyValue : request.getHeaders()){
// 当有 key 时才进行设置
if(StringUtils.isNotBlank(keyValue.getName())){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("header");
authorizationValue.setKeyName(keyValue.getName());
authorizationValue.setValue(keyValue.getValue());
auths.add(authorizationValue);
}
}
}
// 设置 query 参数
if(!CollectionUtils.isEmpty(request.getArguments())){
for(KeyValue keyValue : request.getArguments()){
if(StringUtils.isNotBlank(keyValue.getName())){
AuthorizationValue authorizationValue = new AuthorizationValue();
authorizationValue.setType("query");
authorizationValue.setKeyName(keyValue.getName());
authorizationValue.setValue(keyValue.getValue());
auths.add(authorizationValue);
}
}
}
return CollectionUtils.size(auths) == 0 ? null : auths;
}
private List<ApiDefinitionWithBLOBs> parseRequests(OpenAPI openAPI, ApiTestImportRequest importRequest) {
Paths paths = openAPI.getPaths();
@ -207,14 +252,15 @@ public class Swagger3Parser extends SwaggerAbstractParser {
responses.forEach((responseCode, response) -> {
parseResponseHeader(response, msResponse.getHeaders());
parseResponseBody(response, msResponse.getBody());
parseResponseCode(responseCode, msResponse);
});
} else {
parseResponseHeader(apiResponse, msResponse.getHeaders());
parseResponseBody(apiResponse, msResponse.getBody());
parseResponseCode("200", msResponse);
}
}
responses.forEach((responseCode, response) -> {
parseResponseCode(msResponse.getStatusCode(), responseCode, response);
});
return msResponse;
}
@ -227,14 +273,13 @@ public class Swagger3Parser extends SwaggerAbstractParser {
}
}
private void parseResponseCode(String response, HttpResponse msResponse) {
if (StringUtils.isNotEmpty(response)) {
private void parseResponseCode(List<KeyValue> statusCode, String responseCode, ApiResponse response) {
try {
msResponse.setStatusCode(JSON.parseObject(response, List.class));
statusCode.add(new KeyValue(responseCode, response.getDescription(), response.getDescription()));
} catch (Exception e) {
LogUtil.error(e);
}
}
}
private void parseResponseBody(ApiResponse response, Body body) {
@ -272,6 +317,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
return;
}
mediaType = content.get(contentType);
if (contentType.equals("*/*")) {
contentType = org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
}
}
Set<String> refSet = new HashSet<>();

View File

@ -24,6 +24,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.EnvironmentGroupProjectService;
@ -38,6 +39,7 @@ import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URL;
import java.util.*;
@ -111,7 +113,7 @@ public class ElementUtil {
}
}
public static void addCounter(HashTree tree, List<ScenarioVariable> variables) {
public static void addCounter(HashTree tree, List<ScenarioVariable> variables, boolean isInternal) {
if (CollectionUtils.isNotEmpty(variables)) {
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCounterValid).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
@ -121,7 +123,11 @@ public class ElementUtil {
counterConfig.setProperty(TestElement.TEST_CLASS, CounterConfig.class.getName());
counterConfig.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("CounterConfigGui"));
counterConfig.setName(item.getName());
if (isInternal) {
counterConfig.setStart((item.getStartNumber() + 1));
} else {
counterConfig.setStart(item.getStartNumber());
}
counterConfig.setEnd(item.getEndNumber());
counterConfig.setVarName(item.getName());
counterConfig.setIncrement(item.getIncrement());
@ -265,6 +271,24 @@ public class ElementUtil {
}
};
public final static List<String> requests = new ArrayList<String>() {{
this.add("HTTPSamplerProxy");
this.add("DubboSampler");
this.add("JDBCSampler");
this.add("TCPSampler");
this.add("JSR223Processor");
this.add("JSR223PreProcessor");
this.add("JSR223PostProcessor");
this.add("JDBCPreProcessor");
this.add("JDBCPostProcessor");
this.add("JmeterElement");
this.add("TestPlan");
this.add("ThreadGroup");
this.add("DNSCacheManager");
this.add("DebugSampler");
this.add("AuthManager");
}};
private static void formatSampler(JSONObject element) {
if (element == null || StringUtils.isEmpty(element.getString("type"))) {
return;
@ -335,6 +359,41 @@ public class ElementUtil {
}
}
public static void dataFormatting(JSONArray hashTree, String id, String reportType) {
for (int i = 0; i < hashTree.size(); i++) {
JSONObject element = hashTree.getJSONObject(i);
formatSampler(element);
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (element != null && requests.contains(element.getString("type")) && !element.getString("resourceId").contains(id)) {
element.fluentPut("resourceId", id + "=" + element.getString("resourceId"));
}
}
if (element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, id, reportType);
}
}
}
public static void dataFormatting(JSONObject element, String id, String reportType) {
if (element != null && element.get("clazzName") == null && clazzMap.containsKey(element.getString("type"))) {
element.fluentPut("clazzName", clazzMap.get(element.getString("type")));
}
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
if (element != null && requests.contains(element.getString("type")) && !element.getString("resourceId").contains(id)) {
element.fluentPut("resourceId", id + "=" + element.getString("resourceId"));
}
}
formatSampler(element);
if (element != null && element.containsKey("hashTree")) {
JSONArray elementJSONArray = element.getJSONArray("hashTree");
dataFormatting(elementJSONArray, id, reportType);
}
}
public static void dataSetDomain(JSONArray hashTree, MsParameter msParameter) {
try {
ObjectMapper mapper = new ObjectMapper();
@ -470,4 +529,15 @@ public class ElementUtil {
element.setHashTree(targetHashTree);
}
}
public static String hashTreeToString(HashTree hashTree) {
try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) {
SaveService.saveTree(hashTree, bas);
return bas.toString();
} catch (Exception e) {
e.printStackTrace();
io.metersphere.plugin.core.utils.LogUtil.warn("HashTree error, can't log jmx scenarioDefinition");
}
return null;
}
}

View File

@ -17,9 +17,9 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.EnvironmentGroupProjectService;
@ -162,7 +162,7 @@ public class MsScenario extends MsTestElement {
tree.add(ParameterConfig.valueSupposeMock(arguments));
}
ElementUtil.addCsvDataSet(tree, variables, config, "shareMode.group");
ElementUtil.addCounter(tree, variables);
ElementUtil.addCounter(tree, variables, false);
ElementUtil.addRandom(tree, variables);
if (CollectionUtils.isNotEmpty(this.headers)) {
config.setHeaders(this.headers);

View File

@ -12,8 +12,8 @@ import io.metersphere.api.dto.mockconfig.MockConfigStaticData;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -63,7 +63,7 @@ public class MsThreadGroup extends MsTestElement {
boolean isConnScenarioPost = false;
//获取projectConfig
String projectId = this.checkProjectId(hashTree);
this.checkEnviromentConfig(projectId,config,hashTree);
this.checkEnvironmentConfig(projectId,config,hashTree);
if (config.getConfig() != null) {
if (config.isEffective(projectId)) {
EnvironmentConfig environmentConfig = config.getConfig().get(projectId);
@ -154,7 +154,7 @@ public class MsThreadGroup extends MsTestElement {
return projectId;
}
private void checkEnviromentConfig(String projectId, ParameterConfig config, List<MsTestElement> hashTree) {
private void checkEnvironmentConfig(String projectId, ParameterConfig config, List<MsTestElement> hashTree) {
//检查全局前后置脚本
if (config.getConfig() == null) {
// 单独接口执行

View File

@ -1,18 +0,0 @@
package io.metersphere.api.dto.definition.request.assertions.document;
import lombok.Data;
@Data
public class Condition {
private String key;
private Object value;
public Condition() {
}
public Condition(String key, Object value) {
this.key = key;
this.value = value;
}
}

View File

@ -1,6 +1,8 @@
package io.metersphere.api.dto.definition.request.assertions.document;
import com.alibaba.fastjson.JSON;
import io.metersphere.vo.Condition;
import io.metersphere.vo.ElementCondition;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

View File

@ -1,130 +0,0 @@
package io.metersphere.api.dto.definition.request.assertions.document;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.oro.text.regex.Pattern;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
public class DocumentUtils {
public static boolean documentChecked(Object subj, String condition, ThreadLocal<DecimalFormat> decimalFormatter) {
if (StringUtils.isNotEmpty(condition)) {
ElementCondition elementCondition = JSON.parseObject(condition, ElementCondition.class);
boolean isTrue = true;
if (CollectionUtils.isNotEmpty(elementCondition.getConditions())) {
for (Condition item : elementCondition.getConditions()) {
String expectedValue = item.getValue() != null ? item.getValue().toString() : "";
String resValue = objectToString(subj, decimalFormatter);
switch (item.getKey()) {
case "value_eq":
isTrue = StringUtils.equals(resValue, expectedValue);
break;
case "value_not_eq":
isTrue = !StringUtils.equals(resValue, expectedValue);
break;
case "value_in":
isTrue = StringUtils.contains(resValue, expectedValue);
break;
case "length_eq":
isTrue = getLength(subj, decimalFormatter) == numberOf(item.getValue());
break;
case "length_not_eq":
isTrue = getLength(subj, decimalFormatter) != numberOf(item.getValue());
break;
case "length_gt":
isTrue = getLength(subj, decimalFormatter) > numberOf(item.getValue());
break;
case "length_lt":
isTrue = getLength(subj, decimalFormatter) < numberOf(item.getValue());
break;
case "regular":
Pattern pattern = JMeterUtils.getPatternCache().getPattern(expectedValue);
isTrue = JMeterUtils.getMatcher().matches(resValue, pattern);
break;
}
if (!isTrue) {
break;
}
}
}
return isTrue;
}
return true;
}
public static String objectToString(Object subj, ThreadLocal<DecimalFormat> decimalFormatter) {
String str;
if (subj == null) {
str = "null";
} else if (subj instanceof Map) {
str = new Gson().toJson(subj);
} else if (!(subj instanceof Double) && !(subj instanceof Float)) {
str = subj.toString();
} else {
str = ((DecimalFormat) decimalFormatter.get()).format(subj);
}
return str;
}
private static int getLength(Object value) {
if (value != null) {
if (value instanceof List) {
return ((List) value).size();
}
return value.toString().length();
}
return 0;
}
private static int getLength(Object value, ThreadLocal<DecimalFormat> decimalFormatter) {
if (value != null) {
if (value instanceof Map) {
return ((Map) value).size();
} else if (value instanceof List) {
return ((List) value).size();
} else if (!(value instanceof Double) && !(value instanceof Float)) {
return value.toString().length();
} else {
return ((DecimalFormat) decimalFormatter.get()).format(value).length();
}
}
return 0;
}
private static long numberOf(Object value) {
if (value != null) {
try {
return Long.parseLong(value.toString());
} catch (Exception e) {
return 0;
}
}
return 0;
}
public static String documentMsg(Object resValue, String condition) {
String msg = "";
if (StringUtils.isNotEmpty(condition)) {
ElementCondition elementCondition = JSON.parseObject(condition, ElementCondition.class);
if (CollectionUtils.isNotEmpty(elementCondition.getConditions())) {
for (Condition item : elementCondition.getConditions()) {
if (StringUtils.equalsAny(item.getKey(), "value_eq", "value_not_eq", "value_in")) {
msg = resValue != null ? resValue.toString() : "";
} else if (StringUtils.equalsAny(item.getKey(), "length_eq", "length_not_eq", "length_gt", "length_lt")) {
msg = "长度是:" + getLength(resValue) + "";
} else {
msg = resValue != null ? resValue.toString() : "";
}
}
}
}
return msg;
}
}

View File

@ -1,24 +0,0 @@
package io.metersphere.api.dto.definition.request.assertions.document;
import lombok.Data;
import java.util.List;
@Data
public class ElementCondition {
private boolean include;
private boolean typeVerification;
private boolean arrayVerification;
List<Condition> conditions;
public ElementCondition() {
}
public ElementCondition(boolean include, boolean typeVerification, boolean arrayVerification, List<Condition> conditions) {
this.include = include;
this.typeVerification = typeVerification;
this.arrayVerification = arrayVerification;
this.conditions = conditions;
}
}

View File

@ -60,7 +60,7 @@ public class MsLoopController extends MsTestElement {
final HashTree groupTree = controller(tree);
if (CollectionUtils.isNotEmpty(config.getVariables())) {
ElementUtil.addCsvDataSet(groupTree, config.getVariables(), config, "shareMode.thread");
ElementUtil.addCounter(groupTree, config.getVariables());
ElementUtil.addCounter(groupTree, config.getVariables(), true);
ElementUtil.addRandom(groupTree, config.getVariables());
}

View File

@ -1,9 +1,7 @@
package io.metersphere.api.dto.definition.request.controller;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -37,11 +35,6 @@ public class MsTransactionController extends MsTestElement {
}
TransactionController transactionController = transactionController();
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
transactionController.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
final HashTree groupTree = tree.add(transactionController);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
@ -58,7 +51,7 @@ public class MsTransactionController extends MsTestElement {
if (StringUtils.isEmpty(this.getName())) {
this.setName(getLabelName());
}
transactionController.setName(this.getName());
transactionController.setName("Transaction=" + this.getName());
transactionController.setProperty(TestElement.TEST_CLASS, TransactionController.class.getName());
transactionController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TransactionControllerGui"));
transactionController.setGenerateParentSample(generateParentSample);

View File

@ -66,7 +66,7 @@ public class MsExtract extends MsTestElement {
shell.setProperty(TestElement.TEST_CLASS, JSR223PostProcessor.class.getName());
shell.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
shell.setProperty("cacheKey", false);
shell.setProperty("script", "io.metersphere.api.jmeter.JMeterVars.addVars(prev.hashCode(),vars," + "\"" + extract.toString() + "\"" + ");");
shell.setProperty("script", "io.metersphere.utils.JMeterVars.addVars(prev.hashCode(),vars," + "\"" + extract.toString() + "\"" + ");");
samplerHashTree.add(shell);
}
}

View File

@ -7,7 +7,6 @@ import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -71,10 +70,6 @@ public class MsJSR223Processor extends MsTestElement {
} else {
processor.setName("JSR223Processor");
}
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
processor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
processor.setProperty("MS-ID", this.getId());
processor.setProperty("MS-RESOURCE-ID", this.getResourceId()+ "_" + this.getIndex());
List<String> id_names = new LinkedList<>();

View File

@ -18,12 +18,11 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -244,10 +243,6 @@ public class MsJDBCPostProcessor extends MsTestElement {
JDBCPostProcessor jdbcPostProcessor = new JDBCPostProcessor();
jdbcPostProcessor.setEnabled(this.isEnable());
jdbcPostProcessor.setName(this.getName() == null? "JDBCPostProcessor" : this.getName());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
jdbcPostProcessor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
jdbcPostProcessor.setProperty(TestElement.TEST_CLASS, JDBCPostProcessor.class.getName());
jdbcPostProcessor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
jdbcPostProcessor.setProperty("MS-ID", this.getId());

View File

@ -18,12 +18,11 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -244,10 +243,6 @@ public class MsJDBCPreProcessor extends MsTestElement {
JDBCPreProcessor jdbcPreProcessor = new JDBCPreProcessor();
jdbcPreProcessor.setEnabled(this.isEnable());
jdbcPreProcessor.setName(this.getName() == null? "JDBCPreProcessor" : this.getName());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
jdbcPreProcessor.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
jdbcPreProcessor.setProperty(TestElement.TEST_CLASS, JDBCPreProcessor.class.getName());
jdbcPreProcessor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
jdbcPreProcessor.setProperty("MS-ID", this.getId());

View File

@ -21,7 +21,6 @@ import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
@ -151,10 +150,6 @@ public class MsDubboSampler extends MsTestElement {
DubboSample sampler = new DubboSample();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
sampler.setProperty(TestElement.TEST_CLASS, DubboSample.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("DubboSampleGui"));
sampler.setProperty("MS-ID", this.getId());

View File

@ -7,6 +7,7 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.parse.JMeterScriptUtil;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
@ -32,13 +33,12 @@ import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.commons.constants.ConditionType;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
@ -195,10 +195,6 @@ public class MsHTTPSamplerProxy extends MsTestElement {
if (StringUtils.isEmpty(this.getName())) {
sampler.setName("HTTPSamplerProxy");
}
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
sampler.setProperty("MS-ID", this.getId());
@ -307,12 +303,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
MsJSR223PreProcessor preProcessor = httpConfig.getPreProcessor();
MsJSR223PostProcessor postProcessor = httpConfig.getPostProcessor();
GlobalScriptConfig globalScriptConfig = httpConfig.getGlobalScriptConfig();
List<String> filterPreProtocal = globalScriptConfig == null ? new ArrayList<>() : globalScriptConfig.getFilterRequestPreScript();
List<String> filterPostProtocal = globalScriptConfig == null ? new ArrayList<>() : globalScriptConfig.getFilterRequestPostScript();
boolean filterPre = filterPreProtocal.contains(GlobalScriptFilterRequest.HTTP.name());
boolean filterPost = filterPostProtocal.contains(GlobalScriptFilterRequest.HTTP.name());
List<String> filterPreProtocal = globalScriptConfig == null ? null : globalScriptConfig.getFilterRequestPreScript();
List<String> filterPostProtocal = globalScriptConfig == null ? null : globalScriptConfig.getFilterRequestPostScript();
boolean filterPre = JMeterScriptUtil.isScriptFilter(filterPreProtocal, GlobalScriptFilterRequest.HTTP.name());
boolean filterPost = JMeterScriptUtil.isScriptFilter(filterPostProtocal, GlobalScriptFilterRequest.HTTP.name());
boolean isPreScriptExecAfterPrivateScript = globalScriptConfig == null ? false : globalScriptConfig.isPreScriptExecAfterPrivateScript();
boolean isPostScriptExecAfterPrivateScript = globalScriptConfig == null ? false : globalScriptConfig.isPostScriptExecAfterPrivateScript();
@ -556,6 +551,8 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
if (StringUtils.isEmpty(this.alias)) {
this.alias = sslConfig.getDefaultAlias();
} else {
this.alias = sslConfig.getAlias(this.alias);
}
if (StringUtils.isNotEmpty(this.alias)) {
@ -702,7 +699,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
private String getPostQueryParameters(String path) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(path);
if (path.indexOf("?") != -1) {
stringBuffer.append("&");
} else {
stringBuffer.append("?");
}
this.getArguments().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue -> {
stringBuffer.append(keyValue.getName());
if (keyValue.getValue() != null) {
@ -766,7 +767,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
for (int i = 0; i < headerManager.getHeaders().size(); i++) {
Header header = headerManager.getHeader(i);
String headName = header.getName();
if (StringUtils.equals(headName, keyValue.getName())) {
if (StringUtils.equals(headName, keyValue.getName()) && !StringUtils.equals(headName, "Cookie")) {
hasHead = true;
break;
}

View File

@ -7,14 +7,12 @@ import com.alibaba.fastjson.annotation.JSONType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.parse.JMeterScriptUtil;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.GlobalScriptConfig;
import io.metersphere.api.dto.scenario.environment.GlobalScriptFilterRequest;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiTestCaseService;
@ -22,12 +20,11 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.RunModeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.plugin.core.MsParameter;
import io.metersphere.plugin.core.MsTestElement;
import lombok.Data;
@ -41,7 +38,6 @@ import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@ -152,57 +148,30 @@ public class MsJDBCSampler extends MsTestElement {
if (arguments != null) {
tree.add(arguments);
}
// 环境通用请求头
Arguments envArguments = getConfigArguments(config);
if (envArguments != null) {
tree.add(envArguments);
}
MsJSR223PreProcessor preProcessor = envConfig != null ? envConfig.getPreProcessor() : null;
MsJSR223PostProcessor postProcessor = envConfig != null ? envConfig.getPostProcessor() : null;
GlobalScriptConfig globalScriptConfig = envConfig != null ? envConfig.getGlobalScriptConfig() : null;
if (globalScriptConfig != null) {
boolean isPreScriptExecAfterPrivateScript = globalScriptConfig.isPreScriptExecAfterPrivateScript();
boolean isPostScriptExecAfterPrivateScript = globalScriptConfig.isPostScriptExecAfterPrivateScript();
List<String> preFilters = globalScriptConfig == null ? new ArrayList<>() : globalScriptConfig.getFilterRequestPreScript();
List<String> postFilters = globalScriptConfig == null ? new ArrayList<>() : globalScriptConfig.getFilterRequestPostScript();
boolean globalPreScriptIsFilter = preFilters.contains(GlobalScriptFilterRequest.JDBC.name());
boolean globalPostScriptIsFilter = postFilters.contains(GlobalScriptFilterRequest.JDBC.name());
//处理全局前后置脚本(步骤内)
String enviromentId = this.getEnvironmentId();
if (enviromentId == null) {
enviromentId = this.useEnvironment;
}
//根据配置将脚本放置在私有脚本之前
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.JDBC.name(), enviromentId, config, false);
if (!isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter) {
this.addItemHashTree(preProcessor, samplerHashTree, config);
}
if (!isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter) {
this.addItemHashTree(postProcessor, samplerHashTree, config);
}
if (isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter) {
this.addItemHashTree(preProcessor, samplerHashTree, config);
}
if (isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter) {
this.addItemHashTree(postProcessor, samplerHashTree, config);
}
}
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(samplerHashTree, el.getHashTree(), config);
});
}
//根据配置将脚本放置在私有脚本之后
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.JDBC.name(), enviromentId, config, true);
}
private void addItemHashTree(MsTestElement element, HashTree samplerHashTree, ParameterConfig config) {
if (element != null && element.getEnvironmentId() == null) {
if (this.getEnvironmentId() == null) {
element.setEnvironmentId(useEnvironment);
} else {
element.setEnvironmentId(this.getEnvironmentId());
}
element.toHashTree(samplerHashTree, element.getHashTree(), config);
}
}
/**
* 环境通用变量
*/
@ -329,10 +298,6 @@ public class MsJDBCSampler extends MsTestElement {
JDBCSampler sampler = new JDBCSampler();
sampler.setEnabled(this.isEnable());
sampler.setName(this.getName());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
sampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
sampler.setProperty(TestElement.TEST_CLASS, JDBCSampler.class.getName());
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
sampler.setProperty("MS-ID", this.getId());

View File

@ -9,13 +9,12 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.definition.parse.JMeterScriptUtil;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.environment.GlobalScriptConfig;
import io.metersphere.api.dto.scenario.environment.GlobalScriptFilterRequest;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiTestCaseService;
@ -151,48 +150,23 @@ public class MsTCPSampler extends MsTestElement {
samplerHashTree.add(tcpPreProcessor.getJSR223PreProcessor());
}
MsJSR223PreProcessor preProcessor = null;
MsJSR223PostProcessor postProcessor = null;
GlobalScriptConfig globalScriptConfig = null;
if(envConfig != null){
preProcessor = envConfig.getPreProcessor();
postProcessor = envConfig.getPostProcessor();
globalScriptConfig = envConfig.getGlobalScriptConfig();
}
boolean isPreScriptExecAfterPrivateScript = globalScriptConfig == null? false : globalScriptConfig.isPreScriptExecAfterPrivateScript();
boolean isPostScriptExecAfterPrivateScript = globalScriptConfig == null? false : globalScriptConfig.isPostScriptExecAfterPrivateScript();
boolean globalPreScriptIsFilter = false;
boolean globalPostScriptIsFilter = false;
List<String> preFilterProtocal = globalScriptConfig == null? new ArrayList<>() : globalScriptConfig.getFilterRequestPreScript();
List<String> postFilterProtocal = globalScriptConfig == null? new ArrayList<>() : globalScriptConfig.getFilterRequestPostScript();
if(preFilterProtocal.contains(GlobalScriptFilterRequest.TCP.name())){
globalPreScriptIsFilter = true;
}
if(postFilterProtocal.contains(GlobalScriptFilterRequest.TCP.name())){
globalPostScriptIsFilter = true;
}
if(!isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter){
this.addItemHashTree(preProcessor,samplerHashTree,config);
}
if(!isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter){
this.addItemHashTree(postProcessor,samplerHashTree,config);
//处理全局前后置脚本(步骤内)
String enviromentId = this.getEnvironmentId();
if (enviromentId == null) {
enviromentId = this.useEnvironment;
}
//根据配置将脚本放置在私有脚本之前
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.TCP.name(), enviromentId, config, false);
if (CollectionUtils.isNotEmpty(hashTree)) {
hashTree.forEach(el -> {
el.toHashTree(samplerHashTree, el.getHashTree(), config);
});
}
//根据配置将脚本放置在私有脚本之后
JMeterScriptUtil.setScript(envConfig, samplerHashTree, GlobalScriptFilterRequest.TCP.name(), enviromentId, config, false);
}
if(isPreScriptExecAfterPrivateScript && !globalPreScriptIsFilter){
this.addItemHashTree(preProcessor,samplerHashTree,config);
}
if(isPostScriptExecAfterPrivateScript && !globalPostScriptIsFilter){
this.addItemHashTree(postProcessor,samplerHashTree,config);
}
}
private void addItemHashTree(MsTestElement element, HashTree samplerHashTree, ParameterConfig config) {
if (element != null) {
if (element.getEnvironmentId() == null) {
@ -205,6 +179,7 @@ public class MsTCPSampler extends MsTestElement {
element.toHashTree(samplerHashTree, element.getHashTree(), config);
}
}
private void setRefElement() {
try {
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
@ -268,10 +243,6 @@ public class MsTCPSampler extends MsTestElement {
TCPSampler tcpSampler = new TCPSampler();
tcpSampler.setEnabled(this.isEnable());
tcpSampler.setName(this.getName());
String name = ElementUtil.getParentName(this.getParent());
if (StringUtils.isNotEmpty(name) && !config.isOperating()) {
tcpSampler.setName(this.getName() + DelimiterConstants.SEPARATOR.toString() + name);
}
tcpSampler.setProperty("MS-ID", this.getId());
String indexPath = this.getIndex();
tcpSampler.setProperty("MS-RESOURCE-ID", this.getResourceId() + "_" + ElementUtil.getFullIndexPath(this.getParent(), indexPath));

View File

@ -407,6 +407,8 @@ public class MockApiUtils {
JSONObject queryParamsObj = requestMockParams.getQueryParamsObj();
for (String key : queryParamsObj.keySet()) {
String value = String.valueOf(queryParamsObj.get(key));
value = StringUtils.replace(value, "\\", "\\\\");
value = StringUtils.replace(value, "\"", "\\\"");
scriptStringBuffer.append("requestParams.put(\"query." + key + "\",\"" + value + "\");\n");
}
}
@ -489,14 +491,7 @@ public class MockApiUtils {
return returnJson;
} else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "text/xml")) {
String xmlString = readXml(request);
org.json.JSONObject xmlJSONObj = XML.toJSONObject(xmlString);
String jsonStr = xmlJSONObj.toString();
JSONObject object = null;
try {
object = JSONObject.parseObject(jsonStr);
} catch (Exception e) {
}
JSONObject object = XMLUtils.XmlToJson(xmlString);
return object;
} else if (StringUtils.startsWithIgnoreCase(request.getContentType(), "application/x-www-form-urlencoded")) {
JSONObject object = new JSONObject();

View File

@ -11,4 +11,5 @@ public class PostmanUrl {
private String protocol;
private String port;
private List<PostmanKeyValue> query;
private List<PostmanKeyValue> variable;
}

View File

@ -29,6 +29,7 @@ public class HttpConfig {
private MsJSR223PostProcessor postProcessor;
private GlobalScriptConfig globalScriptConfig;
private ApiModuleMapper apiModuleMapper;
private String description;
public HttpConfig initHttpConfig(HttpConfigCondition configCondition) {

View File

@ -16,4 +16,5 @@ public class TCPConfig {
private String eolByte = "";
private String username = "";
private String password = "";
private String description = "";
}

View File

@ -25,4 +25,14 @@ public class KeyStoreConfig {
}
return null;
}
public String getAlias(String asName) {
if (CollectionUtils.isNotEmpty(entrys)) {
List<KeyStoreEntry> entryList = this.entrys.stream().filter(ks -> StringUtils.equals(asName, ks.getNewAsName())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(entryList) && CollectionUtils.isNotEmpty(files) && files.size() == 1) {
return entryList.get(0).getOriginalAsName();
}
}
return asName;
}
}

View File

@ -0,0 +1,271 @@
package io.metersphere.api.exec.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.RunCaseRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.TcpApiParamService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiExecuteService {
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private JMeterService jMeterService;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiTestEnvironmentService environmentService;
@Resource
private TcpApiParamService tcpApiParamService;
public List<MsExecResponseDTO> run(ApiCaseRunRequest request) {
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("进入执行方法,接收到参数:" + JSON.toJSONString(request));
}
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest) query));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdIn(request.getIds());
List<ApiTestCaseWithBLOBs> list = apiTestCaseMapper.selectByExampleWithBLOBs(example);
LoggerUtil.debug("查询到执行数据:" + list.size());
ApiTestCaseMapper sqlSessionMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
List<RunCaseRequest> executeQueue = new LinkedList<>();
for (ApiTestCaseWithBLOBs caseWithBLOBs : list) {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.initBase(caseWithBLOBs.getId(), APITestStatus.Running.name(), null);
report.setName(caseWithBLOBs.getName());
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
sqlSessionMapper.updateByPrimaryKey(caseWithBLOBs);
// 执行对象
RunCaseRequest runCaseRequest = new RunCaseRequest();
runCaseRequest.setRunMode(ApiRunMode.DEFINITION.name());
runCaseRequest.setCaseId(caseWithBLOBs.getId());
runCaseRequest.setReportId(report.getId());
runCaseRequest.setEnvironmentId(request.getEnvironmentId());
runCaseRequest.setBloBs(caseWithBLOBs);
runCaseRequest.setReport(report);
batchMapper.insert(report);
executeQueue.add(runCaseRequest);
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
LoggerUtil.info("生成执行队列:" + executeQueue.size());
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("生成执行队列:" + JSON.toJSONString(executeQueue));
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
for (RunCaseRequest runCaseRequest : executeQueue) {
responseDTOS.add(exec(runCaseRequest));
}
return responseDTOS;
}
/**
* 单条执行
*
* @param request
* @return
*/
public MsExecResponseDTO exec(RunCaseRequest request) {
ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs();
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getReportId());
request.setCaseId(request.getReportId());
//通过测试计划id查询环境
request.setReportId(request.getTestPlanId());
}
LoggerUtil.info("开始执行单条用例【 " + testCaseWithBLOBs.getId() + "");
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
try {
HashTree jmeterHashTree = this.generateHashTree(request, testCaseWithBLOBs);
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("生成jmx文件" + ElementUtil.hashTreeToString(jmeterHashTree));
}
// 调用执行方法
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testCaseWithBLOBs.getId(), StringUtils.isEmpty(request.getReportId()) ? request.getId() : request.getReportId(), request.getRunMode(), jmeterHashTree);
jMeterService.run(runRequest);
} catch (Exception ex) {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(request.getReportId());
if (result != null) {
result.setStatus("error");
apiDefinitionExecResultMapper.updateByPrimaryKey(result);
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
caseWithBLOBs.setStatus("error");
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
}
LogUtil.error(ex.getMessage(), ex);
}
}
return new MsExecResponseDTO(request.getCaseId(), request.getReport().getId(), request.getRunMode());
}
public MsExecResponseDTO debug(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
ParameterConfig config = new ParameterConfig();
config.setProjectId(request.getProjectId());
Map<String, EnvironmentConfig> envConfig = new HashMap<>();
Map<String, String> map = request.getEnvironmentMap();
if (map != null && map.size() > 0) {
for (String key : map.keySet()) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(map.get(key));
if (environment != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
env.setApiEnvironmentid(environment.getId());
envConfig.put(key, env);
}
}
config.setConfig(envConfig);
}
if (CollectionUtils.isNotEmpty(bodyFiles)) {
List<MsHTTPSamplerProxy> requests = MsHTTPSamplerProxy.findHttpSampleFromHashTree(request.getTestElement());
// 单接口调试生成tmp临时目录
requests.forEach(item -> {
Body body = item.getBody();
String tmpFilePath = "tmp/" + UUID.randomUUID().toString();
body.setTmpFilePath(tmpFilePath);
FileUtils.copyBdyFile(item.getId(), tmpFilePath);
FileUtils.createBodyFiles(tmpFilePath, bodyFiles);
});
}
//检查TCP数据结构等其他进行处理
tcpApiParamService.checkTestElement(request.getTestElement());
HashTree hashTree = request.getTestElement().generateHashTree(config);
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("生成执行JMX内容【 " + request.getTestElement().getJmx(hashTree) + "");
}
String runMode = ApiRunMode.DEFINITION.name();
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {
runMode = ApiRunMode.API_PLAN.name();
}
String testId = request.getTestElement() != null &&
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree()) &&
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree().get(0).getHashTree()) ?
request.getTestElement().getHashTree().get(0).getHashTree().get(0).getName() : request.getId();
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testId, request.getId(), runMode, hashTree);
runRequest.setDebug(request.isDebug());
// 开始执行
jMeterService.run(runRequest);
return new MsExecResponseDTO(runRequest.getTestId(), runRequest.getReportId(), runMode);
}
public HashTree generateHashTree(RunCaseRequest request, ApiTestCaseWithBLOBs testCaseWithBLOBs) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject elementObj = JSON.parseObject(testCaseWithBLOBs.getRequest());
ElementUtil.dataFormatting(elementObj);
MsTestElement element = mapper.readValue(elementObj.toJSONString(), new TypeReference<MsTestElement>() {
});
element.setProjectId(testCaseWithBLOBs.getProjectId());
if (StringUtils.isBlank(request.getEnvironmentId())) {
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
example.createCriteria().andTestPlanIdEqualTo(request.getTestPlanId()).andApiCaseIdEqualTo(request.getCaseId());
List<TestPlanApiCase> list = testPlanApiCaseMapper.selectByExample(example);
request.setEnvironmentId(list.get(0).getEnvironmentId());
element.setName(list.get(0).getId());
} else {
element.setName(request.getCaseId());
}
// 测试计划
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
HashTree jmeterHashTree = new ListedHashTree();
// 线程组
MsThreadGroup group = new MsThreadGroup();
group.setLabel(testCaseWithBLOBs.getName());
group.setName(testCaseWithBLOBs.getId());
group.setOnSampleError(true);
LinkedList<MsTestElement> hashTrees = new LinkedList<>();
hashTrees.add(element);
group.setHashTree(hashTrees);
testPlan.getHashTree().add(group);
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(request.getEnvironmentId());
ParameterConfig parameterConfig = new ParameterConfig();
Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig environmentConfig = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
environmentConfig.setApiEnvironmentid(environment.getId());
envConfig.put(testCaseWithBLOBs.getProjectId(), environmentConfig);
parameterConfig.setConfig(envConfig);
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), parameterConfig);
return jmeterHashTree;
}
}

View File

@ -0,0 +1,150 @@
package io.metersphere.api.exec.api;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiExecutionQueue;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.domain.TestPlanApiCaseExample;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanApiExecuteService {
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private JMeterService jMeterService;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
public List<MsExecResponseDTO> run(BatchRunDefinitionRequest request) {
List<String> ids = request.getPlanIds();
if (CollectionUtils.isEmpty(ids)) {
return new LinkedList<>();
}
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
example.createCriteria().andIdIn(ids);
example.setOrderByClause("`order` DESC");
List<TestPlanApiCase> planApiCases = testPlanApiCaseMapper.selectByExample(example);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ApiRunMode.API_PLAN.name());
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
// 开始选择执行模式
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
Map<TestPlanApiCase, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
//记录案例线程结果以及执行失败的案例ID
Map<String, String> executeThreadIdMap = new HashMap<>();
planApiCases.forEach(testPlanApiCase -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, APITestStatus.Waiting.name(), batchMapper);
executeQueue.put(testPlanApiCase, report);
executeThreadIdMap.put(testPlanApiCase.getId(), report.getId());
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
});
//如果是测试计划生成报告的执行则更新执行信息执行线程信息
if (TestPlanReportExecuteCatch.containsReport(request.getPlanReportId())) {
if (!executeThreadIdMap.isEmpty()) {
TestPlanReportExecuteCatch.updateTestPlanThreadInfo(request.getPlanReportId(), executeThreadIdMap, null, null);
}
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
// 开始串行执行
String runMode = request.getTriggerMode();
DBTestQueue executionQueue = apiExecutionQueueService.add(executeQueue, request.getConfig() != null ? request.getConfig().getResourcePoolId() : null, ApiRunMode.API_PLAN.name(), request.getPlanReportId(), null, runMode);
if (executionQueue != null) {
if (executionQueue.getQueue() != null) {
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
}
}
} else {
Map<String, TestPlanApiCase> executeQueue = new HashMap<>();
//记录案例线程结果以及执行失败的案例ID
Map<String, String> executeThreadIdMap = new HashMap<>();
planApiCases.forEach(testPlanApiCase -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, APITestStatus.Running.name(), batchMapper);
executeQueue.put(report.getId(), testPlanApiCase);
executeThreadIdMap.put(testPlanApiCase.getId(), report.getId());
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
});
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
//如果是测试计划生成报告的执行则更新执行信息执行线程信息
if (TestPlanReportExecuteCatch.containsReport(request.getPlanReportId())) {
if (!executeThreadIdMap.isEmpty()) {
TestPlanReportExecuteCatch.updateTestPlanThreadInfo(request.getPlanReportId(), executeThreadIdMap, null, null);
}
}
// 开始并发执行
this.parallel(executeQueue, request);
}
return responseDTOS;
}
private void parallel(Map<String, TestPlanApiCase> executeQueue, BatchRunDefinitionRequest request) {
List<String> executeErrorList = new ArrayList<>();
String poolId = request.getConfig() != null ? request.getConfig().getResourcePoolId() : null;
String mode = request.getConfig() != null ? request.getConfig().getMode() : null;
ApiExecutionQueue executionQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.API_PLAN.name(), request.getPlanReportId(), mode, request.getTriggerMode());
if (executionQueue != null) {
for (String reportId : executeQueue.keySet()) {
TestPlanApiCase testPlanApiCase = executeQueue.get(reportId);
try {
HashTree hashTree = null;
if (request.getConfig() == null || !GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()).isPool()) {
hashTree = apiScenarioSerialService.generateHashTree(testPlanApiCase.getId());
}
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testPlanApiCase.getId(), reportId, request.getTriggerMode(), hashTree);
if (request.getConfig() != null) {
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()));
}
runRequest.setTestPlanReportId(request.getPlanReportId());
jMeterService.run(runRequest);
} catch (Exception e) {
executeErrorList.add(testPlanApiCase.getId());
}
}
//如果是测试计划生成报告的执行则更新执行信息执行线程信息
TestPlanReportExecuteCatch.set(request.getPlanReportId(), executeErrorList);
}
}
}

View File

@ -0,0 +1,10 @@
package io.metersphere.api.exec.queue;
import io.metersphere.base.domain.ApiExecutionQueue;
import io.metersphere.base.domain.ApiExecutionQueueDetail;
import lombok.Data;
@Data
public class DBTestQueue extends ApiExecutionQueue {
private ApiExecutionQueueDetail queue;
}

View File

@ -0,0 +1,32 @@
package io.metersphere.api.exec.queue;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.utils.LoggerUtil;
public class ExecTask implements Runnable {
private JmeterRunRequestDTO request;
public ExecTask(JmeterRunRequestDTO request) {
this.request = request;
}
public JmeterRunRequestDTO getRequest() {
return this.request;
}
@Override
public void run() {
LoggerUtil.info("开始执行报告ID" + request.getReportId() + " 】,资源ID【 " + request.getTestId() + "");
JMeterService jMeterService = CommonBeanFactory.getBean(JMeterService.class);
jMeterService.addQueue(request);
if (request.getPool() == null || !request.getPool().isPool()) {
Object res = PoolExecBlockingQueueUtil.take(request.getReportId());
if (res == null) {
LoggerUtil.info("执行报告:【 " + request.getReportId() + " 】,资源ID【 " + request.getTestId() + " 】执行超时");
}
}
LoggerUtil.info("任务:【 " + request.getReportId() + " 】执行完成");
}
}

View File

@ -0,0 +1,178 @@
package io.metersphere.api.exec.queue;
import io.metersphere.api.exec.utils.NamedThreadFactory;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Queue;
import java.util.concurrent.*;
@Service
public class ExecThreadPoolExecutor {
// 线程池维护线程的最少数量
private final static int CORE_POOL_SIZE = 10;
// 线程池维护线程的最大数量
private final static int MAX_POOL_SIZE = 10;
// 线程池维护线程所允许的空闲时间
private final static int KEEP_ALIVE_TIME = 1;
// 线程池所使用的缓冲队列大小
private final static int WORK_QUEUE_SIZE = 10000;
private MsRejectedExecutionHandler msRejectedExecutionHandler = new MsRejectedExecutionHandler();
/**
* 创建线程池
*/
private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue(WORK_QUEUE_SIZE),
new NamedThreadFactory("MS-JMETER-RUN-TASK"),
msRejectedExecutionHandler);
/**
* 缓冲区调度线程池
*/
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("MS-BUFFER-SCHEDULED"));
public void addTask(JmeterRunRequestDTO requestDTO) {
outApiThreadPoolExecutorLogger();
ExecTask task = new ExecTask(requestDTO);
threadPool.execute(task);
}
/**
* 调度线程池检查缓冲区
*/
final ScheduledFuture scheduledFuture = scheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//判断缓冲队列是否存在记录
if (CollectionUtils.isNotEmpty(msRejectedExecutionHandler.getBufferQueue())) {
//当线程池的队列容量少于WORK_QUEUE_SIZE则开始把缓冲队列的任务 加入到 线程池
if (threadPool.getQueue().size() < WORK_QUEUE_SIZE) {
JmeterRunRequestDTO requestDTO = msRejectedExecutionHandler.getBufferQueue().poll();
ExecTask task = new ExecTask(requestDTO);
threadPool.submit(task);
LoggerUtil.info("把缓冲区任务重新添加到线程池报告ID" + requestDTO.getReportId());
}
}
}
}, 0, 2, TimeUnit.SECONDS);
/**
* 终止线程池和调度线程池
*/
public void shutdown() {
//true表示如果定时任务在执行立即中止false则等待任务结束后再停止
LoggerUtil.info("终止执行线程池和调度线程池:" + scheduledFuture.cancel(true));
scheduler.shutdown();
threadPool.shutdown();
}
/**
* 保留两位小数
*/
private String divide(int num1, int num2) {
return String.format("%1.2f%%", Double.parseDouble(num1 + "") / Double.parseDouble(num2 + "") * 100);
}
public void outApiThreadPoolExecutorLogger() {
ArrayBlockingQueue queue = (ArrayBlockingQueue) threadPool.getQueue();
StringBuffer buffer = new StringBuffer("API 并发队列详情:\n");
buffer.append(" 核心线程数:" + threadPool.getCorePoolSize()).append("\n");
buffer.append(" 活动线程数:" + threadPool.getActiveCount()).append("\n");
buffer.append(" 最大线程数:" + threadPool.getMaximumPoolSize()).append("\n");
buffer.append(" 线程池活跃度:" + divide(threadPool.getActiveCount(), threadPool.getMaximumPoolSize())).append("\n");
buffer.append(" 任务完成数:" + threadPool.getCompletedTaskCount()).append("\n");
buffer.append(" 队列大小:" + (queue.size() + queue.remainingCapacity())).append("\n");
buffer.append(" 当前排队线程数:" + (msRejectedExecutionHandler.getBufferQueue().size() + queue.size())).append("\n");
buffer.append(" 队列剩余大小:" + queue.remainingCapacity()).append("\n");
buffer.append(" 队列使用度:" + divide(queue.size(), queue.size() + queue.remainingCapacity()));
LoggerUtil.info(buffer.toString());
if (queue.size() > 0 && LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug(this.getWorkerQueue());
}
}
public void setCorePoolSize(int corePoolSize) {
try {
MessageCache.corePoolSize = corePoolSize;
threadPool.setCorePoolSize(corePoolSize);
threadPool.setMaximumPoolSize(corePoolSize);
threadPool.allowCoreThreadTimeOut(true);
LoggerUtil.info("AllCoreThreads: " + threadPool.prestartAllCoreThreads());
} catch (Exception e) {
LoggerUtil.error("设置线程参数异常:" + e);
}
}
public void removeQueue(String reportId) {
// 检查缓冲区
Queue<JmeterRunRequestDTO> bufferQueue = msRejectedExecutionHandler.getBufferQueue();
if (CollectionUtils.isNotEmpty(bufferQueue)) {
bufferQueue.forEach(item -> {
if (item != null && StringUtils.equals(item.getReportId(), reportId)) {
bufferQueue.remove(item);
}
});
}
// 检查等待队列
BlockingQueue workerQueue = threadPool.getQueue();
workerQueue.forEach(item -> {
ExecTask task = (ExecTask) item;
if (task.getRequest() != null && StringUtils.equals(task.getRequest().getReportId(), reportId)) {
workerQueue.remove(item);
}
});
}
public void removeAllQueue() {
// 检查缓冲区
msRejectedExecutionHandler.getBufferQueue().clear();
// 检查等待队列
threadPool.getQueue().clear();
}
public boolean check(String reportId) {
// 检查缓冲区
Queue<JmeterRunRequestDTO> bufferQueue = msRejectedExecutionHandler.getBufferQueue();
if (CollectionUtils.isNotEmpty(bufferQueue)) {
return bufferQueue.stream().filter(task -> StringUtils.equals(task.getReportId(), reportId)).count() > 0;
}
// 检查等待队列
BlockingQueue workerQueue = threadPool.getQueue();
return workerQueue.stream().filter(task -> StringUtils.equals(((ExecTask) task).getRequest().getReportId(), reportId)).count() > 0;
}
public boolean checkPlanReport(String planReportId) {
// 检查缓冲区
Queue<JmeterRunRequestDTO> bufferQueue = msRejectedExecutionHandler.getBufferQueue();
if (CollectionUtils.isNotEmpty(bufferQueue)) {
return bufferQueue.stream().filter(task -> StringUtils.equals(task.getTestPlanReportId(), planReportId)).count() > 0;
}
// 检查等待队列
BlockingQueue workerQueue = threadPool.getQueue();
return workerQueue.stream().filter(task -> StringUtils.equals(((ExecTask) task).getRequest().getTestPlanReportId(), planReportId)).count() > 0;
}
public String getWorkerQueue() {
StringBuffer buffer = new StringBuffer();
BlockingQueue workerQueue = threadPool.getQueue();
workerQueue.forEach(item -> {
ExecTask task = (ExecTask) item;
if (task.getRequest() != null) {
buffer.append("等待队列报告:【 " + task.getRequest().getReportId() + "】资源:【 " + task.getRequest().getTestId() + "").append("\n");
}
});
return buffer.toString();
}
}

View File

@ -0,0 +1,28 @@
package io.metersphere.api.exec.queue;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.utils.LoggerUtil;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class MsRejectedExecutionHandler implements RejectedExecutionHandler {
/**
* 执行任务缓冲队列,当线程池满了则将任务存入到此缓冲队列
* 这里是否搞个redis/写到磁盘
*/
private Queue<JmeterRunRequestDTO> bufferQueue = new LinkedBlockingQueue<>();
public Queue<JmeterRunRequestDTO> getBufferQueue() {
return bufferQueue;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//任务加入到缓冲队列
bufferQueue.offer(((ExecTask) r).getRequest());
LoggerUtil.info("执行任务过多,任务加入缓冲区:" + ((ExecTask) r).getRequest().getReportId());
}
}

View File

@ -0,0 +1,50 @@
package io.metersphere.api.exec.queue;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class PoolExecBlockingQueueUtil {
// 系统级队列控制整体并发数量
public static Map<String, BlockingQueue<Object>> queue = new ConcurrentHashMap<>();
private static final String END_SIGN = "RUN-END";
private static final int QUEUE_SIZE = 1;
public static void offer(String key) {
if (StringUtils.isNotEmpty(key) && queue.containsKey(key)) {
try {
queue.get(key).offer(END_SIGN);
} catch (Exception e) {
LogUtil.error(e);
} finally {
queue.remove(key);
}
}
}
public static Object take(String key) {
try {
if (StringUtils.isNotEmpty(key) && !queue.containsKey(key)) {
BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(QUEUE_SIZE);
queue.put(key, blockingQueue);
return blockingQueue.poll(5, TimeUnit.MINUTES);
}
} catch (Exception e) {
LogUtil.error("初始化队列失败:" + e.getMessage());
}
return null;
}
public static void remove(String key) {
if (StringUtils.isNotEmpty(key) && queue.containsKey(key)) {
queue.get(key).offer(END_SIGN);
queue.remove(key);
}
}
}

View File

@ -0,0 +1,445 @@
package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.ScenarioEnv;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.EnvironmentGroupProjectService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class ApiScenarioEnvService {
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private ProjectMapper projectMapper;
@Resource
private ApiTestEnvironmentMapper apiTestEnvironmentMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
public ScenarioEnv getApiScenarioEnv(String definition) {
ScenarioEnv env = new ScenarioEnv();
List<MsTestElement> hashTree = GenerateHashTreeUtil.getScenarioHashTree(definition);
for (int i = 0; i < hashTree.size(); i++) {
MsTestElement tr = hashTree.get(i);
if (!tr.isEnable()) {
continue;
}
String referenced = tr.getReferenced();
if (StringUtils.equals(MsTestElementConstants.REF.name(), referenced)) {
if (StringUtils.equals(tr.getType(), "HTTPSamplerProxy")) {
MsHTTPSamplerProxy http = (MsHTTPSamplerProxy) tr;
String refType = tr.getRefType();
if (StringUtils.equals(refType, "CASE")) {
http.setUrl(null);
} else {
ApiDefinition apiDefinition = apiDefinitionService.get(tr.getId());
if (apiDefinition != null) {
http.setUrl(apiDefinition.getPath());
}
}
if (http.isEnable()) {
if (StringUtils.isBlank(http.getUrl()) || (http.getIsRefEnvironment() != null && http.getIsRefEnvironment())) {
env.getProjectIds().add(http.getProjectId());
env.setFullUrl(false);
}
}
} else if (StringUtils.equals(tr.getType(), "JDBCSampler") || StringUtils.equals(tr.getType(), "TCPSampler")) {
if (StringUtils.equals(tr.getRefType(), "CASE")) {
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(tr.getId());
if (apiTestCaseWithBLOBs != null) {
env.getProjectIds().add(apiTestCaseWithBLOBs.getProjectId());
}
} else {
ApiDefinition apiDefinition = apiDefinitionService.get(tr.getId());
if (apiDefinition != null) {
env.getProjectIds().add(apiDefinition.getProjectId());
}
}
} else if (StringUtils.equals(tr.getType(), "scenario")) {
if (tr.isEnable()) {
ApiScenarioWithBLOBs apiScenario = apiScenarioMapper.selectByPrimaryKey(tr.getId());
if (apiScenario != null) {
env.getProjectIds().add(apiScenario.getProjectId());
String scenarioDefinition = apiScenario.getScenarioDefinition();
tr.setHashTree(GenerateHashTreeUtil.getScenarioHashTree(scenarioDefinition));
}
}
}
} else {
if (StringUtils.equals(tr.getType(), "HTTPSamplerProxy")) {
// 校验是否是全路径
MsHTTPSamplerProxy httpSamplerProxy = (MsHTTPSamplerProxy) tr;
if (httpSamplerProxy.isEnable()) {
if (StringUtils.isBlank(httpSamplerProxy.getUrl()) || (httpSamplerProxy.getIsRefEnvironment() != null && httpSamplerProxy.getIsRefEnvironment())) {
env.getProjectIds().add(httpSamplerProxy.getProjectId());
env.setFullUrl(false);
}
}
} else if (StringUtils.equals(tr.getType(), "JDBCSampler") || StringUtils.equals(tr.getType(), "TCPSampler")) {
env.getProjectIds().add(tr.getProjectId());
}
}
if (StringUtils.equals(tr.getType(), "scenario")) {
MsScenario scenario = (MsScenario) tr;
if (scenario.isEnvironmentEnable()) {
continue;
}
env.getProjectIds().add(tr.getProjectId());
}
if (CollectionUtils.isNotEmpty(tr.getHashTree())) {
getHashTree(tr.getHashTree(), env);
}
}
return env;
}
private void getHashTree(List<MsTestElement> tree, ScenarioEnv env) {
try {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
for (int i = 0; i < tree.size(); i++) {
MsTestElement tr = tree.get(i);
if (!tr.isEnable()) {
continue;
}
String referenced = tr.getReferenced();
if (StringUtils.equals(MsTestElementConstants.REF.name(), referenced)) {
if (StringUtils.equals(tr.getType(), "HTTPSamplerProxy")) {
MsHTTPSamplerProxy http = (MsHTTPSamplerProxy) tr;
String refType = tr.getRefType();
if (StringUtils.equals(refType, "CASE")) {
http.setUrl(null);
} else {
ApiDefinition apiDefinition = apiDefinitionService.get(tr.getId());
http.setUrl(apiDefinition.getPath());
}
if (http.isEnable()) {
if (StringUtils.isBlank(http.getUrl()) || (http.getIsRefEnvironment() != null && http.getIsRefEnvironment())) {
env.setFullUrl(false);
env.getProjectIds().add(http.getProjectId());
}
}
} else if (StringUtils.equals(tr.getType(), "JDBCSampler") || StringUtils.equals(tr.getType(), "TCPSampler")) {
if (StringUtils.equals(tr.getRefType(), "CASE")) {
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(tr.getId());
env.getProjectIds().add(apiTestCaseWithBLOBs.getProjectId());
} else {
ApiDefinition apiDefinition = apiDefinitionService.get(tr.getId());
env.getProjectIds().add(apiDefinition.getProjectId());
}
} else if (StringUtils.equals(tr.getType(), "scenario")) {
if (tr.isEnable()) {
ApiScenarioWithBLOBs apiScenario = apiScenarioMapper.selectByPrimaryKey(tr.getId());
if (apiScenario != null) {
env.getProjectIds().add(apiScenario.getProjectId());
String scenarioDefinition = apiScenario.getScenarioDefinition();
JSONObject element1 = JSON.parseObject(scenarioDefinition);
ElementUtil.dataFormatting(element1);
LinkedList<MsTestElement> hashTree1 = mapper.readValue(element1.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
tr.setHashTree(hashTree1);
}
}
}
} else {
if (StringUtils.equals(tr.getType(), "HTTPSamplerProxy")) {
// 校验是否是全路径
MsHTTPSamplerProxy httpSamplerProxy = (MsHTTPSamplerProxy) tr;
if (httpSamplerProxy.isEnable()) {
if (StringUtils.isBlank(httpSamplerProxy.getUrl()) || !ElementUtil.isURL(httpSamplerProxy.getUrl())) {
env.setFullUrl(false);
env.getProjectIds().add(httpSamplerProxy.getProjectId());
}
}
} else if (StringUtils.equals(tr.getType(), "JDBCSampler") || StringUtils.equals(tr.getType(), "TCPSampler")) {
env.getProjectIds().add(tr.getProjectId());
}
}
if (StringUtils.equals(tr.getType(), "scenario")) {
MsScenario scenario = (MsScenario) tr;
if (scenario.isEnvironmentEnable()) {
continue;
}
env.getProjectIds().add(tr.getProjectId());
}
if (CollectionUtils.isNotEmpty(tr.getHashTree())) {
getHashTree(tr.getHashTree(), env);
}
}
} catch (JsonProcessingException e) {
LogUtil.error(e);
}
}
/**
* 设置场景的运行环境 环境组/环境JSON
*
* @param apiScenarioWithBLOBs
*/
public void setScenarioEnv(ApiScenarioWithBLOBs apiScenarioWithBLOBs) {
String environmentType = apiScenarioWithBLOBs.getEnvironmentType();
String environmentJson = apiScenarioWithBLOBs.getEnvironmentJson();
String environmentGroupId = apiScenarioWithBLOBs.getEnvironmentGroupId();
if (StringUtils.isBlank(environmentType)) {
environmentType = EnvironmentType.JSON.toString();
}
String definition = apiScenarioWithBLOBs.getScenarioDefinition();
MsScenario scenario = JSONObject.parseObject(definition, MsScenario.class);
GenerateHashTreeUtil.parse(definition, scenario, apiScenarioWithBLOBs.getId(), null);
if (StringUtils.equals(environmentType, EnvironmentType.JSON.toString())) {
scenario.setEnvironmentMap(JSON.parseObject(environmentJson, Map.class));
} else if (StringUtils.equals(environmentType, EnvironmentType.GROUP.toString())) {
Map<String, String> map = environmentGroupProjectService.getEnvMap(environmentGroupId);
scenario.setEnvironmentMap(map);
}
apiScenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(scenario));
}
public boolean checkScenarioEnv(ApiScenarioWithBLOBs apiScenarioWithBLOBs, TestPlanApiScenario testPlanApiScenarios) {
String definition = apiScenarioWithBLOBs.getScenarioDefinition();
MsScenario scenario = JSONObject.parseObject(definition, MsScenario.class);
boolean isEnv = true;
Map<String, String> envMap = scenario.getEnvironmentMap();
if (testPlanApiScenarios != null) {
String envType = testPlanApiScenarios.getEnvironmentType();
String envJson = testPlanApiScenarios.getEnvironment();
String envGroupId = testPlanApiScenarios.getEnvironmentGroupId();
if (StringUtils.equals(envType, EnvironmentType.JSON.toString())
&& StringUtils.isNotBlank(envJson)) {
envMap = JSON.parseObject(testPlanApiScenarios.getEnvironment(), Map.class);
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.name())
&& StringUtils.isNotBlank(envGroupId)) {
envMap = environmentGroupProjectService.getEnvMap(envGroupId);
} else {
envMap = new HashMap<>();
}
}
ScenarioEnv apiScenarioEnv = getApiScenarioEnv(definition);
// 所有请求非全路径检查环境
if (!apiScenarioEnv.getFullUrl()) {
try {
if (envMap == null || envMap.isEmpty()) {
isEnv = false;
} else {
Set<String> projectIds = apiScenarioEnv.getProjectIds();
projectIds.remove(null);
if (CollectionUtils.isNotEmpty(envMap.keySet())) {
for (String id : projectIds) {
Project project = projectMapper.selectByPrimaryKey(id);
if (project == null) {
id = apiScenarioWithBLOBs.getProjectId();
}
String s = envMap.get(id);
if (StringUtils.isBlank(s)) {
isEnv = false;
break;
} else {
ApiTestEnvironmentWithBLOBs env = apiTestEnvironmentMapper.selectByPrimaryKey(s);
if (env == null) {
isEnv = false;
break;
}
}
}
} else {
isEnv = false;
}
}
} catch (Exception e) {
isEnv = false;
LogUtil.error(e.getMessage(), e);
}
}
// 1.8 之前环境是 environmentId
if (!isEnv) {
String envId = scenario.getEnvironmentId();
if (StringUtils.isNotBlank(envId)) {
ApiTestEnvironmentWithBLOBs env = apiTestEnvironmentMapper.selectByPrimaryKey(envId);
if (env != null) {
isEnv = true;
}
}
}
return isEnv;
}
public void checkPlanScenarioEnv(RunScenarioRequest request) {
StringBuilder builder = new StringBuilder();
List<String> planCaseIds = request.getPlanCaseIds();
if (CollectionUtils.isNotEmpty(planCaseIds)) {
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
example.createCriteria().andIdIn(planCaseIds);
List<TestPlanApiScenario> testPlanApiScenarios = testPlanApiScenarioMapper.selectByExampleWithBLOBs(example);
for (TestPlanApiScenario testPlanApiScenario : testPlanApiScenarios) {
try {
ApiScenarioWithBLOBs apiScenarioWithBLOBs = apiScenarioMapper.selectByPrimaryKey(testPlanApiScenario.getApiScenarioId());
boolean haveEnv = this.checkScenarioEnv(apiScenarioWithBLOBs, testPlanApiScenario);
if (!haveEnv) {
builder.append(apiScenarioWithBLOBs.getName()).append("; ");
}
} catch (Exception e) {
MSException.throwException("场景:" + builder.toString() + "运行环境未配置,请检查!");
}
}
if (builder.length() > 0) {
MSException.throwException("场景:" + builder.toString() + "运行环境未配置,请检查!");
}
}
}
public void checkEnv(RunScenarioRequest request, List<ApiScenarioWithBLOBs> apiScenarios) {
if (StringUtils.equals(request.getRequestOriginator(), "TEST_PLAN")) {
this.checkPlanScenarioEnv(request);
} else if (StringUtils.isNotBlank(request.getRunMode()) &&
StringUtils.equalsAny(request.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
StringBuilder builder = new StringBuilder();
for (ApiScenarioWithBLOBs apiScenarioWithBLOBs : apiScenarios) {
try {
this.setScenarioEnv(apiScenarioWithBLOBs);
boolean haveEnv = this.checkScenarioEnv(apiScenarioWithBLOBs, null);
if (!haveEnv) {
builder.append(apiScenarioWithBLOBs.getName()).append("; ");
}
} catch (Exception e) {
MSException.throwException("场景:" + builder.toString() + "运行环境未配置,请检查!");
}
}
if (builder.length() > 0) {
MSException.throwException("场景:" + builder.toString() + "运行环境未配置,请检查!");
}
} else if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO.name())) {
for (ApiScenarioWithBLOBs apiScenarioWithBLOBs : apiScenarios) {
try {
this.setScenarioEnv(apiScenarioWithBLOBs);
} catch (Exception e) {
MSException.throwException("定时任务设置场景环境失败场景ID " + apiScenarioWithBLOBs.getId());
}
}
}
}
public void setApiScenarioEnv(List<ApiScenarioDTO> list) {
List<Project> projectList = projectMapper.selectByExample(new ProjectExample());
List<ApiTestEnvironmentWithBLOBs> apiTestEnvironments = apiTestEnvironmentMapper.selectByExampleWithBLOBs(new ApiTestEnvironmentExample());
for (int i = 0; i < list.size(); i++) {
try {
Map<String, String> map = new HashMap<>();
String environmentType = list.get(i).getEnvironmentType();
String environmentGroupId = list.get(i).getEnvironmentGroupId();
String env = list.get(i).getEnv();
if (StringUtils.equals(environmentType, EnvironmentType.JSON.name())) {
// 环境属性为空 跳过
if (StringUtils.isBlank(env)) {
continue;
}
map = JSON.parseObject(env, Map.class);
} else if (StringUtils.equals(environmentType, EnvironmentType.GROUP.name())) {
map = environmentGroupProjectService.getEnvMap(environmentGroupId);
}
Set<String> set = map.keySet();
HashMap<String, String> envMap = new HashMap<>(16);
// 项目为空 跳过
if (set.isEmpty()) {
continue;
}
for (String projectId : set) {
String envId = map.get(projectId);
if (StringUtils.isBlank(envId)) {
continue;
}
List<Project> projects = projectList.stream().filter(p -> StringUtils.equals(p.getId(), projectId)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(projects)) {
continue;
}
Project project = projects.get(0);
List<ApiTestEnvironmentWithBLOBs> envs = apiTestEnvironments.stream().filter(e -> StringUtils.equals(e.getId(), envId)).collect(Collectors.toList());
if (CollectionUtils.isEmpty(envs)) {
continue;
}
ApiTestEnvironmentWithBLOBs environment = envs.get(0);
String projectName = project.getName();
String envName = environment.getName();
if (StringUtils.isBlank(projectName) || StringUtils.isBlank(envName)) {
continue;
}
envMap.put(projectName, envName);
}
list.get(i).setEnvironmentMap(envMap);
} catch (Exception e) {
LogUtil.error("api scenario environment map incorrect parsing. api scenario id:" + list.get(i).getId());
}
}
}
public void setEnvConfig(Map<String, String> environmentMap, ParameterConfig config) {
final Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
if (environmentMap != null) {
environmentMap.keySet().forEach(projectId -> {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentMap.get(projectId));
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
env.setApiEnvironmentid(environment.getId());
envConfig.put(projectId, env);
}
});
config.setConfig(envConfig);
}
}
public Map<String, String> planEnvMap(String testPlanScenarioId) {
Map<String, String> planEnvMap = new HashMap<>();
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
String envJson = planApiScenario.getEnvironment();
String envType = planApiScenario.getEnvironmentType();
String envGroupId = planApiScenario.getEnvironmentGroupId();
if (StringUtils.equals(envType, EnvironmentType.JSON.toString()) && StringUtils.isNotBlank(envJson)) {
planEnvMap = JSON.parseObject(envJson, Map.class);
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.toString()) && StringUtils.isNotBlank(envGroupId)) {
planEnvMap = environmentGroupProjectService.getEnvMap(envGroupId);
}
return planEnvMap;
}
}

View File

@ -0,0 +1,393 @@
package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.ApiScenarioExample;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.comparators.FixedOrderComparator;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class ApiScenarioExecuteService {
@Resource
private ApiScenarioEnvService apiScenarioEnvService;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
@Lazy
private TestPlanScenarioCaseService testPlanScenarioCaseService;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private RemakeReportService remakeReportService;
@Resource
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private ApiScenarioReportStructureService apiScenarioReportStructureService;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private ApiScenarioParallelService apiScenarioParallelService;
@Resource
private TcpApiParamService tcpApiParamService;
@Resource
private JMeterService jMeterService;
@Resource
private SqlSessionFactory sqlSessionFactory;
public List<MsExecResponseDTO> run(RunScenarioRequest request) {
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("Scenario run-执行脚本装载-接收到场景执行参数:【 " + JSON.toJSONString(request) + "");
}
if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ReportTriggerMode.MANUAL.name());
}
// 生成集成报告
String serialReportId = null;
LoggerUtil.info("Scenario run-执行脚本装载-根据条件查询所有场景 ");
List<ApiScenarioWithBLOBs> apiScenarios = this.get(request);
// 只有一个场景且没有测试步骤则提示
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")));
}
// 环境检查
LoggerUtil.info("Scenario run-执行脚本装载-开始针对所有执行场景进行环境检查");
apiScenarioEnvService.checkEnv(request, apiScenarios);
// 集合报告设置
if (request.getConfig() != null && StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString()) && StringUtils.isNotEmpty(request.getConfig().getReportName())) {
if (request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
request.setExecuteType(ExecuteType.Completed.name());
} else {
request.setExecuteType(ExecuteType.Marge.name());
}
serialReportId = UUID.randomUUID().toString();
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
Map<String, RunModeDataDTO> executeQueue = new LinkedHashMap<>();
List<String> scenarioIds = new ArrayList<>();
StringBuilder scenarioNames = new StringBuilder();
LoggerUtil.info("Scenario run-执行脚本装载-初始化执行队列");
if (StringUtils.equalsAny(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
//测试计划执行
assemblyPlanScenario(apiScenarios, request, executeQueue, scenarioIds, scenarioNames);
} else {
// 按照场景执行
assemblyScenario(apiScenarios, request, executeQueue, scenarioIds, scenarioNames, serialReportId);
}
LoggerUtil.info("Scenario run-执行脚本装载-初始化执行队列完成:" + executeQueue.size());
if (GenerateHashTreeUtil.isSetReport(request.getConfig())) {
LoggerUtil.info("Scenario run-执行脚本装载-初始化集成报告:" + serialReportId);
request.getConfig().setReportId(UUID.randomUUID().toString());
APIScenarioReportResult report = apiScenarioReportService.init(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.length() - 1).toString(),
ReportTriggerMode.MANUAL.name(), ExecuteType.Saved.name(), request.getProjectId(), request.getReportUserID(), request.getConfig(), JSON.toJSONString(scenarioIds));
report.setName(request.getConfig().getReportName());
report.setId(serialReportId);
request.getConfig().setAmassReport(serialReportId);
apiScenarioReportMapper.insert(report);
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(scenarioIds), serialReportId, request.getRunMode()));
// 增加并行集合报告
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.PARALLEL.toString())) {
apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null);
}
}
// 开始执行
if (executeQueue != null && executeQueue.size() > 0) {
String reportType = request.getConfig().getReportType();
DBTestQueue executionQueue = apiExecutionQueueService.add(executeQueue, request.getConfig().getResourcePoolId(), ApiRunMode.SCENARIO.name(), serialReportId, reportType, request.getRunMode());
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (StringUtils.isNotEmpty(serialReportId)) {
apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null);
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
// 非集合报告先生成执行队列
if (StringUtils.isEmpty(serialReportId)) {
for (String reportId : executeQueue.keySet()) {
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
report.setStatus(APITestStatus.Waiting.name());
batchMapper.insert(report);
responseDTOS.add(new MsExecResponseDTO(executeQueue.get(reportId).getTestId(), reportId, request.getRunMode()));
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
if (executionQueue.getQueue() != null) {
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
}
} else {
apiScenarioParallelService.parallel(executeQueue, request, serialReportId, responseDTOS, executionQueue.getId());
}
}
return responseDTOS;
}
private List<ApiScenarioWithBLOBs> get(RunScenarioRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiScenarioMapper.selectIdsByQuery(query));
List<String> ids = request.getIds();
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(ids);
List<ApiScenarioWithBLOBs> apiScenarios = apiScenarioMapper.selectByExampleWithBLOBs(example);
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (request.getCondition() == null || !request.getCondition().isSelectAll()) {
// 按照id指定顺序排序
FixedOrderComparator<String> fixedOrderComparator = new FixedOrderComparator<String>(ids);
fixedOrderComparator.setUnknownObjectBehavior(FixedOrderComparator.UnknownObjectBehavior.BEFORE);
BeanComparator beanComparator = new BeanComparator("id", fixedOrderComparator);
Collections.sort(apiScenarios, beanComparator);
}
}
return apiScenarios;
}
/**
* 测试计划接口场景的预执行生成场景报告
*/
private void assemblyPlanScenario(List<ApiScenarioWithBLOBs> apiScenarios, RunScenarioRequest request, Map<String, RunModeDataDTO> executeQueue, List<String> scenarioIds, StringBuilder scenarioNames) {
String reportId = request.getId();
Map<String, String> planScenarioIdMap = request.getScenarioTestPlanIdMap();
if (MapUtils.isEmpty(planScenarioIdMap)) {
return;
}
String projectId = request.getProjectId();
Map<String, ApiScenarioWithBLOBs> scenarioMap = apiScenarios.stream().collect(Collectors.toMap(ApiScenarioWithBLOBs::getId, Function.identity(), (t1, t2) -> t1));
for (Map.Entry<String, String> entry : planScenarioIdMap.entrySet()) {
String testPlanScenarioId = entry.getKey();
String scenarioId = entry.getValue();
ApiScenarioWithBLOBs scenario = scenarioMap.get(scenarioId);
if (scenario.getStepTotal() == null || scenario.getStepTotal() == 0) {
continue;
}
APIScenarioReportResult report;
Map<String, String> planEnvMap = new HashMap<>();
//测试计划页面触发的执行方式生成报告时createScenarioReport第二个参数需要特殊处理
// 获取场景用例单独的执行环境
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
String envJson = planApiScenario.getEnvironment();
String envType = planApiScenario.getEnvironmentType();
String envGroupId = planApiScenario.getEnvironmentGroupId();
if (StringUtils.equals(envType, EnvironmentType.JSON.toString()) && StringUtils.isNotBlank(envJson)) {
planEnvMap = JSON.parseObject(envJson, Map.class);
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.toString()) && StringUtils.isNotBlank(envGroupId)) {
planEnvMap = environmentGroupProjectService.getEnvMap(envGroupId);
}
if (StringUtils.isEmpty(projectId)) {
projectId = testPlanScenarioCaseService.getProjectIdById(testPlanScenarioId);
}
if (StringUtils.isEmpty(projectId)) {
projectId = scenario.getProjectId();
}
report = apiScenarioReportService.init(reportId, testPlanScenarioId, scenario.getName(), request.getTriggerMode(),
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig(), scenario.getId());
if (report != null && StringUtils.isNotEmpty(request.getTestPlanReportId())) {
Map<String, String> scenarioReportIdMap = new HashMap<>();
scenarioReportIdMap.put(testPlanScenarioId, report.getId());
TestPlanReportExecuteCatch.updateTestPlanThreadInfo(request.getTestPlanReportId(), null, scenarioReportIdMap, null);
}
scenarioIds.add(scenario.getId());
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
runModeDataDTO.setTestId(testPlanScenarioId);
runModeDataDTO.setPlanEnvMap(planEnvMap);
runModeDataDTO.setReport(report);
runModeDataDTO.setReportId(report.getId());
executeQueue.put(report.getId(), runModeDataDTO);
} else {
try {
// 生成并行报告和HashTree
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, testPlanScenarioId);
if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
runModeDataDTO.setHashTree(GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap, request.getConfig().getReportType()));
}
executeQueue.put(report.getId(), runModeDataDTO);
} catch (Exception ex) {
scenarioIds.remove(scenario.getId());
if (StringUtils.equalsAny(request.getTriggerMode(), TriggerMode.BATCH.name(), TriggerMode.SCHEDULE.name())) {
remakeReportService.remakeScenario(request.getRunMode(), testPlanScenarioId, scenario, report);
} else {
MSException.throwException(ex);
}
}
}
scenarioNames.append(scenario.getName()).append(",");
// 生成文档结构
if (request.getConfig() == null || !StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportStructureService.save(scenario, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
// 重置报告ID
reportId = UUID.randomUUID().toString();
}
}
/**
* 接口场景的预执行生成场景报告
*/
private void assemblyScenario(List<ApiScenarioWithBLOBs> apiScenarios, RunScenarioRequest request, Map<String, RunModeDataDTO> executeQueue, List<String> scenarioIds, StringBuilder scenarioNames, String serialReportId) {
String reportId = request.getId();
for (int i = 0; i < apiScenarios.size(); i++) {
ApiScenarioWithBLOBs item = apiScenarios.get(i);
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
continue;
}
APIScenarioReportResult report = apiScenarioReportService.init(reportId, item.getId(), item.getName(), request.getTriggerMode(),
request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig(), item.getId());
scenarioIds.add(item.getId());
scenarioNames.append(item.getName()).append(",");
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
runModeDataDTO.setTestId(item.getId());
runModeDataDTO.setPlanEnvMap(new HashMap<>());
runModeDataDTO.setReport(report);
runModeDataDTO.setReportId(report.getId());
executeQueue.put(report.getId(), runModeDataDTO);
} else {
// 生成报告和HashTree
try {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, item.getId());
if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
HashTree hashTree = GenerateHashTreeUtil.generateHashTree(item, StringUtils.isNotEmpty(serialReportId) ? serialReportId + "-" + i : reportId, new HashMap<>(), request.getConfig().getReportType());
runModeDataDTO.setHashTree(hashTree);
}
executeQueue.put(report.getId(), runModeDataDTO);
} catch (Exception ex) {
scenarioIds.remove(item.getId());
if (StringUtils.equalsAny(request.getTriggerMode(), TriggerMode.BATCH.name(), TriggerMode.SCHEDULE.name())) {
remakeReportService.remakeScenario(request.getRunMode(), null, item, report);
} else {
MSException.throwException(ex);
}
}
}
// 生成报告结构
if (request.getConfig() == null || !StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportStructureService.save(item, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
// 重置报告ID
reportId = UUID.randomUUID().toString();
}
}
public void testElement(RunDefinitionRequest request) {
if (request.getTestElement() != null) {
tcpApiParamService.checkTestElement(request.getTestElement());
}
}
public String debug(RunDefinitionRequest request, List<MultipartFile> bodyFiles, List<MultipartFile> scenarioFiles) {
Map<String, String> map = request.getEnvironmentMap();
String envType = request.getEnvironmentType();
if (StringUtils.equals(envType, EnvironmentType.GROUP.toString())) {
String environmentGroupId = request.getEnvironmentGroupId();
map = environmentGroupProjectService.getEnvMap(environmentGroupId);
}
ParameterConfig config = new ParameterConfig();
if (map != null) {
apiScenarioEnvService.setEnvConfig(map, config);
}
HashTree hashTree = null;
try {
this.testElement(request);
hashTree = request.getTestElement().generateHashTree(config);
LogUtil.info(request.getTestElement().getJmx(hashTree));
} catch (Exception e) {
MSException.throwException(e.getMessage());
}
APIScenarioReportResult report = apiScenarioReportService.init(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
SessionUtils.getUserId(), request.getConfig(), request.getId());
apiScenarioReportMapper.insert(report);
if (request.isSaved()) {
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(request.getScenarioId());
apiScenarioReportStructureService.save(scenario, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);
}
uploadBodyFiles(request.getBodyFileRequestIds(), bodyFiles);
FileUtils.createBodyFiles(request.getScenarioFileIds(), scenarioFiles);
// 调用执行方法
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(request.getId(), request.getId(), ApiRunMode.SCENARIO.name(), hashTree);
runRequest.setDebug(true);
jMeterService.run(runRequest);
return request.getId();
}
private void uploadBodyFiles(List<String> bodyFileRequestIds, List<MultipartFile> bodyFiles) {
if (CollectionUtils.isNotEmpty(bodyFileRequestIds)) {
bodyFileRequestIds.forEach(requestId -> {
FileUtils.createBodyFiles(requestId, bodyFiles);
});
}
}
}

View File

@ -0,0 +1,65 @@
package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@Service
public class ApiScenarioParallelService {
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private JMeterService jMeterService;
public void parallel(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId, List<MsExecResponseDTO> responseDTOS, String queueId) {
if (StringUtils.isEmpty(serialReportId)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
// 开始并发执行
for (String reportId : executeQueue.keySet()) {
//存储报告
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
batchMapper.insert(report);
responseDTOS.add(new MsExecResponseDTO(executeQueue.get(reportId).getTestId(), reportId, request.getRunMode()));
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
for (String reportId : executeQueue.keySet()) {
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(executeQueue.get(reportId).getTestId(), StringUtils.isNotEmpty(serialReportId) ? serialReportId : reportId, request.getRunMode(), executeQueue.get(reportId).getHashTree());
runRequest.setReportType(StringUtils.isNotEmpty(serialReportId) ? RunModeConstants.SET_REPORT.toString() : RunModeConstants.INDEPENDENCE.toString());
runRequest.setQueueId(queueId);
if (request.getConfig() != null) {
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()));
runRequest.setPoolId(request.getConfig().getResourcePoolId());
}
runRequest.setTestPlanReportId(request.getTestPlanReportId());
runRequest.setHashTree(executeQueue.get(reportId).getHashTree());
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("Scenario run-开始并发执行:" + JSON.toJSONString(request));
}
jMeterService.run(runRequest);
}
}
}

View File

@ -0,0 +1,221 @@
package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.TestResultService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@Service
public class ApiScenarioSerialService {
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private JMeterService jMeterService;
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
private ApiScenarioEnvService apiScenarioEnvService;
public void serial(ApiExecutionQueue executionQueue, ApiExecutionQueueDetail queue) {
LoggerUtil.debug("Scenario run-执行脚本装载-进入串行准备");
if (!StringUtils.equals(executionQueue.getReportType(), RunModeConstants.SET_REPORT.toString())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(queue.getReportId());
report.setStatus(APITestStatus.Running.name());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
apiScenarioReportMapper.updateByPrimaryKey(report);
} else {
ApiDefinitionExecResult execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
execResult.setStatus(APITestStatus.Running.name());
apiDefinitionExecResultMapper.updateByPrimaryKey(execResult);
}
}
LoggerUtil.info("Scenario run-开始执行队列ID" + executionQueue.getReportId() + "");
try {
HashTree hashTree = null;
if (StringUtils.isEmpty(executionQueue.getPoolId())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioWithBLOBs scenario = null;
Map<String, String> planEnvMap = new LinkedHashMap<>();
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
scenario = apiScenarioMapper.selectByPrimaryKey(queue.getTestId());
} else {
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(queue.getTestId());
if (planApiScenario != null) {
planEnvMap = apiScenarioEnvService.planEnvMap(queue.getTestId());
queue.setEvnMap(JSON.toJSONString(planEnvMap));
scenario = apiScenarioMapper.selectByPrimaryKey(planApiScenario.getApiScenarioId());
}
}
if ((planEnvMap == null || planEnvMap.isEmpty()) && StringUtils.isNotEmpty(queue.getEvnMap())) {
planEnvMap = JSON.parseObject(queue.getEvnMap(), Map.class);
}
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, queue.getReportId(), planEnvMap, executionQueue.getReportType());
} else {
hashTree = generateHashTree(queue.getTestId());
}
// 更新环境变量
this.initEnv(hashTree);
}
String reportId = StringUtils.isNotEmpty(executionQueue.getReportId()) ? executionQueue.getReportId() : queue.getReportId();
if (!StringUtils.equals(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
reportId = queue.getReportId();
}
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(queue.getTestId(), reportId, executionQueue.getRunMode(), hashTree);
runRequest.setReportType(executionQueue.getReportType());
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(executionQueue.getPoolId()));
runRequest.setTestPlanReportId(executionQueue.getReportId());
runRequest.setRunType(RunModeConstants.SERIAL.toString());
runRequest.setQueueId(executionQueue.getId());
runRequest.setPoolId(executionQueue.getPoolId());
// 开始执行
jMeterService.run(runRequest);
} catch (Exception e) {
LoggerUtil.error("执行终止:" + e.getMessage());
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, queue);
dto.setRunType(RunModeConstants.SERIAL.toString());
dto.setReportType(executionQueue.getReportType());
dto.setRunMode(executionQueue.getRunMode());
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
CommonBeanFactory.getBean(TestResultService.class).testEnded(dto);
} else {
ApiDefinitionExecResult apiDefinitionExecResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (apiDefinitionExecResult != null) {
apiDefinitionExecResult.setStatus("timeout");
apiDefinitionExecResultMapper.updateByPrimaryKey(apiDefinitionExecResult);
}
}
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
}
}
private void initEnv(HashTree hashTree) {
ApiTestEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
HashTreeUtil hashTreeUtil = new HashTreeUtil();
Map<String, Map<String, String>> envParamsMap = hashTreeUtil.getEnvParamsDataByHashTree(hashTree, apiTestEnvironmentService);
hashTreeUtil.mergeParamDataMap(null, envParamsMap);
}
public HashTree generateHashTree(String testId) {
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(testId);
if (apiCase != null) {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(apiCase.getApiCaseId());
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
if (caseWithBLOBs != null) {
try {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(caseWithBLOBs.getName());
group.setName(caseWithBLOBs.getName());
MsTestElement testElement = parse(caseWithBLOBs, testId);
group.setHashTree(new LinkedList<>());
group.getHashTree().add(testElement);
testPlan.getHashTree().add(group);
} catch (Exception ex) {
MSException.throwException(ex.getMessage());
}
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
return jmeterHashTree;
}
return null;
}
private MsTestElement parse(ApiTestCaseWithBLOBs caseWithBLOBs, String planId) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
String api = caseWithBLOBs.getRequest();
JSONObject element = JSON.parseObject(api);
ElementUtil.dataFormatting(element);
LinkedList<MsTestElement> list = new LinkedList<>();
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
list.addAll(elements);
}
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(planId);
if (element.getString("type").equals("HTTPSamplerProxy")) {
MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class);
httpSamplerProxy.setHashTree(list);
httpSamplerProxy.setName(planId);
httpSamplerProxy.setUseEnvironment(apiCase.getEnvironmentId());
return httpSamplerProxy;
}
if (element.getString("type").equals("TCPSampler")) {
MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class);
msTCPSampler.setUseEnvironment(apiCase.getEnvironmentId());
msTCPSampler.setHashTree(list);
msTCPSampler.setName(planId);
return msTCPSampler;
}
if (element.getString("type").equals("DubboSampler")) {
MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class);
dubboSampler.setUseEnvironment(apiCase.getEnvironmentId());
dubboSampler.setHashTree(list);
dubboSampler.setName(planId);
return dubboSampler;
}
if (element.getString("type").equals("JDBCSampler")) {
MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class);
jDBCSampler.setUseEnvironment(apiCase.getEnvironmentId());
jDBCSampler.setHashTree(list);
jDBCSampler.setName(planId);
return jDBCSampler;
}
} catch (Exception e) {
LogUtil.error(e);
}
return null;
}
}

View File

@ -0,0 +1,39 @@
package io.metersphere.api.exec.schedule;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.track.service.TestPlanReportService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TestPlanReportListenerScheduled {
/**
* 定时调用监听检查报告状态
*/
@Scheduled(cron = "*/9 * * * * ?")
public void testPlanScheduled() {
//判断缓冲队列是否存在记录
if (CollectionUtils.isNotEmpty(MessageCache.jobReportCache)) {
for (int i = 0; i < MessageCache.jobReportCache.size(); i++) {
this.listener(MessageCache.jobReportCache.get(i));
}
}
}
private void listener(String planReportId) {
if (TestPlanReportExecuteCatch.getTestPlanExecuteInfo(planReportId) != null) {
if (!CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).checkPlanReport(planReportId)) {
LoggerUtil.info("检查测试计划执行报告:【" + planReportId + "");
CommonBeanFactory.getBean(TestPlanReportService.class).countReport(planReportId);
}
} else {
MessageCache.jobReportCache.remove(planReportId);
LoggerUtil.info("测试计划执行报告:【" + planReportId + "】执行完成,剩余队列:" + MessageCache.jobReportCache.size());
}
}
}

View File

@ -0,0 +1,97 @@
package io.metersphere.api.exec.utils;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.SessionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Objects;
import java.util.UUID;
public class ApiDefinitionExecResultUtil {
public static ApiDefinitionExecResult initBase(String resourceId, String status, String reportId) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString());
} else {
apiResult.setId(reportId);
}
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setEndTime(System.currentTimeMillis());
apiResult.setTriggerMode(TriggerMode.BATCH.name());
apiResult.setActuator("LOCAL");
apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
apiResult.setResourceId(resourceId);
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.DEFINITION.name());
apiResult.setStatus(status);
return apiResult;
}
public static ApiDefinitionExecResult addResult(BatchRunDefinitionRequest request, TestPlanApiCase key, String status, ApiDefinitionExecResultMapper batchMapper) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
apiResult.setId(UUID.randomUUID().toString());
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setEndTime(System.currentTimeMillis());
ApiTestCaseWithBLOBs caseWithBLOBs = CommonBeanFactory.getBean(ApiTestCaseMapper.class).selectByPrimaryKey(key.getApiCaseId());
if (caseWithBLOBs != null) {
apiResult.setName(caseWithBLOBs.getName());
}
if (StringUtils.equalsIgnoreCase(request.getTriggerMode(), ApiRunMode.SCHEDULE_API_PLAN.name())) {
apiResult.setTriggerMode(TriggerMode.SCHEDULE.name());
} else if (StringUtils.equalsIgnoreCase(request.getTriggerMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
apiResult.setTriggerMode(TriggerMode.MANUAL.name());
} else {
apiResult.setTriggerMode(TriggerMode.BATCH.name());
}
apiResult.setActuator("LOCAL");
if (request.getConfig() != null && GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()).isPool()) {
apiResult.setActuator(request.getConfig().getResourcePoolId());
}
if (StringUtils.isEmpty(request.getUserId())) {
if (SessionUtils.getUser() != null) {
apiResult.setUserId(SessionUtils.getUser().getId());
}
} else {
apiResult.setUserId(request.getUserId());
}
apiResult.setResourceId(key.getApiCaseId());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.API_PLAN.name());
apiResult.setStatus(status);
apiResult.setContent(request.getPlanReportId());
batchMapper.insert(apiResult);
return apiResult;
}
public static ApiDefinitionExecResult add(String resourceId, String status, String reportId) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString());
} else {
apiResult.setId(reportId);
}
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setEndTime(System.currentTimeMillis());
apiResult.setTriggerMode(TriggerMode.BATCH.name());
apiResult.setActuator("LOCAL");
apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
apiResult.setResourceId(resourceId);
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.DEFINITION.name());
apiResult.setStatus(status);
return apiResult;
}
}

View File

@ -0,0 +1,134 @@
package io.metersphere.api.exec.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.*;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.jmeter.ResourcePoolCalculation;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.base.mapper.TestResourcePoolMapper;
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JvmInfoDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.vo.BooleanPool;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class GenerateHashTreeUtil {
public static MsScenario parseScenarioDefinition(String scenarioDefinition) {
MsScenario scenario = JSONObject.parseObject(scenarioDefinition, MsScenario.class);
parse(scenarioDefinition, scenario, scenario.getId(), null);
return scenario;
}
public static void parse(String scenarioDefinition, MsScenario scenario, String id, String reportType) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
JSONObject element = JSON.parseObject(scenarioDefinition);
ElementUtil.dataFormatting(element, id, reportType);
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
scenario.setHashTree(elements);
}
if (element != null && StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
new TypeReference<LinkedList<ScenarioVariable>>() {
});
scenario.setVariables(variables);
}
} catch (Exception e) {
LogUtil.error(e);
LogUtil.error(e);
}
}
public static LinkedList<MsTestElement> getScenarioHashTree(String definition) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JSONObject element = JSON.parseObject(definition);
try {
if (element != null) {
ElementUtil.dataFormatting(element);
return objectMapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
}
} catch (JsonProcessingException e) {
LogUtil.error(e.getMessage(), e);
}
return new LinkedList<>();
}
public static BooleanPool isResourcePool(String id) {
BooleanPool pool = new BooleanPool();
pool.setPool(StringUtils.isNotEmpty(id));
if (pool.isPool()) {
TestResourcePool resourcePool = CommonBeanFactory.getBean(TestResourcePoolMapper.class).selectByPrimaryKey(id);
pool.setK8s(resourcePool != null && resourcePool.getApi() && resourcePool.getType().equals(ResourcePoolTypeEnum.K8S.name()));
}
return pool;
}
public static List<JvmInfoDTO> setPoolResource(String id) {
if (GenerateHashTreeUtil.isResourcePool(id).isPool()) {
if (GenerateHashTreeUtil.isResourcePool(id).isK8s()) {
LogUtil.info("K8S 暂时不做校验 ");
} else {
ResourcePoolCalculation resourcePoolCalculation = CommonBeanFactory.getBean(ResourcePoolCalculation.class);
return resourcePoolCalculation.getPools(id);
}
}
return null;
}
public static HashTree generateHashTree(ApiScenarioWithBLOBs item, String reportId, Map<String, String> planEnvMap, String reportType) {
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
try {
MsThreadGroup group = new MsThreadGroup();
group.setLabel(item.getName());
group.setName(reportId);
MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class);
group.setOnSampleError(scenario.getOnSampleError());
if (planEnvMap != null && planEnvMap.size() > 0) {
scenario.setEnvironmentMap(planEnvMap);
}
GenerateHashTreeUtil.parse(item.getScenarioDefinition(), scenario, item.getId(), reportType);
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> scenarios = new LinkedList<>();
scenarios.add(scenario);
group.setHashTree(scenarios);
testPlan.getHashTree().add(group);
} catch (Exception ex) {
MSException.throwException(ex.getMessage());
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
return jmeterHashTree;
}
public static boolean isSetReport(RunModeConfigDTO config) {
return config != null && StringUtils.equals(config.getReportType(), RunModeConstants.SET_REPORT.toString()) && StringUtils.isNotEmpty(config.getReportName());
}
}

View File

@ -1,4 +1,4 @@
package io.metersphere.api.service.task;
package io.metersphere.api.exec.utils;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

View File

@ -1,60 +0,0 @@
package io.metersphere.api.jmeter;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* JMeter BackendListener扩展, jmx脚本中使用
*/
public class APIBackendListenerClient extends AbstractBackendListenerClient implements Serializable {
public final static String TEST_ID = "ms.test.id";
public final static String AMASS_REPORT = "ms.test.amass.report.id";
public String runMode = ApiRunMode.RUN.name();
private String amassReport;
private final List<SampleResult> queue = new ArrayList<>();
// 测试ID
private String testId;
private String debugReportId;
@Override
public void setupTest(BackendListenerContext context) throws Exception {
setParam(context);
super.setupTest(context);
}
@Override
public void handleSampleResults(List<SampleResult> sampleResults, BackendListenerContext context) {
queue.addAll(sampleResults);
}
@Override
public void teardownTest(BackendListenerContext context) throws Exception {
APIBackendListenerHandler apiBackendListenerHandler =
CommonBeanFactory.getBean(APIBackendListenerHandler.class);
apiBackendListenerHandler.handleTeardownTest(queue, this.runMode, this.testId, this.debugReportId, this.amassReport);
super.teardownTest(context);
}
private void setParam(BackendListenerContext context) {
this.testId = context.getParameter(APIBackendListenerClient.TEST_ID);
this.runMode = context.getParameter("runMode");
this.debugReportId = context.getParameter("debugReportId");
this.amassReport = context.getParameter(AMASS_REPORT);
if (StringUtils.isBlank(this.runMode)) {
this.runMode = ApiRunMode.RUN.name();
}
}
}

View File

@ -1,70 +0,0 @@
package io.metersphere.api.jmeter;
import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.service.MsResultService;
import io.metersphere.api.service.TestResultService;
import org.apache.commons.collections.CollectionUtils;
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.*;
/**
* 获取结果和数据库操作分离
* 减少占用的数据库连接
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class APIBackendListenerHandler {
@Resource
private TestResultService testResultService;
@Resource
private MsResultService resultService;
public void handleTeardownTest(List<SampleResult> queue, String runMode, String testId, String debugReportId, String amassReport) throws Exception {
try {
TestResult testResult = new TestResult();
testResult.setTestId(testId);
testResult.setSetReportId(amassReport);
MessageCache.runningEngine.remove(testId);
testResult.setTotal(0);
List<String> environmentList = new ArrayList<>();
// 一个脚本里可能包含多个场景(ThreadGroup)所以要区分开key: 场景Id
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
queue.forEach(result -> {
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如Scenario 2-1
if (StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) {
String evnStr = result.getResponseDataAsString();
environmentList.add(evnStr);
} else {
resultService.formatTestResult(testResult, scenarios, result);
}
});
queue.clear();
testResult.getScenarios().addAll(scenarios.values());
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
testResult.setConsole(resultService.getJmeterLogger(testId, true));
//处理环境参数
ExecutedHandleSingleton.parseEnvironment(environmentList);
testResultService.saveResult(testResult, runMode, debugReportId, testId);
// 清除已经中断的过程数据
if (!MessageCache.reportCache.containsKey(testId) && resultService.getProcessCache().containsKey(testId)) {
resultService.getProcessCache().remove(testId);
}
if (StringUtils.isNotEmpty(testId)) {
MessageCache.executionQueue.remove(testId);
}
} catch (Exception e) {
if (StringUtils.isNotEmpty(amassReport) && MessageCache.cache.get(amassReport) != null
&& StringUtils.isNotEmpty(testId)
&& CollectionUtils.isNotEmpty(MessageCache.cache.get(amassReport).getReportIds())) {
MessageCache.cache.get(amassReport).getReportIds().remove(testId);
}
}
}
}

View File

@ -0,0 +1,39 @@
package io.metersphere.api.jmeter;
import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.MsResultService;
import io.metersphere.api.service.TestResultService;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.dto.ResultDTO;
import io.metersphere.jmeter.MsExecListener;
import io.metersphere.utils.LoggerUtil;
import java.util.Map;
public class APISingleResultListener extends MsExecListener {
@Override
public void handleTeardownTest(ResultDTO dto, Map<String, Object> kafkaConfig) {
LoggerUtil.info("处理单条执行结果报告【" + dto.getReportId() + " 】,资源【 " + dto.getTestId() + "");
dto.setConsole(CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(dto.getReportId()));
CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
}
@Override
public void testEnded(ResultDTO dto, Map<String, Object> kafkaConfig) {
try {
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + " 】整体执行完成;" + dto.getRunMode());
// 全局并发队列
PoolExecBlockingQueueUtil.offer(dto.getReportId());
dto.setConsole(CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(dto.getReportId()));
// 整体执行结束更新资源状态
CommonBeanFactory.getBean(TestResultService.class).testEnded(dto);
LoggerUtil.info("执行队列处理:" + dto.getQueueId());
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
} catch (Exception e) {
LoggerUtil.error(e);
}
}
}

View File

@ -19,7 +19,7 @@ public class ExecutedHandleSingleton {
private ExecutedHandleSingleton() {
}
public synchronized static void parseEnvironment(List<String> evnStrList) {
public static void parseEnvironment(List<String> evnStrList) {
for (String evnStr: evnStrList) {
try {
Thread.sleep(1000);

View File

@ -1,71 +1,21 @@
package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.collections.CollectionUtils;
import io.metersphere.utils.LoggerUtil;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class FixedTask {
public static Map<String, Long> tasks = new HashMap<>();
public static Map<String, Integer> guardTask = new HashMap<>();
private ApiScenarioReportService scenarioReportService;
private ApiExecutionQueueService queueService;
@Scheduled(cron = "*/6 * * * * ?")
@Scheduled(cron = "0 */5 * * * ?")
public void execute() {
if (MessageCache.caseExecResourceLock.size() > 10000) {
MessageCache.caseExecResourceLock.clear();
}
if (MessageCache.scenarioExecResourceLock.size() > 5000) {
MessageCache.scenarioExecResourceLock.clear();
}
if (scenarioReportService == null) {
scenarioReportService = CommonBeanFactory.getBean(ApiScenarioReportService.class);
}
if (MessageCache.cache != null && MessageCache.cache.size() > 0) {
for (String key : MessageCache.cache.keySet()) {
ReportCounter counter = MessageCache.cache.get(key);
LogUtil.info("集成报告:【" + key + "】总执行场景:【" + counter.getReportIds().size() + "】已经执行完成场景:【" + counter.getCompletedIds().size() + "");
List<String> filterList = counter.getReportIds().stream().filter(t -> !counter.getCompletedIds().contains(t)).collect(Collectors.toList());
LogUtil.debug("剩余要执行的报告" + JSON.toJSONString(filterList));
// 合并
if (counter.getCompletedIds().size() >= counter.getReportIds().size()) {
scenarioReportService.margeReport(key, counter.getReportIds());
guardTask.remove(key);
MessageCache.cache.remove(key);
} else {
try {
if (guardTask.containsKey(key)) {
int number = guardTask.get(key);
number += 1;
guardTask.put(key, number);
} else {
guardTask.put(key, 0);
}
if (CollectionUtils.isNotEmpty(counter.getPoolUrls()) && counter.getCompletedIds().size() > 0 && guardTask.get(key) > 200) {
// 资源池中已经没有执行的请求了
int runningCount = scenarioReportService.get(key, counter);
if (runningCount == 0) {
LogUtil.error("发生未知异常,进行资源合并,请检查资源池是否正常运行");
scenarioReportService.margeReport(key, counter.getReportIds());
guardTask.remove(key);
MessageCache.cache.remove(key);
}
}
} catch (Exception ex) {
LogUtil.error(ex.getMessage());
}
}
}
if (queueService == null) {
queueService = CommonBeanFactory.getBean(ApiExecutionQueueService.class);
}
LoggerUtil.info("进入超时处理");
queueService.timeOut();
}
}

View File

@ -0,0 +1,36 @@
package io.metersphere.api.jmeter;
import groovy.lang.GroovyClassLoader;
import io.metersphere.base.domain.JarConfig;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.JarConfigService;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.List;
@Service
public class GroovyLoadJarService {
/**
* groovy 使用的是自己的类加载器
* 这里再执行脚本前使用 groovy的加载器加载jar包
* 解决groovy脚本无法使用jar包的问题
*/
public void loadGroovyJar(GroovyClassLoader classLoader) {
JarConfigService jarConfigService = CommonBeanFactory.getBean(JarConfigService.class);
List<JarConfig> jars = jarConfigService.list();
jars.forEach(jarConfig -> {
try {
String path = jarConfig.getPath();
File file = new File(path);
if (file.isDirectory() && !path.endsWith("/")) {
file = new File(path + "/");
}
classLoader.addURL(file.toURI().toURL());
} catch (Exception e) {
LogUtil.error(e);
}
});
}
}

View File

@ -1,35 +1,27 @@
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;
import io.metersphere.api.exec.queue.ExecThreadPoolExecutor;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.NodeKafkaService;
import io.metersphere.api.service.RemakeReportService;
import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourcePool;
import io.metersphere.base.mapper.*;
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.config.JmeterProperties;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.NodeDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.config.KafkaConfig;
import io.metersphere.dto.*;
import io.metersphere.jmeter.JMeterBase;
import io.metersphere.jmeter.LocalRunner;
import io.metersphere.performance.engine.Engine;
import io.metersphere.performance.engine.EngineFactory;
import io.metersphere.service.SystemParameterService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.visualizers.backend.BackendListener;
import org.apache.jorphan.collections.HashTree;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.ResponseEntity;
@ -40,8 +32,7 @@ import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
@ -50,14 +41,10 @@ public class JMeterService {
@Resource
private JmeterProperties jmeterProperties;
@Resource
private TestResourcePoolMapper testResourcePoolMapper;
@Resource
private RestTemplate restTemplate;
@Resource
private NodeKafkaService nodeKafkaService;
@PostConstruct
public void init() {
private void init() {
String JMETER_HOME = getJmeterHome();
String JMETER_PROPERTIES = JMETER_HOME + "/bin/jmeter.properties";
@ -66,22 +53,6 @@ public class JMeterService {
JMeterUtils.setLocale(LocaleContextHolder.getLocale());
}
public void runOld(String testId, String debugReportId, InputStream is) {
init();
try {
Object scriptWrapper = SaveService.loadElement(is);
HashTree testPlan = getHashTree(scriptWrapper);
JMeterVars.addJSR223PostProcessor(testPlan);
String runMode = StringUtils.isBlank(debugReportId) ? ApiRunMode.RUN.name() : ApiRunMode.DEBUG.name();
addBackendListener(testId, null, debugReportId, runMode, testPlan);
LocalRunner runner = new LocalRunner(testPlan);
runner.run(testId);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("api_load_script_error"));
}
}
public String getJmeterHome() {
String home = getClass().getResource("/").getPath() + "jmeter";
try {
@ -96,111 +67,116 @@ public class JMeterService {
}
}
public static HashTree getHashTree(Object scriptWrapper) throws Exception {
Field field = scriptWrapper.getClass().getDeclaredField("testPlan");
field.setAccessible(true);
return (HashTree) field.get(scriptWrapper);
}
private void addBackendListener(String testId, String amassReport, String debugReportId, String runMode, HashTree testPlan) {
BackendListener backendListener = new BackendListener();
backendListener.setName(testId);
Arguments arguments = new Arguments();
arguments.addArgument(APIBackendListenerClient.TEST_ID, testId);
if (StringUtils.isNotEmpty(amassReport)) {
arguments.addArgument(APIBackendListenerClient.AMASS_REPORT, amassReport);
}
if (StringUtils.isNotBlank(runMode)) {
arguments.addArgument("runMode", runMode);
}
if (StringUtils.isNotBlank(debugReportId)) {
arguments.addArgument("debugReportId", debugReportId);
}
backendListener.setArguments(arguments);
backendListener.setClassname(APIBackendListenerClient.class.getCanonicalName());
testPlan.add(testPlan.getArray()[0], backendListener);
}
private void addResultCollector(String testId, HashTree testPlan) {
MsResultCollector resultCollector = new MsResultCollector();
private void addDebugListener(String testId, HashTree testPlan) {
MsDebugListener resultCollector = new MsDebugListener();
resultCollector.setName(testId);
resultCollector.setProperty(TestElement.TEST_CLASS, MsResultCollector.class.getName());
resultCollector.setProperty(TestElement.TEST_CLASS, MsDebugListener.class.getName());
resultCollector.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ViewResultsFullVisualizer"));
resultCollector.setEnabled(true);
testPlan.add(testPlan.getArray()[0], resultCollector);
}
public void runLocal(String testId, RunModeConfig config, HashTree testPlan, String debugReportId, String runMode) {
private void runLocal(JmeterRunRequestDTO request) {
init();
FixedTask.tasks.put(testId, System.currentTimeMillis());
addBackendListener(testId, config != null ? config.getAmassReport() : "", debugReportId, runMode, testPlan);
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);
if (!MessageCache.jmeterLogTask.containsKey(request.getReportId())) {
MessageCache.jmeterLogTask.put(request.getReportId(), System.currentTimeMillis());
}
public void runTest(String testId, String reportId, String runMode, String testPlanScenarioId, RunModeConfig config) {
// 获取可以执行的资源池
String resourcePoolId = config.getResourcePoolId();
BaseSystemConfigDTO baseInfo = config.getBaseInfo();
if (baseInfo == null) {
baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
LoggerUtil.debug("监听MessageCache.tasks当前容量" + MessageCache.jmeterLogTask.size());
if (request.isDebug() && !StringUtils.equalsAny(request.getRunMode(), ApiRunMode.DEFINITION.name())) {
LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加同步接收结果 Listener");
JMeterBase.addSyncListener(request, request.getHashTree(), APISingleResultListener.class.getCanonicalName());
}
RunRequest runRequest = new RunRequest();
runRequest.setTestId(testId);
runRequest.setReportId(reportId);
runRequest.setPoolId(resourcePoolId);
runRequest.setAmassReport(config.getAmassReport());
if (request.isDebug()) {
LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加Debug Listener");
addDebugListener(request.getReportId(), request.getHashTree());
} else {
LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加同步接收结果 Listener");
JMeterBase.addSyncListener(request, request.getHashTree(), APISingleResultListener.class.getCanonicalName());
}
LocalRunner runner = new LocalRunner(request.getHashTree());
runner.run(request.getReportId());
}
private void runNode(JmeterRunRequestDTO request) {
// 获取可以执行的资源池
BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
// 占位符
String platformUrl = "http://localhost:8081";
if (baseInfo != null) {
platformUrl = baseInfo.getUrl();
}
platformUrl += "/api/jmeter/download?testId=" + testId + "&reportId=" + reportId + "&runMode=" + runMode + "&testPlanScenarioId";
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
platformUrl += "=" + testPlanScenarioId;
}
runRequest.setUrl(platformUrl);
runRequest.setRunMode(runMode);
runRequest.setKafka(nodeKafkaService.getKafka());
platformUrl += "/api/jmeter/download?testId="
+ request.getTestId()
+ "&reportId=" + request.getReportId()
+ "&runMode=" + request.getRunMode()
+ "&reportType=" + request.getReportType();
request.setPlatformUrl(platformUrl);
request.setKafkaConfig(KafkaConfig.getKafka());
// 如果是K8S调用
TestResourcePool pool = testResourcePoolMapper.selectByPrimaryKey(resourcePoolId);
if (pool != null && pool.getApi() && pool.getType().equals(ResourcePoolTypeEnum.K8S.name())) {
if (request.getPool().isK8s()) {
try {
final Engine engine = EngineFactory.createApiEngine(runRequest);
LoggerUtil.error("开始发送请求[ " + request.getTestId() + " ] 到K8S节点执行");
final Engine engine = EngineFactory.createApiEngine(request);
engine.start();
} catch (Exception e) {
LoggerUtil.error("调用K8S执行请求[ " + request.getTestId() + " ] 失败:" + e.getMessage());
ApiScenarioReportService apiScenarioReportService = CommonBeanFactory.getBean(ApiScenarioReportService.class);
apiScenarioReportService.delete(reportId);
apiScenarioReportService.delete(request.getReportId());
MSException.throwException(e.getMessage());
}
} else {
this.send(runRequest, config, reportId);
this.send(request);
}
}
public synchronized void send(RunRequest runRequest, RunModeConfig config, String reportId) {
private synchronized void send(JmeterRunRequestDTO request) {
try {
int index = (int) (Math.random() * config.getTestResources().size());
JvmInfoDTO jvmInfoDTO = config.getTestResources().get(index);
TestResource testResource = jvmInfoDTO.getTestResource();
List<JvmInfoDTO> resources = GenerateHashTreeUtil.setPoolResource(request.getPoolId());
int index = (int) (Math.random() * resources.size());
JvmInfoDTO jvmInfoDTO = resources.get(index);
TestResourceDTO testResource = jvmInfoDTO.getTestResource();
String configuration = testResource.getConfiguration();
request.setCorePoolSize(MessageCache.corePoolSize);
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
String nodeIp = node.getIp();
Integer port = node.getPort();
String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port);
ResponseEntity<String> result = restTemplate.postForEntity(uri, runRequest, String.class);
LoggerUtil.info("开始发送请求【 " + request.getReportId() + " 】,资源【 " + request.getTestId() + "" + uri + " 节点执行");
ResponseEntity<String> result = restTemplate.postForEntity(uri, request, String.class);
if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest, config, reportId);
RunRequest runRequest = new RunRequest();
runRequest.setTestId(request.getTestId());
runRequest.setRunMode(request.getRunMode());
remakeReportService.remake(request);
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 到" + uri + " 节点执行失败");
}
} catch (Exception e) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest, config, reportId);
RunRequest runRequest = new RunRequest();
runRequest.setTestId(request.getTestId());
runRequest.setRunMode(request.getRunMode());
remakeReportService.remake(request);
LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败:" + e.getMessage());
}
}
public void run(JmeterRunRequestDTO request) {
CommonBeanFactory.getBean(ExecThreadPoolExecutor.class).addTask(request);
}
public void addQueue(JmeterRunRequestDTO request) {
if (request.getPool().isPool()) {
this.runNode(request);
} else {
this.runLocal(request);
}
}
}

View File

@ -1,120 +0,0 @@
package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jmeter.extractor.JSR223PostProcessor;
import org.apache.jmeter.extractor.RegexExtractor;
import org.apache.jmeter.extractor.XPath2Extractor;
import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jorphan.collections.HashTree;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class JMeterVars {
private JMeterVars() {
}
/**
* 数据和线程变量保持一致
*/
private static Map<Integer, JMeterVariables> variables = new HashMap<>();
/**
* 线程执行过程调用提取变量值
*
* @param testId
* @param vars
* @param extract
*/
public static void addVars(Integer testId, JMeterVariables vars, String extract) {
JMeterVariables vs = variables.get(testId);
if (vs == null) {
vs = new JMeterVariables();
}
if (!StringUtils.isEmpty(extract) && vars != null) {
List<String> extracts = Arrays.asList(extract.split(";"));
if (CollectionUtils.isNotEmpty(extracts)) {
for (String item : extracts) {
String nrKey = item + "_matchNr";
Object nr = vars.get(nrKey);
JMeterVariables jMeterVariables = new JMeterVariables();
if (nr != null) {
int nrv = 0;
try {
nrv = Integer.valueOf(String.valueOf(nr));
} catch (Exception e) {
}
if (nrv > 0) {
List<Object> data = new ArrayList<>();
for (int i = 1; i < nrv + 1; i++) {
data.add(vars.get(item + "_" + i));
}
String array = JSON.toJSONString(data);
jMeterVariables.put(item, array);
}
}
if (jMeterVariables.get(item) != null) {
vs.put(item, jMeterVariables.get(item));
} else {
vs.put(item, vars.get(item) == null ? "" : vars.get(item));
}
}
vs.remove("TESTSTART.MS"); // 标示变量移除
}
}
variables.put(testId, vs);
}
/**
* 处理所有请求有提取变量的请求增加后置脚本提取变量值
*
* @param tree
*/
public static void addJSR223PostProcessor(HashTree tree) {
for (Object key : tree.keySet()) {
HashTree node = tree.get(key);
if (key instanceof HTTPSamplerProxy || key instanceof DubboSample || key instanceof JDBCSampler) {
StringJoiner extract = new StringJoiner(";");
for (Object child : node.keySet()) {
if (child instanceof RegexExtractor) {
RegexExtractor regexExtractor = (RegexExtractor) child;
extract.add(regexExtractor.getRefName());
} else if (child instanceof XPath2Extractor) {
XPath2Extractor regexExtractor = (XPath2Extractor) child;
extract.add(regexExtractor.getRefName());
} else if (child instanceof JSONPostProcessor) {
JSONPostProcessor regexExtractor = (JSONPostProcessor) child;
extract.add(regexExtractor.getRefNames());
}
}
if (Optional.ofNullable(extract).orElse(extract).length() > 0) {
JSR223PostProcessor shell = new JSR223PostProcessor();
shell.setEnabled(true);
shell.setProperty("script", "io.metersphere.api.jmeter.JMeterVars.addVars(prev.hashCode(),vars," + "\"" + extract.toString() + "\"" + ");");
node.add(shell);
}
}
if (node != null) {
addJSR223PostProcessor(node);
}
}
}
public static JMeterVariables get(Integer key) {
return variables.get(key);
}
public static void remove(Integer key) {
variables.remove(key);
}
}

View File

@ -16,10 +16,6 @@ public class JmeterThreadUtils {
StringBuilder threadNames = new StringBuilder();
for (int i = 0; i < noThreads; i++) {
if (StringUtils.isNotEmpty(lstThreads[i].getName()) && lstThreads[i].getName().startsWith(name)) {
String threadName = StringUtils.substringBeforeLast(lstThreads[i].getName(), THREAD_SPLIT);
if (StringUtils.isNotEmpty(threadName)) {
MessageCache.executionQueue.remove(threadName);
}
System.out.println("异常强制处理线程编号:" + i + " = " + lstThreads[i].getName());
LogUtil.error("异常强制处理线程编号:" + i + " = " + lstThreads[i].getName());
threadNames.append(lstThreads[i].getName()).append("");

View File

@ -1,43 +0,0 @@
package io.metersphere.api.jmeter;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.engine.JMeterEngineException;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jorphan.collections.HashTree;
public class LocalRunner {
private HashTree jmxTree;
public LocalRunner(HashTree jmxTree) {
this.jmxTree = jmxTree;
}
public LocalRunner() {
}
public void run(String report) {
StandardJMeterEngine engine = new StandardJMeterEngine();
engine.configure(jmxTree);
try {
engine.runTest();
if (StringUtils.isNotEmpty(report)) {
MessageCache.runningEngine.put(report, engine);
}
} catch (JMeterEngineException e) {
engine.stopTest(true);
}
}
public void stop(String report) {
try {
StandardJMeterEngine engine = MessageCache.runningEngine.get(report);
if (engine != null && StringUtils.isNotEmpty(report)) {
engine.stopTest();
MessageCache.runningEngine.remove(report);
}
} catch (Exception e) {
LogUtil.error(e);
}
}
}

View File

@ -1,30 +1,19 @@
package io.metersphere.api.jmeter;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import org.apache.jmeter.engine.StandardJMeterEngine;
import javax.websocket.Session;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
public class MessageCache {
public static Map<String, ReportCounter> cache = new HashMap<>();
public final static ConcurrentHashMap<String, Session> reportCache = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, Session> reportCache = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, StandardJMeterEngine> runningEngine = new ConcurrentHashMap<>();
public static ConcurrentLinkedDeque<String> terminationOrderDeque = new ConcurrentLinkedDeque<>();
// 用例并发锁
public static ConcurrentHashMap<String, ApiDefinitionExecResult> caseExecResourceLock = new ConcurrentHashMap<>();
// 场景并发锁
public static ConcurrentHashMap<String, APIScenarioReportResult> scenarioExecResourceLock = new ConcurrentHashMap<>();
// 串行执行队列 KEY=报告ID VALUE=开始时间
public static Map<String, Long> executionQueue = new HashMap<>();
public final static Map<String, Long> jmeterLogTask = new HashMap<>();
// 定时任务报告
public final static List<String> jobReportCache = new LinkedList<>();
public static int corePoolSize = 10;
}

View File

@ -22,6 +22,11 @@ import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.service.MsResultService;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.ResultDTO;
import io.metersphere.jmeter.JMeterBase;
import io.metersphere.utils.JMeterVars;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.websocket.c.to.c.MsWebSocketClient;
import io.metersphere.websocket.c.to.c.util.MsgDto;
import org.apache.commons.collections4.CollectionUtils;
@ -39,7 +44,7 @@ import java.util.Map;
/**
* 实时结果监听
*/
public class MsResultCollector extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
public class MsDebugListener extends AbstractListenerElement implements SampleListener, Clearable, Serializable,
TestStateListener, Remoteable, NoThreadClone {
private static final String ERROR_LOGGING = "MsResultCollector.error_logging"; // $NON-NLS-1$
@ -50,13 +55,11 @@ public class MsResultCollector extends AbstractListenerElement implements Sample
public static final String TEST_END = "MS_TEST_END";
private MsResultService msResultService;
private MsWebSocketClient client;
@Override
public Object clone() {
MsResultCollector clone = (MsResultCollector) super.clone();
MsDebugListener clone = (MsDebugListener) super.clone();
return clone;
}
@ -96,10 +99,11 @@ public class MsResultCollector extends AbstractListenerElement implements Sample
@Override
public void testEnded(String host) {
LogUtil.debug("TestEnded " + this.getName());
LoggerUtil.debug("TestEnded " + this.getName());
SampleResult result = new SampleResult();
result.setResponseCode(TEST_END);
msResultService.setCache(this.getName(), result);
ResultDTO dto = new ResultDTO();
dto.setReportId(this.getName());
try {
if (client != null) {
client.close();
@ -112,10 +116,6 @@ public class MsResultCollector extends AbstractListenerElement implements Sample
@Override
public void testStarted(String host) {
LogUtil.debug("TestStarted " + this.getName());
msResultService = CommonBeanFactory.getBean(MsResultService.class);
if (msResultService == null) {
LogUtil.error("testResultService is required");
}
try {
client = new MsWebSocketClient("ws://127.0.0.1:8081/ws/" + "send." + this.getName());
client.connect();
@ -141,7 +141,7 @@ public class MsResultCollector extends AbstractListenerElement implements Sample
dto.setContent(e.getThreadGroup());
dto.setReportId("send." + this.getName());
dto.setToReport(this.getName());
LogUtil.debug("send. " + this.getName());
LoggerUtil.debug("send. " + this.getName());
if (client != null) {
client.send(JSON.toJSONString(dto));
}
@ -167,7 +167,23 @@ public class MsResultCollector extends AbstractListenerElement implements Sample
}
}
if (isSampleWanted(result.isSuccessful()) && !StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) {
msResultService.setCache(this.getName(), result);
RequestResult requestResult = JMeterBase.getRequestResult(result);
if (requestResult != null) {
if (StringUtils.isNotEmpty(requestResult.getName()) && requestResult.getName().startsWith("Transaction=") && CollectionUtils.isEmpty(requestResult.getSubRequestResults())) {
LoggerUtil.debug("进入合并事物,暂不处理");
} else {
requestResult.getResponseResult().setConsole(CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(this.getName()));
MsgDto dto = new MsgDto();
dto.setExecEnd(false);
dto.setContent("result_" + JSON.toJSONString(requestResult));
dto.setReportId("send." + this.getName());
dto.setToReport(this.getName());
LoggerUtil.debug("send. " + this.getName());
if (client != null) {
client.send(JSON.toJSONString(dto));
}
}
}
}
}

View File

@ -3,10 +3,14 @@ package io.metersphere.api.jmeter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
import io.metersphere.api.service.ApiEnvironmentRunningParamService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.TestResultService;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.config.KafkaConfig;
import io.metersphere.dto.ResultDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
@ -20,13 +24,19 @@ public class MsKafkaListener {
@KafkaListener(id = CONSUME_ID, topics = KafkaConfig.TOPICS, groupId = "${spring.kafka.consumer.group-id}")
public void consume(ConsumerRecord<?, String> record) {
LogUtil.info("接收到执行结果开始存储");
try {
this.save(record.value());
} catch (Exception e) {
LogUtil.error(e.getMessage());
LoggerUtil.info("接收到执行结果开始存储");
ResultDTO testResult = this.formatResult(record.value());
if (testResult != null && testResult.getArbitraryData() != null && testResult.getArbitraryData().containsKey("TEST_END") && (Boolean) testResult.getArbitraryData().get("TEST_END")) {
LoggerUtil.info("报告 【 " + testResult.getReportId() + " 】资源 " + testResult.getTestId() + " 整体执行完成");
testResultService.testEnded(testResult);
LoggerUtil.info("执行队列处理:" + testResult.getQueueId());
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(testResult);
// 全局并发队列
PoolExecBlockingQueueUtil.offer(testResult.getReportId());
} else {
testResultService.saveResults(testResult);
}
LogUtil.info("执行内容存储结束");
LoggerUtil.info("执行内容存储结束");
}
@Resource
@ -35,32 +45,24 @@ public class MsKafkaListener {
@Resource
private ApiEnvironmentRunningParamService apiEnvironmentRunningParamService;
private TestResult formatResult(String result) {
private ResultDTO formatResult(String result) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (StringUtils.isNotEmpty(result)) {
TestResult element = mapper.readValue(result, new TypeReference<TestResult>() {
ResultDTO element = mapper.readValue(result, new TypeReference<ResultDTO>() {
});
if (StringUtils.isNotEmpty(element.getRunningDebugSampler())) {
String evnStr = element.getRunningDebugSampler();
apiEnvironmentRunningParamService.parseEvn(evnStr);
}
LoggerUtil.info("formatResult 完成:" + element.getReportId());
return element;
}
} catch (Exception e) {
LogUtil.error(e);
LoggerUtil.error("formatResult 格式化数据失败:" + e.getMessage());
}
return null;
}
private void save(String execResult) {
TestResult testResult = this.formatResult(execResult);
String testId = testResult.getTestId();
testResultService.saveResult(testResult, testResult.getRunMode(), null, testResult.getTestId());
if (StringUtils.isNotEmpty(testId)) {
MessageCache.executionQueue.remove(testId);
}
}
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.jmeter;
import io.metersphere.api.dto.JvmInfoDTO;
import io.metersphere.dto.JvmInfoDTO;
import lombok.Data;
import java.util.List;
@ -9,5 +9,5 @@ import java.util.List;
public class ReportCounter {
private List<String> completedIds;
private List<JvmInfoDTO> poolUrls;
private List<String> reportIds;
private List<String> testIds;
}

View File

@ -1,52 +0,0 @@
package io.metersphere.api.jmeter;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class RequestResult {
// 请求ID
private String id;
// 步骤请求唯一ID
private String resourceId;
private String name;
private String url;
private String method;
private String scenario;
private long requestSize;
private long startTime;
private long endTime;
private int error;
private boolean success;
private String headers;
private String cookies;
private String body;
private int totalAssertions = 0;
private int passAssertions = 0;
private final List<RequestResult> subRequestResults = new ArrayList<>();
private final ResponseResult responseResult = new ResponseResult();
public void addPassAssertions() {
this.passAssertions++;
}
}

View File

@ -1,7 +1,6 @@
package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.JvmInfoDTO;
import io.metersphere.base.domain.TestResource;
import io.metersphere.base.domain.TestResourceExample;
import io.metersphere.base.domain.TestResourcePool;
@ -9,7 +8,10 @@ import io.metersphere.base.domain.TestResourcePoolExample;
import io.metersphere.base.mapper.TestResourceMapper;
import io.metersphere.base.mapper.TestResourcePoolMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.dto.JvmInfoDTO;
import io.metersphere.dto.NodeDTO;
import io.metersphere.dto.TestResourceDTO;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -40,41 +42,6 @@ public class ResourcePoolCalculation {
}
}
public TestResource getPool(String resourcePoolId) {
// 获取可以执行的资源池
TestResourcePoolExample example = new TestResourcePoolExample();
example.createCriteria().andStatusEqualTo("VALID").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("未获取到资源池,请检查配置【系统设置-系统-测试资源池】");
}
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();
@ -98,7 +65,9 @@ public class ResourcePoolCalculation {
if (nodeJvm == null) {
continue;
}
nodeJvm.setTestResource(testResource);
TestResourceDTO dto = new TestResourceDTO();
BeanUtils.copyBean(dto,testResource);
nodeJvm.setTestResource(dto);
availableNodes.add(nodeJvm);
}
}

View File

@ -1,17 +0,0 @@
package io.metersphere.api.jmeter;
import lombok.Data;
@Data
public class ResponseAssertionResult {
private String name;
private String content;
private String script;
private String message;
private boolean pass;
}

View File

@ -1,32 +0,0 @@
package io.metersphere.api.jmeter;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class ResponseResult {
private String responseCode;
private String responseMessage;
private long responseTime;
private long latency;
private long responseSize;
private String headers;
private String body;
private String vars;
private String console;
private final List<ResponseAssertionResult> assertions = new ArrayList<>();
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.jmeter;
import io.metersphere.dto.RequestResult;
import lombok.Data;
import java.util.ArrayList;

View File

@ -3,6 +3,7 @@ package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import io.metersphere.commons.constants.DelimiterConstants;
import io.metersphere.dto.RequestResult;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

View File

@ -31,6 +31,7 @@ public abstract class PostmanAbstractParserParser<T> extends ApiImportAbstractPa
requestDesc.getAuth(); // todo 认证方式等待优化
PostmanUrl url = requestDesc.getUrl();
MsHTTPSamplerProxy request = buildRequest(requestItem.getName(), url == null ? "" : url.getRaw(), requestDesc.getMethod());
request.setRest(parseKeyValue(requestDesc.getUrl().getVariable()));
if (StringUtils.isNotBlank(request.getPath())) {
String path = request.getPath().split("\\?")[0];
path = parseVariable(path);

View File

@ -1,7 +1,6 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.client.utils.StringUtils;
import io.github.ningyu.jmeter.plugin.dubbo.sample.ProviderService;
import io.metersphere.api.dto.*;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
@ -22,16 +21,20 @@ import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.QueryScheduleRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.ScheduleDao;
import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService;
import io.metersphere.service.ScheduleService;
import io.metersphere.track.service.TestCaseService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.jorphan.collections.HashTree;
@ -41,7 +44,6 @@ import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
@ -232,12 +234,6 @@ public class APITestService {
apiTest.setUserId(request.getUserId());
}
String reportId = apiReportService.create(apiTest, request.getTriggerMode());
/*if (request.getTriggerMode().equals("SCHEDULE")) {
List<Notice> notice = noticeService.queryNotice(request.getId());
mailService.sendHtml(reportId,notice,"api");
}*/
changeStatus(request.getId(), APITestStatus.Running);
jMeterService.runOld(request.getId(), null, is);
return reportId;
}
@ -445,8 +441,6 @@ public class APITestService {
} catch (IOException e) {
LogUtil.error(e.getMessage(), e);
}
jMeterService.runOld(request.getId(), reportId, is);
return reportId;
}
@ -510,6 +504,10 @@ public class APITestService {
//HTTPSamplerProxy 进行附件转化 1.elementProp里去掉路径 2elementProp->filePath获取路径并读出来
attachmentFilePathList.addAll(this.parseAttachmentFileInfo(element));
//检查并去掉RunningDebugSampler,转jmx的时候去掉
this.checkAndRemoveRunningDebugSampler(element);
}
//如果存在证书文件也要匹配出来
attachmentFilePathList.addAll(this.parseAttachmentFileInfo(innerHashTreeElement));
@ -548,6 +546,23 @@ public class APITestService {
return returnDTO;
}
private void checkAndRemoveRunningDebugSampler(Element element) {
List<Element> childElements = element.elements();
if (CollectionUtils.isNotEmpty(childElements)) {
if (childElements.size() > 1) {
Element checkElement = childElements.get(childElements.size() - 2);
String elementName = checkElement.attributeValue("testname");
if (StringUtils.equalsIgnoreCase(elementName, RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) {
Element checkHashTreeElement = childElements.get(childElements.size() - 1);
if (StringUtils.equalsIgnoreCase("hashtree", checkHashTreeElement.getName())) {
element.remove(checkHashTreeElement);
element.remove(checkElement);
}
}
}
}
}
private List<String> parseAttachmentFileInfo(Element parentHashTreeElement) {
List<String> attachmentFilePathList = new ArrayList<>();
List<Element> parentElementList = parentHashTreeElement.elements();
@ -652,7 +667,7 @@ private List<String> parseAttachmentFileInfo(Element parentHashTreeElement) {
String scriptName = scriptElement.attributeValue("name");
String contentValue = scriptElement.getStringValue();
if ("script".equals(scriptName) && contentValue.startsWith("io.metersphere.api.jmeter.JMeterVars.addVars")) {
if ("script".equals(scriptName) && contentValue.startsWith("io.metersphere.utils.JMeterVars.addVars")) {
isRemove = true;
removeElement.add(hashTreeItemElement);
}

View File

@ -4,9 +4,6 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.jmeter.MessageCache;
import io.metersphere.api.jmeter.RequestResult;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiDefinitionMapper;
@ -15,14 +12,20 @@ import io.metersphere.base.mapper.TestCaseReviewApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.ResultDTO;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testcase.TrackCount;
import io.metersphere.track.service.TestCaseReviewApiCaseService;
import io.metersphere.track.service.TestPlanApiCaseService;
import io.metersphere.track.service.TestPlanService;
import io.metersphere.track.service.TestPlanTestCaseService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -33,6 +36,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@ -53,94 +57,35 @@ public class ApiDefinitionExecResultService {
@Resource
private ApiDefinitionMapper apiDefinitionMapper;
@Resource
TestCaseReviewApiCaseMapper testCaseReviewApiCaseMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
private TestCaseReviewApiCaseMapper testCaseReviewApiCaseMapper;
@Resource
private NoticeSendService noticeSendService;
@Resource
private TestPlanTestCaseService testPlanTestCaseService;
@Resource
private ApiTestCaseService apiTestCaseService;
public ApiDefinitionExecResult getInfo(String id) {
return apiDefinitionExecResultMapper.selectByPrimaryKey(id);
}
public void saveApiResult(List<RequestResult> requestResults, ResultDTO dto) {
boolean isFirst = true;
int count = requestResults.stream()
.filter(item -> !StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_"))
.collect(Collectors.toList()).size();
public void saveApiResult(TestResult result, String type, String triggerMode) {
if (CollectionUtils.isNotEmpty(result.getScenarios())) {
final boolean[] isFirst = {true};
result.getScenarios().forEach(scenarioResult -> {
if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) {
int countExpectProcessResultCount = 0;
for (RequestResult resultItem : scenarioResult.getRequestResults()) {
if (!StringUtils.startsWithAny(resultItem.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
countExpectProcessResultCount++;
LoggerUtil.info("接收到API/CASE执行结果【 " + requestResults.size() + "");
for (RequestResult item : requestResults) {
item.setEndTime(System.currentTimeMillis());
if (item.getResponseResult() != null) {
item.getResponseResult().setResponseTime((item.getEndTime() - item.getStartTime()));
}
}
final int expectProcessResultCount = countExpectProcessResultCount;
scenarioResult.getRequestResults().forEach(item -> {
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = MessageCache.caseExecResourceLock.get(result.getTestId());
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId());
}
item.getResponseResult().setConsole(result.getConsole());
boolean saved = true;
if (saveResult == null || expectProcessResultCount > 1) {
saveResult = new ApiDefinitionExecResult();
if (isFirst[0]) {
isFirst[0] = false;
saveResult.setId(result.getTestId());
} else {
saveResult.setId(UUID.randomUUID().toString());
}
saveResult.setActuator("LOCAL");
saveResult.setName(item.getName());
saveResult.setTriggerMode(triggerMode);
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (StringUtils.isNotEmpty(result.getUserId())) {
saveResult.setUserId(result.getUserId());
} else {
if (SessionUtils.getUser() != null) {
saveResult.setUserId(SessionUtils.getUser().getId());
}
}
saved = false;
}
String status = item.isSuccess() ? "success" : "error";
saveResult.setName(getName(type, item.getName(), status, saveResult.getCreateTime(), saveResult.getId()));
saveResult.setStatus(status);
saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime());
saveResult.setEndTime(item.getResponseResult().getResponseTime());
// 清空上次执行结果的内容只保留近五条结果
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) {
prevResult.setContent(null);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
if (!saved) {
apiDefinitionExecResultMapper.insert(saveResult);
} else {
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
}
apiDefinitionService.removeCache(result.getTestId());
if (StringUtils.isNotEmpty(result.getTestId())) {
MessageCache.caseExecResourceLock.remove(result.getTestId());
}
ApiDefinitionExecResult result = this.save(item, dto.getReportId(), dto.getConsole(), count, dto.getRunMode(), dto.getTestId(), isFirst);
if (result != null) {
// 发送通知
sendNotice(saveResult);
sendNotice(result);
}
});
isFirst = false;
}
});
}
}
@ -151,7 +96,6 @@ public class ApiDefinitionExecResultService {
if (apiTestCaseWithBLOBs == null) {
return;
}
BeanMap beanMap = new BeanMap(apiTestCaseWithBLOBs);
String event;
@ -186,182 +130,117 @@ public class ApiDefinitionExecResultService {
}
}
private String getName(String type, String id, String status, Long time, String resourceId) {
if (id.indexOf(DelimiterConstants.SEPARATOR.toString()) != -1) {
return id.substring(0, id.indexOf(DelimiterConstants.SEPARATOR.toString()));
}
private String editStatus(String type, String status, Long time, String reportId, String testId) {
if (StringUtils.equalsAnyIgnoreCase(type, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(id);
TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(testId);
ApiTestCaseWithBLOBs caseWithBLOBs = null;
if (testPlanApiCase != null) {
testPlanApiCaseService.setExecResult(id, status, time);
testPlanApiCaseService.setExecResult(testId, status, time);
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testPlanApiCase.getApiCaseId());
testPlanApiCase.setStatus(status);
testPlanApiCase.setUpdateTime(System.currentTimeMillis());
testPlanApiCaseService.updateByPrimaryKeySelective(testPlanApiCase);
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("更新测试计划用例【 " + testPlanApiCase.getId() + "");
}
TestCaseReviewApiCase testCaseReviewApiCase = testCaseReviewApiCaseMapper.selectByPrimaryKey(id);
}
TestCaseReviewApiCase testCaseReviewApiCase = testCaseReviewApiCaseMapper.selectByPrimaryKey(testId);
if (testCaseReviewApiCase != null) {
testCaseReviewApiCaseService.setExecResult(id, status, time);
testCaseReviewApiCaseService.setExecResult(testId, status, time);
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testCaseReviewApiCase.getApiCaseId());
testCaseReviewApiCase.setStatus(status);
testCaseReviewApiCase.setUpdateTime(System.currentTimeMillis());
testCaseReviewApiCaseService.updateByPrimaryKeySelective(testCaseReviewApiCase);
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("更新用例评审用例【 " + testCaseReviewApiCase.getId() + "");
}
}
if (caseWithBLOBs != null) {
return caseWithBLOBs.getName();
}
} else {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(id);
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(testId);
if (apiDefinition != null) {
return apiDefinition.getName();
} else {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(id);
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testId);
if (caseWithBLOBs != null) {
// 更新用例最后执行结果
caseWithBLOBs.setLastResultId(resourceId);
caseWithBLOBs.setLastResultId(reportId);
caseWithBLOBs.setStatus(status);
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("更新用例【 " + caseWithBLOBs.getId() + "");
}
return caseWithBLOBs.getName();
}
}
}
return id;
return testId;
}
/**
* 定时任务触发的保存逻辑
* 定时任务时userID要改为定时任务中的用户
*
* @param result
* @param type
*/
public void saveApiResultByScheduleTask(TestResult result, String testPlanReportId, String type) {
String saveResultType = type;
if (StringUtils.equalsAny(saveResultType, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
saveResultType = ApiRunMode.API_PLAN.name();
}
String finalSaveResultType = saveResultType;
public void saveApiResultByScheduleTask(List<RequestResult> requestResults, ResultDTO dto) {
Map<String, String> apiIdResultMap = new HashMap<>();
Map<String, String> caseReportMap = new HashMap<>();
String testId = result.getTestId();
if (testId.contains(":")) {
String[] testIdArr = testId.split(":");
if (testIdArr.length == 3) {
result.setTestId(testIdArr[2]);
} else {
result.setTestId(testIdArr[0]);
}
testPlanReportId = testIdArr[1];
}
String creator = TestPlanReportExecuteCatch.getCreator(testPlanReportId);
if (CollectionUtils.isNotEmpty(result.getScenarios())) {
result.getScenarios().forEach(scenarioResult -> {
final boolean[] isFirst = {true};
if (scenarioResult != null && CollectionUtils.isNotEmpty(scenarioResult.getRequestResults())) {
boolean isFirst = true;
int countExpectProcessResultCount = 0;
for (RequestResult resultItem : scenarioResult.getRequestResults()) {
if (CollectionUtils.isNotEmpty(requestResults)) {
for (RequestResult resultItem : requestResults) {
if (!StringUtils.startsWithAny(resultItem.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
countExpectProcessResultCount++;
}
}
final int expectProcessResultCount = countExpectProcessResultCount;
LoggerUtil.info("接收到定时任务执行结果【 " + requestResults.size() + "");
scenarioResult.getRequestResults().forEach(item -> {
for (RequestResult item : requestResults) {
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = MessageCache.caseExecResourceLock.get(result.getTestId());
if (saveResult == null) {
saveResult = apiDefinitionExecResultMapper.selectByPrimaryKey(result.getTestId());
}
item.getResponseResult().setConsole(result.getConsole());
boolean saved = true;
if (saveResult == null || expectProcessResultCount > 1) {
saveResult = new ApiDefinitionExecResult();
if (isFirst[0]) {
isFirst[0] = false;
saveResult.setId(result.getTestId());
} else {
saveResult.setId(UUID.randomUUID().toString());
}
saveResult.setActuator("LOCAL");
saveResult.setName(item.getName());
if (StringUtils.equals(type, ApiRunMode.JENKINS_API_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.API.name());
} else if (StringUtils.equals(type, ApiRunMode.MANUAL_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
} else {
saveResult.setTriggerMode(TriggerMode.SCHEDULE.name());
}
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (StringUtils.isNotEmpty(result.getUserId())) {
saveResult.setUserId(result.getUserId());
} else {
if (SessionUtils.getUser() != null) {
saveResult.setUserId(SessionUtils.getUser().getId());
}
}
saved = false;
}
ApiDefinitionExecResult saveResult = this.save(item, dto.getReportId(), dto.getConsole(), countExpectProcessResultCount, dto.getRunMode(), dto.getTestId(), isFirst);
String status = item.isSuccess() ? "success" : "error";
saveResult.setName(getName(type, item.getName(), status, saveResult.getCreateTime(), saveResult.getId()));
saveResult.setStatus(status);
saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime());
saveResult.setEndTime(item.getResponseResult().getResponseTime());
// 清空上次执行结果的内容只保留近五条结果
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) {
prevResult.setContent(null);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
if (!saved) {
apiDefinitionExecResultMapper.insert(saveResult);
} else {
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
}
apiDefinitionService.removeCache(result.getTestId());
if (StringUtils.isNotEmpty(result.getTestId())) {
MessageCache.caseExecResourceLock.remove(result.getTestId());
}
String caseId = item.getName();
if (StringUtils.equalsAny(type, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
TestPlanApiCase apiCase = testPlanApiCaseService.getById(caseId);
if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
TestPlanApiCase apiCase = testPlanApiCaseService.getById(dto.getTestId());
if (apiCase != null) {
apiCase.setStatus(status);
apiCase.setUpdateTime(System.currentTimeMillis());
testPlanApiCaseService.updateByPrimaryKeySelective(apiCase);
} else {
testPlanApiCaseService.setExecResult(caseId, status, item.getStartTime());
testCaseReviewApiCaseService.setExecResult(caseId, status, item.getStartTime());
}
if (StringUtils.isNotEmpty(caseId)) {
apiIdResultMap.put(caseId, item.isSuccess() ? TestPlanApiExecuteStatus.SUCCESS.name() : TestPlanApiExecuteStatus.FAILD.name());
} else {
testPlanApiCaseService.setExecResult(dto.getTestId(), status, item.getStartTime());
testCaseReviewApiCaseService.setExecResult(dto.getTestId(), status, item.getStartTime());
}
if (StringUtils.isNotEmpty(dto.getTestId())) {
apiIdResultMap.put(dto.getTestId(), item.isSuccess() ? TestPlanApiExecuteStatus.SUCCESS.name() : TestPlanApiExecuteStatus.FAILD.name());
}
//更新报告ID
caseReportMap.put(caseId, saveResult.getId());
caseReportMap.put(dto.getTestId(), saveResult.getId());
isFirst = false;
}
}
}
updateTestCaseStates(dto.getTestId());
testPlanLog.info("TestPlanReportId[" + dto.getTestPlanReportId() + "] APICASE OVER. API CASE STATUS:" + JSONObject.toJSONString(apiIdResultMap));
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(dto.getTestPlanReportId(), apiIdResultMap, null, null);
TestPlanReportExecuteCatch.updateTestPlanReport(dto.getTestPlanReportId(), caseReportMap, null);
}
});
/**
* 更新测试计划中, 关联接口测试的功能用例的状态
*/
public void updateTestCaseStates(String testPlanApiCaseId) {
try {
TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(testPlanApiCaseId);
if (testPlanApiCase == null) return;
ApiTestCaseWithBLOBs apiTestCase = apiTestCaseService.get(testPlanApiCase.getApiCaseId());
testPlanTestCaseService.updateTestCaseStates(apiTestCase.getId(), apiTestCase.getName(), testPlanApiCase.getTestPlanId(), TrackCount.TESTCASE);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
});
}
testPlanLog.info("TestPlanReportId[" + testPlanReportId + "] APICASE OVER. API CASE STATUS:" + JSONObject.toJSONString(apiIdResultMap));
TestPlanReportExecuteCatch.updateApiTestPlanExecuteInfo(testPlanReportId, apiIdResultMap, null, null);
TestPlanReportExecuteCatch.updateTestPlanReport(testPlanReportId, caseReportMap, null);
}
public void deleteByResourceId(String resourceId) {
@ -380,11 +259,8 @@ public class ApiDefinitionExecResultService {
}
public long countByTestCaseIDInProjectAndExecutedInThisWeek(String projectId) {
Map<String, Date> startAndEndDateInWeek = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date firstTime = startAndEndDateInWeek.get("firstTime");
Date lastTime = startAndEndDateInWeek.get("lastTime");
Date firstTime = DateUtils.getWeedFirstTimeAndLastTime(new Date()).get("firstTime");
Date lastTime = DateUtils.getWeedFirstTimeAndLastTime(new Date()).get("lastTime");
if (firstTime == null || lastTime == null) {
return 0;
} else {
@ -397,7 +273,7 @@ public class ApiDefinitionExecResultService {
}
public List<ExecutedCaseInfoResult> findFaliureCaseInfoByProjectIDAndLimitNumberInSevenDays(String projectId, int limitNumber) {
public List<ExecutedCaseInfoResult> findFailureCaseInfoByProjectIDAndLimitNumberInSevenDays(String projectId, int limitNumber) {
//获取7天之前的日期
Date startDay = DateUtils.dateSum(new Date(), -6);
@ -441,6 +317,49 @@ public class ApiDefinitionExecResultService {
}
}
private ApiDefinitionExecResult save(RequestResult item, String reportId, String console, int expectProcessResultCount, String type, String testId, boolean isFirst) {
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = new ApiDefinitionExecResult();
item.getResponseResult().setConsole(console);
saveResult.setId(reportId);
saveResult.setActuator("LOCAL");
saveResult.setName(item.getName());
if (StringUtils.equals(type, ApiRunMode.JENKINS_API_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.API.name());
} else if (StringUtils.equals(type, ApiRunMode.MANUAL_PLAN.name())) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
} else {
saveResult.setTriggerMode(TriggerMode.SCHEDULE.name());
}
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
if (SessionUtils.getUser() != null) {
saveResult.setUserId(SessionUtils.getUser().getId());
}
String status = item.isSuccess() ? "success" : "error";
saveResult.setName(editStatus(type, status, saveResult.getCreateTime(), saveResult.getId(), testId));
saveResult.setStatus(status);
saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime());
saveResult.setEndTime(item.getResponseResult().getResponseTime());
// 清空上次执行结果的内容只保留近五条结果
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) {
prevResult.setContent(null);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(saveResult);
return saveResult;
}
return null;
}
public Map<String, String> selectReportResultByReportIds(Collection<String> values) {
if (CollectionUtils.isEmpty(values)) {
return new HashMap<>();
@ -455,4 +374,8 @@ public class ApiDefinitionExecResultService {
return returnMap;
}
}
public ApiDefinitionExecResult getInfo(String id) {
return apiDefinitionExecResultMapper.selectByPrimaryKey(id);
}
}

View File

@ -13,20 +13,15 @@ import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImportParserFactory;
import io.metersphere.api.dto.definition.parse.Swagger3Parser;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.assertions.document.DocumentElement;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.RequestResult;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.api.exec.api.ApiExecuteService;
import io.metersphere.api.parse.ApiImportParser;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
@ -38,7 +33,7 @@ import io.metersphere.commons.json.JSONToDocumentUtils;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.controller.request.ScheduleRequest;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.RelationshipEdgeDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.SwaggerUrlImportJob;
@ -58,13 +53,12 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;
import sun.security.util.Cache;
import javax.annotation.Resource;
import java.net.MalformedURLException;
@ -90,7 +84,7 @@ public class ApiDefinitionService {
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private JMeterService jMeterService;
private ApiExecuteService apiExecuteService;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
@ -131,8 +125,6 @@ public class ApiDefinitionService {
@Lazy
private TestPlanService testPlanService;
private static Cache cache = Cache.newHardMemoryCache(0, 3600);
private ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
private ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
@ -288,7 +280,7 @@ public class ApiDefinitionService {
MockConfigService mockConfigService = CommonBeanFactory.getBean(MockConfigService.class);
mockConfigService.updateMockReturnMsgByApi(returnModel);
FileUtils.createBodyFiles(request.getRequest().getId(), bodyFiles);
return returnModel;
return getBLOBs(request.getId());
}
private void checkQuota() {
@ -514,11 +506,13 @@ public class ApiDefinitionService {
}
this.setModule(test);
apiDefinitionMapper.updateByPrimaryKeySelective(test);
// 同步修改用例
// 同步修改用例路径
if (StringUtils.equals(test.getProtocol(), "HTTP")) {
List<String> ids = new ArrayList<>();
ids.add(request.getId());
apiTestCaseService.updateByApiDefinitionId(ids, test.getPath(), test.getMethod(), test.getProtocol());
//saveFollows(test.getId(), request.getFollows());
}
return test;
}
@ -652,7 +646,7 @@ public class ApiDefinitionService {
if (order == null) {
order = ServiceUtils.getNextOrder(projectId, extApiDefinitionMapper::getLastOrder);
}
order = (order == null ? 0 : order) + 5000;
order = (order == null ? 0 : order) + ServiceUtils.ORDER_STEP;
currentApiOrder.set(order);
return order;
}
@ -662,7 +656,7 @@ public class ApiDefinitionService {
if (order == null) {
order = ServiceUtils.getNextOrder(projectId, extApiTestCaseMapper::getLastOrder);
}
order = (order == null ? 0 : order) + 5000;
order = (order == null ? 0 : order) + ServiceUtils.ORDER_STEP;
currentApiCaseOrder.set(order);
return order;
}
@ -819,6 +813,7 @@ public class ApiDefinitionService {
apiTestCase.setUpdateUserId(SessionUtils.getUserId());
if (sameCase == null) {
apiTestCase.setId(UUID.randomUUID().toString());
apiTestCase.setStatus("");
apiTestCase.setNum(apiTestCaseService.getNextNum(apiTestCase.getApiDefinitionId(), apiDefinition.getNum()));
apiTestCase.setCreateTime(System.currentTimeMillis());
apiTestCase.setUpdateTime(System.currentTimeMillis());
@ -859,111 +854,8 @@ public class ApiDefinitionService {
* @param bodyFiles
* @return
*/
public String run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
int count = 100;
BaseSystemConfigDTO dto = systemParameterService.getBaseInfo();
if (StringUtils.isNotEmpty(dto.getConcurrency())) {
count = Integer.parseInt(dto.getConcurrency());
}
if (request.getTestElement() != null && request.getTestElement().getHashTree().size() == 1 && request.getTestElement().getHashTree().get(0).getHashTree().size() > count) {
MSException.throwException("并发数量过大,请重新选择!");
}
ParameterConfig config = new ParameterConfig();
config.setProjectId(request.getProjectId());
Map<String, EnvironmentConfig> envConfig = new HashMap<>();
Map<String, String> map = request.getEnvironmentMap();
if (map != null && map.size() > 0) {
for (String key : map.keySet()) {
ApiTestEnvironmentWithBLOBs environment = environmentService.get(map.get(key));
if (environment != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
env.setApiEnvironmentid(environment.getId());
envConfig.put(key, env);
}
}
config.setConfig(envConfig);
}
if (CollectionUtils.isNotEmpty(bodyFiles)) {
List<MsHTTPSamplerProxy> requests = MsHTTPSamplerProxy.findHttpSampleFromHashTree(request.getTestElement());
// 单接口调试生成tmp临时目录
requests.forEach(item -> {
Body body = item.getBody();
String tmpFilePath = "tmp/" + UUID.randomUUID().toString();
body.setTmpFilePath(tmpFilePath);
FileUtils.copyBdyFile(item.getId(), tmpFilePath);
FileUtils.createBodyFiles(tmpFilePath, bodyFiles);
});
}
try {
//检查TCP数据结构等其他进行处理
tcpApiParamService.checkTestElement(request.getTestElement());
} catch (Exception e) {
}
HashTree hashTree = request.getTestElement().generateHashTree(config);
String runMode = ApiRunMode.DEFINITION.name();
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {
runMode = ApiRunMode.API_PLAN.name();
}
// 调用执行方法
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
jMeterService.runTest(request.getId(), request.getId(), runMode, null, request.getConfig());
} else {
jMeterService.runLocal(request.getId(), request.getConfig(), hashTree, request.getReportId(), runMode);
}
return request.getId();
}
public void addResult(TestResult res) {
if (res != null && CollectionUtils.isNotEmpty(res.getScenarios()) && res.getScenarios().get(0) != null && CollectionUtils.isNotEmpty(res.getScenarios().get(0).getRequestResults())) {
RequestResult result = null;
for (RequestResult itemResult : res.getScenarios().get(0).getRequestResults()) {
if (!StringUtils.startsWithAny(itemResult.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
result = itemResult;
break;
}
}
if (result.getName().indexOf(DelimiterConstants.SEPARATOR.toString()) != -1) {
result.setName(result.getName().substring(0, result.getName().indexOf(DelimiterConstants.SEPARATOR.toString())));
}
result.getResponseResult().setConsole(res.getConsole());
cache.put(res.getTestId(), result);
} else {
RequestResult result = new RequestResult();
result.getResponseResult().setConsole(res.getConsole());
cache.put(res.getTestId(), result);
//MSException.throwException(Translator.get("test_not_found"));
}
}
/**
* 获取零时执行结果报告
*
* @param testId
* @param test
* @return
*/
public APIReportResult getResult(String testId, String test) {
Object res = cache.get(testId);
if (res != null) {
cache.remove(testId);
APIReportResult reportResult = new APIReportResult();
reportResult.setContent(JSON.toJSONString(res));
return reportResult;
}
return null;
}
public void removeCache(String testId) {
if (StringUtils.isNotEmpty(testId)) {
cache.remove(testId);
}
public MsExecResponseDTO run(RunDefinitionRequest request, List<MultipartFile> bodyFiles) {
return apiExecuteService.debug(request, bodyFiles);
}
/**
@ -1023,10 +915,10 @@ public class ApiDefinitionService {
public ApiDefinitionImport apiTestImport(MultipartFile file, ApiTestImportRequest request) {
//通过platform获取对应的导入解析类型
ApiImportParser apiImportParser = ApiDefinitionImportParserFactory.getApiImportParser(request.getPlatform());
ApiImportParser runService = ApiDefinitionImportParserFactory.getApiImportParser(request.getPlatform());
ApiDefinitionImport apiImport = null;
try {
apiImport = (ApiDefinitionImport) Objects.requireNonNull(apiImportParser).parse(file == null ? null : file.getInputStream(), request);
apiImport = (ApiDefinitionImport) Objects.requireNonNull(runService).parse(file == null ? null : file.getInputStream(), request);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
String returnThrowException = e.getMessage();
@ -1143,6 +1035,9 @@ public class ApiDefinitionService {
if (!CollectionUtils.isEmpty(apiImport.getCases())) {
importMsCase(apiImport, sqlSession, request);
}
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
@ -1345,10 +1240,13 @@ public class ApiDefinitionService {
/*swagger定时导入*/
public void createSchedule(ScheduleRequest request) {
String config = setAuthParams(request);
/*保存swaggerUrl*/
SwaggerUrlProject swaggerUrlProject = new SwaggerUrlProject();
BeanUtils.copyBean(swaggerUrlProject, request);
swaggerUrlProject.setId(UUID.randomUUID().toString());
// 设置鉴权信息
swaggerUrlProject.setConfig(config);
scheduleService.addSwaggerUrlSchedule(swaggerUrlProject);
request.setResourceId(swaggerUrlProject.getId());
@ -1369,8 +1267,11 @@ public class ApiDefinitionService {
}
public void updateSchedule(ScheduleRequest request) {
String config = setAuthParams(request);
SwaggerUrlProject swaggerUrlProject = new SwaggerUrlProject();
BeanUtils.copyBean(swaggerUrlProject, request);
// 设置鉴权信息
swaggerUrlProject.setConfig(config);
scheduleService.updateSwaggerUrlSchedule(swaggerUrlProject);
// 只修改表达式和名称
Schedule schedule = new Schedule();
@ -1388,6 +1289,23 @@ public class ApiDefinitionService {
this.addOrUpdateSwaggerImportCronJob(request);
}
// 设置 SwaggerUrl 同步鉴权参数
public String setAuthParams(ScheduleRequest request) {
// list 数组转化成 json 字符串
JSONObject configObj = new JSONObject();
configObj.put("headers", request.getHeaders());
configObj.put("arguments", request.getArguments());
// 设置 BaseAuth 参数
if (request.getAuthManager() != null
&& StringUtils.isNotBlank(request.getAuthManager().getUsername())
&& StringUtils.isNotBlank(request.getAuthManager().getPassword())) {
configObj.put("authManager", request.getAuthManager());
}
return JSONObject.toJSONString(configObj);
}
/**
* 列表开关切换
*

View File

@ -9,6 +9,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -102,11 +103,19 @@ public class ApiEnvironmentRunningParamService {
sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);
ApiTestEnvironmentMapper batchMapper = sqlSession.getMapper(ApiTestEnvironmentMapper.class);
batchMapper.updateByPrimaryKeyWithBLOBs(apiTestEnvironmentWithBLOBs);
sqlSession.commit();
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}catch (Exception e){
sqlSession.rollback();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}finally {
sqlSession.close();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
}

View File

@ -0,0 +1,223 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.mapper.ApiExecutionQueueMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.ext.ExtApiExecutionQueueMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TestPlanReportStatus;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.ResultDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
public class ApiExecutionQueueService {
@Resource
private ApiExecutionQueueMapper queueMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private ExtApiExecutionQueueMapper extApiExecutionQueueMapper;
public DBTestQueue add(Object runObj, String poolId, String type, String reportId, String reportType, String runMode) {
ApiExecutionQueue executionQueue = new ApiExecutionQueue();
executionQueue.setId(UUID.randomUUID().toString());
executionQueue.setCreateTime(System.currentTimeMillis());
executionQueue.setPoolId(poolId);
executionQueue.setReportId(reportId);
executionQueue.setReportType(StringUtils.isNotEmpty(reportType) ? reportType : RunModeConstants.INDEPENDENCE.toString());
executionQueue.setRunMode(runMode);
queueMapper.insert(executionQueue);
DBTestQueue resQueue = new DBTestQueue();
BeanUtils.copyBean(resQueue, executionQueue);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiExecutionQueueDetailMapper batchMapper = sqlSession.getMapper(ApiExecutionQueueDetailMapper.class);
if (StringUtils.equals(type, ApiRunMode.API_PLAN.name())) {
final int[] sort = {0};
if (StringUtils.equals(reportType, RunModeConstants.PARALLEL.toString())) {
Map<String, TestPlanApiCase> runMap = (Map<String, TestPlanApiCase>) runObj;
runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(k, v.getId(), type, sort[0], executionQueue.getId(), null);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
batchMapper.insert(queue);
});
} else {
Map<TestPlanApiCase, ApiDefinitionExecResult> runMap = (Map<TestPlanApiCase, ApiDefinitionExecResult>) runObj;
runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(v.getId(), k.getId(), type, sort[0], executionQueue.getId(), null);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
batchMapper.insert(queue);
});
}
} else {
Map<String, RunModeDataDTO> runMap = (Map<String, RunModeDataDTO>) runObj;
final int[] sort = {0};
runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(k, v.getTestId(), type, sort[0], executionQueue.getId(), JSON.toJSONString(v.getPlanEnvMap()));
queue.setSort(sort[0]);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
batchMapper.insert(queue);
});
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
return resQueue;
}
private ApiExecutionQueueDetail detail(String reportId, String testId, String type, int sort, String queueId, String envMap) {
ApiExecutionQueueDetail queue = new ApiExecutionQueueDetail();
queue.setCreateTime(System.currentTimeMillis());
queue.setId(UUID.randomUUID().toString());
queue.setEvnMap(envMap);
queue.setReportId(reportId);
queue.setTestId(testId);
queue.setType(type);
queue.setSort(sort);
queue.setQueueId(queueId);
return queue;
}
public DBTestQueue edit(String id, String testId) {
ApiExecutionQueue executionQueue = queueMapper.selectByPrimaryKey(id);
if (executionQueue != null) {
DBTestQueue queue = new DBTestQueue();
BeanUtils.copyBean(queue, executionQueue);
if (executionQueue != null) {
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.setOrderByClause("sort asc");
example.createCriteria().andQueueIdEqualTo(id);
List<ApiExecutionQueueDetail> queues = executionQueueDetailMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(queues)) {
List<ApiExecutionQueueDetail> list = queues.stream().filter(item -> StringUtils.equals(item.getTestId(), testId)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) {
executionQueueDetailMapper.deleteByPrimaryKey(list.get(0).getId());
queues.remove(list.get(0));
BeanUtils.copyBean(queue, executionQueue);
if (CollectionUtils.isNotEmpty(queues)) {
queue.setQueue(queues.get(0));
}
}
if (CollectionUtils.isEmpty(queues)) {
queueMapper.deleteByPrimaryKey(id);
}
} else {
queueMapper.deleteByPrimaryKey(id);
}
}
return queue;
}
return null;
}
public void queueNext(ResultDTO dto) {
DBTestQueue executionQueue = this.edit(dto.getQueueId(), dto.getTestId());
if (executionQueue != null) {
LoggerUtil.info("开始处理执行队列:" + executionQueue.getId());
if (executionQueue.getQueue() != null && StringUtils.isNotEmpty(executionQueue.getQueue().getTestId())) {
if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) {
LoggerUtil.info("当前执行队列是:" + JSON.toJSONString(executionQueue.getQueue()));
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
}
} else {
if (StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportService.margeReport(dto.getReportId());
}
queueMapper.deleteByPrimaryKey(executionQueue.getId());
LoggerUtil.info("队列:" + dto.getQueueId() + " 执行结束");
}
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andQueueIdEqualTo(dto.getQueueId()).andTestIdEqualTo(dto.getTestId());
executionQueueDetailMapper.deleteByExample(example);
}
}
public void timeOut() {
final int SECOND_MILLIS = 1000;
final int MINUTE_MILLIS = 60 * SECOND_MILLIS;
long now = System.currentTimeMillis();
// 八分钟前的数据
now = now - 8 * MINUTE_MILLIS;
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andCreateTimeLessThan(now);
List<ApiExecutionQueueDetail> queueDetails = executionQueueDetailMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(queueDetails)) {
queueDetails.forEach(item -> {
if (StringUtils.equalsAny(item.getType(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name())) {
report.setStatus("timeout");
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
}
} else {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(item.getReportId());
if (result != null && StringUtils.equalsAny(result.getStatus(), TestPlanReportStatus.RUNNING.name())) {
result.setStatus("timeout");
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
}
}
executionQueueDetailMapper.deleteByPrimaryKey(item.getId());
});
}
ApiExecutionQueueExample queueDetailExample = new ApiExecutionQueueExample();
queueDetailExample.createCriteria().andReportTypeEqualTo(RunModeConstants.SET_REPORT.toString()).andCreateTimeLessThan(now);
List<ApiExecutionQueue> executionQueues = queueMapper.selectByExample(queueDetailExample);
if (CollectionUtils.isNotEmpty(executionQueues)) {
executionQueues.forEach(item -> {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
if (report != null && StringUtils.equalsAny(report.getStatus(), TestPlanReportStatus.RUNNING.name())) {
report.setStatus("timeout");
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
}
});
}
// 清除异常队列/一般是服务突然停止产生
extApiExecutionQueueMapper.delete();
}
}

View File

@ -4,7 +4,12 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.base.domain.*;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.JarConfig;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.ApiRunMode;
@ -15,7 +20,6 @@ import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.service.JarConfigService;
import io.metersphere.service.PluginService;
import io.metersphere.track.service.TestPlanApiCaseService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
@ -34,9 +38,7 @@ import java.util.zip.ZipOutputStream;
public class ApiJmeterFileService {
@Resource
private ApiAutomationService apiAutomationService;
@Resource
private TestPlanApiCaseService testPlanApiCaseService;
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
@ -56,11 +58,12 @@ public class ApiJmeterFileService {
return listBytesToZip(files);
}
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String testPlanScenarioId) {
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String reportType) {
Map<String, String> planEnvMap = new HashMap<>();
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
ApiScenarioWithBLOBs scenario = null;
if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
// 获取场景用例单独的执行环境
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(remoteTestId);
if (planApiScenario != null) {
String envType = planApiScenario.getEnvironmentType();
String environmentGroupId = planApiScenario.getEnvironmentGroupId();
@ -70,59 +73,32 @@ public class ApiJmeterFileService {
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.name()) && StringUtils.isNotBlank(environmentGroupId)) {
planEnvMap = environmentGroupProjectService.getEnvMap(environmentGroupId);
}
scenario = apiScenarioMapper.selectByPrimaryKey(planApiScenario.getApiScenarioId());
}
}
HashTree hashTree;
if (StringUtils.equalsAnyIgnoreCase(runMode, ApiRunMode.DEFINITION.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
String testId = remoteTestId;
if (remoteTestId.contains(":")) {
//执行测试计划案例时会有拼接ID,ID为 planTestCaseId:测试计划报告ID
testId = remoteTestId.split(":")[0];
}
hashTree = testPlanApiCaseService.generateHashTree(testId);
hashTree = apiScenarioSerialService.generateHashTree(remoteTestId);
} else {
ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(remoteTestId);
if (item == null) {
if (scenario == null) {
scenario = apiScenarioMapper.selectByPrimaryKey(remoteTestId);
}
if (scenario == null) {
MSException.throwException("未找到执行场景。");
}
if (StringUtils.isBlank(testPlanScenarioId)) {
String envType = item.getEnvironmentType();
String envJson = item.getEnvironmentJson();
String envGroupId = item.getEnvironmentGroupId();
if (!StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
String envType = scenario.getEnvironmentType();
String envJson = scenario.getEnvironmentJson();
String envGroupId = scenario.getEnvironmentGroupId();
if (StringUtils.equals(envType, EnvironmentType.JSON.name()) && StringUtils.isNotBlank(envJson)) {
planEnvMap = JSON.parseObject(envJson, Map.class);
} else if (StringUtils.equals(envType, EnvironmentType.GROUP.name()) && StringUtils.isNotBlank(envGroupId)) {
planEnvMap = environmentGroupProjectService.getEnvMap(envGroupId);
}
}
hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap);
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, reportId, planEnvMap, reportType);
}
return zipFilesToByteArray(remoteTestId, hashTree);
}
public byte[] downloadJmx(String runMode, String testId, String reportId, String testPlanScenarioId) {
Map<String, String> planEnvMap = new HashMap<>();
if (StringUtils.isNotEmpty(testPlanScenarioId)) {
// 获取场景用例单独的执行环境
TestPlanApiScenario planApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(testPlanScenarioId);
String environment = planApiScenario.getEnvironment();
if (StringUtils.isNotBlank(environment)) {
planEnvMap = JSON.parseObject(environment, Map.class);
}
}
HashTree hashTree = null;
if (ApiRunMode.DEFINITION.name().equals(runMode) || ApiRunMode.API_PLAN.name().equals(runMode)) {
hashTree = testPlanApiCaseService.generateHashTree(testId);
} else {
ApiScenarioWithBLOBs item = apiScenarioMapper.selectByPrimaryKey(testId);
if (item == null) {
MSException.throwException("未找到执行场景。");
}
hashTree = apiAutomationService.generateHashTree(item, reportId, planEnvMap);
}
//jMeterService.addBackendListener(reportId, hashTree);
String jmx = new MsTestPlan().getJmx(hashTree);
return jmx.getBytes(StandardCharsets.UTF_8);
return zipFilesToByteArray((reportId + "_" + remoteTestId), hashTree);
}
public byte[] downloadJmeterJar() {
@ -254,11 +230,6 @@ 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();

Some files were not shown because too many files have changed in this diff Show More