merge: 合并dev最新修改
This commit is contained in:
commit
3448c90c10
|
@ -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}
|
||||
|
|
219
backend/pom.xml
219
backend/pom.xml
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<>();
|
||||
}
|
||||
}
|
|
@ -30,4 +30,5 @@ public class ApiScenarioDTO extends ApiScenarioWithBLOBs {
|
|||
*/
|
||||
private String env;
|
||||
private Map<String, String> environmentMap;
|
||||
private String creator;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
// 单独接口执行
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -11,4 +11,5 @@ public class PostmanUrl {
|
|||
private String protocol;
|
||||
private String port;
|
||||
private List<PostmanKeyValue> query;
|
||||
private List<PostmanKeyValue> variable;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public class HttpConfig {
|
|||
private MsJSR223PostProcessor postProcessor;
|
||||
private GlobalScriptConfig globalScriptConfig;
|
||||
private ApiModuleMapper apiModuleMapper;
|
||||
private String description;
|
||||
|
||||
|
||||
public HttpConfig initHttpConfig(HttpConfigCondition configCondition) {
|
||||
|
|
|
@ -16,4 +16,5 @@ public class TCPConfig {
|
|||
private String eolByte = "";
|
||||
private String username = "";
|
||||
private String password = "";
|
||||
private String description = "";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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() + " 】执行完成");
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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(";");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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<>();
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import io.metersphere.dto.RequestResult;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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里去掉路径; 2。elementProp->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);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 列表开关切换
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue