Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
155b340e11
|
@ -36,10 +36,6 @@
|
|||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
@ -133,6 +129,13 @@
|
|||
<version>5.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- easyexcel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>2.1.7</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LoadTestReportDetail implements Serializable {
|
||||
private String reportId;
|
||||
|
||||
private String content;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public String getReportId() {
|
||||
return reportId;
|
||||
}
|
||||
|
||||
public void setReportId(String reportId) {
|
||||
this.reportId = reportId == null ? null : reportId.trim();
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content == null ? null : content.trim();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LoadTestReportDetailExample {
|
||||
protected String orderByClause;
|
||||
|
||||
protected boolean distinct;
|
||||
|
||||
protected List<Criteria> oredCriteria;
|
||||
|
||||
public LoadTestReportDetailExample() {
|
||||
oredCriteria = new ArrayList<Criteria>();
|
||||
}
|
||||
|
||||
public void setOrderByClause(String orderByClause) {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
public String getOrderByClause() {
|
||||
return orderByClause;
|
||||
}
|
||||
|
||||
public void setDistinct(boolean distinct) {
|
||||
this.distinct = distinct;
|
||||
}
|
||||
|
||||
public boolean isDistinct() {
|
||||
return distinct;
|
||||
}
|
||||
|
||||
public List<Criteria> getOredCriteria() {
|
||||
return oredCriteria;
|
||||
}
|
||||
|
||||
public void or(Criteria criteria) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
|
||||
public Criteria or() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
oredCriteria.add(criteria);
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public Criteria createCriteria() {
|
||||
Criteria criteria = createCriteriaInternal();
|
||||
if (oredCriteria.size() == 0) {
|
||||
oredCriteria.add(criteria);
|
||||
}
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected Criteria createCriteriaInternal() {
|
||||
Criteria criteria = new Criteria();
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
oredCriteria.clear();
|
||||
orderByClause = null;
|
||||
distinct = false;
|
||||
}
|
||||
|
||||
protected abstract static class GeneratedCriteria {
|
||||
protected List<Criterion> criteria;
|
||||
|
||||
protected GeneratedCriteria() {
|
||||
super();
|
||||
criteria = new ArrayList<Criterion>();
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return criteria.size() > 0;
|
||||
}
|
||||
|
||||
public List<Criterion> getAllCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
public List<Criterion> getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition) {
|
||||
if (condition == null) {
|
||||
throw new RuntimeException("Value for condition cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value, String property) {
|
||||
if (value == null) {
|
||||
throw new RuntimeException("Value for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value));
|
||||
}
|
||||
|
||||
protected void addCriterion(String condition, Object value1, Object value2, String property) {
|
||||
if (value1 == null || value2 == null) {
|
||||
throw new RuntimeException("Between values for " + property + " cannot be null");
|
||||
}
|
||||
criteria.add(new Criterion(condition, value1, value2));
|
||||
}
|
||||
|
||||
public Criteria andReportIdIsNull() {
|
||||
addCriterion("report_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdIsNotNull() {
|
||||
addCriterion("report_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdEqualTo(String value) {
|
||||
addCriterion("report_id =", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdNotEqualTo(String value) {
|
||||
addCriterion("report_id <>", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdGreaterThan(String value) {
|
||||
addCriterion("report_id >", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("report_id >=", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdLessThan(String value) {
|
||||
addCriterion("report_id <", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("report_id <=", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdLike(String value) {
|
||||
addCriterion("report_id like", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdNotLike(String value) {
|
||||
addCriterion("report_id not like", value, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdIn(List<String> values) {
|
||||
addCriterion("report_id in", values, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdNotIn(List<String> values) {
|
||||
addCriterion("report_id not in", values, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdBetween(String value1, String value2) {
|
||||
addCriterion("report_id between", value1, value2, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andReportIdNotBetween(String value1, String value2) {
|
||||
addCriterion("report_id not between", value1, value2, "reportId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
||||
protected Criteria() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criterion {
|
||||
private String condition;
|
||||
|
||||
private Object value;
|
||||
|
||||
private Object secondValue;
|
||||
|
||||
private boolean noValue;
|
||||
|
||||
private boolean singleValue;
|
||||
|
||||
private boolean betweenValue;
|
||||
|
||||
private boolean listValue;
|
||||
|
||||
private String typeHandler;
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object getSecondValue() {
|
||||
return secondValue;
|
||||
}
|
||||
|
||||
public boolean isNoValue() {
|
||||
return noValue;
|
||||
}
|
||||
|
||||
public boolean isSingleValue() {
|
||||
return singleValue;
|
||||
}
|
||||
|
||||
public boolean isBetweenValue() {
|
||||
return betweenValue;
|
||||
}
|
||||
|
||||
public boolean isListValue() {
|
||||
return listValue;
|
||||
}
|
||||
|
||||
public String getTypeHandler() {
|
||||
return typeHandler;
|
||||
}
|
||||
|
||||
protected Criterion(String condition) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.typeHandler = null;
|
||||
this.noValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.typeHandler = typeHandler;
|
||||
if (value instanceof List<?>) {
|
||||
this.listValue = true;
|
||||
} else {
|
||||
this.singleValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value) {
|
||||
this(condition, value, null);
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
|
||||
super();
|
||||
this.condition = condition;
|
||||
this.value = value;
|
||||
this.secondValue = secondValue;
|
||||
this.typeHandler = typeHandler;
|
||||
this.betweenValue = true;
|
||||
}
|
||||
|
||||
protected Criterion(String condition, Object value, Object secondValue) {
|
||||
this(condition, value, secondValue, null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
public class ZaleniumTest {
|
||||
|
||||
private String seleniumSessionId;
|
||||
private String testName;
|
||||
private String timestamp;
|
||||
private String addedToDashboardTime;
|
||||
private String browser;
|
||||
private String browserVersion;
|
||||
private String proxyName;
|
||||
private String platform;
|
||||
private String fileName;
|
||||
private String fileExtension;
|
||||
private String videoFolderPath;
|
||||
private String logsFolderPath;
|
||||
private String testNameNoExtension;
|
||||
private String screenDimension;
|
||||
private String timeZone;
|
||||
private String build;
|
||||
private String testFileNameTemplate;
|
||||
private String browserDriverLogFileName;
|
||||
private String retentionDate;
|
||||
private String testStatus;
|
||||
private boolean videoRecorded;
|
||||
|
||||
public String getSeleniumSessionId() {
|
||||
return seleniumSessionId;
|
||||
}
|
||||
|
||||
public void setSeleniumSessionId(String seleniumSessionId) {
|
||||
this.seleniumSessionId = seleniumSessionId;
|
||||
}
|
||||
|
||||
public String getTestName() {
|
||||
return testName;
|
||||
}
|
||||
|
||||
public void setTestName(String testName) {
|
||||
this.testName = testName;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(String timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getAddedToDashboardTime() {
|
||||
return addedToDashboardTime;
|
||||
}
|
||||
|
||||
public void setAddedToDashboardTime(String addedToDashboardTime) {
|
||||
this.addedToDashboardTime = addedToDashboardTime;
|
||||
}
|
||||
|
||||
public String getBrowser() {
|
||||
return browser;
|
||||
}
|
||||
|
||||
public void setBrowser(String browser) {
|
||||
this.browser = browser;
|
||||
}
|
||||
|
||||
public String getBrowserVersion() {
|
||||
return browserVersion;
|
||||
}
|
||||
|
||||
public void setBrowserVersion(String browserVersion) {
|
||||
this.browserVersion = browserVersion;
|
||||
}
|
||||
|
||||
public String getProxyName() {
|
||||
return proxyName;
|
||||
}
|
||||
|
||||
public void setProxyName(String proxyName) {
|
||||
this.proxyName = proxyName;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFileExtension() {
|
||||
return fileExtension;
|
||||
}
|
||||
|
||||
public void setFileExtension(String fileExtension) {
|
||||
this.fileExtension = fileExtension;
|
||||
}
|
||||
|
||||
public String getVideoFolderPath() {
|
||||
return videoFolderPath;
|
||||
}
|
||||
|
||||
public void setVideoFolderPath(String videoFolderPath) {
|
||||
this.videoFolderPath = videoFolderPath;
|
||||
}
|
||||
|
||||
public String getLogsFolderPath() {
|
||||
return logsFolderPath;
|
||||
}
|
||||
|
||||
public void setLogsFolderPath(String logsFolderPath) {
|
||||
this.logsFolderPath = logsFolderPath;
|
||||
}
|
||||
|
||||
public String getTestNameNoExtension() {
|
||||
return testNameNoExtension;
|
||||
}
|
||||
|
||||
public void setTestNameNoExtension(String testNameNoExtension) {
|
||||
this.testNameNoExtension = testNameNoExtension;
|
||||
}
|
||||
|
||||
public String getScreenDimension() {
|
||||
return screenDimension;
|
||||
}
|
||||
|
||||
public void setScreenDimension(String screenDimension) {
|
||||
this.screenDimension = screenDimension;
|
||||
}
|
||||
|
||||
public String getTimeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
public void setTimeZone(String timeZone) {
|
||||
this.timeZone = timeZone;
|
||||
}
|
||||
|
||||
public String getBuild() {
|
||||
return build;
|
||||
}
|
||||
|
||||
public void setBuild(String build) {
|
||||
this.build = build;
|
||||
}
|
||||
|
||||
public String getTestFileNameTemplate() {
|
||||
return testFileNameTemplate;
|
||||
}
|
||||
|
||||
public void setTestFileNameTemplate(String testFileNameTemplate) {
|
||||
this.testFileNameTemplate = testFileNameTemplate;
|
||||
}
|
||||
|
||||
public String getBrowserDriverLogFileName() {
|
||||
return browserDriverLogFileName;
|
||||
}
|
||||
|
||||
public void setBrowserDriverLogFileName(String browserDriverLogFileName) {
|
||||
this.browserDriverLogFileName = browserDriverLogFileName;
|
||||
}
|
||||
|
||||
public String getRetentionDate() {
|
||||
return retentionDate;
|
||||
}
|
||||
|
||||
public void setRetentionDate(String retentionDate) {
|
||||
this.retentionDate = retentionDate;
|
||||
}
|
||||
|
||||
public String getTestStatus() {
|
||||
return testStatus;
|
||||
}
|
||||
|
||||
public void setTestStatus(String testStatus) {
|
||||
this.testStatus = testStatus;
|
||||
}
|
||||
|
||||
public boolean isVideoRecorded() {
|
||||
return videoRecorded;
|
||||
}
|
||||
|
||||
public void setVideoRecorded(boolean videoRecorded) {
|
||||
this.videoRecorded = videoRecorded;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package io.metersphere.base.mapper;
|
||||
|
||||
import io.metersphere.base.domain.LoadTestReportDetail;
|
||||
import io.metersphere.base.domain.LoadTestReportDetailExample;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface LoadTestReportDetailMapper {
|
||||
long countByExample(LoadTestReportDetailExample example);
|
||||
|
||||
int deleteByExample(LoadTestReportDetailExample example);
|
||||
|
||||
int deleteByPrimaryKey(String reportId);
|
||||
|
||||
int insert(LoadTestReportDetail record);
|
||||
|
||||
int insertSelective(LoadTestReportDetail record);
|
||||
|
||||
List<LoadTestReportDetail> selectByExampleWithBLOBs(LoadTestReportDetailExample example);
|
||||
|
||||
List<LoadTestReportDetail> selectByExample(LoadTestReportDetailExample example);
|
||||
|
||||
LoadTestReportDetail selectByPrimaryKey(String reportId);
|
||||
|
||||
int updateByExampleSelective(@Param("record") LoadTestReportDetail record, @Param("example") LoadTestReportDetailExample example);
|
||||
|
||||
int updateByExampleWithBLOBs(@Param("record") LoadTestReportDetail record, @Param("example") LoadTestReportDetailExample example);
|
||||
|
||||
int updateByExample(@Param("record") LoadTestReportDetail record, @Param("example") LoadTestReportDetailExample example);
|
||||
|
||||
int updateByPrimaryKeySelective(LoadTestReportDetail record);
|
||||
|
||||
int updateByPrimaryKeyWithBLOBs(LoadTestReportDetail record);
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.base.mapper.LoadTestReportDetailMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
<id column="report_id" jdbcType="VARCHAR" property="reportId" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
<result column="content" jdbcType="LONGVARCHAR" property="content" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
<foreach collection="oredCriteria" item="criteria" separator="or">
|
||||
<if test="criteria.valid">
|
||||
<trim prefix="(" prefixOverrides="and" suffix=")">
|
||||
<foreach collection="criteria.criteria" item="criterion">
|
||||
<choose>
|
||||
<when test="criterion.noValue">
|
||||
and ${criterion.condition}
|
||||
</when>
|
||||
<when test="criterion.singleValue">
|
||||
and ${criterion.condition} #{criterion.value}
|
||||
</when>
|
||||
<when test="criterion.betweenValue">
|
||||
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
|
||||
</when>
|
||||
<when test="criterion.listValue">
|
||||
and ${criterion.condition}
|
||||
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
|
||||
#{listItem}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</foreach>
|
||||
</where>
|
||||
</sql>
|
||||
<sql id="Update_By_Example_Where_Clause">
|
||||
<where>
|
||||
<foreach collection="example.oredCriteria" item="criteria" separator="or">
|
||||
<if test="criteria.valid">
|
||||
<trim prefix="(" prefixOverrides="and" suffix=")">
|
||||
<foreach collection="criteria.criteria" item="criterion">
|
||||
<choose>
|
||||
<when test="criterion.noValue">
|
||||
and ${criterion.condition}
|
||||
</when>
|
||||
<when test="criterion.singleValue">
|
||||
and ${criterion.condition} #{criterion.value}
|
||||
</when>
|
||||
<when test="criterion.betweenValue">
|
||||
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
|
||||
</when>
|
||||
<when test="criterion.listValue">
|
||||
and ${criterion.condition}
|
||||
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
|
||||
#{listItem}
|
||||
</foreach>
|
||||
</when>
|
||||
</choose>
|
||||
</foreach>
|
||||
</trim>
|
||||
</if>
|
||||
</foreach>
|
||||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
report_id
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
content
|
||||
</sql>
|
||||
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.LoadTestReportDetailExample" resultMap="ResultMapWithBLOBs">
|
||||
select
|
||||
<if test="distinct">
|
||||
distinct
|
||||
</if>
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from load_test_report_detail
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.LoadTestReportDetailExample" resultMap="BaseResultMap">
|
||||
select
|
||||
<if test="distinct">
|
||||
distinct
|
||||
</if>
|
||||
<include refid="Base_Column_List" />
|
||||
from load_test_report_detail
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from load_test_report_detail
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</select>
|
||||
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
|
||||
delete from load_test_report_detail
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</delete>
|
||||
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.LoadTestReportDetailExample">
|
||||
delete from load_test_report_detail
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
insert into load_test_report_detail (report_id, content)
|
||||
values (#{reportId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
insert into load_test_report_detail
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="reportId != null">
|
||||
report_id,
|
||||
</if>
|
||||
<if test="content != null">
|
||||
content,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="reportId != null">
|
||||
#{reportId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="content != null">
|
||||
#{content,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.base.domain.LoadTestReportDetailExample" resultType="java.lang.Long">
|
||||
select count(*) from load_test_report_detail
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</select>
|
||||
<update id="updateByExampleSelective" parameterType="map">
|
||||
update load_test_report_detail
|
||||
<set>
|
||||
<if test="record.reportId != null">
|
||||
report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.content != null">
|
||||
content = #{record.content,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExampleWithBLOBs" parameterType="map">
|
||||
update load_test_report_detail
|
||||
set report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||
content = #{record.content,jdbcType=LONGVARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExample" parameterType="map">
|
||||
update load_test_report_detail
|
||||
set report_id = #{record.reportId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
update load_test_report_detail
|
||||
<set>
|
||||
<if test="content != null">
|
||||
content = #{content,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.LoadTestReportDetail">
|
||||
update load_test_report_detail
|
||||
set content = #{content,jdbcType=LONGVARCHAR}
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -0,0 +1,7 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface ExtLoadTestReportDetailMapper {
|
||||
int appendLine(@Param("reportId") String id, @Param("line") String line);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtLoadTestReportDetailMapper">
|
||||
<update id="appendLine">
|
||||
UPDATE load_test_report_detail
|
||||
SET content = concat(content, #{line})
|
||||
WHERE report_id = #{reportId}
|
||||
</update>
|
||||
</mapper>
|
|
@ -0,0 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum PerformanceTestStatus {
|
||||
Saved, Starting, Running, Completed, Error
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public class TestCaseConstants {
|
||||
public static final int MAX_NODE_DEPTH = 5;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum TestStatus {
|
||||
Starting, Running, Completed, Error
|
||||
}
|
|
@ -4,7 +4,6 @@ import com.github.pagehelper.Page;
|
|||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.base.domain.FileMetadata;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.controller.request.testplan.*;
|
||||
|
@ -86,10 +85,7 @@ public class PerformanceTestController {
|
|||
|
||||
@PostMapping("/run")
|
||||
public void run(@RequestBody RunTestPlanRequest request) {
|
||||
boolean started = performanceTestService.run(request);
|
||||
if (!started) {
|
||||
MSException.throwException("Start engine error, please check log.");
|
||||
}
|
||||
performanceTestService.run(request);
|
||||
}
|
||||
|
||||
@GetMapping("/file/metadata/{testId}")
|
||||
|
|
|
@ -6,14 +6,11 @@ import io.metersphere.base.domain.*;
|
|||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
|
||||
import io.metersphere.controller.request.testplan.QueryTestPlanRequest;
|
||||
import io.metersphere.dto.LoadTestDTO;
|
||||
import io.metersphere.dto.TestCaseNodeDTO;
|
||||
import io.metersphere.dto.TestPlanCaseDTO;
|
||||
import io.metersphere.service.TestCaseNodeService;
|
||||
import io.metersphere.excel.domain.ExcelResponse;
|
||||
import io.metersphere.service.TestCaseService;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
@ -74,5 +71,10 @@ public class TestCaseController {
|
|||
return testCaseService.deleteTestCase(testCaseId);
|
||||
}
|
||||
|
||||
@PostMapping("/import/{projectId}")
|
||||
public ExcelResponse testCaseImport(MultipartFile file, @PathVariable String projectId){
|
||||
return testCaseService.testCaseImport(file, projectId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import com.alibaba.fastjson.JSONObject;
|
|||
import io.metersphere.base.domain.LoadTestWithBLOBs;
|
||||
import io.metersphere.base.domain.TestResource;
|
||||
import io.metersphere.base.domain.TestResourcePool;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
|
||||
import io.metersphere.commons.constants.TestStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
|
@ -70,7 +70,7 @@ public abstract class AbstractEngine implements Engine {
|
|||
List<LoadTestWithBLOBs> loadTests = performanceTestService.selectByTestResourcePoolId(loadTest.getTestResourcePoolId());
|
||||
// 使用当前资源池正在运行的测试占用的并发数
|
||||
return loadTests.stream()
|
||||
.filter(t -> TestStatus.Running.name().equals(t.getStatus()))
|
||||
.filter(t -> PerformanceTestStatus.Running.name().equals(t.getStatus()))
|
||||
.map(this::getThreadNum)
|
||||
.reduce(Integer::sum)
|
||||
.orElse(0);
|
||||
|
|
|
@ -12,6 +12,7 @@ import io.metersphere.engine.EngineContext;
|
|||
import io.metersphere.engine.EngineFactory;
|
||||
import io.metersphere.engine.docker.request.BaseRequest;
|
||||
import io.metersphere.engine.docker.request.TestRequest;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -41,7 +42,7 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
.reduce(Integer::sum)
|
||||
.orElse(0);
|
||||
if (threadNum > totalThreadNum - runningSumThreadNum) {
|
||||
MSException.throwException("Insufficient resources");
|
||||
MSException.throwException(Translator.get("max_thread_insufficient"));
|
||||
}
|
||||
List<Integer> resourceRatio = resourceList.stream()
|
||||
.filter(r -> ResourceStatusEnum.VALID.name().equals(r.getStatus()))
|
||||
|
|
|
@ -15,6 +15,7 @@ import io.metersphere.engine.kubernetes.crds.jmeter.Jmeter;
|
|||
import io.metersphere.engine.kubernetes.crds.jmeter.JmeterSpec;
|
||||
import io.metersphere.engine.kubernetes.provider.ClientCredential;
|
||||
import io.metersphere.engine.kubernetes.provider.KubernetesProvider;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -43,7 +44,7 @@ public class KubernetesTestEngine extends AbstractEngine {
|
|||
Integer maxConcurrency = clientCredential.getMaxConcurrency();
|
||||
// 当前测试需要的并发数大于剩余的并发数报错
|
||||
if (threadNum > maxConcurrency - sumThreadNum) {
|
||||
MSException.throwException("Insufficient resources");
|
||||
MSException.throwException(Translator.get("max_thread_insufficient"));
|
||||
}
|
||||
try {
|
||||
EngineContext context = EngineFactory.createContext(loadTest, threadNum, this.getStartTime(), this.getReportId());
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package io.metersphere.excel.domain;
|
||||
|
||||
public class ExcelErrData<T> {
|
||||
|
||||
private T t;
|
||||
|
||||
private Integer rowNum;
|
||||
|
||||
private String errMsg;
|
||||
|
||||
public ExcelErrData(){}
|
||||
|
||||
public ExcelErrData(T t, Integer rowNum,String errMsg){
|
||||
this.t = t;
|
||||
this.rowNum = rowNum;
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
public T getT() {
|
||||
return t;
|
||||
}
|
||||
|
||||
public void setT(T t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public String getErrMsg() {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
public void setErrMsg(String errMsg) {
|
||||
this.errMsg = errMsg;
|
||||
}
|
||||
|
||||
public Integer getRowNum() {
|
||||
return rowNum;
|
||||
}
|
||||
|
||||
public void setRowNum(Integer rowNum) {
|
||||
this.rowNum = rowNum;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.excel.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ExcelResponse<T> {
|
||||
|
||||
private Boolean success;
|
||||
private List<ExcelErrData<T>> errList;
|
||||
|
||||
public Boolean getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(Boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public List<ExcelErrData<T>> getErrList() {
|
||||
return errList;
|
||||
}
|
||||
|
||||
public void setErrList(List<ExcelErrData<T>> errList) {
|
||||
this.errList = errList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package io.metersphere.excel.domain;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
public class TestCaseExcelData {
|
||||
|
||||
@NotBlank
|
||||
@Length(max=1000)
|
||||
@ExcelProperty("所属模块")
|
||||
@Pattern(regexp = "^(?!.*//).*$", message = "格式不正确")
|
||||
private String nodePath;
|
||||
|
||||
@NotBlank
|
||||
@Length(max=50)
|
||||
@ExcelProperty("用例名称")
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
@ExcelProperty("用例类型")
|
||||
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "必须为functional、performance、api")
|
||||
private String type;
|
||||
|
||||
@NotBlank
|
||||
@ExcelProperty("维护人")
|
||||
private String maintainer;
|
||||
|
||||
@NotBlank
|
||||
@ExcelProperty("优先级")
|
||||
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "必须为P0、P1、P2、P3")
|
||||
private String priority;
|
||||
|
||||
@NotBlank
|
||||
@ExcelProperty("测试方式")
|
||||
@Pattern(regexp = "(^manual$)|(^auto$)", message = "必须为manual、auto")
|
||||
private String method;
|
||||
|
||||
@ExcelProperty("前置条件")
|
||||
@Length(min=0, max=1000)
|
||||
private String prerequisite;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
@Length(max=1000)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty("步骤描述")
|
||||
@Length(max=1000)
|
||||
private String stepDesc;
|
||||
|
||||
@ExcelProperty("预期结果")
|
||||
@Length(max=1000)
|
||||
private String stepResult;
|
||||
|
||||
public String getNodePath() {
|
||||
return nodePath;
|
||||
}
|
||||
|
||||
public void setNodePath(String nodePath) {
|
||||
this.nodePath = nodePath;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getMaintainer() {
|
||||
return maintainer;
|
||||
}
|
||||
|
||||
public void setMaintainer(String maintainer) {
|
||||
this.maintainer = maintainer;
|
||||
}
|
||||
|
||||
public String getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(String priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public String getPrerequisite() {
|
||||
return prerequisite;
|
||||
}
|
||||
|
||||
public void setPrerequisite(String prerequisite) {
|
||||
this.prerequisite = prerequisite;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public String getStepDesc() {
|
||||
return stepDesc;
|
||||
}
|
||||
|
||||
public void setStepDesc(String stepDesc) {
|
||||
this.stepDesc = stepDesc;
|
||||
}
|
||||
|
||||
public String getStepResult() {
|
||||
return stepResult;
|
||||
}
|
||||
|
||||
public void setStepResult(String stepResult) {
|
||||
this.stepResult = stepResult;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package io.metersphere.excel.listener;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
import com.alibaba.excel.exception.ExcelAnalysisException;
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.excel.util.ExcelValidateHelper;
|
||||
import io.metersphere.excel.domain.ExcelErrData;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
|
||||
|
||||
protected List<ExcelErrData<T>> errList = new ArrayList<>();
|
||||
|
||||
protected List<T> list = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 每隔2000条存储数据库,然后清理list ,方便内存回收
|
||||
*/
|
||||
protected static final int BATCH_COUNT = 2000;
|
||||
|
||||
protected Class<T> clazz;
|
||||
|
||||
|
||||
public EasyExcelListener(Class<T> clazz){
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个每一条数据解析都会来调用
|
||||
*
|
||||
* @param t
|
||||
* @param analysisContext
|
||||
*/
|
||||
@Override
|
||||
public void invoke(T t, AnalysisContext analysisContext) {
|
||||
String errMsg;
|
||||
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
||||
try {
|
||||
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
||||
errMsg = ExcelValidateHelper.validateEntity(t);
|
||||
//自定义校验规则
|
||||
errMsg = validate(t, errMsg);
|
||||
} catch (NoSuchFieldException e) {
|
||||
errMsg = "解析数据出错";
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(errMsg)) {
|
||||
ExcelErrData excelErrData = new ExcelErrData(t, rowIndex, "第" + rowIndex + "行出错:" + errMsg);
|
||||
errList.add(excelErrData);
|
||||
} else {
|
||||
list.add(t);
|
||||
}
|
||||
|
||||
if (list.size() > BATCH_COUNT) {
|
||||
saveData();
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 可重写该方法
|
||||
* 自定义校验规则
|
||||
* @param data
|
||||
* @param errMsg
|
||||
* @return
|
||||
*/
|
||||
public String validate(T data, String errMsg) {
|
||||
return errMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义数据保存操作
|
||||
*/
|
||||
public abstract void saveData();
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||
saveData();
|
||||
list.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验excel头部
|
||||
* @param headMap 传入excel的头部(第一行数据)数据的index,name
|
||||
* @param context
|
||||
*/
|
||||
@Override
|
||||
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
|
||||
super.invokeHeadMap(headMap, context);
|
||||
if (clazz != null){
|
||||
try {
|
||||
Set<String> fieldNameSet = getFieldNameSet(clazz);
|
||||
Collection<String> values = headMap.values();
|
||||
for (String key : fieldNameSet) {
|
||||
if (!values.contains(key)){
|
||||
throw new ExcelAnalysisException("缺少头部信息:" + key);
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 获取注解里ExcelProperty的value
|
||||
*/
|
||||
public Set<String> getFieldNameSet(Class clazz) throws NoSuchFieldException {
|
||||
Set<String> result = new HashSet<>();
|
||||
Field field;
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (int i = 0; i < fields.length ; i++) {
|
||||
field = clazz.getDeclaredField(fields[i].getName());
|
||||
field.setAccessible(true);
|
||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||
if(excelProperty != null){
|
||||
StringBuilder value = new StringBuilder();
|
||||
for (String v : excelProperty.value()) {
|
||||
value.append(v);
|
||||
}
|
||||
result.add(value.toString());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public List<ExcelErrData<T>> getErrList() {
|
||||
return errList;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package io.metersphere.excel.listener;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.service.TestCaseService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
||||
|
||||
private TestCaseService testCaseService;
|
||||
|
||||
private String projectId;
|
||||
|
||||
Set<String> testCaseNames;
|
||||
|
||||
Set<String> userNames;
|
||||
|
||||
public TestCaseDataListener(TestCaseService testCaseService, String projectId,
|
||||
Set<String> testCaseNames, Set<String> userNames, Class<TestCaseExcelData> clazz) {
|
||||
super(clazz);
|
||||
this.testCaseService = testCaseService;
|
||||
this.projectId = projectId;
|
||||
this.testCaseNames = testCaseNames;
|
||||
this.userNames = userNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String validate(TestCaseExcelData data, String errMsg) {
|
||||
String nodePath = data.getNodePath();
|
||||
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
||||
if ( nodePath.split("/").length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
|
||||
stringBuilder.append("节点最多为" + TestCaseConstants.MAX_NODE_DEPTH + "层;");
|
||||
}
|
||||
if (!userNames.contains(data.getMaintainer())) {
|
||||
stringBuilder.append("该工作空间下无该用户:" + data.getMaintainer() + ";");
|
||||
}
|
||||
if (testCaseNames.contains(data.getName())) {
|
||||
stringBuilder.append("该项目下已存在该测试用例:" + data.getName() + ";");
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData() {
|
||||
|
||||
//无错误数据才插入数据
|
||||
if (!errList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<TestCaseWithBLOBs> result = list.stream()
|
||||
.map(item -> this.convert2TestCase(item))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
testCaseService.saveImportData(result, projectId);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private TestCaseWithBLOBs convert2TestCase(TestCaseExcelData data) {
|
||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||
BeanUtils.copyBean(testCase, data);
|
||||
testCase.setId(UUID.randomUUID().toString());
|
||||
testCase.setProjectId(this.projectId);
|
||||
testCase.setCreateTime(System.currentTimeMillis());
|
||||
testCase.setUpdateTime(System.currentTimeMillis());
|
||||
String nodePath = data.getNodePath();
|
||||
|
||||
if (!nodePath.startsWith("/")) {
|
||||
nodePath = "/" + nodePath;
|
||||
}
|
||||
if (nodePath.endsWith("/")) {
|
||||
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
||||
}
|
||||
|
||||
testCase.setNodePath(nodePath);
|
||||
|
||||
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
|
||||
String[] stepDesc = new String[0];
|
||||
String[] stepRes = new String[0];
|
||||
|
||||
if (data.getStepDesc() != null) {
|
||||
stepDesc = data.getStepDesc().split("\n");
|
||||
}
|
||||
if (data.getStepResult() != null) {
|
||||
stepRes = data.getStepResult().split("\n");
|
||||
}
|
||||
|
||||
String pattern = "(^\\d+)(\\.)?";
|
||||
int index = stepDesc.length > stepRes.length ? stepDesc.length : stepRes.length;
|
||||
|
||||
for (int i = 0; i < index; i++){
|
||||
|
||||
JSONObject step = new JSONObject();
|
||||
step.put("num", i + 1);
|
||||
|
||||
Pattern descPattern = Pattern.compile(pattern);
|
||||
Pattern resPattern = Pattern.compile(pattern);
|
||||
|
||||
if (i < stepDesc.length) {
|
||||
Matcher descMatcher = descPattern.matcher(stepDesc[i]);
|
||||
if (descMatcher.find()) {
|
||||
step.put("desc", descMatcher.replaceAll(""));
|
||||
} else {
|
||||
step.put("desc", stepDesc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < stepRes.length) {
|
||||
Matcher resMatcher = resPattern.matcher(stepRes[i]);
|
||||
if (resMatcher.find()) {
|
||||
step.put("result", resMatcher.replaceAll(""));
|
||||
} else {
|
||||
step.put("result", stepRes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
jsonArray.add(step);
|
||||
}
|
||||
|
||||
testCase.setSteps(jsonArray.toJSONString());
|
||||
|
||||
return testCase;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package io.metersphere.excel.util;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.groups.Default;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class ExcelValidateHelper {
|
||||
|
||||
private ExcelValidateHelper(){}
|
||||
|
||||
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
|
||||
public static <T> String validateEntity(T obj) throws NoSuchFieldException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
|
||||
if (set != null && !set.isEmpty()) {
|
||||
for (ConstraintViolation<T> cv : set) {
|
||||
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
|
||||
ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
|
||||
//拼接错误信息,包含当前出错数据的标题名字+错误信息
|
||||
result.append(annotation.value()[0]+cv.getMessage()).append(";");
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package io.metersphere.exception;
|
||||
|
||||
/**
|
||||
* @author jianxing.chen
|
||||
*/
|
||||
public class ExcelImportException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ExcelImportException(String message, Exception e){
|
||||
super(message, e);
|
||||
}
|
||||
|
||||
public ExcelImportException(String message){
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -104,7 +104,7 @@ public class JtlResolver {
|
|||
String average = decimalFormat.format((float) oneLineElapsedTime / jtlSamplesSize);
|
||||
requestStatistics.setAverage(average);
|
||||
|
||||
/**
|
||||
/*
|
||||
* TP90的计算
|
||||
* 1,把一段时间内全部的请求的响应时间,从小到大排序,获得序列A
|
||||
* 2,总的请求数量,乘以90%,获得90%对应的请求个数C
|
||||
|
@ -123,7 +123,7 @@ public class JtlResolver {
|
|||
requestStatistics.setMax(elapsedList.get(jtlSamplesSize - 1) + "");
|
||||
requestStatistics.setErrors(decimalFormat.format(failSize * 100.0 / jtlSamplesSize) + "%");
|
||||
requestStatistics.setKo(failSize);
|
||||
/**
|
||||
/*
|
||||
* 所有的相同请求的bytes总和 / 1024 / 请求持续运行的时间=sum(bytes)/1024/total time
|
||||
* total time = 最大时间戳 - 最小时间戳 + 最后请求的响应时间
|
||||
*/
|
||||
|
@ -268,20 +268,34 @@ public class JtlResolver {
|
|||
DecimalFormat decimalFormat = new DecimalFormat("0.00");
|
||||
|
||||
List<Metric> totalLineList = JtlResolver.resolver(jtlString);
|
||||
// todo
|
||||
List<Metric> totalLineList2 = JtlResolver.resolver(jtlString);
|
||||
// 时间戳转时间
|
||||
for (Metric metric : totalLineList2) {
|
||||
metric.setTimestamp(stampToDate(DATE_TIME_PATTERN, metric.getTimestamp()));
|
||||
}
|
||||
|
||||
Map<String, List<Metric>> collect2 = Objects.requireNonNull(totalLineList2).stream().collect(Collectors.groupingBy(Metric::getTimestamp));
|
||||
List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(collect2.entrySet());
|
||||
int maxUsers = 0;
|
||||
for (Map.Entry<String, List<Metric>> entry : entries) {
|
||||
List<Metric> metrics = entry.getValue();
|
||||
Map<String, List<Metric>> metricsMap = metrics.stream().collect(Collectors.groupingBy(Metric::getThreadName));
|
||||
if (metricsMap.size() > maxUsers) {
|
||||
maxUsers = metricsMap.size();
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, List<Metric>> collect = totalLineList.stream().collect(Collectors.groupingBy(Metric::getTimestamp));
|
||||
Iterator<Map.Entry<String, List<Metric>>> iterator = collect.entrySet().iterator();
|
||||
|
||||
int maxUsers = 0, totalElapsed = 0;
|
||||
int totalElapsed = 0;
|
||||
float totalBytes = 0f;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<Metric>> entry = iterator.next();
|
||||
List<Metric> metricList = entry.getValue();
|
||||
|
||||
if (metricList.size() > maxUsers) {
|
||||
maxUsers = metricList.size();
|
||||
}
|
||||
|
||||
for (Metric metric : metricList) {
|
||||
String elapsed = metric.getElapsed();
|
||||
totalElapsed += Integer.parseInt(elapsed);
|
||||
|
@ -420,22 +434,22 @@ public class JtlResolver {
|
|||
totalLineList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
|
||||
|
||||
String startTimeStamp = totalLineList.get(0).getTimestamp();
|
||||
String endTimeStamp = totalLineList.get(totalLineList.size() - 1).getTimestamp();
|
||||
String endTimeStamp = totalLineList.get(totalLineList.size()-1).getTimestamp();
|
||||
|
||||
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
|
||||
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
|
||||
String startTime = dtf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(startTimeStamp)), ZoneId.systemDefault()));
|
||||
String endTime = dtf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(endTimeStamp)), ZoneId.systemDefault()));
|
||||
reportTimeInfo.setStartTime(startTime);
|
||||
reportTimeInfo.setEndTime(endTime);
|
||||
|
||||
Date startDate = new Date(Long.parseLong(startTimeStamp));
|
||||
Date endDate = new Date(Long.parseLong(endTimeStamp));
|
||||
long timestamp = endDate.getTime() - startDate.getTime();
|
||||
reportTimeInfo.setDuration(String.valueOf(timestamp*1.0 / 1000 / 60));
|
||||
|
||||
// todo 时间问题
|
||||
long seconds = Duration.between(Instant.ofEpochMilli(Long.parseLong(startTimeStamp)), Instant.ofEpochMilli(Long.parseLong(endTimeStamp))).getSeconds();
|
||||
String duration;
|
||||
if (seconds / 60 == 0) {
|
||||
duration = String.valueOf(1);
|
||||
} else {
|
||||
duration = String.valueOf(seconds / 60);
|
||||
}
|
||||
reportTimeInfo.setDuration(duration);
|
||||
reportTimeInfo.setDuration(String.valueOf(seconds));
|
||||
|
||||
return reportTimeInfo;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@ package io.metersphere.service;
|
|||
import io.metersphere.base.domain.*;
|
||||
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.FileType;
|
||||
import io.metersphere.commons.constants.TestStatus;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.controller.request.testplan.*;
|
||||
|
@ -48,6 +49,10 @@ public class PerformanceTestService {
|
|||
private LoadTestReportMapper loadTestReportMapper;
|
||||
@Resource
|
||||
private ExtLoadTestReportMapper extLoadTestReportMapper;
|
||||
@Resource
|
||||
private LoadTestReportDetailMapper loadTestReportDetailMapper;
|
||||
@Resource
|
||||
private ExtLoadTestReportDetailMapper extLoadTestReportDetailMapper;
|
||||
|
||||
public List<LoadTestDTO> list(QueryTestPlanRequest request) {
|
||||
return extLoadTestMapper.list(request);
|
||||
|
@ -93,6 +98,7 @@ public class PerformanceTestService {
|
|||
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
|
||||
loadTest.setLoadConfiguration(request.getLoadConfiguration());
|
||||
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
|
||||
loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||
loadTestMapper.insert(loadTest);
|
||||
return loadTest;
|
||||
}
|
||||
|
@ -158,19 +164,22 @@ public class PerformanceTestService {
|
|||
loadTest.setLoadConfiguration(request.getLoadConfiguration());
|
||||
loadTest.setAdvancedConfiguration(request.getAdvancedConfiguration());
|
||||
loadTest.setTestResourcePoolId(request.getTestResourcePoolId());
|
||||
// todo 修改 load_test 的时候排除状态,这里存在修改了 Running 的测试状态的风险
|
||||
// loadTest.setStatus(PerformanceTestStatus.Saved.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
}
|
||||
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
public boolean run(RunTestPlanRequest request) {
|
||||
@Transactional(noRollbackFor = MSException.class)// 保存失败的信息
|
||||
public void run(RunTestPlanRequest request) {
|
||||
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
|
||||
if (loadTest == null) {
|
||||
MSException.throwException(Translator.get("run_load_test_not_found") + request.getId());
|
||||
}
|
||||
|
||||
if (StringUtils.equalsAny(loadTest.getStatus(), TestStatus.Running.name(), TestStatus.Starting.name())) {
|
||||
if (StringUtils.equalsAny(loadTest.getStatus(), PerformanceTestStatus.Running.name(), PerformanceTestStatus.Starting.name())) {
|
||||
MSException.throwException(Translator.get("load_test_is_running"));
|
||||
}
|
||||
|
||||
|
@ -181,12 +190,12 @@ public class PerformanceTestService {
|
|||
MSException.throwException(String.format("Test cannot be run,test ID:%s", request.getId()));
|
||||
}
|
||||
|
||||
return startEngine(loadTest, engine);
|
||||
startEngine(loadTest, engine);
|
||||
|
||||
// todo:通过调用stop方法能够停止正在运行的engine,但是如果部署了多个backend实例,页面发送的停止请求如何定位到具体的engine
|
||||
}
|
||||
|
||||
private boolean startEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||
private void startEngine(LoadTestWithBLOBs loadTest, Engine engine) {
|
||||
LoadTestReportWithBLOBs testReport = new LoadTestReportWithBLOBs();
|
||||
testReport.setId(engine.getReportId());
|
||||
testReport.setCreateTime(engine.getStartTime());
|
||||
|
@ -194,31 +203,32 @@ public class PerformanceTestService {
|
|||
testReport.setTestId(loadTest.getId());
|
||||
testReport.setName(loadTest.getName());
|
||||
// 启动测试
|
||||
boolean started = true;
|
||||
|
||||
try {
|
||||
engine.start();
|
||||
// 标记running状态
|
||||
loadTest.setStatus(TestStatus.Starting.name());
|
||||
// 启动正常修改状态 starting
|
||||
loadTest.setStatus(PerformanceTestStatus.Starting.name());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
|
||||
// 启动正常插入 report
|
||||
testReport.setContent(HEADERS);
|
||||
testReport.setStatus(TestStatus.Starting.name());
|
||||
testReport.setStatus(PerformanceTestStatus.Starting.name());
|
||||
loadTestReportMapper.insertSelective(testReport);
|
||||
|
||||
LoadTestReportDetail reportDetail = new LoadTestReportDetail();
|
||||
reportDetail.setContent(HEADERS);
|
||||
reportDetail.setReportId(testReport.getId());
|
||||
loadTestReportDetailMapper.insertSelective(reportDetail);
|
||||
// append \n
|
||||
extLoadTestReportMapper.appendLine(testReport.getId(), "\n");
|
||||
|
||||
} catch (Exception e) {
|
||||
// append \n
|
||||
extLoadTestReportDetailMapper.appendLine(testReport.getId(), "\n");
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
started = false;
|
||||
|
||||
loadTest.setStatus(TestStatus.Error.name());
|
||||
loadTest.setStatus(PerformanceTestStatus.Error.name());
|
||||
loadTest.setDescription(e.getMessage());
|
||||
loadTestMapper.updateByPrimaryKeySelective(loadTest);
|
||||
//
|
||||
testReport.setStatus(TestStatus.Error.name());
|
||||
testReport.setDescription(e.getMessage());
|
||||
loadTestReportMapper.insertSelective(testReport);
|
||||
throw e;
|
||||
}
|
||||
return started;
|
||||
}
|
||||
|
||||
public List<LoadTestDTO> recentTestPlans(QueryTestPlanRequest request) {
|
||||
|
|
|
@ -5,7 +5,7 @@ import io.metersphere.base.domain.LoadTestReportExample;
|
|||
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
|
||||
import io.metersphere.base.mapper.LoadTestReportMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
|
||||
import io.metersphere.commons.constants.TestStatus;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.controller.request.ReportRequest;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
|
@ -112,9 +112,9 @@ public class ReportService {
|
|||
public void checkReportStatus(String reportId) {
|
||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||
String reportStatus = loadTestReport.getStatus();
|
||||
if (StringUtils.equals(TestStatus.Running.name(), reportStatus)) {
|
||||
if (StringUtils.equals(PerformanceTestStatus.Running.name(), reportStatus)) {
|
||||
MSException.throwException("Reporting in progress...");
|
||||
} else if (StringUtils.equals(TestStatus.Error.name(), reportStatus)) {
|
||||
} else if (StringUtils.equals(PerformanceTestStatus.Error.name(), reportStatus)) {
|
||||
MSException.throwException("Report generation error!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,11 @@ import io.metersphere.base.mapper.TestCaseMapper;
|
|||
import io.metersphere.base.mapper.TestCaseNodeMapper;
|
||||
import io.metersphere.base.mapper.TestPlanMapper;
|
||||
import io.metersphere.base.mapper.TestPlanTestCaseMapper;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.dto.TestCaseNodeDTO;
|
||||
import io.metersphere.exception.ExcelImportException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -30,8 +33,8 @@ public class TestCaseNodeService {
|
|||
|
||||
public int addNode(TestCaseNode node) {
|
||||
|
||||
if(node.getLevel() > 5){
|
||||
throw new RuntimeException("模块树最大深度为5层!");
|
||||
if(node.getLevel() > TestCaseConstants.MAX_NODE_DEPTH){
|
||||
throw new RuntimeException("模块树最大深度为" + TestCaseConstants.MAX_NODE_DEPTH + "层!");
|
||||
}
|
||||
node.setCreateTime(System.currentTimeMillis());
|
||||
node.setUpdateTime(System.currentTimeMillis());
|
||||
|
@ -196,4 +199,124 @@ public class TestCaseNodeService {
|
|||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId);
|
||||
return getNodeTreeByProjectId(testPlan.getProjectId());
|
||||
}
|
||||
|
||||
public Map<String, Integer> createNodeByTestCases(List<TestCaseWithBLOBs> testCases, String projectId) {
|
||||
|
||||
List<TestCaseNodeDTO> nodeTrees = getNodeTreeByProjectId(projectId);
|
||||
|
||||
Map<String, Integer> pathMap = new HashMap<>();
|
||||
|
||||
List<String> nodePaths = testCases.stream()
|
||||
.map(TestCase::getNodePath)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
nodePaths.forEach(path -> {
|
||||
|
||||
if (path == null) {
|
||||
throw new ExcelImportException("所属模块不能为空!");
|
||||
}
|
||||
List<String> nodeNameList = new ArrayList<>(Arrays.asList(path.split("/")));
|
||||
Iterator<String> pathIterator = nodeNameList.iterator();
|
||||
|
||||
Boolean hasNode = false;
|
||||
String rootNodeName = null;
|
||||
|
||||
if (nodeNameList.size() <= 1) {
|
||||
throw new ExcelImportException("创建模块失败:" + path);
|
||||
} else {
|
||||
pathIterator.next();
|
||||
pathIterator.remove();
|
||||
|
||||
rootNodeName = pathIterator.next().trim();
|
||||
for (TestCaseNodeDTO nodeTree : nodeTrees) {
|
||||
if (StringUtils.equals(rootNodeName, nodeTree.getName())) {
|
||||
hasNode = true;
|
||||
createNodeByPathIterator(pathIterator, "/" + rootNodeName, nodeTree,
|
||||
pathMap, projectId, 2);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasNode) {
|
||||
createNodeByPath(pathIterator, rootNodeName, null, projectId, 1, "", pathMap);
|
||||
}
|
||||
});
|
||||
|
||||
return pathMap;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据目标节点路径,创建相关节点
|
||||
* @param pathIterator 遍历子路径
|
||||
* @param path 当前路径
|
||||
* @param treeNode 当前节点
|
||||
* @param pathMap 记录节点路径对应的nodeId
|
||||
*/
|
||||
private void createNodeByPathIterator(Iterator<String> pathIterator, String path, TestCaseNodeDTO treeNode,
|
||||
Map<String, Integer> pathMap, String projectId, Integer level) {
|
||||
|
||||
List<TestCaseNodeDTO> children = treeNode.getChildren();
|
||||
|
||||
if (children == null || children.isEmpty() || !pathIterator.hasNext()) {
|
||||
pathMap.put(path , treeNode.getId());
|
||||
if (pathIterator.hasNext()) {
|
||||
createNodeByPath(pathIterator, pathIterator.next().trim(), treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String nodeName = pathIterator.next().trim();
|
||||
|
||||
Boolean hasNode = false;
|
||||
|
||||
for (TestCaseNodeDTO child : children) {
|
||||
if (StringUtils.equals(nodeName, child.getName())) {
|
||||
hasNode = true;
|
||||
createNodeByPathIterator(pathIterator, path + "/" + child.getName(),
|
||||
child, pathMap, projectId, level + 1);
|
||||
};
|
||||
}
|
||||
|
||||
//若子节点中不包含该目标节点,则在该节点下创建
|
||||
if (!hasNode) {
|
||||
createNodeByPath(pathIterator, nodeName, treeNode, projectId, level, path, pathMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pathIterator 迭代器,遍历子节点
|
||||
* @param nodeName 当前节点
|
||||
* @param pNode 父节点
|
||||
*/
|
||||
private void createNodeByPath(Iterator<String> pathIterator, String nodeName,
|
||||
TestCaseNodeDTO pNode, String projectId, Integer level,
|
||||
String rootPath, Map<String, Integer> pathMap) {
|
||||
|
||||
StringBuilder path = new StringBuilder(rootPath);
|
||||
|
||||
Integer pid = insertTestCaseNode(nodeName, pNode == null ? null : pNode.getId(), projectId, level);
|
||||
path.append("/" + nodeName);
|
||||
pathMap.put(path.toString(), pid);
|
||||
while (pathIterator.hasNext()) {
|
||||
String nextNodeName = pathIterator.next();
|
||||
path.append("/" + nextNodeName);
|
||||
pid = insertTestCaseNode(nextNodeName, pid, projectId, ++level);
|
||||
pathMap.put(path.toString(), pid);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer insertTestCaseNode(String nodName, Integer pId, String projectId, Integer level) {
|
||||
TestCaseNode testCaseNode = new TestCaseNode();
|
||||
testCaseNode.setName(nodName.trim());
|
||||
testCaseNode.setpId(pId);
|
||||
testCaseNode.setProjectId(projectId);
|
||||
testCaseNode.setCreateTime(System.currentTimeMillis());
|
||||
testCaseNode.setUpdateTime(System.currentTimeMillis());
|
||||
testCaseNode.setLevel(level);
|
||||
testCaseNodeMapper.insert(testCaseNode);
|
||||
return testCaseNode.getId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,34 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ProjectMapper;
|
||||
import io.metersphere.base.mapper.TestCaseMapper;
|
||||
import io.metersphere.base.mapper.TestPlanMapper;
|
||||
import io.metersphere.base.mapper.TestPlanTestCaseMapper;
|
||||
import io.metersphere.base.mapper.*;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
|
||||
import io.metersphere.dto.TestPlanCaseDTO;
|
||||
import io.metersphere.excel.domain.ExcelErrData;
|
||||
import io.metersphere.excel.domain.ExcelResponse;
|
||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||
import io.metersphere.excel.listener.EasyExcelListener;
|
||||
import io.metersphere.excel.listener.TestCaseDataListener;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -41,6 +49,15 @@ public class TestCaseService {
|
|||
@Resource
|
||||
ProjectMapper projectMapper;
|
||||
|
||||
@Resource
|
||||
SqlSessionFactory sqlSessionFactory;
|
||||
|
||||
@Resource
|
||||
TestCaseNodeService testCaseNodeService;
|
||||
|
||||
@Resource
|
||||
UserMapper userMapper;
|
||||
|
||||
public void addTestCase(TestCaseWithBLOBs testCase) {
|
||||
testCase.setId(UUID.randomUUID().toString());
|
||||
testCase.setCreateTime(System.currentTimeMillis());
|
||||
|
@ -144,4 +161,59 @@ public class TestCaseService {
|
|||
}
|
||||
return projectMapper.selectByPrimaryKey(testCaseWithBLOBs.getProjectId());
|
||||
}
|
||||
|
||||
public ExcelResponse testCaseImport(MultipartFile file, String projectId) {
|
||||
|
||||
try {
|
||||
|
||||
ExcelResponse excelResponse = new ExcelResponse();
|
||||
|
||||
String currentWorkspaceId = SessionUtils.getCurrentWorkspaceId();
|
||||
QueryTestCaseRequest queryTestCaseRequest = new QueryTestCaseRequest();
|
||||
queryTestCaseRequest.setProjectId(projectId);
|
||||
List<TestCase> testCases = extTestCaseMapper.getTestCaseNames(queryTestCaseRequest);
|
||||
Set<String> testCaseNames = testCases.stream()
|
||||
.map(TestCase::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
UserExample userExample = new UserExample();
|
||||
userExample.createCriteria().andLastWorkspaceIdEqualTo(currentWorkspaceId);
|
||||
List<User> users = userMapper.selectByExample(userExample);
|
||||
Set<String> userNames = users.stream().map(User::getName).collect(Collectors.toSet());
|
||||
|
||||
EasyExcelListener easyExcelListener = new TestCaseDataListener(this, projectId,
|
||||
testCaseNames, userNames, TestCaseExcelData.class);
|
||||
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class, easyExcelListener).sheet().doRead();
|
||||
|
||||
List<ExcelErrData<TestCaseExcelData>> errList = easyExcelListener.getErrList();
|
||||
//如果包含错误信息就导出错误信息
|
||||
if (!errList.isEmpty()) {
|
||||
excelResponse.setSuccess(false);
|
||||
excelResponse.setErrList(errList);
|
||||
} else {
|
||||
excelResponse.setSuccess(true);
|
||||
}
|
||||
return excelResponse;
|
||||
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void saveImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
||||
|
||||
Map<String, Integer> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||
if (!testCases.isEmpty()) {
|
||||
testCases.forEach(testcase -> {
|
||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
mapper.insert(testcase);
|
||||
});
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,15 @@ CREATE TABLE IF NOT EXISTS `load_test_report` (
|
|||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_bin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `load_test_report_detail` (
|
||||
`report_id` varchar(50) NOT NULL,
|
||||
`content` longtext,
|
||||
PRIMARY KEY (`report_id`)
|
||||
)
|
||||
ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `organization` (
|
||||
`id` varchar(50) NOT NULL COMMENT 'Organization ID',
|
||||
`name` varchar(64) NOT NULL COMMENT 'Organization name',
|
||||
|
|
|
@ -18,5 +18,6 @@
|
|||
"no_nodes_message": "No node message",
|
||||
"duplicate_node_ip": "Duplicate IPs",
|
||||
"only_one_k8s": "Only one K8s can be added",
|
||||
"organization_id_is_null": "Organization ID cannot be null"
|
||||
"organization_id_is_null": "Organization ID cannot be null",
|
||||
"max_thread_insufficient": "The number of concurrent users exceeds"
|
||||
}
|
|
@ -18,5 +18,6 @@
|
|||
"no_nodes_message": "没有节点信息",
|
||||
"duplicate_node_ip": "节点 IP 重复",
|
||||
"only_one_k8s": "只能添加一个 K8s",
|
||||
"organization_id_is_null": "组织 ID 不能为空"
|
||||
"organization_id_is_null": "组织 ID 不能为空",
|
||||
"max_thread_insufficient": "并发用户数超额"
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package io.metersphere;
|
||||
|
||||
import com.opencsv.bean.CsvToBean;
|
||||
import com.opencsv.bean.CsvToBeanBuilder;
|
||||
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
|
||||
import io.metersphere.base.domain.LoadTestReportDetail;
|
||||
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
|
||||
import io.metersphere.base.mapper.LoadTestReportDetailMapper;
|
||||
import io.metersphere.base.mapper.LoadTestReportMapper;
|
||||
import io.metersphere.report.base.Metric;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class ReportContentTests {
|
||||
@Resource
|
||||
private LoadTestReportDetailMapper loadTestReportDetailMapper;
|
||||
@Resource
|
||||
private LoadTestReportMapper loadTestReportMapper;
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
String reportId = "ba972086-7d74-4f58-99b0-9c014114fd99";
|
||||
LoadTestReportDetail loadTestReportDetail = loadTestReportDetailMapper.selectByPrimaryKey(reportId);
|
||||
LoadTestReportWithBLOBs loadTestReportWithBLOBs = loadTestReportMapper.selectByPrimaryKey(reportId);
|
||||
|
||||
HeaderColumnNameMappingStrategy<Metric> ms = new HeaderColumnNameMappingStrategy<>();
|
||||
ms.setType(Metric.class);
|
||||
try (Reader reader = new StringReader(loadTestReportDetail.getContent())) {
|
||||
CsvToBean<Metric> cb = new CsvToBeanBuilder<Metric>(reader)
|
||||
.withType(Metric.class)
|
||||
.withSkipLines(0)
|
||||
.withMappingStrategy(ms)
|
||||
.withIgnoreLeadingWhiteSpace(true)
|
||||
.build();
|
||||
System.out.println(cb.parse().size());
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
try (Reader reader = new StringReader(loadTestReportWithBLOBs.getContent())) {
|
||||
CsvToBean<Metric> cb = new CsvToBeanBuilder<Metric>(reader)
|
||||
.withType(Metric.class)
|
||||
.withSkipLines(0)
|
||||
.withMappingStrategy(ms)
|
||||
.withIgnoreLeadingWhiteSpace(true)
|
||||
.build();
|
||||
System.out.println(cb.parse().size());
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@
|
|||
TokenKey,
|
||||
WORKSPACE_ID
|
||||
} from '../../../../common/js/constants';
|
||||
import {hasRoles} from "../../../../common/js/utils";
|
||||
import {hasRoles, saveLocalStorage} from "../../../../common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsUser",
|
||||
|
@ -136,7 +136,7 @@
|
|||
changeOrg(data) {
|
||||
let orgId = data.id;
|
||||
this.$post("/user/switch/source/org/" + orgId, {}, response => {
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
saveLocalStorage(response);
|
||||
this.$router.push('/');
|
||||
window.location.reload();
|
||||
})
|
||||
|
@ -147,7 +147,7 @@
|
|||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/ws/" + workspaceId, {}, response => {
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
saveLocalStorage(response);
|
||||
localStorage.setItem("workspace_id", workspaceId);
|
||||
this.$router.push('/');
|
||||
window.location.reload();
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</el-col>
|
||||
<el-col :span="8">
|
||||
<span class="ms-report-time-desc">
|
||||
持续时间: {{minutes}} 分钟
|
||||
持续时间: {{minutes}} 分钟 {{seconds}} 秒
|
||||
</span>
|
||||
<span class="ms-report-time-desc">
|
||||
开始时间: {{startTime}}
|
||||
|
@ -79,6 +79,7 @@
|
|||
startTime: '0',
|
||||
endTime: '0',
|
||||
minutes: '0',
|
||||
seconds: '0'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -101,7 +102,9 @@
|
|||
if(data){
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
this.minutes = data.duration;
|
||||
let duration = data.duration;
|
||||
this.minutes = Math.floor(duration / 60);
|
||||
this.seconds = duration % 60;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -144,7 +147,9 @@
|
|||
if(data){
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
this.minutes = data.duration;
|
||||
let duration = data.duration;
|
||||
this.minutes = Math.floor(duration / 60);
|
||||
this.seconds = duration % 60;
|
||||
}
|
||||
})
|
||||
window.location.reload();
|
||||
|
|
|
@ -96,6 +96,10 @@
|
|||
})
|
||||
this.$get("/performance/report/content/load_chart/" + this.id, res => {
|
||||
let data = res.data;
|
||||
let userList = data.filter(m => m.groupName === "users").map(m => m.yAxis);
|
||||
let hitsList = data.filter(m => m.groupName === "hits").map(m => m.yAxis);
|
||||
let userMax = this._getChartMax(userList);
|
||||
let hitsMax = this._getChartMax(hitsList);
|
||||
let loadOption = {
|
||||
title: {
|
||||
text: 'Load',
|
||||
|
@ -105,30 +109,57 @@
|
|||
color: '#65A2FF'
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {},
|
||||
xAxis: {},
|
||||
yAxis: [{
|
||||
name: 'User',
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: userMax,
|
||||
splitNumber: 5,
|
||||
// interval: 10 / 5
|
||||
interval: userMax / 5
|
||||
},
|
||||
{
|
||||
name: 'Hits/s',
|
||||
type: 'value',
|
||||
splitNumber: 5,
|
||||
min: 0,
|
||||
// max: 5,
|
||||
// interval: 5 / 5
|
||||
max: hitsMax,
|
||||
interval: hitsMax / 5
|
||||
}
|
||||
],
|
||||
series: []
|
||||
};
|
||||
let setting = {
|
||||
series: [
|
||||
{
|
||||
name: 'users',
|
||||
color: '#0CA74A',
|
||||
},
|
||||
{
|
||||
name: 'hits',
|
||||
yAxisIndex: '1',
|
||||
color: '#65A2FF',
|
||||
},
|
||||
{
|
||||
name: 'errors',
|
||||
yAxisIndex: '1',
|
||||
color: '#E6113C',
|
||||
}
|
||||
]
|
||||
}
|
||||
this.loadOption = this.generateOption(loadOption, data);
|
||||
this.loadOption = this.generateOption(loadOption, data, setting);
|
||||
})
|
||||
this.$get("/performance/report/content/res_chart/" + this.id, res => {
|
||||
let data = res.data;
|
||||
let userList = data.filter(m => m.groupName === "users").map(m => m.yAxis);
|
||||
let responseTimeList = data.filter(m => m.groupName === "responseTime").map(m => m.yAxis);
|
||||
let userMax = this._getChartMax(userList);
|
||||
let resMax = this._getChartMax(responseTimeList);
|
||||
let resOption = {
|
||||
title: {
|
||||
text: 'Response Time',
|
||||
|
@ -138,28 +169,55 @@
|
|||
color: '#99743C'
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {},
|
||||
xAxis: {},
|
||||
yAxis: [{
|
||||
name: 'User',
|
||||
type: 'value',
|
||||
splitNumber: 5,
|
||||
min: 0
|
||||
min: 0,
|
||||
max: userMax,
|
||||
interval: userMax / 5
|
||||
},
|
||||
{
|
||||
name: 'Response Time',
|
||||
type: 'value',
|
||||
splitNumber: 5,
|
||||
min: 0
|
||||
min: 0,
|
||||
max: resMax,
|
||||
interval: resMax / 5
|
||||
}
|
||||
],
|
||||
series: []
|
||||
}
|
||||
this.resOption = this.generateOption(resOption, data);
|
||||
let setting = {
|
||||
series: [
|
||||
{
|
||||
name: 'users',
|
||||
color: '#0CA74A',
|
||||
},
|
||||
{
|
||||
name: "responseTime",
|
||||
yAxisIndex: '1',
|
||||
color: '#99743C',
|
||||
}
|
||||
]
|
||||
}
|
||||
this.resOption = this.generateOption(resOption, data, setting);
|
||||
})
|
||||
},
|
||||
generateOption(option, data) {
|
||||
generateOption(option, data, setting) {
|
||||
let chartData = data;
|
||||
let seriesArray = [];
|
||||
for (let set in setting) {
|
||||
if (set === "series") {
|
||||
seriesArray = setting[set];
|
||||
continue;
|
||||
}
|
||||
this.$set(option, set, setting[set]);
|
||||
}
|
||||
let legend = [], series = {}, xAxis = [], seriesData = [];
|
||||
chartData.forEach(item => {
|
||||
if (!xAxis.includes(item.xAxis)) {
|
||||
|
@ -183,11 +241,24 @@
|
|||
type: 'line',
|
||||
data: data
|
||||
};
|
||||
let seriesArrayNames = seriesArray.map(m => m.name);
|
||||
if (seriesArrayNames.includes(name)) {
|
||||
for (let j = 0; j < seriesArray.length; j++) {
|
||||
let seriesObj = seriesArray[j];
|
||||
if (seriesObj['name'] === name) {
|
||||
Object.assign(items, seriesObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
seriesData.push(items);
|
||||
}
|
||||
this.$set(option, "series", seriesData);
|
||||
return option;
|
||||
},
|
||||
_getChartMax(arr) {
|
||||
const max = Math.max(...arr);
|
||||
return Math.ceil(max / 4.5) * 5;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status() {
|
||||
|
|
|
@ -46,7 +46,10 @@
|
|||
prop="status"
|
||||
:label="$t('commons.status')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-tag size="mini" type="primary" v-if="row.status === 'Starting'">
|
||||
<el-tag size="mini" type="info" v-if="row.status === 'Saved'">
|
||||
{{ row.status }}
|
||||
</el-tag>
|
||||
<el-tag size="mini" type="primary" v-else-if="row.status === 'Starting'">
|
||||
{{ row.status }}
|
||||
</el-tag>
|
||||
<el-tag size="mini" type="success" v-else-if="row.status === 'Running'">
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
:current-project="currentProject"
|
||||
@openTestCaseEditDialog="openTestCaseEditDialog"
|
||||
@testCaseEdit="openTestCaseEditDialog"
|
||||
@refresh="refresh"
|
||||
ref="testCaseList">
|
||||
</test-case-list>
|
||||
</el-main>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-tooltip class="item" effect="dark" content="导出用例" placement="right">
|
||||
<el-button type="info" icon="el-icon-download" size="mini" circle></el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TestCaseImport"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,134 @@
|
|||
<template>
|
||||
|
||||
<div>
|
||||
<el-tooltip class="item" effect="dark" content="导入用例" placement="right">
|
||||
<el-button type="info" icon="el-icon-upload2" size="mini" circle
|
||||
@click="dialogVisible = true"></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<el-dialog width="30%" title="导入测试用例" :visible.sync="dialogVisible"
|
||||
@close="init">
|
||||
|
||||
<el-row>
|
||||
<el-link type="primary" class="download-template">下载模版</el-link>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-upload
|
||||
class="upload-demo"
|
||||
:action="'/test/case/import/' + projectId"
|
||||
:on-preview="handlePreview"
|
||||
multiple
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
:beforeUpload="UploadValidate"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:file-list="fileList">
|
||||
<template v-slot:trigger>
|
||||
<el-button size="mini" type="success" plain>点击上传</el-button>
|
||||
</template>
|
||||
<template v-slot:tip>
|
||||
<div class="el-upload__tip">只能上传xls/xlsx文件,且不超过20M</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<ul>
|
||||
<li v-for="errFile in errList" :key="errFile.rowNum">
|
||||
{{errFile.errMsg}}
|
||||
</li>
|
||||
</ul>
|
||||
</el-row>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ElUploadList from "element-ui/packages/upload/src/upload-list";
|
||||
export default {
|
||||
name: "TestCaseImport",
|
||||
components: {ElUploadList},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
fileList: [],
|
||||
errList: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
projectId: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePreview(file) {
|
||||
console.log("init");
|
||||
this.init();
|
||||
},
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件`);
|
||||
},
|
||||
UploadValidate(file) {
|
||||
var suffix =file.name.substring(file.name.lastIndexOf('.') + 1);
|
||||
if (suffix != 'xls' && suffix != 'xlsx') {
|
||||
this.$message({
|
||||
message: '上传文件只能是 xls、xlsx格式!',
|
||||
type: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.size / 1024 / 1024 > 20) {
|
||||
this.$message({
|
||||
message: '上传文件大小不能超过 20MB!',
|
||||
type: 'warning'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handleSuccess(response) {
|
||||
let res = response.data;
|
||||
if (res.success) {
|
||||
this.$message.success("导入成功!");
|
||||
this.dialogVisible = false;
|
||||
this.$emit("refresh");
|
||||
} else {
|
||||
this.errList = res.errList;
|
||||
}
|
||||
this.fileList = [];
|
||||
},
|
||||
handleError(err, file, fileList) {
|
||||
this.$message.error(err.message);
|
||||
},
|
||||
init() {
|
||||
this.fileList = [];
|
||||
this.errList = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.el-dialog__body {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.download-template {
|
||||
padding-top: 0px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
</style>
|
|
@ -4,12 +4,21 @@
|
|||
<el-card v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<div>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<el-row type="flex" justify="start" align="middle">
|
||||
<el-col :span="5">
|
||||
<span class="title">{{$t('test_track.test_case')}}</span>
|
||||
<ms-create-box :tips="$t('test_track.create')" :exec="testCaseCreate"/>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="1" :offset="12">
|
||||
<test-case-import :projectId="currentProject == null? null : currentProject.id"
|
||||
@refresh="refresh"/>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="1">
|
||||
<test-case-export/>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="5">
|
||||
<span class="search">
|
||||
<el-input type="text" size="small" :placeholder="$t('load_test.search_by_name')"
|
||||
|
@ -105,10 +114,12 @@
|
|||
<script>
|
||||
|
||||
import MsCreateBox from '../../../settings/CreateBox';
|
||||
import TestCaseImport from '../components/TestCaseImport';
|
||||
import TestCaseExport from '../components/TestCaseExport';
|
||||
|
||||
export default {
|
||||
name: "TestCaseList",
|
||||
components: {MsCreateBox},
|
||||
components: {MsCreateBox, TestCaseImport, TestCaseExport},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -195,6 +206,9 @@
|
|||
type: 'success'
|
||||
});
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.$emit('refresh');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,3 +28,12 @@ export function checkoutCurrentWorkspace() {
|
|||
// 查看当前用户是否是 lastWorkspaceId 的工作空间用户
|
||||
return user.userRoles.filter(ur => hasRoles(ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER) && user.lastWorkspaceId === ur.sourceId).length > 0;
|
||||
}
|
||||
|
||||
export function saveLocalStorage(response) {
|
||||
// 登录信息保存 cookie
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
let rolesArray = response.data.roles;
|
||||
let roles = rolesArray.map(r => r.id);
|
||||
// 保存角色
|
||||
localStorage.setItem("roles", roles);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {TokenKey} from '../common/js/constants';
|
||||
import {saveLocalStorage} from '../common/js/utils';
|
||||
|
||||
|
||||
export default {
|
||||
|
@ -105,12 +105,7 @@
|
|||
this.$refs[form].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$post("signin", this.form, (response) => {
|
||||
// 登录信息保存 cookie
|
||||
localStorage.setItem(TokenKey, JSON.stringify(response.data));
|
||||
let rolesArray = response.data.roles;
|
||||
let roles = rolesArray.map(r => r.id);
|
||||
// 保存角色
|
||||
localStorage.setItem("roles", roles);
|
||||
saveLocalStorage(response);
|
||||
window.location.href = "/"
|
||||
});
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue