Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
5c04697c86
|
@ -162,9 +162,15 @@
|
|||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<groupId>com.fit2cloud</groupId>
|
||||
<artifactId>quartz-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>0.0.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- LDAP Module -->
|
||||
|
@ -288,5 +294,43 @@
|
|||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jcenter-snapshots</id>
|
||||
<name>jcenter</name>
|
||||
<url>https://jcenter.bintray.com/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>fit2cloud-enterprise-release</id>
|
||||
<name>Fit2Cloud Enterprise Release</name>
|
||||
<url>http://repository.fit2cloud.com/content/repositories/fit2cloud-enterprise-release/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>fit2cloud</id>
|
||||
<name>fit2cloud</name>
|
||||
<url>http://repository.fit2cloud.com/content/groups/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
</project>
|
|
@ -8,6 +8,7 @@ import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
|
||||
@ServletComponentScan
|
||||
|
@ -15,6 +16,7 @@ import org.springframework.context.annotation.PropertySource;
|
|||
KafkaProperties.class,
|
||||
JmeterProperties.class
|
||||
})
|
||||
@EnableScheduling
|
||||
@PropertySource(value = {"file:/opt/metersphere/conf/metersphere.properties"}, encoding = "UTF-8", ignoreResourceNotFound = true)
|
||||
public class Application {
|
||||
public static void main(String[] args) {
|
||||
|
|
|
@ -22,4 +22,6 @@ public class SaveAPITestRequest {
|
|||
private String userId;
|
||||
|
||||
private Schedule schedule;
|
||||
|
||||
private String triggerMode;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode;
|
|||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class ExtractRegex extends ExtractCommon {
|
||||
private String useHeaders;
|
||||
public ExtractRegex() {
|
||||
setType(ExtractType.REGEX);
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class APIReportService {
|
|||
apiTestReportMapper.updateByPrimaryKeySelective(report);
|
||||
}
|
||||
|
||||
public String create(ApiTest test) {
|
||||
public String create(ApiTest test, String triggerMode) {
|
||||
ApiTestReport running = getRunningReport(test.getId());
|
||||
if (running != null) {
|
||||
return running.getId();
|
||||
|
@ -104,6 +104,7 @@ public class APIReportService {
|
|||
report.setId(UUID.randomUUID().toString());
|
||||
report.setTestId(test.getId());
|
||||
report.setName(test.getName());
|
||||
report.setTriggerMode(triggerMode);
|
||||
report.setDescription(test.getDescription());
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
|
|
|
@ -14,35 +14,24 @@ import io.metersphere.commons.constants.ScheduleGroup;
|
|||
import io.metersphere.commons.constants.ScheduleType;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
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.i18n.Translator;
|
||||
import io.metersphere.job.QuartzManager;
|
||||
import io.metersphere.job.sechedule.ApiTestJob;
|
||||
import io.metersphere.job.sechedule.PerformanceTestJob;
|
||||
import io.metersphere.service.FileService;
|
||||
import io.metersphere.service.ScheduleService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.TriggerKey;
|
||||
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;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -148,7 +137,7 @@ public class APITestService {
|
|||
if (SessionUtils.getUser() == null) {
|
||||
apiTest.setUserId(request.getUserId());
|
||||
}
|
||||
String reportId = apiReportService.create(apiTest);
|
||||
String reportId = apiReportService.create(apiTest, request.getTriggerMode());
|
||||
changeStatus(request.getId(), APITestStatus.Running);
|
||||
|
||||
jMeterService.run(request.getId(), is);
|
||||
|
|
|
@ -31,5 +31,7 @@ public class TestCase implements Serializable {
|
|||
|
||||
private String testId;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -385,142 +385,142 @@ public class TestCaseExample {
|
|||
}
|
||||
|
||||
public Criteria andNameIsNull() {
|
||||
addCriterion("name is null");
|
||||
addCriterion("`name` is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameIsNotNull() {
|
||||
addCriterion("name is not null");
|
||||
addCriterion("`name` is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameEqualTo(String value) {
|
||||
addCriterion("name =", value, "name");
|
||||
addCriterion("`name` =", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameNotEqualTo(String value) {
|
||||
addCriterion("name <>", value, "name");
|
||||
addCriterion("`name` <>", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameGreaterThan(String value) {
|
||||
addCriterion("name >", value, "name");
|
||||
addCriterion("`name` >", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("name >=", value, "name");
|
||||
addCriterion("`name` >=", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameLessThan(String value) {
|
||||
addCriterion("name <", value, "name");
|
||||
addCriterion("`name` <", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameLessThanOrEqualTo(String value) {
|
||||
addCriterion("name <=", value, "name");
|
||||
addCriterion("`name` <=", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameLike(String value) {
|
||||
addCriterion("name like", value, "name");
|
||||
addCriterion("`name` like", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameNotLike(String value) {
|
||||
addCriterion("name not like", value, "name");
|
||||
addCriterion("`name` not like", value, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameIn(List<String> values) {
|
||||
addCriterion("name in", values, "name");
|
||||
addCriterion("`name` in", values, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameNotIn(List<String> values) {
|
||||
addCriterion("name not in", values, "name");
|
||||
addCriterion("`name` not in", values, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameBetween(String value1, String value2) {
|
||||
addCriterion("name between", value1, value2, "name");
|
||||
addCriterion("`name` between", value1, value2, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andNameNotBetween(String value1, String value2) {
|
||||
addCriterion("name not between", value1, value2, "name");
|
||||
addCriterion("`name` not between", value1, value2, "name");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeIsNull() {
|
||||
addCriterion("type is null");
|
||||
addCriterion("`type` is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeIsNotNull() {
|
||||
addCriterion("type is not null");
|
||||
addCriterion("`type` is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeEqualTo(String value) {
|
||||
addCriterion("type =", value, "type");
|
||||
addCriterion("`type` =", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeNotEqualTo(String value) {
|
||||
addCriterion("type <>", value, "type");
|
||||
addCriterion("`type` <>", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeGreaterThan(String value) {
|
||||
addCriterion("type >", value, "type");
|
||||
addCriterion("`type` >", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("type >=", value, "type");
|
||||
addCriterion("`type` >=", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeLessThan(String value) {
|
||||
addCriterion("type <", value, "type");
|
||||
addCriterion("`type` <", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeLessThanOrEqualTo(String value) {
|
||||
addCriterion("type <=", value, "type");
|
||||
addCriterion("`type` <=", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeLike(String value) {
|
||||
addCriterion("type like", value, "type");
|
||||
addCriterion("`type` like", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeNotLike(String value) {
|
||||
addCriterion("type not like", value, "type");
|
||||
addCriterion("`type` not like", value, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeIn(List<String> values) {
|
||||
addCriterion("type in", values, "type");
|
||||
addCriterion("`type` in", values, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeNotIn(List<String> values) {
|
||||
addCriterion("type not in", values, "type");
|
||||
addCriterion("`type` not in", values, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeBetween(String value1, String value2) {
|
||||
addCriterion("type between", value1, value2, "type");
|
||||
addCriterion("`type` between", value1, value2, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTypeNotBetween(String value1, String value2) {
|
||||
addCriterion("type not between", value1, value2, "type");
|
||||
addCriterion("`type` not between", value1, value2, "type");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
|
@ -665,72 +665,72 @@ public class TestCaseExample {
|
|||
}
|
||||
|
||||
public Criteria andMethodIsNull() {
|
||||
addCriterion("method is null");
|
||||
addCriterion("`method` is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodIsNotNull() {
|
||||
addCriterion("method is not null");
|
||||
addCriterion("`method` is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodEqualTo(String value) {
|
||||
addCriterion("method =", value, "method");
|
||||
addCriterion("`method` =", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodNotEqualTo(String value) {
|
||||
addCriterion("method <>", value, "method");
|
||||
addCriterion("`method` <>", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodGreaterThan(String value) {
|
||||
addCriterion("method >", value, "method");
|
||||
addCriterion("`method` >", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("method >=", value, "method");
|
||||
addCriterion("`method` >=", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodLessThan(String value) {
|
||||
addCriterion("method <", value, "method");
|
||||
addCriterion("`method` <", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodLessThanOrEqualTo(String value) {
|
||||
addCriterion("method <=", value, "method");
|
||||
addCriterion("`method` <=", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodLike(String value) {
|
||||
addCriterion("method like", value, "method");
|
||||
addCriterion("`method` like", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodNotLike(String value) {
|
||||
addCriterion("method not like", value, "method");
|
||||
addCriterion("`method` not like", value, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodIn(List<String> values) {
|
||||
addCriterion("method in", values, "method");
|
||||
addCriterion("`method` in", values, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodNotIn(List<String> values) {
|
||||
addCriterion("method not in", values, "method");
|
||||
addCriterion("`method` not in", values, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodBetween(String value1, String value2) {
|
||||
addCriterion("method between", value1, value2, "method");
|
||||
addCriterion("`method` between", value1, value2, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andMethodNotBetween(String value1, String value2) {
|
||||
addCriterion("method not between", value1, value2, "method");
|
||||
addCriterion("`method` not between", value1, value2, "method");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
|
@ -993,6 +993,66 @@ public class TestCaseExample {
|
|||
addCriterion("test_id not between", value1, value2, "testId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortIsNull() {
|
||||
addCriterion("sort is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortIsNotNull() {
|
||||
addCriterion("sort is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortEqualTo(Integer value) {
|
||||
addCriterion("sort =", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortNotEqualTo(Integer value) {
|
||||
addCriterion("sort <>", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortGreaterThan(Integer value) {
|
||||
addCriterion("sort >", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortGreaterThanOrEqualTo(Integer value) {
|
||||
addCriterion("sort >=", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortLessThan(Integer value) {
|
||||
addCriterion("sort <", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortLessThanOrEqualTo(Integer value) {
|
||||
addCriterion("sort <=", value, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortIn(List<Integer> values) {
|
||||
addCriterion("sort in", values, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortNotIn(List<Integer> values) {
|
||||
addCriterion("sort not in", values, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortBetween(Integer value1, Integer value2) {
|
||||
addCriterion("sort between", value1, value2, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSortNotBetween(Integer value1, Integer value2) {
|
||||
addCriterion("sort not between", value1, value2, "sort");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
||||
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
|
||||
<result column="test_id" jdbcType="VARCHAR" property="testId" />
|
||||
<result column="sort" jdbcType="INTEGER" property="sort" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseWithBLOBs">
|
||||
<result column="remark" jdbcType="LONGVARCHAR" property="remark" />
|
||||
|
@ -79,8 +80,8 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, node_id, node_path, project_id, name, type, maintainer, priority, method, prerequisite,
|
||||
create_time, update_time, test_id
|
||||
id, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`,
|
||||
prerequisite, create_time, update_time, test_id, sort
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
remark, steps
|
||||
|
@ -135,17 +136,17 @@
|
|||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
|
||||
insert into test_case (id, node_id, node_path,
|
||||
project_id, name, type,
|
||||
maintainer, priority, method,
|
||||
project_id, `name`, `type`,
|
||||
maintainer, priority, `method`,
|
||||
prerequisite, create_time, update_time,
|
||||
test_id, remark, steps
|
||||
)
|
||||
test_id, sort, remark,
|
||||
steps)
|
||||
values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR},
|
||||
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
|
||||
#{maintainer,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR},
|
||||
#{prerequisite,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
|
||||
#{testId,jdbcType=VARCHAR}, #{remark,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR}
|
||||
)
|
||||
#{testId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{remark,jdbcType=LONGVARCHAR},
|
||||
#{steps,jdbcType=LONGVARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
|
||||
insert into test_case
|
||||
|
@ -163,10 +164,10 @@
|
|||
project_id,
|
||||
</if>
|
||||
<if test="name != null">
|
||||
name,
|
||||
`name`,
|
||||
</if>
|
||||
<if test="type != null">
|
||||
type,
|
||||
`type`,
|
||||
</if>
|
||||
<if test="maintainer != null">
|
||||
maintainer,
|
||||
|
@ -175,7 +176,7 @@
|
|||
priority,
|
||||
</if>
|
||||
<if test="method != null">
|
||||
method,
|
||||
`method`,
|
||||
</if>
|
||||
<if test="prerequisite != null">
|
||||
prerequisite,
|
||||
|
@ -189,6 +190,9 @@
|
|||
<if test="testId != null">
|
||||
test_id,
|
||||
</if>
|
||||
<if test="sort != null">
|
||||
sort,
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
remark,
|
||||
</if>
|
||||
|
@ -236,6 +240,9 @@
|
|||
<if test="testId != null">
|
||||
#{testId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="sort != null">
|
||||
#{sort,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
#{remark,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
|
@ -266,10 +273,10 @@
|
|||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.name != null">
|
||||
name = #{record.name,jdbcType=VARCHAR},
|
||||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.type != null">
|
||||
type = #{record.type,jdbcType=VARCHAR},
|
||||
`type` = #{record.type,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.maintainer != null">
|
||||
maintainer = #{record.maintainer,jdbcType=VARCHAR},
|
||||
|
@ -278,7 +285,7 @@
|
|||
priority = #{record.priority,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.method != null">
|
||||
method = #{record.method,jdbcType=VARCHAR},
|
||||
`method` = #{record.method,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.prerequisite != null">
|
||||
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
|
||||
|
@ -292,6 +299,9 @@
|
|||
<if test="record.testId != null">
|
||||
test_id = #{record.testId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.sort != null">
|
||||
sort = #{record.sort,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="record.remark != null">
|
||||
remark = #{record.remark,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
|
@ -309,15 +319,16 @@
|
|||
node_id = #{record.nodeId,jdbcType=VARCHAR},
|
||||
node_path = #{record.nodePath,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
name = #{record.name,jdbcType=VARCHAR},
|
||||
type = #{record.type,jdbcType=VARCHAR},
|
||||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
`type` = #{record.type,jdbcType=VARCHAR},
|
||||
maintainer = #{record.maintainer,jdbcType=VARCHAR},
|
||||
priority = #{record.priority,jdbcType=VARCHAR},
|
||||
method = #{record.method,jdbcType=VARCHAR},
|
||||
`method` = #{record.method,jdbcType=VARCHAR},
|
||||
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
test_id = #{record.testId,jdbcType=VARCHAR},
|
||||
sort = #{record.sort,jdbcType=INTEGER},
|
||||
remark = #{record.remark,jdbcType=LONGVARCHAR},
|
||||
steps = #{record.steps,jdbcType=LONGVARCHAR}
|
||||
<if test="_parameter != null">
|
||||
|
@ -330,15 +341,16 @@
|
|||
node_id = #{record.nodeId,jdbcType=VARCHAR},
|
||||
node_path = #{record.nodePath,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
name = #{record.name,jdbcType=VARCHAR},
|
||||
type = #{record.type,jdbcType=VARCHAR},
|
||||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
`type` = #{record.type,jdbcType=VARCHAR},
|
||||
maintainer = #{record.maintainer,jdbcType=VARCHAR},
|
||||
priority = #{record.priority,jdbcType=VARCHAR},
|
||||
method = #{record.method,jdbcType=VARCHAR},
|
||||
`method` = #{record.method,jdbcType=VARCHAR},
|
||||
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
update_time = #{record.updateTime,jdbcType=BIGINT},
|
||||
test_id = #{record.testId,jdbcType=VARCHAR}
|
||||
test_id = #{record.testId,jdbcType=VARCHAR},
|
||||
sort = #{record.sort,jdbcType=INTEGER}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -356,10 +368,10 @@
|
|||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="name != null">
|
||||
name = #{name,jdbcType=VARCHAR},
|
||||
`name` = #{name,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="type != null">
|
||||
type = #{type,jdbcType=VARCHAR},
|
||||
`type` = #{type,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="maintainer != null">
|
||||
maintainer = #{maintainer,jdbcType=VARCHAR},
|
||||
|
@ -368,7 +380,7 @@
|
|||
priority = #{priority,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="method != null">
|
||||
method = #{method,jdbcType=VARCHAR},
|
||||
`method` = #{method,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="prerequisite != null">
|
||||
prerequisite = #{prerequisite,jdbcType=VARCHAR},
|
||||
|
@ -382,6 +394,9 @@
|
|||
<if test="testId != null">
|
||||
test_id = #{testId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="sort != null">
|
||||
sort = #{sort,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
remark = #{remark,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
|
@ -396,15 +411,16 @@
|
|||
set node_id = #{nodeId,jdbcType=VARCHAR},
|
||||
node_path = #{nodePath,jdbcType=VARCHAR},
|
||||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
name = #{name,jdbcType=VARCHAR},
|
||||
type = #{type,jdbcType=VARCHAR},
|
||||
`name` = #{name,jdbcType=VARCHAR},
|
||||
`type` = #{type,jdbcType=VARCHAR},
|
||||
maintainer = #{maintainer,jdbcType=VARCHAR},
|
||||
priority = #{priority,jdbcType=VARCHAR},
|
||||
method = #{method,jdbcType=VARCHAR},
|
||||
`method` = #{method,jdbcType=VARCHAR},
|
||||
prerequisite = #{prerequisite,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
test_id = #{testId,jdbcType=VARCHAR},
|
||||
sort = #{sort,jdbcType=INTEGER},
|
||||
remark = #{remark,jdbcType=LONGVARCHAR},
|
||||
steps = #{steps,jdbcType=LONGVARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
|
@ -414,15 +430,16 @@
|
|||
set node_id = #{nodeId,jdbcType=VARCHAR},
|
||||
node_path = #{nodePath,jdbcType=VARCHAR},
|
||||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
name = #{name,jdbcType=VARCHAR},
|
||||
type = #{type,jdbcType=VARCHAR},
|
||||
`name` = #{name,jdbcType=VARCHAR},
|
||||
`type` = #{type,jdbcType=VARCHAR},
|
||||
maintainer = #{maintainer,jdbcType=VARCHAR},
|
||||
priority = #{priority,jdbcType=VARCHAR},
|
||||
method = #{method,jdbcType=VARCHAR},
|
||||
`method` = #{method,jdbcType=VARCHAR},
|
||||
prerequisite = #{prerequisite,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
update_time = #{updateTime,jdbcType=BIGINT},
|
||||
test_id = #{testId,jdbcType=VARCHAR}
|
||||
test_id = #{testId,jdbcType=VARCHAR},
|
||||
sort = #{sort,jdbcType=INTEGER}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<select id="list" resultMap="BaseResultMap">
|
||||
SELECT t.name AS test_name,
|
||||
r.name, r.description, r.id, r.test_id, r.create_time, r.update_time, r.status,
|
||||
r.name, r.description, r.id, r.test_id, r.create_time, r.update_time, r.status, r.trigger_mode,
|
||||
project.name AS project_name, user.name AS user_name
|
||||
FROM api_test_report r JOIN api_test t ON r.test_id = t.id
|
||||
LEFT JOIN project ON project.id = t.project_id
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<select id="getReportList" resultType="io.metersphere.dto.ReportDTO">
|
||||
select ltr.id, ltr.name, ltr.test_id as testId, ltr.description, user.name as userName, project.name as
|
||||
projectName,
|
||||
projectName, ltr.trigger_mode,
|
||||
ltr.create_time as createTime, ltr.update_time as updateTime, ltr.status as status, lt.name as testName
|
||||
from load_test_report ltr
|
||||
join load_test lt on ltr.test_id = lt.id
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ReportKeys {
|
||||
LoadChart, ResponseTimeChart, Errors, ErrorsTop5, RequestStatistics, Overview, TimeInfo
|
||||
LoadChart, ResponseTimeChart, Errors, ErrorsTop5, RequestStatistics, Overview, TimeInfo, ResultStatus
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ReportTriggerMode {
|
||||
MANUAL,SCHEDULE,API
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package io.metersphere.config;
|
||||
|
||||
import com.fit2cloud.autoconfigure.QuartzProperties;
|
||||
import com.fit2cloud.quartz.QuartzInstanceIdGenerator;
|
||||
import com.fit2cloud.quartz.SchedulerStarter;
|
||||
import com.fit2cloud.quartz.service.QuartzManageService;
|
||||
import com.fit2cloud.quartz.util.QuartzBeanFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(QuartzProperties.class)
|
||||
@ConditionalOnClass(DataSource.class)
|
||||
@AutoConfigureAfter(DataSource.class)
|
||||
public class QuartzAutoConfiguration {
|
||||
private DataSource dataSource;
|
||||
|
||||
private QuartzProperties properties;
|
||||
|
||||
public QuartzAutoConfiguration(ObjectProvider<DataSource> dataSourceProvider, QuartzProperties properties) {
|
||||
this.dataSource = dataSourceProvider.getIfAvailable();
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
|
||||
public SchedulerStarter schedulerStarter() {
|
||||
return new SchedulerStarter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
|
||||
public QuartzBeanFactory quartzBeanFactory() {
|
||||
return new QuartzBeanFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
|
||||
public QuartzManageService quartzManageService() {
|
||||
return new QuartzManageService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
|
||||
public TimeZone quartzTimeZone() {
|
||||
return TimeZone.getTimeZone(properties.getTimeZone());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(DataSource.class)
|
||||
@ConditionalOnProperty(prefix = "quartz", value = "enabled", havingValue = "true")
|
||||
public SchedulerFactoryBean clusterSchedulerFactoryBean() {
|
||||
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
|
||||
schedulerFactoryBean.setDataSource(this.dataSource);
|
||||
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContextKey");
|
||||
schedulerFactoryBean.setOverwriteExistingJobs(true);
|
||||
schedulerFactoryBean.setStartupDelay(60);// 60 秒之后开始执行定时任务
|
||||
Properties props = new Properties();
|
||||
props.put("org.quartz.scheduler.instanceName", "clusterScheduler");
|
||||
props.put("org.quartz.scheduler.instanceId", "AUTO"); // 集群下的instanceId 必须唯一
|
||||
props.put("org.quartz.scheduler.instanceIdGenerator.class", QuartzInstanceIdGenerator.class.getName());// instanceId 生成的方式
|
||||
props.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
|
||||
props.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
|
||||
props.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
|
||||
props.put("org.quartz.jobStore.isClustered", "true");
|
||||
props.put("org.quartz.jobStore.clusterCheckinInterval", "20000");
|
||||
props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
|
||||
props.put("org.quartz.threadPool.threadCount", "10");
|
||||
props.put("org.quartz.threadPool.threadPriority", "5");
|
||||
props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true");
|
||||
schedulerFactoryBean.setQuartzProperties(props);
|
||||
if (!StringUtils.isEmpty(this.properties.getSchedulerName())) {
|
||||
schedulerFactoryBean.setBeanName(this.properties.getSchedulerName());
|
||||
}
|
||||
return schedulerFactoryBean;
|
||||
}
|
||||
}
|
|
@ -19,4 +19,5 @@ public class ReportDTO {
|
|||
private String projectId;
|
||||
private String projectName;
|
||||
private String userName;
|
||||
private String triggerMode;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.metersphere.i18n.Translator;
|
|||
import io.metersphere.track.service.TestCaseService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
@ -72,6 +73,8 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
|||
return;
|
||||
}
|
||||
|
||||
Collections.reverse(list);
|
||||
|
||||
List<TestCaseWithBLOBs> result = list.stream()
|
||||
.map(item -> this.convert2TestCase(item))
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -2,12 +2,13 @@ package io.metersphere.job.sechedule;
|
|||
|
||||
import io.metersphere.api.dto.SaveAPITestRequest;
|
||||
import io.metersphere.api.service.APITestService;
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.job.QuartzManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.*;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
|
||||
public class ApiTestJob extends MsScheduleJob {
|
||||
|
||||
|
@ -18,15 +19,11 @@ public class ApiTestJob extends MsScheduleJob {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
if (StringUtils.isBlank(resourceId)) {
|
||||
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
|
||||
}
|
||||
LogUtil.info("ApiTestSchedule Running: " + resourceId);
|
||||
LogUtil.info("CronExpression: " + expression);
|
||||
void businessExecute(JobExecutionContext context) {
|
||||
SaveAPITestRequest request = new SaveAPITestRequest();
|
||||
request.setId(resourceId);
|
||||
request.setUserId(userId);
|
||||
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||
apiTestService.run(request);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package io.metersphere.job.sechedule;
|
||||
|
||||
import org.quartz.Job;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.quartz.*;
|
||||
|
||||
public abstract class MsScheduleJob implements Job{
|
||||
public abstract class MsScheduleJob implements Job {
|
||||
|
||||
protected String resourceId;
|
||||
|
||||
|
@ -10,15 +11,19 @@ public abstract class MsScheduleJob implements Job{
|
|||
|
||||
protected String expression;
|
||||
|
||||
public void setResourceId(String resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
|
||||
JobKey jobKey = context.getTrigger().getJobKey();
|
||||
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||
this.resourceId = jobDataMap.getString("resourceId");
|
||||
this.userId = jobDataMap.getString("userId");
|
||||
this.expression = jobDataMap.getString("expression");
|
||||
|
||||
LogUtil.info(jobKey.getGroup()+ " Running: " + resourceId);
|
||||
LogUtil.info("CronExpression: " + expression);
|
||||
businessExecute(context);
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
abstract void businessExecute(JobExecutionContext context);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
package io.metersphere.job.sechedule;
|
||||
|
||||
import io.metersphere.commons.constants.ReportTriggerMode;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.job.QuartzManager;
|
||||
import io.metersphere.performance.service.PerformanceTestService;
|
||||
import io.metersphere.track.request.testplan.RunTestPlanRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
|
@ -21,17 +18,12 @@ public class PerformanceTestJob extends MsScheduleJob {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
if (StringUtils.isBlank(resourceId)) {
|
||||
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
|
||||
}
|
||||
LogUtil.info("PerformanceTestSchedule Running: " + resourceId);
|
||||
LogUtil.info("CronExpression: " + expression);
|
||||
void businessExecute(JobExecutionContext context) {
|
||||
RunTestPlanRequest request = new RunTestPlanRequest();
|
||||
request.setId(resourceId);
|
||||
request.setUserId(userId);
|
||||
request.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||
performanceTestService.run(request);
|
||||
|
||||
}
|
||||
|
||||
public static JobKey getJobKey(String testId) {
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package io.metersphere.job;
|
||||
package io.metersphere.job.sechedule;
|
||||
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.StdSchedulerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
public class QuartzManager {
|
||||
import javax.annotation.Resource;
|
||||
|
||||
public static StdSchedulerFactory sf = new StdSchedulerFactory();
|
||||
@Component
|
||||
public class ScheduleManager {
|
||||
|
||||
@Resource
|
||||
private Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* 添加 simpleJob
|
||||
|
@ -17,24 +21,28 @@ public class QuartzManager {
|
|||
* @param jobDataMap
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public static void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime,
|
||||
JobDataMap jobDataMap) throws SchedulerException {
|
||||
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime,
|
||||
JobDataMap jobDataMap) throws SchedulerException {
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
JobBuilder jobBuilder = JobBuilder.newJob(cls).withIdentity(jobKey);
|
||||
|
||||
JobDetail jd = JobBuilder.newJob(cls).withIdentity(jobKey).setJobData(jobDataMap).build();
|
||||
if (jobDataMap != null) {
|
||||
jobBuilder.usingJobData(jobDataMap);
|
||||
}
|
||||
|
||||
JobDetail jd = jobBuilder.build();
|
||||
|
||||
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
|
||||
.withSchedule(
|
||||
SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(repeatIntervalTime).repeatForever())
|
||||
.startNow().build();
|
||||
|
||||
sched.scheduleJob(jd, trigger);
|
||||
scheduler.scheduleJob(jd, trigger);
|
||||
|
||||
try {
|
||||
|
||||
if (!sched.isShutdown()) {
|
||||
sched.start();
|
||||
if (!scheduler.isShutdown()) {
|
||||
scheduler.start();
|
||||
}
|
||||
|
||||
} catch (SchedulerException e) {
|
||||
|
@ -44,8 +52,8 @@ public class QuartzManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime) throws SchedulerException {
|
||||
addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime);
|
||||
public void addSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class<? extends Job> cls, int repeatIntervalTime) throws SchedulerException {
|
||||
addSimpleJob(jobKey, triggerKey, cls, repeatIntervalTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,11 +64,14 @@ public class QuartzManager {
|
|||
* @param cron
|
||||
* @param jobDataMap
|
||||
*/
|
||||
public static void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) {
|
||||
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) {
|
||||
try {
|
||||
|
||||
LogUtil.info("addCronJob: " + triggerKey.getName() + "," + triggerKey.getGroup());
|
||||
|
||||
JobBuilder jobBuilder = JobBuilder.newJob(jobClass).withIdentity(jobKey);
|
||||
if (jobDataMap != null) {
|
||||
jobBuilder.setJobData(jobDataMap);
|
||||
jobBuilder.usingJobData(jobDataMap);
|
||||
}
|
||||
JobDetail jobDetail = jobBuilder.build();
|
||||
|
||||
|
@ -74,12 +85,10 @@ public class QuartzManager {
|
|||
|
||||
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
|
||||
sched.scheduleJob(jobDetail, trigger);
|
||||
|
||||
if (!sched.isShutdown()) {
|
||||
sched.start();
|
||||
if (!scheduler.isShutdown()) {
|
||||
scheduler.start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
|
@ -87,7 +96,7 @@ public class QuartzManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) {
|
||||
public void addCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) {
|
||||
addCronJob(jobKey, triggerKey, jobClass, cron, null);
|
||||
}
|
||||
|
||||
|
@ -97,14 +106,12 @@ public class QuartzManager {
|
|||
* @param cron
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public static void modifyCronJobTime(TriggerKey triggerKey, String cron) throws SchedulerException {
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
public void modifyCronJobTime(TriggerKey triggerKey, String cron) throws SchedulerException {
|
||||
|
||||
LogUtil.info("modifyCronJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
|
||||
|
||||
try {
|
||||
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
|
||||
if (trigger == null) {
|
||||
return;
|
||||
|
@ -125,7 +132,7 @@ public class QuartzManager {
|
|||
|
||||
trigger = (CronTrigger) triggerBuilder.build();// 创建Trigger对象
|
||||
|
||||
sched.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
|
||||
scheduler.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
|
||||
/** 方式一 :调用 rescheduleJob 结束 */
|
||||
|
||||
/** 方式二:先删除,然后在创建一个新的Job */
|
||||
|
@ -146,15 +153,13 @@ public class QuartzManager {
|
|||
* @param repeatIntervalTime
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public static void modifySimpleJobTime(TriggerKey triggerKey, int repeatIntervalTime) throws SchedulerException {
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
public void modifySimpleJobTime(TriggerKey triggerKey, int repeatIntervalTime) throws SchedulerException {
|
||||
|
||||
try {
|
||||
|
||||
LogUtil.info("modifySimpleJobTime: " + triggerKey.getName() + "," + triggerKey.getGroup());
|
||||
|
||||
SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(triggerKey);
|
||||
SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);
|
||||
|
||||
if (trigger == null) {
|
||||
return;
|
||||
|
@ -175,7 +180,7 @@ public class QuartzManager {
|
|||
|
||||
trigger = (SimpleTrigger) triggerBuilder.build();// 创建Trigger对象
|
||||
|
||||
sched.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
|
||||
scheduler.rescheduleJob(triggerKey, trigger);// 修改一个任务的触发时间
|
||||
|
||||
/** 方式一 :调用 rescheduleJob 结束 */
|
||||
|
||||
|
@ -201,19 +206,17 @@ public class QuartzManager {
|
|||
* @param jobKey
|
||||
* @param triggerKey
|
||||
*/
|
||||
public static void removeJob(JobKey jobKey, TriggerKey triggerKey) {
|
||||
public void removeJob(JobKey jobKey, TriggerKey triggerKey) {
|
||||
|
||||
try {
|
||||
|
||||
LogUtil.info("RemoveJob: " + jobKey.getName() + "," + jobKey.getGroup());
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
scheduler.pauseTrigger(triggerKey);
|
||||
|
||||
sched.pauseTrigger(triggerKey);
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
|
||||
sched.unscheduleJob(triggerKey);
|
||||
|
||||
sched.deleteJob(jobKey);
|
||||
scheduler.deleteJob(jobKey);
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
|
@ -232,7 +235,7 @@ public class QuartzManager {
|
|||
}
|
||||
|
||||
|
||||
public static void shutdownJobs(Scheduler sched) {
|
||||
public void shutdownJobs(Scheduler sched) {
|
||||
try {
|
||||
if (!sched.isShutdown()) {
|
||||
sched.shutdown();
|
||||
|
@ -252,12 +255,10 @@ public class QuartzManager {
|
|||
* @param jobDataMap
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public static void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
|
||||
int intervalTime, JobDataMap jobDataMap) throws SchedulerException {
|
||||
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz,
|
||||
int intervalTime, JobDataMap jobDataMap) throws SchedulerException {
|
||||
|
||||
Scheduler sched = sf.getScheduler();
|
||||
|
||||
if (sched.checkExists(triggerKey)) {
|
||||
if (scheduler.checkExists(triggerKey)) {
|
||||
modifySimpleJobTime(triggerKey, intervalTime);
|
||||
} else {
|
||||
addSimpleJob(jobKey, triggerKey, clz, intervalTime, jobDataMap);
|
||||
|
@ -265,7 +266,7 @@ public class QuartzManager {
|
|||
|
||||
}
|
||||
|
||||
public static void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime) throws SchedulerException {
|
||||
public void addOrUpdateSimpleJob(JobKey jobKey, TriggerKey triggerKey, Class clz, int intervalTime) throws SchedulerException {
|
||||
addOrUpdateSimpleJob(jobKey, triggerKey, clz, intervalTime, null);
|
||||
}
|
||||
|
||||
|
@ -279,23 +280,22 @@ public class QuartzManager {
|
|||
* @param jobDataMap
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public static void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) throws SchedulerException {
|
||||
Scheduler sched = sf.getScheduler();
|
||||
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron, JobDataMap jobDataMap) throws SchedulerException {
|
||||
|
||||
LogUtil.info("AddOrUpdateCronJob: " + jobKey.getName() + "," + triggerKey.getGroup());
|
||||
|
||||
if (sched.checkExists(triggerKey)) {
|
||||
if (scheduler.checkExists(triggerKey)) {
|
||||
modifyCronJobTime(triggerKey, cron);
|
||||
} else {
|
||||
addCronJob(jobKey, triggerKey, jobClass, cron, jobDataMap);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) throws SchedulerException {
|
||||
public void addOrUpdateCronJob(JobKey jobKey, TriggerKey triggerKey, Class jobClass, String cron) throws SchedulerException {
|
||||
addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, null);
|
||||
}
|
||||
|
||||
public static JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) {
|
||||
public JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) {
|
||||
JobDataMap jobDataMap = new JobDataMap();
|
||||
jobDataMap.put("resourceId", resourceId);
|
||||
jobDataMap.put("expression", expression);
|
|
@ -20,9 +20,8 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "performance/report")
|
||||
|
@ -63,7 +62,7 @@ public class PerformanceReportController {
|
|||
|
||||
@GetMapping("/content/{reportId}")
|
||||
public List<Statistics> getReportContent(@PathVariable String reportId) {
|
||||
return reportService.getReport(reportId);
|
||||
return reportService.getReportStatistics(reportId);
|
||||
}
|
||||
|
||||
@GetMapping("/content/errors/{reportId}")
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -101,6 +102,11 @@ public class PerformanceTestController {
|
|||
return performanceTestService.run(request);
|
||||
}
|
||||
|
||||
@GetMapping("stop/{reportId}")
|
||||
public void stopTest(@PathVariable String reportId) {
|
||||
performanceTestService.stopTest(reportId);
|
||||
}
|
||||
|
||||
@GetMapping("/file/metadata/{testId}")
|
||||
public List<FileMetadata> getFileMetadata(@PathVariable String testId) {
|
||||
return fileService.getFileMetadataByTestId(testId);
|
||||
|
|
|
@ -5,10 +5,7 @@ import io.metersphere.base.mapper.*;
|
|||
import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportDetailMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
|
||||
import io.metersphere.commons.constants.APITestStatus;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.constants.ScheduleType;
|
||||
import io.metersphere.commons.constants.*;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.ServiceUtils;
|
||||
|
@ -74,6 +71,8 @@ public class PerformanceTestService {
|
|||
private KafkaProperties kafkaProperties;
|
||||
@Resource
|
||||
private ScheduleService scheduleService;
|
||||
@Resource
|
||||
private TestCaseMapper testCaseMapper;
|
||||
|
||||
public List<LoadTestDTO> list(QueryTestPlanRequest request) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
|
@ -82,6 +81,20 @@ public class PerformanceTestService {
|
|||
|
||||
public void delete(DeleteTestPlanRequest request) {
|
||||
String testId = request.getId();
|
||||
|
||||
// 是否关联测试用例
|
||||
TestCaseExample testCaseExample = new TestCaseExample();
|
||||
testCaseExample.createCriteria().andTestIdEqualTo(testId);
|
||||
List<TestCase> testCases = testCaseMapper.selectByExample(testCaseExample);
|
||||
if (testCases.size() > 0) {
|
||||
String caseName = "";
|
||||
for (int i = 0; i < testCases.size(); i++) {
|
||||
caseName = caseName + testCases.get(i).getName() + ",";
|
||||
}
|
||||
caseName = caseName.substring(0, caseName.length() - 1);
|
||||
MSException.throwException(Translator.get("related_case_del_fail_prefix") + caseName + Translator.get("related_case_del_fail_suffix"));
|
||||
}
|
||||
|
||||
LoadTestReportExample loadTestReportExample = new LoadTestReportExample();
|
||||
loadTestReportExample.createCriteria().andTestIdEqualTo(testId);
|
||||
List<LoadTestReport> loadTestReports = loadTestReportMapper.selectByExample(loadTestReportExample);
|
||||
|
@ -222,7 +235,7 @@ public class PerformanceTestService {
|
|||
MSException.throwException(String.format("Test cannot be run,test ID:%s", request.getId()));
|
||||
}
|
||||
|
||||
startEngine(loadTest, engine);
|
||||
startEngine(loadTest, engine, request.getTriggerMode());
|
||||
|
||||
// todo:通过调用stop方法能够停止正在运行的engine,但是如果部署了多个backend实例,页面发送的停止请求如何定位到具体的engine
|
||||
|
||||
|
@ -254,14 +267,19 @@ public class PerformanceTestService {
|
|||
}
|
||||
}
|
||||
|
||||
private void startEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||
private void startEngine(LoadTestWithBLOBs loadTest, Engine engine, String triggerMode) {
|
||||
LoadTestReport testReport = new LoadTestReport();
|
||||
testReport.setId(engine.getReportId());
|
||||
testReport.setCreateTime(engine.getStartTime());
|
||||
testReport.setUpdateTime(engine.getStartTime());
|
||||
testReport.setTestId(loadTest.getId());
|
||||
testReport.setName(loadTest.getName());
|
||||
testReport.setUserId(Optional.ofNullable(SessionUtils.getUser().getId()).orElse(loadTest.getUserId()));
|
||||
testReport.setTriggerMode(triggerMode);
|
||||
if (SessionUtils.getUser() == null) {
|
||||
testReport.setUserId(loadTest.getUserId());
|
||||
} else {
|
||||
testReport.setUserId(SessionUtils.getUser().getId());
|
||||
}
|
||||
// 启动测试
|
||||
|
||||
try {
|
||||
|
@ -280,6 +298,13 @@ public class PerformanceTestService {
|
|||
loadTestReportDetailMapper.insertSelective(reportDetail);
|
||||
// append \n
|
||||
extLoadTestReportDetailMapper.appendLine(testReport.getId(), "\n");
|
||||
// 保存一个 reportStatus
|
||||
LoadTestReportResult reportResult = new LoadTestReportResult();
|
||||
reportResult.setId(UUID.randomUUID().toString());
|
||||
reportResult.setReportId(testReport.getId());
|
||||
reportResult.setReportKey(ReportKeys.ResultStatus.name());
|
||||
reportResult.setReportValue("Ready"); // 初始化一个 result_status, 这个值用在data-streaming中
|
||||
loadTestReportResultMapper.insertSelective(reportResult);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
loadTest.setStatus(PerformanceTestStatus.Error.name());
|
||||
|
@ -388,4 +413,8 @@ public class PerformanceTestService {
|
|||
private void addOrUpdatePerformanceTestCronJob(Schedule request) {
|
||||
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
|
||||
}
|
||||
|
||||
public void stopTest(String reportId) {
|
||||
reportService.deleteReport(reportId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,10 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ReportService {
|
||||
|
@ -109,7 +108,7 @@ public class ReportService {
|
|||
return loadTestReportResults.get(0).getReportValue();
|
||||
}
|
||||
|
||||
public List<Statistics> getReport(String id) {
|
||||
public List<Statistics> getReportStatistics(String id) {
|
||||
checkReportStatus(id);
|
||||
String reportValue = getContent(id, ReportKeys.RequestStatistics);
|
||||
return JSON.parseArray(reportValue, Statistics.class);
|
||||
|
@ -154,11 +153,7 @@ public class ReportService {
|
|||
public void checkReportStatus(String reportId) {
|
||||
LoadTestReport loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||
String reportStatus = loadTestReport.getStatus();
|
||||
if (StringUtils.equals(PerformanceTestStatus.Running.name(), reportStatus)) {
|
||||
MSException.throwException("Reporting in progress...");
|
||||
} else if (StringUtils.equals(PerformanceTestStatus.Reporting.name(), reportStatus)) {
|
||||
MSException.throwException("Reporting in progress...");
|
||||
} else if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) {
|
||||
if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) {
|
||||
MSException.throwException("Report generation error!");
|
||||
}
|
||||
}
|
||||
|
@ -214,4 +209,8 @@ public class ReportService {
|
|||
String content = loadTestReportLogs.stream().map(LoadTestReportLog::getContent).reduce("", (a, b) -> a + b);
|
||||
return content.getBytes();
|
||||
}
|
||||
|
||||
public LoadTestReport getReport(String reportId) {
|
||||
return loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,10 @@ import com.alibaba.fastjson.JSON;
|
|||
import io.metersphere.base.domain.Schedule;
|
||||
import io.metersphere.base.domain.ScheduleExample;
|
||||
import io.metersphere.base.mapper.ScheduleMapper;
|
||||
import io.metersphere.commons.constants.ScheduleGroup;
|
||||
import io.metersphere.commons.constants.ScheduleType;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.job.QuartzManager;
|
||||
import io.metersphere.job.sechedule.ApiTestJob;
|
||||
import io.metersphere.job.sechedule.ScheduleManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.SchedulerException;
|
||||
|
@ -28,6 +25,8 @@ public class ScheduleService {
|
|||
|
||||
@Resource
|
||||
private ScheduleMapper scheduleMapper;
|
||||
@Resource
|
||||
private ScheduleManager scheduleManager;
|
||||
|
||||
public void addSchedule(Schedule schedule) {
|
||||
schedule.setId(UUID.randomUUID().toString());
|
||||
|
@ -73,11 +72,10 @@ public class ScheduleService {
|
|||
try {
|
||||
if (schedule.getEnable()) {
|
||||
LogUtil.error("初始化任务:" + JSON.toJSONString(schedule));
|
||||
QuartzManager.addOrUpdateCronJob(new JobKey(schedule.getKey(), schedule.getGroup()),
|
||||
scheduleManager.addOrUpdateCronJob(new JobKey(schedule.getKey(), schedule.getGroup()),
|
||||
new TriggerKey(schedule.getKey(), schedule.getGroup()), Class.forName(schedule.getJob()), schedule.getValue(),
|
||||
QuartzManager.getDefaultJobDataMap(schedule.getResourceId(), schedule.getValue(), schedule.getUserId()));
|
||||
scheduleManager.getDefaultJobDataMap(schedule.getResourceId(), schedule.getValue(), schedule.getUserId()));
|
||||
}
|
||||
Thread.sleep(1*60*1000);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error("初始化任务失败", e);
|
||||
e.printStackTrace();
|
||||
|
@ -100,14 +98,14 @@ public class ScheduleService {
|
|||
String cronExpression = request.getValue();
|
||||
if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) {
|
||||
try {
|
||||
QuartzManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression, QuartzManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
|
||||
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression, scheduleManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
|
||||
} catch (SchedulerException e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
MSException.throwException("定时任务开启异常");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
QuartzManager.removeJob(jobKey, triggerKey);
|
||||
scheduleManager.removeJob(jobKey, triggerKey);
|
||||
} catch (Exception e) {
|
||||
MSException.throwException("定时任务关闭异常");
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ public class TestResourcePoolService {
|
|||
List<TestResourcePoolDTO> testResourcePools = listResourcePools(request);
|
||||
// 重新校验 pool
|
||||
for (TestResourcePoolDTO pool : testResourcePools) {
|
||||
// 手动设置成无效的, 排除
|
||||
// 手动设置成无效的, 排除
|
||||
if (INVALID.name().equals(pool.getStatus())) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -7,4 +7,5 @@ import lombok.Setter;
|
|||
@Setter
|
||||
public class RunTestPlanRequest extends TestPlanRequest {
|
||||
private String userId;
|
||||
private String triggerMode;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.track.request.testplan;
|
||||
|
||||
import io.metersphere.base.domain.Schedule;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
@ -27,7 +28,7 @@ public class TestPlanRequest {
|
|||
|
||||
private String runtimeConfiguration;
|
||||
|
||||
private String schedule;
|
||||
private Schedule schedule;
|
||||
|
||||
private String testResourcePoolId;
|
||||
|
||||
|
|
|
@ -229,6 +229,9 @@ public class TestCaseNodeService {
|
|||
|
||||
public List<TestCaseNodeDTO> getAllNodeByPlanId(String planId) {
|
||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId);
|
||||
if (testPlan == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return getNodeTreeByProjectId(testPlan.getProjectId());
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -121,7 +122,13 @@ public class TestCaseService {
|
|||
}
|
||||
|
||||
public List<TestCaseDTO> listTestCase(QueryTestCaseRequest request) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
List<OrderRequest> orderList = ServiceUtils.getDefaultOrder(request.getOrders());
|
||||
OrderRequest order = new OrderRequest();
|
||||
// 对模板导入的测试用例排序
|
||||
order.setName("sort");
|
||||
order.setType("desc");
|
||||
orderList.add(order);
|
||||
request.setOrders(orderList);
|
||||
return extTestCaseMapper.list(request);
|
||||
}
|
||||
|
||||
|
@ -140,7 +147,9 @@ public class TestCaseService {
|
|||
public List<TestCase> getTestCaseNames(QueryTestCaseRequest request) {
|
||||
if (StringUtils.isNotBlank(request.getPlanId())) {
|
||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());
|
||||
request.setProjectId(testPlan.getProjectId());
|
||||
if (testPlan != null) {
|
||||
request.setProjectId(testPlan.getProjectId());
|
||||
}
|
||||
}
|
||||
|
||||
List<TestCase> testCaseNames = extTestCaseMapper.getTestCaseNames(request);
|
||||
|
@ -182,7 +191,7 @@ public class TestCaseService {
|
|||
|
||||
TestCaseExample testCaseExample = new TestCaseExample();
|
||||
testCaseExample.createCriteria().andProjectIdIn(projectIds);
|
||||
testCaseExample.setOrderByClause("update_time desc");
|
||||
testCaseExample.setOrderByClause("update_time desc, sort desc");
|
||||
return testCaseMapper.selectByExample(testCaseExample);
|
||||
}
|
||||
|
||||
|
@ -241,8 +250,10 @@ public class TestCaseService {
|
|||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||
if (!testCases.isEmpty()) {
|
||||
AtomicInteger sort = new AtomicInteger();
|
||||
testCases.forEach(testcase -> {
|
||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
testcase.setSort(sort.getAndIncrement());
|
||||
mapper.insert(testcase);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class TestPlanService {
|
|||
}
|
||||
|
||||
public TestPlan getTestPlan(String testPlanId) {
|
||||
return testPlanMapper.selectByPrimaryKey(testPlanId);
|
||||
return Optional.ofNullable(testPlanMapper.selectByPrimaryKey(testPlanId)).orElse(new TestPlan());
|
||||
}
|
||||
|
||||
public int editTestPlan(TestPlan testPlan) {
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package io.metersphere.websocket;
|
||||
|
||||
import io.metersphere.base.domain.LoadTestReport;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.performance.service.ReportService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
|
||||
@ServerEndpoint("/performance/report/{reportId}")
|
||||
@Component
|
||||
public class ReportWebSocket {
|
||||
|
||||
private static ReportService reportService;
|
||||
|
||||
@Resource
|
||||
public void setReportService(ReportService reportService) {
|
||||
ReportWebSocket.reportService = reportService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启连接的操作
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(@PathParam("reportId") String reportId, Session session) throws IOException {
|
||||
//开启一个线程对数据库中的数据进行轮询
|
||||
ReportThread reportThread = new ReportThread(session, reportId);
|
||||
Thread thread = new Thread(reportThread);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭的操作
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 给服务器发送消息告知数据库发生变化
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(Session session, String message) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 出错的操作
|
||||
*/
|
||||
@OnError
|
||||
public void onError(Throwable error) {
|
||||
System.out.println(error);
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
public static class ReportThread implements Runnable {
|
||||
private boolean stopMe = true;
|
||||
private final String reportId;
|
||||
private final Session session;
|
||||
private int refresh;
|
||||
|
||||
public ReportThread(Session session, String reportId) {
|
||||
this.session = session;
|
||||
this.reportId = reportId;
|
||||
this.refresh = 0;
|
||||
}
|
||||
|
||||
public void stopMe() {
|
||||
stopMe = false;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (stopMe) {
|
||||
try {
|
||||
LoadTestReport report = reportService.getReport(reportId);
|
||||
if (StringUtils.equalsAny(report.getStatus(), PerformanceTestStatus.Completed.name(), PerformanceTestStatus.Error.name())) {
|
||||
this.stopMe();
|
||||
session.close();
|
||||
break;
|
||||
}
|
||||
if (PerformanceTestStatus.Running.name().equals(report.getStatus())) {
|
||||
session.getBasicRemote().sendText("refresh-" + this.refresh++);
|
||||
}
|
||||
Thread.sleep(20 * 1000L);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,4 +64,13 @@ kafka.ssl.provider=
|
|||
kafka.ssl.truststore-type=
|
||||
|
||||
# jmeter
|
||||
jmeter.home=/opt/jmeter
|
||||
jmeter.home=/opt/jmeter
|
||||
|
||||
# quartz
|
||||
quartz.enabled=true
|
||||
quartz.scheduler-name=msServerJob
|
||||
|
||||
# file upload
|
||||
spring.servlet.multipart.max-file-size=30MB
|
||||
spring.servlet.multipart.max-request-size=30MB
|
||||
|
||||
|
|
|
@ -1,3 +1,155 @@
|
|||
-- quartz start
|
||||
CREATE TABLE `qrtz_job_details` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`JOB_NAME` varchar(200) NOT NULL,
|
||||
`JOB_GROUP` varchar(200) NOT NULL,
|
||||
`DESCRIPTION` varchar(250) DEFAULT NULL,
|
||||
`JOB_CLASS_NAME` varchar(250) NOT NULL,
|
||||
`IS_DURABLE` varchar(1) NOT NULL,
|
||||
`IS_NONCONCURRENT` varchar(1) NOT NULL,
|
||||
`IS_UPDATE_DATA` varchar(1) NOT NULL,
|
||||
`REQUESTS_RECOVERY` varchar(1) NOT NULL,
|
||||
`JOB_DATA` blob,
|
||||
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
||||
KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
|
||||
KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`JOB_NAME` varchar(200) NOT NULL,
|
||||
`JOB_GROUP` varchar(200) NOT NULL,
|
||||
`DESCRIPTION` varchar(250) DEFAULT NULL,
|
||||
`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
|
||||
`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
|
||||
`PRIORITY` int(11) DEFAULT NULL,
|
||||
`TRIGGER_STATE` varchar(16) NOT NULL,
|
||||
`TRIGGER_TYPE` varchar(8) NOT NULL,
|
||||
`START_TIME` bigint(13) NOT NULL,
|
||||
`END_TIME` bigint(13) DEFAULT NULL,
|
||||
`CALENDAR_NAME` varchar(200) DEFAULT NULL,
|
||||
`MISFIRE_INSTR` smallint(2) DEFAULT NULL,
|
||||
`JOB_DATA` blob,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
||||
KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
|
||||
KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
|
||||
KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
|
||||
KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
|
||||
KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
||||
KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
||||
KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
|
||||
KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
|
||||
KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
|
||||
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
|
||||
KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
|
||||
CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_blob_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`BLOB_DATA` blob,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_calendars` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`CALENDAR_NAME` varchar(200) NOT NULL,
|
||||
`CALENDAR` blob NOT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_cron_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`CRON_EXPRESSION` varchar(120) NOT NULL,
|
||||
`TIME_ZONE_ID` varchar(80) DEFAULT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_fired_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`ENTRY_ID` varchar(95) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`INSTANCE_NAME` varchar(200) NOT NULL,
|
||||
`FIRED_TIME` bigint(13) NOT NULL,
|
||||
`SCHED_TIME` bigint(13) NOT NULL,
|
||||
`PRIORITY` int(11) NOT NULL,
|
||||
`STATE` varchar(16) NOT NULL,
|
||||
`JOB_NAME` varchar(200) DEFAULT NULL,
|
||||
`JOB_GROUP` varchar(200) DEFAULT NULL,
|
||||
`IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
|
||||
`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
|
||||
KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
|
||||
KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
|
||||
KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
|
||||
KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
|
||||
KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_locks` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`LOCK_NAME` varchar(40) NOT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_paused_trigger_grps` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_scheduler_state` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`INSTANCE_NAME` varchar(200) NOT NULL,
|
||||
`LAST_CHECKIN_TIME` bigint(13) NOT NULL,
|
||||
`CHECKIN_INTERVAL` bigint(13) NOT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_simple_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`REPEAT_COUNT` bigint(7) NOT NULL,
|
||||
`REPEAT_INTERVAL` bigint(12) NOT NULL,
|
||||
`TIMES_TRIGGERED` bigint(10) NOT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `qrtz_simprop_triggers` (
|
||||
`SCHED_NAME` varchar(120) NOT NULL,
|
||||
`TRIGGER_NAME` varchar(200) NOT NULL,
|
||||
`TRIGGER_GROUP` varchar(200) NOT NULL,
|
||||
`STR_PROP_1` varchar(512) DEFAULT NULL,
|
||||
`STR_PROP_2` varchar(512) DEFAULT NULL,
|
||||
`STR_PROP_3` varchar(512) DEFAULT NULL,
|
||||
`INT_PROP_1` int(11) DEFAULT NULL,
|
||||
`INT_PROP_2` int(11) DEFAULT NULL,
|
||||
`LONG_PROP_1` bigint(20) DEFAULT NULL,
|
||||
`LONG_PROP_2` bigint(20) DEFAULT NULL,
|
||||
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
|
||||
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
|
||||
`BOOL_PROP_1` varchar(1) DEFAULT NULL,
|
||||
`BOOL_PROP_2` varchar(1) DEFAULT NULL,
|
||||
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
|
||||
CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- quartz end
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `schedule` (
|
||||
`id` varchar(50) NOT NULL COMMENT 'Schedule ID',
|
||||
`key` varchar(50) NOT NULL COMMENT 'Schedule Key',
|
||||
|
@ -16,4 +168,8 @@ CREATE TABLE IF NOT EXISTS `schedule` (
|
|||
ALTER TABLE `api_test` DROP COLUMN `schedule`;
|
||||
ALTER TABLE `load_test` DROP COLUMN `schedule`;
|
||||
ALTER TABLE `api_test_report` ADD `trigger_mode` varchar(64) NULL;
|
||||
ALTER TABLE `load_test_report` ADD `trigger_mode` varchar(64) NULL;
|
||||
ALTER TABLE `load_test_report` ADD `trigger_mode` varchar(64) NULL;
|
||||
UPDATE `api_test_report` SET `trigger_mode` = 'MANUAL' WHERE 1;
|
||||
UPDATE `load_test_report` SET `trigger_mode` = 'MANUAL' WHERE 1;
|
||||
|
||||
alter table test_case add sort int null comment 'Import test case sort';
|
|
@ -43,6 +43,8 @@ load_test_already_exists=Duplicate load test name
|
|||
no_nodes_message=No node message
|
||||
duplicate_node_ip=Duplicate IPs
|
||||
max_thread_insufficient=The number of concurrent users exceeds
|
||||
related_case_del_fail_prefix=Connected to
|
||||
related_case_del_fail_suffix=TestCase, please disassociate first
|
||||
#workspace
|
||||
workspace_name_is_null=Workspace name cannot be null
|
||||
workspace_name_already_exists=The workspace name already exists
|
||||
|
|
|
@ -43,6 +43,8 @@ load_test_already_exists=测试名称不能重复
|
|||
no_nodes_message=没有节点信息
|
||||
duplicate_node_ip=节点 IP 重复
|
||||
max_thread_insufficient=并发用户数超额
|
||||
related_case_del_fail_prefix=已关联到
|
||||
related_case_del_fail_suffix=测试用例,请先解除关联
|
||||
#workspace
|
||||
workspace_name_is_null=工作空间名不能为空
|
||||
workspace_name_already_exists=工作空间名已存在
|
||||
|
|
|
@ -43,6 +43,8 @@ load_test_already_exists=測試名稱不能重復
|
|||
no_nodes_message=沒有節點信息
|
||||
duplicate_node_ip=節點 IP 重復
|
||||
max_thread_insufficient=並發用戶數超額
|
||||
related_case_del_fail_prefix=已關聯到
|
||||
related_case_del_fail_suffix=測試用例,請先解除關聯
|
||||
#workspace
|
||||
workspace_name_is_null=工作空間名不能為空
|
||||
workspace_name_already_exists=工作空間名已存在
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'">
|
||||
<template v-slot:default="scope">
|
||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')">
|
||||
<template v-slot:default="{row}">
|
||||
<ms-api-report-status :row="row"/>
|
||||
|
@ -26,11 +31,12 @@
|
|||
|
||||
<script>
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportRecentList",
|
||||
|
||||
components: {MsApiReportStatus},
|
||||
components: {ReportTriggerModeItem, MsApiReportStatus},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'" column-key="triggerMode" :filters="triggerFilters">
|
||||
<template v-slot:default="scope">
|
||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')"
|
||||
column-key="status"
|
||||
:filters="statusFilters">
|
||||
|
@ -49,9 +54,11 @@
|
|||
import MsApiReportStatus from "./ApiReportStatus";
|
||||
import {_filter, _sort} from "../../../../common/js/utils";
|
||||
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
|
||||
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ReportTriggerModeItem,
|
||||
MsTableOperatorButton,
|
||||
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination},
|
||||
data() {
|
||||
|
@ -71,7 +78,12 @@
|
|||
{text: 'Reporting', value: 'Reporting'},
|
||||
{text: 'Completed', value: 'Completed'},
|
||||
{text: 'Error', value: 'Error'}
|
||||
]
|
||||
],
|
||||
triggerFilters: [
|
||||
{text: '手动', value: 'MANUAL'},
|
||||
{text: '定时任务', value: 'SCHEDULE'},
|
||||
{text: 'API', value: 'API'}
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -85,7 +97,7 @@
|
|||
this.condition.testId = this.testId;
|
||||
}
|
||||
|
||||
let url = "/api/report/list/" + this.currentPage + "/" + this.pageSize
|
||||
let url = "/api/report/list/" + this.currentPage + "/" + this.pageSize;
|
||||
this.result = this.$post(url, this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
})
|
||||
},
|
||||
runTest() {
|
||||
this.result = this.$post("/api/run", {id: this.test.id}, (response) => {
|
||||
this.result = this.$post("/api/run", {id: this.test.id, triggerMode: 'MANUAL'}, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<el-dialog :title="'环境配置'" :visible.sync="visible" class="environment-dialog">
|
||||
<el-container >
|
||||
<ms-aside-item :title="'环境列表'" :data="environments" :add-fuc="addEnvironment" :delete-fuc="deleteEnvironment" @itemSelected="environmentSelected"/>
|
||||
<el-main>
|
||||
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsApiCollapse from "./collapse/ApiCollapse";
|
||||
import MsApiCollapseItem from "./collapse/ApiCollapseItem";
|
||||
import draggable from 'vuedraggable';
|
||||
import MsContainer from "../../../common/components/MsContainer";
|
||||
import MsAsideContainer from "../../../common/components/MsAsideContainer";
|
||||
import MsMainContainer from "../../../common/components/MsMainContainer";
|
||||
import MsAsideItem from "../../../common/components/MsAsideItem";
|
||||
|
||||
export default {
|
||||
name: "ApiEnvironmentConfig",
|
||||
components: {
|
||||
MsAsideItem,
|
||||
MsMainContainer, MsAsideContainer, MsContainer, MsApiCollapseItem, MsApiCollapse, draggable},
|
||||
data() {
|
||||
return {
|
||||
visible:false,
|
||||
environments: [{name: 'tesddd'}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(project) {
|
||||
this.visible = true
|
||||
},
|
||||
deleteEnvironment(environment) {
|
||||
console.log(environment);
|
||||
for (let i = 0; i < this.environments.length; i++) {
|
||||
if (this.environments[i].name === environment.name) {
|
||||
this.environments.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
addEnvironment() {
|
||||
this.environments.push({name: '新建'});
|
||||
console.log('add');
|
||||
},
|
||||
environmentSelected() {
|
||||
console.log('select');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.environment-dialog >>> .el-dialog__body {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.ms-aside-container {
|
||||
height: calc(100vh - 500px);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -4,7 +4,7 @@
|
|||
{{$t('api_test.request.extract.description')}}
|
||||
</div>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="4">
|
||||
<el-col :span="2">
|
||||
<el-select :disabled="isReadOnly" class="extract-item" v-model="type" :placeholder="$t('api_test.request.extract.select_type')"
|
||||
size="small">
|
||||
<el-option :label="$t('api_test.request.extract.regex')" :value="options.REGEX"/>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<el-option label="XPath" :value="options.XPATH"/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<el-col :span="22">
|
||||
<ms-api-extract-common :is-read-only="isReadOnly" :extract-type="type" :list="list" v-if="type" :callback="after"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
|
||||
<el-col :span="10">
|
||||
<el-col v-if="extractType == 'Regex'" :span="5">
|
||||
<el-select :disabled="isReadOnly" class="extract-item" v-model="common.useHeaders" :placeholder="$t('api_test.request.assertions.select_subject')" size="small">
|
||||
<el-option v-for="item in useHeadersOption" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<ms-api-variable-input :is-read-only="isReadOnly" v-model="common.variable" size="small" maxlength="60"
|
||||
@change="change" show-word-limit :placeholder="$t('api_test.variable_name')"/>
|
||||
</el-col>
|
||||
|
@ -53,7 +58,17 @@
|
|||
|
||||
data() {
|
||||
return {
|
||||
visible: false
|
||||
visible: false,
|
||||
useHeadersOption: [
|
||||
{label: 'Body',value:'false'},
|
||||
{label: 'Request Headers',value:'request_headers'},
|
||||
{label: 'Body (unescaped)', value:'unescaped'},
|
||||
{label: 'Body as a Document', value:'as_document'},
|
||||
{label: 'Response Headers', value:'true'},
|
||||
{label: 'URL', value:'URL'},
|
||||
{label: 'Response Code', value:'code'},
|
||||
{label: 'Response Message', value:'message'}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ export class ExtractCommon extends ExtractType {
|
|||
constructor(type, options) {
|
||||
super(type);
|
||||
this.variable = undefined;
|
||||
this.useHeaders = undefined;
|
||||
this.value = ""; // ${variable}
|
||||
this.expression = undefined;
|
||||
this.description = undefined;
|
||||
|
@ -562,7 +563,7 @@ class JMXGenerator {
|
|||
switch (extractCommon.type) {
|
||||
case EXTRACT_TYPE.REGEX:
|
||||
testName += " RegexExtractor";
|
||||
props.headers = "false"; // 对应jMeter body
|
||||
props.headers = extractCommon.useHeaders; // 对应jMeter body
|
||||
props.template = "$1$";
|
||||
return new RegexExtractor(testName, props);
|
||||
case EXTRACT_TYPE.JSON_PATH:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
|
||||
<el-aside class="ms-aside-container">
|
||||
<el-aside :width="width" class="ms-aside-container">
|
||||
<slot></slot>
|
||||
</el-aside>
|
||||
|
||||
|
@ -8,7 +8,13 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsAsideContainer"
|
||||
name: "MsAsideContainer",
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '300px'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<ms-aside-container :width="width">
|
||||
<div class="title-bar">
|
||||
<span class="title-left">{{title}}</span>
|
||||
<span class="title-right">
|
||||
<i class="el-icon-plus" @click="addFuc"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-for="(item, index) in data" :key="index" class="item-bar" @click="itemSelected(index, item)" :class="{'item-selected' : index == selectIndex}">
|
||||
<span class="item-left">{{item.name}}</span>
|
||||
<span class="item-right">
|
||||
<i class="el-icon-delete" @click="deleteFuc(item)"/>
|
||||
</span>
|
||||
</div>
|
||||
</ms-aside-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsAsideContainer from "./MsAsideContainer";
|
||||
|
||||
export default {
|
||||
name: "MsAsideItem",
|
||||
components: {MsAsideContainer},
|
||||
data() {
|
||||
return {
|
||||
selectIndex: -1
|
||||
}
|
||||
},
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '200px'
|
||||
},
|
||||
title: String,
|
||||
data: Array,
|
||||
deleteFuc: Function,
|
||||
addFuc: Function,
|
||||
},
|
||||
methods: {
|
||||
itemSelected(index, item) {
|
||||
this.selectIndex = index;
|
||||
this.$emit('itemSelected', item);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.title-bar {
|
||||
width: 100%;
|
||||
background: #e9ebef;
|
||||
height: 40px;
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.title-bar span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.item-bar {
|
||||
width: 100%;
|
||||
background: #F9F9F9;
|
||||
height: 35px;
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-bar span {
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.title-right,.item-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.item-right {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.ms-aside-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
color: #409EFF;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.item-bar:hover .item-right {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.item-selected {
|
||||
background: #edf6fd;
|
||||
}
|
||||
|
||||
.item-selected .item-right {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -6,8 +6,8 @@
|
|||
<span class="character" @click="scheduleEdit">SCHEDULER</span>
|
||||
</span>
|
||||
<el-switch :disabled="!schedule.value" v-model="schedule.enable" @change="scheduleChange"/>
|
||||
<ms-schedule-edit :schedule="schedule" :save="save" ref="scheduleEdit"/>
|
||||
<crontab-result v-show="false" :ex="schedule.value" ref="crontabResult" @resultListChange="recentListChange"/>
|
||||
<ms-schedule-edit :schedule="schedule" :save="save" :custom-validate="customValidate" ref="scheduleEdit"/>
|
||||
<crontab-result v-show="false" :ex="schedule.value" ref="crontabResult" @resultListChange="resultListChange"/>
|
||||
</div>
|
||||
<div>
|
||||
<span :class="{'disable-character': !schedule.enable}"> 下次执行时间:{{this.recentList.length > 0 ? this.recentList[0] : '未设置'}} </span>
|
||||
|
@ -18,6 +18,9 @@
|
|||
<script>
|
||||
import MsScheduleEdit from "./MsScheduleEdit";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
|
||||
function defaultCustomValidate() {return {pass: true};}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleConfig",
|
||||
components: {CrontabResult, MsScheduleEdit},
|
||||
|
@ -37,6 +40,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
scheduleEdit() {
|
||||
|
@ -48,8 +55,11 @@
|
|||
scheduleChange() {
|
||||
this.$emit('scheduleChange');
|
||||
},
|
||||
recentListChange(resultList) {
|
||||
resultListChange(resultList) {
|
||||
this.recentList = resultList;
|
||||
},
|
||||
flashResultList() {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
<el-button type="primary" @click="showCronDialog">生成 Cron</el-button>
|
||||
<el-button type="primary" @click="saveCron">保存</el-button>
|
||||
</el-form-item>
|
||||
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
|
||||
<crontab-result :ex="form.cronValue" ref="crontabResult" />
|
||||
</el-form>
|
||||
<el-dialog title="生成 cron" :visible.sync="showCron" :modal="false">
|
||||
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"/>
|
||||
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value" ref="crontab"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
@ -24,12 +24,18 @@
|
|||
import CrontabResult from "../cron/CrontabResult";
|
||||
import {cronValidate} from "../../../../common/js/cron";
|
||||
|
||||
function defaultCustomValidate() {return {pass: true};}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleEdit",
|
||||
components: {CrontabResult, Crontab},
|
||||
props: {
|
||||
save: Function,
|
||||
schedule: {},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'schedule.value'() {
|
||||
|
@ -38,8 +44,13 @@
|
|||
},
|
||||
data() {
|
||||
const validateCron = (rule, cronValue, callback) => {
|
||||
let customValidate = this.customValidate(this.getIntervalTime());
|
||||
if (!cronValidate(cronValue)) {
|
||||
callback(new Error('Cron 表达式格式错误'));
|
||||
} else if(!this.intervalShortValidate()) {
|
||||
callback(new Error('间隔时间请大于 5 分钟'));
|
||||
} else if (!customValidate.pass){
|
||||
callback(new Error(customValidate.info));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
@ -58,10 +69,12 @@
|
|||
methods: {
|
||||
open() {
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
},
|
||||
crontabFill(value) {
|
||||
crontabFill(value, resultList) {
|
||||
//确定后回传的值
|
||||
this.form.cronValue = value;
|
||||
this.$refs.crontabResult.resultList = resultList;
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
showCronDialog() {
|
||||
|
@ -78,11 +91,27 @@
|
|||
});
|
||||
},
|
||||
close() {
|
||||
this.dialogVisible = false;
|
||||
this.form.cronValue = '';
|
||||
this.$refs['from'].resetFields();
|
||||
if (!this.schedule.value) {
|
||||
this.$refs.crontabResult.resultList = [];
|
||||
}
|
||||
},
|
||||
intervalShortValidate() {
|
||||
if (this.getIntervalTime() < 5*60*1000) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resultListChange() {
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
getIntervalTime() {
|
||||
let resultList = this.$refs.crontabResult.resultList;
|
||||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<crontab-result :ex="contabValueString"/>
|
||||
<crontab-result :ex="contabValueString" ref="crontabResult"/>
|
||||
|
||||
<div class="pop_btn">
|
||||
<el-button size="small" type="primary" @click="submitFill">确定</el-button>
|
||||
|
@ -305,7 +305,7 @@
|
|||
},
|
||||
// 填充表达式
|
||||
submitFill() {
|
||||
this.$emit("fill", this.contabValueString);
|
||||
this.$emit("fill", this.contabValueString, this.$refs.crontabResult.resultList);
|
||||
this.hidePopup();
|
||||
},
|
||||
clearCron() {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {cronValidate} from "../../../../common/js/cron";
|
||||
|
||||
export default {
|
||||
name: 'CrontabResult',
|
||||
data() {
|
||||
|
@ -30,11 +32,11 @@ export default {
|
|||
this.expressionChange();
|
||||
},
|
||||
methods: {
|
||||
// 表达式值变化时,开始去计算结果
|
||||
// 表达式值变化时,开始去计算 结果
|
||||
expressionChange() {
|
||||
// 计算开始-隐藏结果
|
||||
this.isShow = false;
|
||||
if (!this.ex) {
|
||||
if (!cronValidate(this.ex)) {
|
||||
this.resultList = [];
|
||||
this.$emit("resultListChange", this.resultList);
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<span>
|
||||
<span v-if="triggerMode == 'MANUAL'">手动</span>
|
||||
<span v-if="triggerMode == 'SCHEDULE'">定时任务</span>
|
||||
<span v-if="triggerMode == 'API'">API</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ReportTriggerModeItem",
|
||||
props: ['triggerMode']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -15,6 +15,11 @@
|
|||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'">
|
||||
<template v-slot:default="scope">
|
||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')">
|
||||
<template v-slot:default="{row}">
|
||||
<ms-performance-report-status :row="row"/>
|
||||
|
@ -27,10 +32,11 @@
|
|||
<script>
|
||||
|
||||
import MsPerformanceReportStatus from "../report/PerformanceReportStatus";
|
||||
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
|
||||
|
||||
export default {
|
||||
name: "MsPerformanceReportRecentList",
|
||||
components: {MsPerformanceReportStatus},
|
||||
components: {ReportTriggerModeItem, MsPerformanceReportStatus},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
|
|
@ -13,12 +13,21 @@
|
|||
<el-breadcrumb-item>{{reportName}}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</el-row>
|
||||
<!-- <el-row class="ms-report-view-btns">-->
|
||||
<!-- <el-button :disabled="isReadOnly" type="primary" plain size="mini">{{$t('report.test_stop_now')}}</el-button>-->
|
||||
<!-- <el-button :disabled="isReadOnly" type="success" plain size="mini">{{$t('report.test_execute_again')}}</el-button>-->
|
||||
<!-- <el-button :disabled="isReadOnly" type="info" plain size="mini">{{$t('report.export')}}</el-button>-->
|
||||
<!-- <el-button :disabled="isReadOnly" type="warning" plain size="mini">{{$t('report.compare')}}</el-button>-->
|
||||
<!-- </el-row>-->
|
||||
<el-row class="ms-report-view-btns">
|
||||
<el-button :disabled="isReadOnly || status !== 'Running'" type="primary" plain size="mini"
|
||||
@click="stopTest(reportId)">
|
||||
{{$t('report.test_stop_now')}}
|
||||
</el-button>
|
||||
<!--<el-button :disabled="isReadOnly || status !== 'Completed'" type="success" plain size="mini">
|
||||
{{$t('report.test_execute_again')}}
|
||||
</el-button>
|
||||
<el-button :disabled="isReadOnly" type="info" plain size="mini">
|
||||
{{$t('report.export')}}
|
||||
</el-button>
|
||||
<el-button :disabled="isReadOnly" type="warning" plain size="mini">
|
||||
{{$t('report.compare')}}
|
||||
</el-button>-->
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<span class="ms-report-time-desc">
|
||||
|
@ -37,7 +46,7 @@
|
|||
|
||||
<el-tabs v-model="active" type="border-card" :stretch="true">
|
||||
<el-tab-pane :label="$t('report.test_overview')">
|
||||
<!-- <ms-report-test-overview :id="reportId" :status="status"/>-->
|
||||
<!-- <ms-report-test-overview :id="reportId" :status="status"/>-->
|
||||
<ms-report-test-overview :report="report"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('report.test_request_statistics')">
|
||||
|
@ -92,7 +101,8 @@
|
|||
seconds: '0',
|
||||
title: 'Logging',
|
||||
report: {},
|
||||
isReadOnly: false
|
||||
isReadOnly: false,
|
||||
websocket: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -114,19 +124,27 @@
|
|||
if (this.reportId) {
|
||||
this.result = this.$get("/performance/report/content/report_time/" + this.reportId)
|
||||
.then(res => {
|
||||
let data = res.data.data;
|
||||
if (data) {
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
let duration = data.duration;
|
||||
this.minutes = Math.floor(duration / 60);
|
||||
this.seconds = duration % 60;
|
||||
}
|
||||
}).catch(() => {
|
||||
this.clearData();
|
||||
})
|
||||
let data = res.data.data;
|
||||
if (data) {
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
let duration = data.duration;
|
||||
this.minutes = Math.floor(duration / 60);
|
||||
this.seconds = duration % 60;
|
||||
}
|
||||
}).catch(() => {
|
||||
this.clearData();
|
||||
})
|
||||
}
|
||||
},
|
||||
initWebSocket() {
|
||||
const uri = "ws://" + window.location.host + "/performance/report/" + this.reportId;
|
||||
this.websocket = new WebSocket(uri);
|
||||
this.websocket.onmessage = this.onMessage;
|
||||
this.websocket.onopen = this.onOpen;
|
||||
this.websocket.onerror = this.onError;
|
||||
this.websocket.onclose = this.onClose;
|
||||
},
|
||||
checkReportStatus(status) {
|
||||
switch (status) {
|
||||
case 'Error':
|
||||
|
@ -136,11 +154,7 @@
|
|||
this.$warning(this.$t('report.start_status'));
|
||||
break;
|
||||
case 'Reporting':
|
||||
this.$info(this.$t('report.being_generated'));
|
||||
break;
|
||||
case 'Running':
|
||||
this.$warning(this.$t('report.run_status'));
|
||||
break;
|
||||
case 'Completed':
|
||||
default:
|
||||
break;
|
||||
|
@ -151,6 +165,33 @@
|
|||
this.endTime = '0';
|
||||
this.minutes = '0';
|
||||
this.seconds = '0';
|
||||
},
|
||||
stopTest(reportId) {
|
||||
this.$confirm(this.$t('report.test_stop_now_confirm'), '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
cancelButtonText: this.$t('commons.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.result = this.$get('/performance/stop/' + reportId, () => {
|
||||
this.$success(this.$t('report.test_stop_success'));
|
||||
this.$router.push('/performance/report/all');
|
||||
})
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
onOpen() {
|
||||
window.console.log("open WebSocket");
|
||||
},
|
||||
onError(e) {
|
||||
window.console.error(e)
|
||||
},
|
||||
onMessage(e) {
|
||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
||||
this.initReportTimeInfo();
|
||||
},
|
||||
onClose(e) {
|
||||
this.$set(this.report, "refresh", e.data); // 触发刷新
|
||||
this.initReportTimeInfo();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -165,12 +206,15 @@
|
|||
this.$set(this.report, "id", this.reportId);
|
||||
this.$set(this.report, "status", data.status);
|
||||
this.checkReportStatus(data.status);
|
||||
if (this.status === "Completed") {
|
||||
if (this.status === "Completed" || this.status === "Running") {
|
||||
this.initReportTimeInfo();
|
||||
}
|
||||
})
|
||||
this.initBreadcrumb();
|
||||
|
||||
this.initWebSocket();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.websocket.close() //离开路由之后断开websocket连接
|
||||
},
|
||||
watch: {
|
||||
'$route'(to) {
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'" column-key="triggerMode" :filters="triggerFilters">
|
||||
<template v-slot:default="scope">
|
||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="status"
|
||||
column-key="status"
|
||||
|
@ -85,10 +90,13 @@
|
|||
import MsPerformanceReportStatus from "./PerformanceReportStatus";
|
||||
import {_filter, _sort} from "../../../../common/js/utils";
|
||||
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
|
||||
import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem";
|
||||
|
||||
export default {
|
||||
name: "PerformanceTestReport",
|
||||
components: {MsTableOperatorButton, MsPerformanceReportStatus, MsTablePagination, MsContainer, MsMainContainer},
|
||||
components: {
|
||||
ReportTriggerModeItem,
|
||||
MsTableOperatorButton, MsPerformanceReportStatus, MsTablePagination, MsContainer, MsMainContainer},
|
||||
created: function () {
|
||||
this.initTableData();
|
||||
},
|
||||
|
@ -112,7 +120,12 @@
|
|||
{text: 'Reporting', value: 'Reporting'},
|
||||
{text: 'Completed', value: 'Completed'},
|
||||
{text: 'Error', value: 'Error'}
|
||||
]
|
||||
],
|
||||
triggerFilters: [
|
||||
{text: '手动', value: 'MANUAL'},
|
||||
{text: '定时任务', value: 'SCHEDULE'},
|
||||
{text: 'API', value: 'API'}
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -155,7 +155,7 @@
|
|||
handler(val) {
|
||||
let status = val.status;
|
||||
this.id = val.id;
|
||||
if (status === "Completed") {
|
||||
if (status === "Completed" || status === "Running") {
|
||||
this.initTableData();
|
||||
} else {
|
||||
this.tableData = [];
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
handler(val) {
|
||||
let status = val.status;
|
||||
this.id = val.id;
|
||||
if (status === "Completed") {
|
||||
if (status === "Completed" || status === "Running") {
|
||||
this.getResource();
|
||||
} else {
|
||||
this.resource = [];
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
handler(val){
|
||||
let status = val.status;
|
||||
this.id = val.id;
|
||||
if (status === "Completed") {
|
||||
if (status === "Completed" || status === "Running") {
|
||||
this.initTableData();
|
||||
} else {
|
||||
this.tableData = [];
|
||||
|
|
|
@ -324,10 +324,10 @@
|
|||
},
|
||||
watch: {
|
||||
report: {
|
||||
handler(val){
|
||||
handler(val) {
|
||||
let status = val.status;
|
||||
this.id = val.id;
|
||||
if (status === "Completed") {
|
||||
if (status === "Completed" || status === "Running") {
|
||||
this.initTableData();
|
||||
} else {
|
||||
this.maxUsers = '0';
|
||||
|
@ -340,7 +340,7 @@
|
|||
this.resOption = {};
|
||||
}
|
||||
},
|
||||
deep:true
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
props: ['report']
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">{{$t('load_test.save_and_run')}}</el-button>
|
||||
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
|
||||
|
||||
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit"/>
|
||||
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit" :custom-validate="durationValidate"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
@ -177,7 +177,7 @@
|
|||
this.result = this.$request(options, (response) => {
|
||||
this.testPlan.id = response.data;
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.result = this.$post(this.runPath, {id: this.testPlan.id}, () => {
|
||||
this.result = this.$post(this.runPath, {id: this.testPlan.id, triggerMode: 'MANUAL'}, () => {
|
||||
this.$success(this.$t('load_test.is_running'))
|
||||
this.$router.push({path: '/performance/report/all'})
|
||||
})
|
||||
|
@ -278,6 +278,18 @@
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
durationValidate(intervalTime) {
|
||||
let duration = this.$refs.pressureConfig.duration * 60 * 1000;
|
||||
if (intervalTime < duration) {
|
||||
return {
|
||||
pass: false,
|
||||
info: '间隔时间不能小于压测时长'
|
||||
}
|
||||
}
|
||||
return {
|
||||
pass: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,13 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator :is-tester-permission="true" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)"/>
|
||||
<template v-if="baseUrl == 'api'" v-slot:default="scope">
|
||||
<ms-table-operator :is-tester-permission="true" @editClick="edit(scope.row)" @deleteClick="handleDelete(scope.row)">
|
||||
<template v-slot:behind>
|
||||
<ms-table-operator-button :is-tester-permission="true" :tip="'环境配置'" icon="el-icon-setting"
|
||||
type="info" @exec="openEnvironmentConfig(scope.row)"/>
|
||||
</template>
|
||||
</ms-table-operator>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
@ -59,6 +64,8 @@
|
|||
|
||||
<ms-delete-confirm :title="$t('project.delete')" @delete="_handleDelete" ref="deleteConfirm"/>
|
||||
|
||||
<api-environment-config ref="environmentConfig"/>
|
||||
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
|
@ -69,15 +76,18 @@
|
|||
import MsTableHeader from "../common/components/MsTableHeader";
|
||||
import MsTableOperator from "../common/components/MsTableOperator";
|
||||
import MsDialogFooter from "../common/components/MsDialogFooter";
|
||||
import {_sort, getCurrentOrganizationId, getCurrentUser, refreshSessionAndCookies} from "../../../common/js/utils";
|
||||
import {_sort, getCurrentUser} from "../../../common/js/utils";
|
||||
import MsContainer from "../common/components/MsContainer";
|
||||
import MsMainContainer from "../common/components/MsMainContainer";
|
||||
import MsDeleteConfirm from "../common/components/MsDeleteConfirm";
|
||||
import {DEFAULT} from "../../../common/js/constants";
|
||||
import MsTableOperatorButton from "../common/components/MsTableOperatorButton";
|
||||
import ApiEnvironmentConfig from "../api/test/components/ApiEnvironmentConfig";
|
||||
|
||||
export default {
|
||||
name: "MsProject",
|
||||
components: {
|
||||
ApiEnvironmentConfig,
|
||||
MsTableOperatorButton,
|
||||
MsDeleteConfirm,
|
||||
MsMainContainer,
|
||||
MsContainer, MsTableOperator, MsCreateBox, MsTablePagination, MsTableHeader, MsDialogFooter},
|
||||
|
@ -227,6 +237,9 @@
|
|||
_sort(column, this.condition);
|
||||
this.list();
|
||||
},
|
||||
openEnvironmentConfig(project) {
|
||||
this.$refs.environmentConfig.open(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -151,11 +151,7 @@
|
|||
this.$warning(this.$t('report.start_status'));
|
||||
break;
|
||||
case 'Reporting':
|
||||
this.$info(this.$t('report.being_generated'));
|
||||
break;
|
||||
case 'Running':
|
||||
this.$warning(this.$t('report.run_status'));
|
||||
break;
|
||||
case 'Completed':
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -128,9 +128,9 @@ export function _filter(filters, condition) {
|
|||
for (let filter in filters) {
|
||||
if (filters.hasOwnProperty(filter)) {
|
||||
if (filters[filter] && filters[filter].length > 0) {
|
||||
condition.filters[filter] = filters[filter];
|
||||
condition.filters[humpToLine(filter)] = filters[filter];
|
||||
} else {
|
||||
condition.filters[filter] = null;
|
||||
condition.filters[humpToLine(filter)] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,6 +204,8 @@ export default {
|
|||
'test_start_time': 'Test Start Time',
|
||||
'test_end_time': 'Test End Time',
|
||||
'test_stop_now': 'Test Stop Now',
|
||||
'test_stop_now_confirm': 'Are you sure you want to stop the current test immediately?',
|
||||
'test_stop_success': 'Test stop successfully',
|
||||
'test_execute_again': 'Test Execute Again',
|
||||
'export': 'Export',
|
||||
'compare': 'Compare',
|
||||
|
|
|
@ -202,6 +202,8 @@ export default {
|
|||
'test_start_time': '开始时间',
|
||||
'test_end_time': '结束时间',
|
||||
'test_stop_now': '立即停止',
|
||||
'test_stop_now_confirm': '确定要立即停止当前测试吗?',
|
||||
'test_stop_success': '停止成功',
|
||||
'test_execute_again': '再次执行',
|
||||
'export': '导出',
|
||||
'compare': '比较',
|
||||
|
|
|
@ -202,6 +202,8 @@ export default {
|
|||
'test_start_time': '開始時間',
|
||||
'test_end_time': '結束時間',
|
||||
'test_stop_now': '立即停止',
|
||||
'test_stop_now_confirm': '確定要立即停止當前測試嗎?',
|
||||
'test_stop_success': '停止成功',
|
||||
'test_execute_again': '再次執行',
|
||||
'export': '導出',
|
||||
'compare': '比較',
|
||||
|
|
Loading…
Reference in New Issue