refactor(接口测试): 场景优化csv

This commit is contained in:
wxg0103 2024-01-25 16:29:04 +08:00 committed by 刘瑞斌
parent d6f633062b
commit 20b693abb2
20 changed files with 3246 additions and 47 deletions

View File

@ -0,0 +1,176 @@
package io.metersphere.api.domain;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
@Data
public class ApiScenarioCsv implements Serializable {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "文件id/引用文件id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.file_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.file_id.length_range}", groups = {Created.class, Updated.class})
private String fileId;
@Schema(description = "场景id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.scenario_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.scenario_id.length_range}", groups = {Created.class, Updated.class})
private String scenarioId;
@Schema(description = "csv变量名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.name.not_blank}", groups = {Created.class})
@Size(min = 1, max = 255, message = "{api_scenario_csv.name.length_range}", groups = {Created.class, Updated.class})
private String name;
@Schema(description = "文件名称")
private String fileName;
@Schema(description = "作用域 SCENARIO/STEP", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.scope.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.scope.length_range}", groups = {Created.class, Updated.class})
private String scope;
@Schema(description = "启用/禁用")
private Boolean enable;
@Schema(description = "是否引用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.association.not_blank}", groups = {Created.class})
private Boolean association;
@Schema(description = "文件编码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.encoding.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.encoding.length_range}", groups = {Created.class, Updated.class})
private String encoding;
@Schema(description = "是否随机", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.random.not_blank}", groups = {Created.class})
private Boolean random;
@Schema(description = "变量名称(西文逗号间隔)")
private String variableNames;
@Schema(description = "忽略首行(只有在设置了变量名称后才生效)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.ignore_first_line.not_blank}", groups = {Created.class})
private Boolean ignoreFirstLine;
@Schema(description = "分隔符")
private String delimiter;
@Schema(description = "是否允许带引号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.allow_quoted_data.not_blank}", groups = {Created.class})
private Boolean allowQuotedData;
@Schema(description = "遇到文件结束符再次循环", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.recycle_on_eof.not_blank}", groups = {Created.class})
private Boolean recycleOnEof;
@Schema(description = "遇到文件结束符停止线程", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_scenario_csv.stop_thread_on_eof.not_blank}", groups = {Created.class})
private Boolean stopThreadOnEof;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv.project_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv.project_id.length_range}", groups = {Created.class, Updated.class})
private String projectId;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
fileId("file_id", "fileId", "VARCHAR", false),
scenarioId("scenario_id", "scenarioId", "VARCHAR", false),
name("name", "name", "VARCHAR", true),
fileName("file_name", "fileName", "VARCHAR", false),
scope("scope", "scope", "VARCHAR", true),
enable("enable", "enable", "BIT", true),
association("association", "association", "BIT", false),
encoding("encoding", "encoding", "VARCHAR", true),
random("random", "random", "BIT", false),
variableNames("variable_names", "variableNames", "VARCHAR", false),
ignoreFirstLine("ignore_first_line", "ignoreFirstLine", "BIT", false),
delimiter("delimiter", "delimiter", "VARCHAR", true),
allowQuotedData("allow_quoted_data", "allowQuotedData", "BIT", false),
recycleOnEof("recycle_on_eof", "recycleOnEof", "BIT", false),
stopThreadOnEof("stop_thread_on_eof", "stopThreadOnEof", "BIT", false),
projectId("project_id", "projectId", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -0,0 +1,102 @@
package io.metersphere.api.domain;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class ApiScenarioCsvStep implements Serializable {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv_step.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv_step.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "文件id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv_step.file_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv_step.file_id.length_range}", groups = {Created.class, Updated.class})
private String fileId;
@Schema(description = "步骤id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_scenario_csv_step.step_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_scenario_csv_step.step_id.length_range}", groups = {Created.class, Updated.class})
private String stepId;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
fileId("file_id", "fileId", "VARCHAR", false),
stepId("step_id", "stepId", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -0,0 +1,410 @@
package io.metersphere.api.domain;
import java.util.ArrayList;
import java.util.List;
public class ApiScenarioCsvStepExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public ApiScenarioCsvStepExample() {
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 andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andFileIdIsNull() {
addCriterion("file_id is null");
return (Criteria) this;
}
public Criteria andFileIdIsNotNull() {
addCriterion("file_id is not null");
return (Criteria) this;
}
public Criteria andFileIdEqualTo(String value) {
addCriterion("file_id =", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotEqualTo(String value) {
addCriterion("file_id <>", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdGreaterThan(String value) {
addCriterion("file_id >", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdGreaterThanOrEqualTo(String value) {
addCriterion("file_id >=", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLessThan(String value) {
addCriterion("file_id <", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLessThanOrEqualTo(String value) {
addCriterion("file_id <=", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdLike(String value) {
addCriterion("file_id like", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotLike(String value) {
addCriterion("file_id not like", value, "fileId");
return (Criteria) this;
}
public Criteria andFileIdIn(List<String> values) {
addCriterion("file_id in", values, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotIn(List<String> values) {
addCriterion("file_id not in", values, "fileId");
return (Criteria) this;
}
public Criteria andFileIdBetween(String value1, String value2) {
addCriterion("file_id between", value1, value2, "fileId");
return (Criteria) this;
}
public Criteria andFileIdNotBetween(String value1, String value2) {
addCriterion("file_id not between", value1, value2, "fileId");
return (Criteria) this;
}
public Criteria andStepIdIsNull() {
addCriterion("step_id is null");
return (Criteria) this;
}
public Criteria andStepIdIsNotNull() {
addCriterion("step_id is not null");
return (Criteria) this;
}
public Criteria andStepIdEqualTo(String value) {
addCriterion("step_id =", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdNotEqualTo(String value) {
addCriterion("step_id <>", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdGreaterThan(String value) {
addCriterion("step_id >", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdGreaterThanOrEqualTo(String value) {
addCriterion("step_id >=", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdLessThan(String value) {
addCriterion("step_id <", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdLessThanOrEqualTo(String value) {
addCriterion("step_id <=", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdLike(String value) {
addCriterion("step_id like", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdNotLike(String value) {
addCriterion("step_id not like", value, "stepId");
return (Criteria) this;
}
public Criteria andStepIdIn(List<String> values) {
addCriterion("step_id in", values, "stepId");
return (Criteria) this;
}
public Criteria andStepIdNotIn(List<String> values) {
addCriterion("step_id not in", values, "stepId");
return (Criteria) this;
}
public Criteria andStepIdBetween(String value1, String value2) {
addCriterion("step_id between", value1, value2, "stepId");
return (Criteria) this;
}
public Criteria andStepIdNotBetween(String value1, String value2) {
addCriterion("step_id not between", value1, value2, "stepId");
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);
}
}
}

View File

@ -0,0 +1,34 @@
package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiScenarioCsv;
import io.metersphere.api.domain.ApiScenarioCsvExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface ApiScenarioCsvMapper {
long countByExample(ApiScenarioCsvExample example);
int deleteByExample(ApiScenarioCsvExample example);
int deleteByPrimaryKey(String id);
int insert(ApiScenarioCsv record);
int insertSelective(ApiScenarioCsv record);
List<ApiScenarioCsv> selectByExample(ApiScenarioCsvExample example);
ApiScenarioCsv selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiScenarioCsv record, @Param("example") ApiScenarioCsvExample example);
int updateByExample(@Param("record") ApiScenarioCsv record, @Param("example") ApiScenarioCsvExample example);
int updateByPrimaryKeySelective(ApiScenarioCsv record);
int updateByPrimaryKey(ApiScenarioCsv record);
int batchInsert(@Param("list") List<ApiScenarioCsv> list);
int batchInsertSelective(@Param("list") List<ApiScenarioCsv> list, @Param("selective") ApiScenarioCsv.Column ... selective);
}

View File

@ -0,0 +1,481 @@
<?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.api.mapper.ApiScenarioCsvMapper">
<resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiScenarioCsv">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="file_name" jdbcType="VARCHAR" property="fileName" />
<result column="scope" jdbcType="VARCHAR" property="scope" />
<result column="enable" jdbcType="BIT" property="enable" />
<result column="association" jdbcType="BIT" property="association" />
<result column="encoding" jdbcType="VARCHAR" property="encoding" />
<result column="random" jdbcType="BIT" property="random" />
<result column="variable_names" jdbcType="VARCHAR" property="variableNames" />
<result column="ignore_first_line" jdbcType="BIT" property="ignoreFirstLine" />
<result column="delimiter" jdbcType="VARCHAR" property="delimiter" />
<result column="allow_quoted_data" jdbcType="BIT" property="allowQuotedData" />
<result column="recycle_on_eof" jdbcType="BIT" property="recycleOnEof" />
<result column="stop_thread_on_eof" jdbcType="BIT" property="stopThreadOnEof" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
</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">
id, file_id, scenario_id, `name`, file_name, `scope`, `enable`, association, `encoding`,
random, variable_names, ignore_first_line, `delimiter`, allow_quoted_data, recycle_on_eof,
stop_thread_on_eof, project_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from api_scenario_csv
<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="BaseResultMap">
select
<include refid="Base_Column_List" />
from api_scenario_csv
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from api_scenario_csv
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvExample">
delete from api_scenario_csv
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.api.domain.ApiScenarioCsv">
insert into api_scenario_csv (id, file_id, scenario_id,
`name`, file_name, `scope`,
`enable`, association, `encoding`,
random, variable_names, ignore_first_line,
`delimiter`, allow_quoted_data, recycle_on_eof,
stop_thread_on_eof, project_id)
values (#{id,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR},
#{name,jdbcType=VARCHAR}, #{fileName,jdbcType=VARCHAR}, #{scope,jdbcType=VARCHAR},
#{enable,jdbcType=BIT}, #{association,jdbcType=BIT}, #{encoding,jdbcType=VARCHAR},
#{random,jdbcType=BIT}, #{variableNames,jdbcType=VARCHAR}, #{ignoreFirstLine,jdbcType=BIT},
#{delimiter,jdbcType=VARCHAR}, #{allowQuotedData,jdbcType=BIT}, #{recycleOnEof,jdbcType=BIT},
#{stopThreadOnEof,jdbcType=BIT}, #{projectId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiScenarioCsv">
insert into api_scenario_csv
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="fileId != null">
file_id,
</if>
<if test="scenarioId != null">
scenario_id,
</if>
<if test="name != null">
`name`,
</if>
<if test="fileName != null">
file_name,
</if>
<if test="scope != null">
`scope`,
</if>
<if test="enable != null">
`enable`,
</if>
<if test="association != null">
association,
</if>
<if test="encoding != null">
`encoding`,
</if>
<if test="random != null">
random,
</if>
<if test="variableNames != null">
variable_names,
</if>
<if test="ignoreFirstLine != null">
ignore_first_line,
</if>
<if test="delimiter != null">
`delimiter`,
</if>
<if test="allowQuotedData != null">
allow_quoted_data,
</if>
<if test="recycleOnEof != null">
recycle_on_eof,
</if>
<if test="stopThreadOnEof != null">
stop_thread_on_eof,
</if>
<if test="projectId != null">
project_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="fileId != null">
#{fileId,jdbcType=VARCHAR},
</if>
<if test="scenarioId != null">
#{scenarioId,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="fileName != null">
#{fileName,jdbcType=VARCHAR},
</if>
<if test="scope != null">
#{scope,jdbcType=VARCHAR},
</if>
<if test="enable != null">
#{enable,jdbcType=BIT},
</if>
<if test="association != null">
#{association,jdbcType=BIT},
</if>
<if test="encoding != null">
#{encoding,jdbcType=VARCHAR},
</if>
<if test="random != null">
#{random,jdbcType=BIT},
</if>
<if test="variableNames != null">
#{variableNames,jdbcType=VARCHAR},
</if>
<if test="ignoreFirstLine != null">
#{ignoreFirstLine,jdbcType=BIT},
</if>
<if test="delimiter != null">
#{delimiter,jdbcType=VARCHAR},
</if>
<if test="allowQuotedData != null">
#{allowQuotedData,jdbcType=BIT},
</if>
<if test="recycleOnEof != null">
#{recycleOnEof,jdbcType=BIT},
</if>
<if test="stopThreadOnEof != null">
#{stopThreadOnEof,jdbcType=BIT},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvExample" resultType="java.lang.Long">
select count(*) from api_scenario_csv
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update api_scenario_csv
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.fileId != null">
file_id = #{record.fileId,jdbcType=VARCHAR},
</if>
<if test="record.scenarioId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.fileName != null">
file_name = #{record.fileName,jdbcType=VARCHAR},
</if>
<if test="record.scope != null">
`scope` = #{record.scope,jdbcType=VARCHAR},
</if>
<if test="record.enable != null">
`enable` = #{record.enable,jdbcType=BIT},
</if>
<if test="record.association != null">
association = #{record.association,jdbcType=BIT},
</if>
<if test="record.encoding != null">
`encoding` = #{record.encoding,jdbcType=VARCHAR},
</if>
<if test="record.random != null">
random = #{record.random,jdbcType=BIT},
</if>
<if test="record.variableNames != null">
variable_names = #{record.variableNames,jdbcType=VARCHAR},
</if>
<if test="record.ignoreFirstLine != null">
ignore_first_line = #{record.ignoreFirstLine,jdbcType=BIT},
</if>
<if test="record.delimiter != null">
`delimiter` = #{record.delimiter,jdbcType=VARCHAR},
</if>
<if test="record.allowQuotedData != null">
allow_quoted_data = #{record.allowQuotedData,jdbcType=BIT},
</if>
<if test="record.recycleOnEof != null">
recycle_on_eof = #{record.recycleOnEof,jdbcType=BIT},
</if>
<if test="record.stopThreadOnEof != null">
stop_thread_on_eof = #{record.stopThreadOnEof,jdbcType=BIT},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update api_scenario_csv
set id = #{record.id,jdbcType=VARCHAR},
file_id = #{record.fileId,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
file_name = #{record.fileName,jdbcType=VARCHAR},
`scope` = #{record.scope,jdbcType=VARCHAR},
`enable` = #{record.enable,jdbcType=BIT},
association = #{record.association,jdbcType=BIT},
`encoding` = #{record.encoding,jdbcType=VARCHAR},
random = #{record.random,jdbcType=BIT},
variable_names = #{record.variableNames,jdbcType=VARCHAR},
ignore_first_line = #{record.ignoreFirstLine,jdbcType=BIT},
`delimiter` = #{record.delimiter,jdbcType=VARCHAR},
allow_quoted_data = #{record.allowQuotedData,jdbcType=BIT},
recycle_on_eof = #{record.recycleOnEof,jdbcType=BIT},
stop_thread_on_eof = #{record.stopThreadOnEof,jdbcType=BIT},
project_id = #{record.projectId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.api.domain.ApiScenarioCsv">
update api_scenario_csv
<set>
<if test="fileId != null">
file_id = #{fileId,jdbcType=VARCHAR},
</if>
<if test="scenarioId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR},
</if>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="fileName != null">
file_name = #{fileName,jdbcType=VARCHAR},
</if>
<if test="scope != null">
`scope` = #{scope,jdbcType=VARCHAR},
</if>
<if test="enable != null">
`enable` = #{enable,jdbcType=BIT},
</if>
<if test="association != null">
association = #{association,jdbcType=BIT},
</if>
<if test="encoding != null">
`encoding` = #{encoding,jdbcType=VARCHAR},
</if>
<if test="random != null">
random = #{random,jdbcType=BIT},
</if>
<if test="variableNames != null">
variable_names = #{variableNames,jdbcType=VARCHAR},
</if>
<if test="ignoreFirstLine != null">
ignore_first_line = #{ignoreFirstLine,jdbcType=BIT},
</if>
<if test="delimiter != null">
`delimiter` = #{delimiter,jdbcType=VARCHAR},
</if>
<if test="allowQuotedData != null">
allow_quoted_data = #{allowQuotedData,jdbcType=BIT},
</if>
<if test="recycleOnEof != null">
recycle_on_eof = #{recycleOnEof,jdbcType=BIT},
</if>
<if test="stopThreadOnEof != null">
stop_thread_on_eof = #{stopThreadOnEof,jdbcType=BIT},
</if>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.api.domain.ApiScenarioCsv">
update api_scenario_csv
set file_id = #{fileId,jdbcType=VARCHAR},
scenario_id = #{scenarioId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
file_name = #{fileName,jdbcType=VARCHAR},
`scope` = #{scope,jdbcType=VARCHAR},
`enable` = #{enable,jdbcType=BIT},
association = #{association,jdbcType=BIT},
`encoding` = #{encoding,jdbcType=VARCHAR},
random = #{random,jdbcType=BIT},
variable_names = #{variableNames,jdbcType=VARCHAR},
ignore_first_line = #{ignoreFirstLine,jdbcType=BIT},
`delimiter` = #{delimiter,jdbcType=VARCHAR},
allow_quoted_data = #{allowQuotedData,jdbcType=BIT},
recycle_on_eof = #{recycleOnEof,jdbcType=BIT},
stop_thread_on_eof = #{stopThreadOnEof,jdbcType=BIT},
project_id = #{projectId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into api_scenario_csv
(id, file_id, scenario_id, `name`, file_name, `scope`, `enable`, association, `encoding`,
random, variable_names, ignore_first_line, `delimiter`, allow_quoted_data, recycle_on_eof,
stop_thread_on_eof, project_id)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.scenarioId,jdbcType=VARCHAR},
#{item.name,jdbcType=VARCHAR}, #{item.fileName,jdbcType=VARCHAR}, #{item.scope,jdbcType=VARCHAR},
#{item.enable,jdbcType=BIT}, #{item.association,jdbcType=BIT}, #{item.encoding,jdbcType=VARCHAR},
#{item.random,jdbcType=BIT}, #{item.variableNames,jdbcType=VARCHAR}, #{item.ignoreFirstLine,jdbcType=BIT},
#{item.delimiter,jdbcType=VARCHAR}, #{item.allowQuotedData,jdbcType=BIT}, #{item.recycleOnEof,jdbcType=BIT},
#{item.stopThreadOnEof,jdbcType=BIT}, #{item.projectId,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into api_scenario_csv (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'file_id'.toString() == column.value">
#{item.fileId,jdbcType=VARCHAR}
</if>
<if test="'scenario_id'.toString() == column.value">
#{item.scenarioId,jdbcType=VARCHAR}
</if>
<if test="'name'.toString() == column.value">
#{item.name,jdbcType=VARCHAR}
</if>
<if test="'file_name'.toString() == column.value">
#{item.fileName,jdbcType=VARCHAR}
</if>
<if test="'scope'.toString() == column.value">
#{item.scope,jdbcType=VARCHAR}
</if>
<if test="'enable'.toString() == column.value">
#{item.enable,jdbcType=BIT}
</if>
<if test="'association'.toString() == column.value">
#{item.association,jdbcType=BIT}
</if>
<if test="'encoding'.toString() == column.value">
#{item.encoding,jdbcType=VARCHAR}
</if>
<if test="'random'.toString() == column.value">
#{item.random,jdbcType=BIT}
</if>
<if test="'variable_names'.toString() == column.value">
#{item.variableNames,jdbcType=VARCHAR}
</if>
<if test="'ignore_first_line'.toString() == column.value">
#{item.ignoreFirstLine,jdbcType=BIT}
</if>
<if test="'delimiter'.toString() == column.value">
#{item.delimiter,jdbcType=VARCHAR}
</if>
<if test="'allow_quoted_data'.toString() == column.value">
#{item.allowQuotedData,jdbcType=BIT}
</if>
<if test="'recycle_on_eof'.toString() == column.value">
#{item.recycleOnEof,jdbcType=BIT}
</if>
<if test="'stop_thread_on_eof'.toString() == column.value">
#{item.stopThreadOnEof,jdbcType=BIT}
</if>
<if test="'project_id'.toString() == column.value">
#{item.projectId,jdbcType=VARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -0,0 +1,34 @@
package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiScenarioCsvStep;
import io.metersphere.api.domain.ApiScenarioCsvStepExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface ApiScenarioCsvStepMapper {
long countByExample(ApiScenarioCsvStepExample example);
int deleteByExample(ApiScenarioCsvStepExample example);
int deleteByPrimaryKey(String id);
int insert(ApiScenarioCsvStep record);
int insertSelective(ApiScenarioCsvStep record);
List<ApiScenarioCsvStep> selectByExample(ApiScenarioCsvStepExample example);
ApiScenarioCsvStep selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiScenarioCsvStep record, @Param("example") ApiScenarioCsvStepExample example);
int updateByExample(@Param("record") ApiScenarioCsvStep record, @Param("example") ApiScenarioCsvStepExample example);
int updateByPrimaryKeySelective(ApiScenarioCsvStep record);
int updateByPrimaryKey(ApiScenarioCsvStep record);
int batchInsert(@Param("list") List<ApiScenarioCsvStep> list);
int batchInsertSelective(@Param("list") List<ApiScenarioCsvStep> list, @Param("selective") ApiScenarioCsvStep.Column ... selective);
}

View File

@ -0,0 +1,213 @@
<?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.api.mapper.ApiScenarioCsvStepMapper">
<resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiScenarioCsvStep">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
<result column="step_id" jdbcType="VARCHAR" property="stepId" />
</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">
id, file_id, step_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvStepExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from api_scenario_csv_step
<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="BaseResultMap">
select
<include refid="Base_Column_List" />
from api_scenario_csv_step
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from api_scenario_csv_step
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvStepExample">
delete from api_scenario_csv_step
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.api.domain.ApiScenarioCsvStep">
insert into api_scenario_csv_step (id, file_id, step_id
)
values (#{id,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{stepId,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiScenarioCsvStep">
insert into api_scenario_csv_step
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="fileId != null">
file_id,
</if>
<if test="stepId != null">
step_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="fileId != null">
#{fileId,jdbcType=VARCHAR},
</if>
<if test="stepId != null">
#{stepId,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvStepExample" resultType="java.lang.Long">
select count(*) from api_scenario_csv_step
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update api_scenario_csv_step
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.fileId != null">
file_id = #{record.fileId,jdbcType=VARCHAR},
</if>
<if test="record.stepId != null">
step_id = #{record.stepId,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update api_scenario_csv_step
set id = #{record.id,jdbcType=VARCHAR},
file_id = #{record.fileId,jdbcType=VARCHAR},
step_id = #{record.stepId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.api.domain.ApiScenarioCsvStep">
update api_scenario_csv_step
<set>
<if test="fileId != null">
file_id = #{fileId,jdbcType=VARCHAR},
</if>
<if test="stepId != null">
step_id = #{stepId,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.api.domain.ApiScenarioCsvStep">
update api_scenario_csv_step
set file_id = #{fileId,jdbcType=VARCHAR},
step_id = #{stepId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into api_scenario_csv_step
(id, file_id, step_id)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.stepId,jdbcType=VARCHAR}
)
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into api_scenario_csv_step (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'file_id'.toString() == column.value">
#{item.fileId,jdbcType=VARCHAR}
</if>
<if test="'step_id'.toString() == column.value">
#{item.stepId,jdbcType=VARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -583,6 +583,48 @@ CREATE TABLE IF NOT EXISTS api_definition_custom_field(
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '自定义字段接口定义关系';
CREATE TABLE api_scenario_csv
(
`id` VARCHAR(50) NOT NULL COMMENT 'id',
`file_id` VARCHAR(50) NOT NULL COMMENT '文件id/引用文件id',
`scenario_id` VARCHAR(50) NOT NULL COMMENT '场景id',
`name` VARCHAR(255) NOT NULL COMMENT 'csv变量名称',
`file_name` VARCHAR(255) COMMENT '文件名称',
`scope` VARCHAR(50) NOT NULL COMMENT '作用域 SCENARIO/STEP',
`enable` BIT(1) NOT NULL DEFAULT 1 COMMENT '启用/禁用',
`association` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否引用',
`encoding` VARCHAR(50) NOT NULL DEFAULT 'UTF-8' COMMENT '文件编码',
`random` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否随机',
`variable_names` VARCHAR(255) COMMENT '变量名称(西文逗号间隔)',
`ignore_first_line` BIT(1) NOT NULL DEFAULT 0 COMMENT '忽略首行(只有在设置了变量名称后才生效)',
`delimiter` VARCHAR(50) COMMENT '分隔符',
`allow_quoted_data` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否允许带引号',
`recycle_on_eof` BIT(1) NOT NULL DEFAULT 1 COMMENT '遇到文件结束符再次循环',
`stop_thread_on_eof` BIT(1) NOT NULL DEFAULT 0 COMMENT '遇到文件结束符停止线程',
`project_id` VARCHAR(50) NOT NULL COMMENT '项目id',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '场景csv';
CREATE INDEX idx_scenario_id ON api_scenario_csv(scenario_id);
CREATE INDEX idx_name ON api_scenario_csv(name);
CREATE INDEX idx_file_name ON api_scenario_csv(file_name);
CREATE INDEX idx_project_id ON api_scenario_csv(project_id);
DROP TABLE IF EXISTS api_scenario_csv_step;
CREATE TABLE api_scenario_csv_step
(
`id` VARCHAR(50) NOT NULL COMMENT 'id',
`file_id` VARCHAR(50) NOT NULL COMMENT '文件id',
`step_id` VARCHAR(50) NOT NULL COMMENT '步骤id',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '场景csv引用关系';
CREATE INDEX idx_file_id ON api_scenario_csv_step(file_id);
CREATE INDEX idx_step_id ON api_scenario_csv_step(step_id);
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -381,3 +381,21 @@ api_case_report_not_exist=用例报告不存在
api_scenario_report_not_exist=场景报告不存在
permission.api_plugin.name=接口插件
#moduleApiScenarioCsv
api_scenario_csv.file_id.not_blank=文件ID不能为空
api_scenario_csv.file_id.length_range=文件ID长度必须在1-50之间
api_scenario_csv.scenario_id.not_blank=场景ID不能为空
api_scenario_csv.scenario_id.length_range=场景ID长度必须在1-50之间
api_scenario_csv.name.not_blank=csv名称不能为空
api_scenario_csv.name.length_range=csv名称长度必须在1-255之间
api_scenario_csv.scope.not_blank=csv作用域不能为空
api_scenario_csv.scope.length_range=csv作用域长度必须在1-50之间
api_scenario_csv.association.not_blank=csv是否是关联
api_scenario_csv.encoding.not_blank=csv编码不能为空
api_scenario_csv.encoding.length_range=csv编码长度必须在1-50之间
api_scenario_csv.random.not_blank=是否随机
api_scenario_csv.ignore_first_line.not_blank=是否忽略第一行
api_scenario_csv.allow_quoted_data.not_blank=是否允许带引号
api_scenario_csv.recycle_on_eof.not_blank=是否循环
api_scenario_csv.stop_thread_on_eof.not_blank=是否停止线程

View File

@ -391,4 +391,22 @@ api_scenario_exist=The scenario already exists
schedule_not_exist=The scheduled task does not exist
api_case_report_not_exist=Api report does not exist
api_scenario_report_not_exist=Scenario report does not exist
permission.api_plugin.name=Api Plugin
permission.api_plugin.name=Api Plugin
#moduleApiScenarioCsv
api_scenario_csv.file_id.not_blank=File ID cannot be empty
api_scenario_csv.file_id.length_range=File ID length must be between 1-50
api_scenario_csv.scenario_id.not_blank=Scene ID cannot be empty
api_scenario_csv.scenario_id.length_range=Scene ID length must be between 1-50
api_scenario_csv.name.not_blank=Csv file name cannot be empty
api_scenario_csv.name.length_range=Csv file name length must be between 1-255
api_scenario_csv.scope.not_blank=Scope cannot be empty
api_scenario_csv.scope.length_range=Scope length must be between 1-20
api_scenario_csv.association.not_blank=Association cannot be empty
api_scenario_csv.encoding.not_blank=Encoding cannot be empty
api_scenario_csv.encoding.length_range=Encoding length must be between 1-20
api_scenario_csv.random.not_blank=Random cannot be empty
api_scenario_csv.ignore_first_line.not_blank=Ignore the first line cannot be empty
api_scenario_csv.allow_quoted_data.not_blank=Allow quoted data cannot be empty
api_scenario_csv.recycle_on_eof.not_blank=Recycle on EOF cannot be empty
api_scenario_csv.stop_thread_on_eof.not_blank=Stop thread on EOF cannot be empty

View File

@ -360,4 +360,22 @@ api_scenario_exist=场景已存在
schedule_not_exist=定时任务不存在
api_case_report_not_exist=用例报告不存在
api_scenario_report_not_exist=场景报告不存在
permission.api_plugin.name=接口插件
permission.api_plugin.name=接口插件
#moduleApiScenarioCsv
api_scenario_csv.file_id.not_blank=文件ID不能为空
api_scenario_csv.file_id.length_range=文件ID长度必须在1-50之间
api_scenario_csv.scenario_id.not_blank=场景ID不能为空
api_scenario_csv.scenario_id.length_range=场景ID长度必须在1-50之间
api_scenario_csv.name.not_blank=csv名称不能为空
api_scenario_csv.name.length_range=csv名称长度必须在1-255之间
api_scenario_csv.scope.not_blank=csv作用域不能为空
api_scenario_csv.scope.length_range=csv作用域长度必须在1-50之间
api_scenario_csv.association.not_blank=csv是否是关联
api_scenario_csv.encoding.not_blank=csv编码不能为空
api_scenario_csv.encoding.length_range=csv编码长度必须在1-50之间
api_scenario_csv.random.not_blank=是否随机
api_scenario_csv.ignore_first_line.not_blank=是否忽略第一行
api_scenario_csv.allow_quoted_data.not_blank=是否允许带引号
api_scenario_csv.recycle_on_eof.not_blank=是否循环
api_scenario_csv.stop_thread_on_eof.not_blank=是否停止线程

View File

@ -360,4 +360,22 @@ api_scenario_exist=場景已存在
schedule_not_exist=定時任務不存在
api_case_report_not_exist=用例報告不存在
api_scenario_report_not_exist=場景報告不存在
permission.api_plugin.name=接口插件
permission.api_plugin.name=接口插件
#moduleApiScenarioCsv 繁体
api_scenario_csv.file_id.not_blank=文件ID不能為空
api_scenario_csv.file_id.length_range=文件ID長度必須在1-50之間
api_scenario_csv.scenario_id.not_blank=場景ID不能為空
api_scenario_csv.scenario_id.length_range=場景ID長度必須在1-50之間
api_scenario_csv.name.not_blank=csv名称不能為空
api_scenario_csv.name.length_range=csv名称長度必须在1-200之间
api_scenario_csv.scope.not_blank=csv作用域不能為空
api_scenario_csv.scope.length_range=csv作用域長度必须在1-50之间
api_scenario_csv.association.not_blank=csv关联字段不能為空
api_scenario_csv.encoding.not_blank=csv编码不能為空
api_scenario_csv.encoding.length_range=csv编码長度必须在1-50之间
api_scenario_csv.random.not_blank=是否随机不能為空
api_scenario_csv.ignore_first_line.not_blank=是否忽略首行不能為空
api_scenario_csv.allow_quoted_data.not_blank=是否允许引用数据不能為空
api_scenario_csv.recycle_on_eof.not_blank=是否循环读取
api_scenario_csv.stop_thread_on_eof.not_blank=是否停止线程

View File

@ -14,6 +14,7 @@ import java.util.List;
/**
* 步骤解析使用的核心数据
* 用于步骤解析的统一处理
*
* @Author: jianxing
* @CreateTime: 2024-01-10 11:24
*/
@ -40,8 +41,9 @@ public class ApiScenarioStepCommonDTO {
/**
* 引用模式默认完全引用
* - 完全引用步骤状态不可调整
* - 部分引用步骤状态可调整
* - 完全引用步骤状态不可调整
* - 部分引用步骤状态可调整
*
* @see ApiScenarioStepRefType
*/
@Schema(description = "引用/复制/自定义")
@ -51,6 +53,9 @@ public class ApiScenarioStepCommonDTO {
@Schema(description = "循环等组件基础数据")
private Object config;
@Schema(description = "csv文件id集合")
private List<String> csvFileIds;
@Valid
@Schema(description = "子步骤")
private List<? extends ApiScenarioStepCommonDTO> children;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.scenario;
import io.metersphere.api.dto.ApiFile;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -10,45 +10,63 @@ import lombok.Data;
*/
@Data
public class CsvVariable {
@Schema(description = "id")
private String id;
@Schema(description = "文件id/引用文件id", requiredMode = Schema.RequiredMode.REQUIRED)
private String fileId;
@Schema(description = "场景id", requiredMode = Schema.RequiredMode.REQUIRED)
private String scenarioId;
@Schema(description = "csv变量名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "文件名称")
private String fileName;
@Schema(description = "作用域 SCENARIO/STEP")
/**
* @see CsvVariableScope
*/
private String scope;
/**
* 文件信息
*/
private ApiFile file;
/**
* 分隔符
*/
private String delimiter;
/**
* 是否允许带引号
*/
private Boolean allowQuotationMarks = false;
/**
* 是否忽略首行
*/
private Boolean ignoreFirstLine = false;
/**
* 是否随机
*/
private Boolean random = false;
/**
* 遇到文件结束符再次循环
*/
private Boolean endFileLoopsAgain = true;
/**
* 遇到文件结束符停止线程
*/
private Boolean endFileStopThread = false;
@Schema(description = "启用/禁用")
private Boolean enable = true;
@Schema(description = "是否引用")
private Boolean association = false;
@Schema(description = "文件编码")
/**
* 文件编码
*
* @see CsvEncodingType
*/
private String encoding;
@Schema(description = "是否随机")
private Boolean random = false;
@Schema(description = "变量名称(西文逗号间隔)")
private String variableNames;
@Schema(description = "忽略首行(只有在设置了变量名称后才生效)")
private Boolean ignoreFirstLine = false;
@Schema(description = "分隔符")
private String delimiter;
@Schema(description = "是否允许带引号")
private Boolean allowQuotedData = false;
@Schema(description = "遇到文件结束符再次循环")
private Boolean recycleOnEof = true;
@Schema(description = "遇到文件结束符停止线程")
private Boolean stopThreadOnEof = false;
public enum CsvEncodingType {
UTF8("UTF-8"), UFT16("UTF-16"), ISO885915("ISO-8859-15"), US_ASCII("US-ASCII");

View File

@ -1,6 +1,8 @@
package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiScenarioCsvStep;
import io.metersphere.api.dto.scenario.ApiScenarioStepDTO;
import io.metersphere.api.dto.scenario.CsvVariable;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -13,4 +15,8 @@ public interface ExtApiScenarioStepMapper {
List<String> getStepIdsByScenarioId(@Param("scenarioId") String scenarioId);
List<ApiScenarioStepDTO> getStepDTOByScenarioIds(@Param("scenarioIds") List<String> scenarioIds);
List<CsvVariable> getCsvVariableByScenarioId(@Param("id") String id);
List<ApiScenarioCsvStep> getCsvStepByStepIds(@Param("ids") List<String> stepIds);
}

View File

@ -13,4 +13,17 @@
#{scenarioId}
</foreach>
</select>
<select id="getCsvVariableByScenarioId" resultType="io.metersphere.api.dto.scenario.CsvVariable">
select
<include refid="io.metersphere.api.mapper.ApiScenarioCsvMapper.Base_Column_List"/>
from api_scenario_csv where scenario_id = #{id}
</select>
<select id="getCsvStepByStepIds" resultType="io.metersphere.api.domain.ApiScenarioCsvStep">
select
<include refid="io.metersphere.api.mapper.ApiScenarioCsvStepMapper.Base_Column_List"/>
from api_scenario_csv_step where step_id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -9,12 +9,12 @@ import io.metersphere.project.dto.filemanagement.FileLogRecord;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.sdk.file.FileCenter;
import io.metersphere.sdk.file.FileCopyRequest;
import io.metersphere.sdk.file.FileRepository;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -47,7 +47,7 @@ public class ApiFileResourceService {
* @param folder
* @param addFileMap key:fileId value:fileName
*/
private void uploadFileResource(String folder, Map<String, String> addFileMap) {
public void uploadFileResource(String folder, Map<String, String> addFileMap) {
if (MapUtils.isEmpty(addFileMap)) {
return;
}
@ -138,7 +138,7 @@ public class ApiFileResourceService {
}
}
private FileLogRecord createFileLogRecord(String operator, String projectId, String logModule) {
public FileLogRecord createFileLogRecord(String operator, String projectId, String logModule) {
return FileLogRecord.builder()
.logModule(logModule)
.operator(operator)
@ -189,6 +189,7 @@ public class ApiFileResourceService {
/**
* 删除资源下所有的文件或者关联关系
*
* @param apiDebugDir
* @param resourceId
* @param projectId
@ -246,10 +247,10 @@ public class ApiFileResourceService {
public void copyFileByResourceId(String sourceId, String sourceFolder, String targetId, String targetFolder) {
List<ApiFileResource> files = getByResourceId(sourceId);
if(!files.isEmpty()){
if (!files.isEmpty()) {
FileRepository defaultRepository = FileCenter.getDefaultRepository();
List<ApiFileResource> apiFileResources = new ArrayList<>();
files.forEach(item->{
files.forEach(item -> {
try {
// 按ID建文件夹避免文件名重复
FileCopyRequest fileCopyRequest = new FileCopyRequest();

View File

@ -16,7 +16,10 @@ import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.FileMetadata;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ApplicationNumScope;
@ -26,6 +29,8 @@ import io.metersphere.sdk.domain.EnvironmentExample;
import io.metersphere.sdk.domain.EnvironmentGroup;
import io.metersphere.sdk.domain.EnvironmentGroupExample;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.file.FileCenter;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
import io.metersphere.sdk.mapper.EnvironmentMapper;
import io.metersphere.sdk.util.*;
@ -100,6 +105,14 @@ public class ApiScenarioService {
private ApiDefinitionService apiDefinitionService;
@Resource
private ApiTestCaseService apiTestCaseService;
@Resource
private FileAssociationService fileAssociationService;
@Resource
private FileMetadataService fileMetadataService;
@Resource
private ApiScenarioCsvMapper apiScenarioCsvMapper;
@Resource
private ApiScenarioCsvStepMapper apiScenarioCsvStepMapper;
public static final String PRIORITY = "Priority";
public static final String STATUS = "Status";
public static final String TAGS = "Tags";
@ -299,7 +312,8 @@ public class ApiScenarioService {
// 插入步骤
if (CollectionUtils.isNotEmpty(request.getSteps())) {
// 获取待添加的步骤
List<ApiScenarioStep> steps = getApiScenarioSteps(null, request.getSteps());
List<ApiScenarioCsvStep> csvSteps = new ArrayList<>();
List<ApiScenarioStep> steps = getApiScenarioSteps(null, request.getSteps(), csvSteps);
steps.forEach(step -> step.setScenarioId(scenario.getId()));
// 获取待添加的步骤详情
List<ApiScenarioStepBlob> apiScenarioStepsDetails = getPartialRefStepDetails(request.getSteps());
@ -312,6 +326,8 @@ public class ApiScenarioService {
if (CollectionUtils.isNotEmpty(apiScenarioStepsDetails)) {
apiScenarioStepBlobMapper.batchInsert(apiScenarioStepsDetails);
}
saveStepCsv(steps, csvSteps);
}
// 处理文件
@ -319,9 +335,168 @@ public class ApiScenarioService {
resourceUpdateRequest.setUploadFileIds(request.getUploadFileIds());
resourceUpdateRequest.setLinkFileIds(request.getLinkFileIds());
apiFileResourceService.addFileResource(resourceUpdateRequest);
//处理csv变量
if (request.getScenarioConfig() != null
&& request.getScenarioConfig().getVariable() != null) {
saveCsv(request.getScenarioConfig().getVariable().getCsvVariables(), resourceUpdateRequest);
}
return scenario;
}
private void saveStepCsv(List<ApiScenarioStep> steps, List<ApiScenarioCsvStep> csvSteps) {
//获取所有的步骤id 然后删掉历史的关联关系
List<String> stepIds = steps.stream().map(ApiScenarioStep::getId).toList();
SubListUtils.dealForSubList(stepIds, 500, subList -> {
ApiScenarioCsvStepExample csvStepExample = new ApiScenarioCsvStepExample();
csvStepExample.createCriteria().andStepIdIn(subList);
apiScenarioCsvStepMapper.deleteByExample(csvStepExample);
});
//插入csv步骤
if (CollectionUtils.isNotEmpty(csvSteps)) {
SubListUtils.dealForSubList(csvSteps, 100, subList -> apiScenarioCsvStepMapper.batchInsert(subList));
}
}
private void saveCsv(List<CsvVariable> csvVariables, ApiFileResourceUpdateRequest resourceUpdateRequest) {
//进行比较一下 哪些是已存在的 那些是新上传的
//查询已经存在的fileId 这里直接过滤所有的数据 拿到新上传的本地文件id 和已经存在的文件id 关联的文件id 关于新的 需要删除的 已经存在的
ApiScenarioCsvExample apiScenarioCsvExample = new ApiScenarioCsvExample();
apiScenarioCsvExample.createCriteria().andScenarioIdEqualTo(resourceUpdateRequest.getResourceId());
List<ApiScenarioCsv> dbFileIds = apiScenarioCsvMapper.selectByExample(apiScenarioCsvExample);
//取出所有的fileId Association为false的数据
List<String> dbLocalFileIds = dbFileIds.stream().filter(c -> BooleanUtils.isFalse(c.getAssociation())).map(ApiScenarioCsv::getFileId).toList();
//取出所有的fileId Association为true的数据
List<String> dbRefFileIds = dbFileIds.stream().filter(c -> BooleanUtils.isTrue(c.getAssociation())).map(ApiScenarioCsv::getFileId).toList();
//获取传的所有Association为false的数据
List<String> localFileIds = csvVariables.stream().filter(c -> BooleanUtils.isFalse(c.getAssociation())).map(CsvVariable::getFileId).toList();
//获取传的所有Association为true的数据
List<String> refFileIds = csvVariables.stream().filter(c -> BooleanUtils.isTrue(c.getAssociation())).map(CsvVariable::getFileId).toList();
//取交集 交集数据是已存在的 不需要重新上传 和处理关联关系 但是需要更新apiScenarioCsv表的数据
List<String> intersectionLocal = ListUtils.intersection(dbLocalFileIds, localFileIds);
//取差集 dbFileIds和 intersection的差集是需要删除的数据 本地数据需要删除的数据
List<String> deleteLocals = ListUtils.subtract(dbLocalFileIds, intersectionLocal);
resourceUpdateRequest.setDeleteFileIds(deleteLocals);
List<String> addLocal = ListUtils.subtract(localFileIds, intersectionLocal);
resourceUpdateRequest.setUploadFileIds(addLocal);
//获取 关联文件的交集
List<String> intersectionRef = ListUtils.intersection(dbRefFileIds, refFileIds);
//获取删除的
List<String> deleteRefs = ListUtils.subtract(dbRefFileIds, intersectionRef);
List<String> addRef = ListUtils.subtract(refFileIds, intersectionRef);
resourceUpdateRequest.setLinkFileIds(addRef);
resourceUpdateRequest.setUnLinkRefIds(deleteRefs);
//删除不存在的数据
deleteCsvResource(resourceUpdateRequest);
addCsvResource(resourceUpdateRequest, csvVariables);
}
private void addCsvResource(ApiFileResourceUpdateRequest resourceUpdateRequest,
List<CsvVariable> csvVariables) {
List<ApiScenarioCsv> addData = new ArrayList<>();
List<ApiScenarioCsv> updateData = new ArrayList<>();
List<String> addFileIds = resourceUpdateRequest.getUploadFileIds();
List<String> linkFileIds = resourceUpdateRequest.getLinkFileIds();
Map<String, String> refFilesMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(linkFileIds)) {
//根据fileId查询文件名
List<FileMetadata> fileList = fileMetadataService.selectByList(linkFileIds);
if (CollectionUtils.isNotEmpty(fileList)) {
//生成map key为文件id 值为文件名称 文件名称为name.类型
refFilesMap = fileList.stream().collect(Collectors.toMap(FileMetadata::getId, f -> f.getName() + "." + f.getType()));
}
fileAssociationService.association(resourceUpdateRequest.getResourceId(), FileAssociationSourceUtil.SOURCE_TYPE_API_SCENARIO, linkFileIds,
apiFileResourceService.createFileLogRecord(resourceUpdateRequest.getOperator(), resourceUpdateRequest.getProjectId(), OperationLogModule.API_SCENARIO));
}
Map<String, String> finalRefFilesMap = refFilesMap;
// 添加文件与接口的关联关系
Map<String, String> addFileMap = new HashMap<>();
csvVariables.forEach(item -> {
ApiScenarioCsv scenarioCsv = new ApiScenarioCsv();
BeanUtils.copyBean(scenarioCsv, item);
scenarioCsv.setScenarioId(resourceUpdateRequest.getResourceId());
scenarioCsv.setProjectId(resourceUpdateRequest.getProjectId());
// uploadFileIds里包含的数据 全部需要上传到minio上或者需要重新建立关联关系
if (BooleanUtils.isFalse(item.getAssociation())
&& CollectionUtils.isNotEmpty(addFileIds)
&& addFileIds.contains(item.getFileId())) {
scenarioCsv.setFileName(apiFileResourceService.getTempFileNameByFileId(item.getFileId()));
addFileMap.put(item.getFileId(), scenarioCsv.getId());
} else if (BooleanUtils.isTrue(item.getAssociation())
&& finalRefFilesMap.containsKey(item.getFileId())
&& CollectionUtils.isNotEmpty(linkFileIds)
&& linkFileIds.contains(item.getFileId())) {
scenarioCsv.setFileName(finalRefFilesMap.get(item.getFileId()));
}
if (StringUtils.isBlank(item.getId())) {
scenarioCsv.setId(IDGenerator.nextStr());
addData.add(scenarioCsv);
} else {
updateData.add(scenarioCsv);
}
});
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioCsvMapper mapper = sqlSession.getMapper(ApiScenarioCsvMapper.class);
if (CollectionUtils.isNotEmpty(updateData)) {
//更新apiScenarioCsv表
updateData.forEach(mapper::updateByPrimaryKeySelective);
}
if (CollectionUtils.isNotEmpty(addData)) {
//插入apiScenarioCsv表
addData.forEach(mapper::insertSelective);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
if (MapUtils.isNotEmpty(addFileMap)) {
// 上传文件到对象存储
apiFileResourceService.uploadFileResource(resourceUpdateRequest.getFolder(), addFileMap);
}
}
private void deleteCsvResource(ApiFileResourceUpdateRequest resourceUpdateRequest) {
// 处理本地上传文件
List<String> deleteFileIds = resourceUpdateRequest.getDeleteFileIds();
ApiScenarioCsvExample example = new ApiScenarioCsvExample();
ApiScenarioCsvStepExample stepExample = new ApiScenarioCsvStepExample();
if (CollectionUtils.isNotEmpty(deleteFileIds)) {
// 删除关联关系
deleteFileIds.forEach(fileId -> {
FileRequest request = new FileRequest();
// 删除文件所在目录
request.setFolder(resourceUpdateRequest.getFolder() + "/" + fileId);
try {
FileCenter.getDefaultRepository().deleteFolder(request);
} catch (Exception e) {
LogUtils.error(e);
}
});
example.createCriteria()
.andScenarioIdEqualTo(resourceUpdateRequest.getResourceId())
.andFileIdIn(deleteFileIds);
apiScenarioCsvMapper.deleteByExample(example);
stepExample.createCriteria().andFileIdIn(deleteFileIds);
apiScenarioCsvStepMapper.deleteByExample(stepExample);
}
List<String> unLinkRefIds = resourceUpdateRequest.getUnLinkRefIds();
// 处理关联文件
if (CollectionUtils.isNotEmpty(unLinkRefIds)) {
fileAssociationService.deleteBySourceIdAndFileIds(resourceUpdateRequest.getResourceId(), unLinkRefIds,
apiFileResourceService.createFileLogRecord(resourceUpdateRequest.getOperator(), resourceUpdateRequest.getProjectId(), resourceUpdateRequest.getLogModule()));
example.clear();
example.createCriteria()
.andScenarioIdEqualTo(resourceUpdateRequest.getResourceId())
.andFileIdIn(unLinkRefIds);
apiScenarioCsvMapper.deleteByExample(example);
stepExample.clear();
stepExample.createCriteria().andFileIdIn(deleteFileIds);
apiScenarioCsvStepMapper.deleteByExample(stepExample);
}
}
private ApiScenario getAddApiScenario(ApiScenarioAddRequest request, String creator) {
ApiScenario scenario = new ApiScenario();
BeanUtils.copyBean(scenario, request);
@ -371,6 +546,13 @@ public class ApiScenarioService {
resourceUpdateRequest.setDeleteFileIds(request.getDeleteFileIds());
apiFileResourceService.updateFileResource(resourceUpdateRequest);
//处理csv变量
if (request.getScenarioConfig() != null
&& request.getScenarioConfig().getVariable() != null) {
saveCsv(request.getScenarioConfig().getVariable().getCsvVariables(), resourceUpdateRequest);
} else {
saveCsv(new ArrayList<>(), resourceUpdateRequest);
}
return scenario;
}
@ -389,11 +571,12 @@ public class ApiScenarioService {
deleteStepDetailByScenarioId(scenario.getId());
return;
}
List<ApiScenarioCsvStep> scenarioCsvSteps = new ArrayList<>();
// 获取待更新的步骤
List<ApiScenarioStep> apiScenarioSteps = getApiScenarioSteps(null, request.getSteps());
List<ApiScenarioStep> apiScenarioSteps = getApiScenarioSteps(null, request.getSteps(), scenarioCsvSteps);
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
saveStepCsv(apiScenarioSteps, scenarioCsvSteps);
// 获取待更新的步骤详情
List<ApiScenarioStepBlob> apiScenarioStepsDetails = getPartialRefStepDetails(request.getSteps());
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
@ -504,7 +687,7 @@ public class ApiScenarioService {
* @return
*/
private List<ApiScenarioStep> getApiScenarioSteps(ApiScenarioStepCommonDTO parent,
List<? extends ApiScenarioStepCommonDTO> steps) {
List<? extends ApiScenarioStepCommonDTO> steps, List<ApiScenarioCsvStep> csvSteps) {
if (CollectionUtils.isEmpty(steps)) {
return Collections.emptyList();
}
@ -520,6 +703,16 @@ public class ApiScenarioService {
if (step.getConfig() != null) {
apiScenarioStep.setConfig(JSON.toJSONString(step.getConfig()));
}
if (CollectionUtils.isNotEmpty(step.getCsvFileIds())) {
//如果是csv文件 需要保存到apiScenarioCsvStep表中
step.getCsvFileIds().forEach(fileId -> {
ApiScenarioCsvStep csvStep = new ApiScenarioCsvStep();
csvStep.setId(IDGenerator.nextStr());
csvStep.setStepId(apiScenarioStep.getId());
csvStep.setFileId(fileId);
csvSteps.add(csvStep);
});
}
apiScenarioSteps.add(apiScenarioStep);
if (StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name())) {
@ -527,7 +720,7 @@ public class ApiScenarioService {
continue;
}
// 解析子步骤
apiScenarioSteps.addAll(getApiScenarioSteps(step, step.getChildren()));
apiScenarioSteps.addAll(getApiScenarioSteps(step, step.getChildren(), csvSteps));
}
return apiScenarioSteps;
}
@ -740,7 +933,7 @@ public class ApiScenarioService {
private void setPartialRefStepEnable(ApiScenarioStepCommonDTO step, Map<String, String> stepDetailMap) {
String stepDetail = stepDetailMap.get(step.getId());
if (!isPartialRef(step) || StringUtils.isBlank(stepDetail)) {
return;
return;
}
PartialRefStepDetail partialRefStepDetail = JSON.parseObject(stepDetail, PartialRefStepDetail.class);
setChildPartialRefEnable(step.getChildren(), partialRefStepDetail.getEnableStepIds());
@ -898,9 +1091,26 @@ public class ApiScenarioService {
if (apiScenarioBlob != null) {
apiScenarioDetail.setScenarioConfig(JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class));
}
//存放csv变量
List<CsvVariable> csvVariables = extApiScenarioStepMapper.getCsvVariableByScenarioId(scenarioId);
if (CollectionUtils.isNotEmpty(csvVariables) && apiScenarioDetail.getScenarioConfig() != null
&& apiScenarioDetail.getScenarioConfig().getVariable() != null) {
apiScenarioDetail.getScenarioConfig().getVariable().setCsvVariables(csvVariables);
}
// 获取所有步骤
List<ApiScenarioStepDTO> allSteps = getAllStepsByScenarioIds(List.of(scenarioId));
//获取所有步骤的csv的关联关系
List<String> stepIds = allSteps.stream().map(ApiScenarioStepDTO::getId).toList();
List<ApiScenarioCsvStep> csvSteps = extApiScenarioStepMapper.getCsvStepByStepIds(stepIds);
// 构造 mapkey 为步骤IDvalue 为csv文件ID列表
Map<String, List<String>> stepsCsvMap = csvSteps.stream()
.collect(Collectors.groupingBy(ApiScenarioCsvStep::getStepId, Collectors.mapping(ApiScenarioCsvStep::getFileId, Collectors.toList())));
//将stepsCsvMap根据步骤id放入到allSteps中
if (CollectionUtils.isNotEmpty(allSteps)) {
allSteps.forEach(step -> step.setCsvFileIds(stepsCsvMap.get(step.getId())));
}
// 构造 mapkey 为场景IDvalue 为步骤列表
Map<String, List<ApiScenarioStepDTO>> scenarioStepMap = allSteps.stream()
.collect(Collectors.groupingBy(step -> Optional.ofNullable(step.getScenarioId()).orElse(StringUtils.EMPTY)));
@ -1007,6 +1217,7 @@ public class ApiScenarioService {
/**
* 判断步骤是否是引用的场景
*
* @param step
* @return
*/

View File

@ -16,7 +16,9 @@ import io.metersphere.api.service.BaseResourcePoolTestService;
import io.metersphere.api.service.definition.ApiDefinitionService;
import io.metersphere.api.service.definition.ApiTestCaseService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.project.dto.filemanagement.request.FileUploadRequest;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
@ -47,6 +49,7 @@ import org.springframework.test.web.servlet.ResultMatcher;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
import static io.metersphere.api.controller.result.ApiResultCode.API_SCENARIO_EXIST;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
@ -93,6 +96,12 @@ public class ApiScenarioControllerTests extends BaseTest {
private ApiTestCaseService apiTestCaseService;
@Resource
private BaseResourcePoolTestService baseResourcePoolTestService;
@Resource
private FileMetadataService fileMetadataService;
@Resource
private ApiScenarioCsvMapper apiScenarioCsvMapper;
private static String fileMetadataId;
private static String localFileId;
private static ApiScenario addApiScenario;
private static List<ApiScenarioStepRequest> addApiScenarioSteps;
private static ApiScenario anOtherAddApiScenario;
@ -162,6 +171,16 @@ public class ApiScenarioControllerTests extends BaseTest {
}
}
@Test
@Order(0)
public void uploadTempFileTest() throws Exception {
// 准备数据上传文件管理文件
uploadFileMetadata();
MockMultipartFile file = getMockMultipartFile();
localFileId = doUploadTempFile(file);
}
public void initApiScenarioTrash() {
ApiScenarioModule apiScenarioModule = new ApiScenarioModule();
apiScenarioModule.setId("scenario-moduleId-trash");
@ -294,7 +313,7 @@ public class ApiScenarioControllerTests extends BaseTest {
}
}
private ScenarioConfig getScenarioConfig() {
private ScenarioConfig getScenarioConfig() throws Exception {
ScenarioConfig scenarioConfig = new ScenarioConfig();
MsAssertionConfig msAssertionConfig = new MsAssertionConfig();
MsScriptAssertion scriptAssertion = new MsScriptAssertion();
@ -307,9 +326,40 @@ public class ApiScenarioControllerTests extends BaseTest {
scenarioOtherConfig.setFailureStrategy(ScenarioOtherConfig.FailureStrategy.CONTINUE.name());
scenarioOtherConfig.setEnableCookieShare(true);
scenarioConfig.setOtherConfig(scenarioOtherConfig);
ScenarioVariable scenarioVariable = new ScenarioVariable();
scenarioVariable.setCsvVariables(getCsvVariables());
scenarioConfig.setVariable(scenarioVariable);
return scenarioConfig;
}
/**
* 文件管理插入一条数据
* 便于测试关联文件
*/
private void uploadFileMetadata() throws Exception {
FileUploadRequest fileUploadRequest = new FileUploadRequest();
fileUploadRequest.setProjectId(DEFAULT_PROJECT_ID);
//导入正常文件
MockMultipartFile file = new MockMultipartFile("file", "file.csv", MediaType.APPLICATION_OCTET_STREAM_VALUE, "aa".getBytes());
fileMetadataId = fileMetadataService.upload(fileUploadRequest, "admin", file);
}
public List<CsvVariable> getCsvVariables() throws Exception {
List<CsvVariable> csvVariables = new ArrayList<>();
CsvVariable csvVariable = new CsvVariable();
csvVariable.setFileId(localFileId);
csvVariable.setName("csv变量");
csvVariable.setScope(CsvVariable.CsvVariableScope.SCENARIO.name());
csvVariables.add(csvVariable);
csvVariable = new CsvVariable();
csvVariable.setFileId(fileMetadataId);
csvVariable.setName("csv-关联的");
csvVariable.setScope(CsvVariable.CsvVariableScope.SCENARIO.name());
csvVariable.setAssociation(true);
csvVariables.add(csvVariable);
return csvVariables;
}
private List<ApiScenarioStepRequest> getApiScenarioStepRequests() {
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
stepRequest.setId(IDGenerator.nextStr());
@ -322,6 +372,7 @@ public class ApiScenarioControllerTests extends BaseTest {
stepRequest.setStepType(ApiScenarioStepType.API_CASE.name());
stepRequest.setProjectId(DEFAULT_PROJECT_ID);
stepRequest.setConfig(new HashMap<>());
stepRequest.setCsvFileIds(List.of(fileMetadataId));
ApiScenarioStepRequest stepRequest2 = new ApiScenarioStepRequest();
stepRequest2.setId(IDGenerator.nextStr());
@ -333,6 +384,7 @@ public class ApiScenarioControllerTests extends BaseTest {
stepRequest2.setStepType(ApiScenarioStepType.API_CASE.name());
stepRequest2.setRefType(ApiScenarioStepRefType.COPY.name());
stepRequest2.setProjectId(DEFAULT_PROJECT_ID);
stepRequest2.setCsvFileIds(List.of(fileMetadataId));
ApiScenarioStepRequest stepRequest3 = new ApiScenarioStepRequest();
stepRequest3.setId(IDGenerator.nextStr());
@ -380,6 +432,7 @@ public class ApiScenarioControllerTests extends BaseTest {
apiTestCase = apiTestCaseService.addCase(apiTestCaseAddRequest, "admin");
}
@Test
@Order(2)
public void update() throws Exception {
@ -417,8 +470,16 @@ public class ApiScenarioControllerTests extends BaseTest {
this.requestPostWithOk(DEFAULT_UPDATE, request);
assertUpdateSteps(steps, steptDetailMap);
ApiScenarioCsvExample apiScenarioCsvExample = new ApiScenarioCsvExample();
apiScenarioCsvExample.createCriteria().andScenarioIdEqualTo(addApiScenario.getId());
List<ApiScenarioCsv> apiScenarioCsvs = apiScenarioCsvMapper.selectByExample(apiScenarioCsvExample);
Map<String, ApiScenarioCsv> collect = apiScenarioCsvs.stream().collect(Collectors.toMap(ApiScenarioCsv::getFileId, t -> t));
// 验证修改步骤
steps.get(0).setName("test name update");
CsvVariable csvVariable = request.getScenarioConfig().getVariable().getCsvVariables().get(0);
request.getScenarioConfig().getVariable().getCsvVariables().get(0).setId(collect.get(csvVariable.getFileId()).getId());
CsvVariable csvVariable1 = request.getScenarioConfig().getVariable().getCsvVariables().get(0);
request.getScenarioConfig().getVariable().getCsvVariables().get(1).setId(collect.get(csvVariable1.getFileId()).getId());
this.requestPostWithOk(DEFAULT_UPDATE, request);
assertUpdateSteps(steps, steptDetailMap);
addApiScenarioSteps = steps;