feat(接口测试): 场景csv功能
This commit is contained in:
parent
21fbfee0b4
commit
b74eef8a6c
|
@ -25,12 +25,18 @@ public class ApiScenarioCsvStep implements Serializable {
|
|||
@Size(min = 1, max = 50, message = "{api_scenario_csv_step.step_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String stepId;
|
||||
|
||||
@Schema(description = "场景ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario_csv_step.scenario_id.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 50, message = "{api_scenario_csv_step.scenario_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String scenarioId;
|
||||
|
||||
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);
|
||||
stepId("step_id", "stepId", "VARCHAR", false),
|
||||
scenarioId("scenario_id", "scenarioId", "VARCHAR", false);
|
||||
|
||||
private static final String BEGINNING_DELIMITER = "`";
|
||||
|
||||
|
|
|
@ -313,6 +313,76 @@ public class ApiScenarioCsvStepExample {
|
|||
addCriterion("step_id not between", value1, value2, "stepId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNull() {
|
||||
addCriterion("scenario_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNotNull() {
|
||||
addCriterion("scenario_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdEqualTo(String value) {
|
||||
addCriterion("scenario_id =", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotEqualTo(String value) {
|
||||
addCriterion("scenario_id <>", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThan(String value) {
|
||||
addCriterion("scenario_id >", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id >=", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThan(String value) {
|
||||
addCriterion("scenario_id <", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id <=", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLike(String value) {
|
||||
addCriterion("scenario_id like", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotLike(String value) {
|
||||
addCriterion("scenario_id not like", value, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIn(List<String> values) {
|
||||
addCriterion("scenario_id in", values, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotIn(List<String> values) {
|
||||
addCriterion("scenario_id not in", values, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id between", value1, value2, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id not between", value1, value2, "scenarioId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<id column="id" jdbcType="VARCHAR" property="id" />
|
||||
<result column="file_id" jdbcType="VARCHAR" property="fileId" />
|
||||
<result column="step_id" jdbcType="VARCHAR" property="stepId" />
|
||||
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
|
@ -65,7 +66,7 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, file_id, step_id
|
||||
id, file_id, step_id, scenario_id
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvStepExample" resultMap="BaseResultMap">
|
||||
select
|
||||
|
@ -98,10 +99,10 @@
|
|||
</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 into api_scenario_csv_step (id, file_id, step_id,
|
||||
scenario_id)
|
||||
values (#{id,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{stepId,jdbcType=VARCHAR},
|
||||
#{scenarioId,jdbcType=VARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiScenarioCsvStep">
|
||||
insert into api_scenario_csv_step
|
||||
|
@ -115,6 +116,9 @@
|
|||
<if test="stepId != null">
|
||||
step_id,
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
|
@ -126,6 +130,9 @@
|
|||
<if test="stepId != null">
|
||||
#{stepId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
#{scenarioId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.api.domain.ApiScenarioCsvStepExample" resultType="java.lang.Long">
|
||||
|
@ -146,6 +153,9 @@
|
|||
<if test="record.stepId != null">
|
||||
step_id = #{record.stepId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.scenarioId != null">
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -155,7 +165,8 @@
|
|||
update api_scenario_csv_step
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
file_id = #{record.fileId,jdbcType=VARCHAR},
|
||||
step_id = #{record.stepId,jdbcType=VARCHAR}
|
||||
step_id = #{record.stepId,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -169,22 +180,26 @@
|
|||
<if test="stepId != null">
|
||||
step_id = #{stepId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id = #{scenarioId,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}
|
||||
step_id = #{stepId,jdbcType=VARCHAR},
|
||||
scenario_id = #{scenarioId,jdbcType=VARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<insert id="batchInsert" parameterType="map">
|
||||
insert into api_scenario_csv_step
|
||||
(id, file_id, step_id)
|
||||
(id, file_id, step_id, scenario_id)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.stepId,jdbcType=VARCHAR}
|
||||
)
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.stepId,jdbcType=VARCHAR},
|
||||
#{item.scenarioId,jdbcType=VARCHAR})
|
||||
</foreach>
|
||||
</insert>
|
||||
<insert id="batchInsertSelective" parameterType="map">
|
||||
|
@ -206,6 +221,9 @@
|
|||
<if test="'step_id'.toString() == column.value">
|
||||
#{item.stepId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'scenario_id'.toString() == column.value">
|
||||
#{item.scenarioId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
</foreach>
|
||||
)
|
||||
</foreach>
|
||||
|
|
|
@ -127,6 +127,10 @@ CREATE TABLE IF NOT EXISTS test_plan_report_bug(
|
|||
|
||||
CREATE UNIQUE INDEX idx_test_plan_report_id ON test_plan_report_bug(test_plan_report_id);
|
||||
|
||||
-- 场景步骤 csv 表增加场景ID字段
|
||||
ALTER TABLE api_scenario_csv_step ADD scenario_id varchar(50) NOT NULL COMMENT '场景ID';
|
||||
CREATE INDEX idx_scenario_id USING BTREE ON api_scenario_csv_step (scenario_id);
|
||||
|
||||
-- set innodb lock wait timeout to default
|
||||
SET SESSION innodb_lock_wait_timeout = DEFAULT;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.apache.jorphan.collections.HashTree;
|
|||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
|
@ -22,10 +24,25 @@ public abstract class AbstractJmeterElementConverter<T extends MsTestElement> im
|
|||
|
||||
/**
|
||||
* 获取转换器的函数
|
||||
* 主应用在实例化转换器的时候会设置
|
||||
*/
|
||||
@Setter
|
||||
private Function<Class<? extends MsTestElement>, AbstractJmeterElementConverter> getConverterFunc;
|
||||
private static Function<Class<? extends MsTestElement>, AbstractJmeterElementConverter> getConverterFunc;
|
||||
/**
|
||||
* 解析子步骤前的前置处理函数
|
||||
*/
|
||||
private static List<AbstractJmeterElementConverter> childPreConverters = new ArrayList<>();
|
||||
/**
|
||||
* 解析子步骤前的前置处理函数
|
||||
*/
|
||||
private static List<AbstractJmeterElementConverter> childPostConverters = new ArrayList<>();
|
||||
|
||||
public static void registerChildPreConverters(AbstractJmeterElementConverter converter) {
|
||||
childPreConverters.add(converter);
|
||||
}
|
||||
|
||||
public static void registerChildPostConverters(AbstractJmeterElementConverter converter) {
|
||||
childPostConverters.add(converter);
|
||||
}
|
||||
|
||||
public AbstractJmeterElementConverter() {
|
||||
Type genericSuperclass = getClass().getGenericSuperclass();
|
||||
|
@ -45,10 +62,14 @@ public abstract class AbstractJmeterElementConverter<T extends MsTestElement> im
|
|||
*/
|
||||
public void parseChild(HashTree tree, AbstractMsTestElement element, ParameterConfig config) {
|
||||
if (element != null && element.getChildren() != null) {
|
||||
// 解析子步骤前的前置处理函数
|
||||
childPreConverters.forEach(processor -> processor.toHashTree(tree, element, config));
|
||||
element.getChildren().forEach(child -> {
|
||||
child.setParent(element);
|
||||
getConverterFunc.apply(child.getClass()).toHashTree(tree, child, config);
|
||||
});
|
||||
// 解析子步骤后的后置处理函数
|
||||
childPostConverters.forEach(processor -> processor.toHashTree(tree, element, config));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||
import lombok.Data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -50,4 +51,8 @@ public abstract class AbstractMsTestElement implements MsTestElement {
|
|||
* 父组件
|
||||
*/
|
||||
private AbstractMsTestElement parent;
|
||||
/**
|
||||
* 关联的 csv ID
|
||||
*/
|
||||
private List<String> csvIds;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto;
|
||||
|
||||
import io.metersphere.api.dto.scenario.CsvVariable;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
|
||||
|
@ -80,4 +81,13 @@ public class ApiParamConfig extends ParameterConfig {
|
|||
public EnvironmentInfoDTO getEnvConfig(String projectId) {
|
||||
return getEnvConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 csv 信息
|
||||
* @param csvId
|
||||
* @return
|
||||
*/
|
||||
public CsvVariable getCsvVariable(String csvId) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package io.metersphere.api.dto;
|
||||
|
||||
import io.metersphere.api.dto.scenario.CsvVariable;
|
||||
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +33,13 @@ public class ApiScenarioParamConfig extends ApiParamConfig {
|
|||
*/
|
||||
private Boolean grouped;
|
||||
|
||||
/**
|
||||
* csv Map
|
||||
* key 为 csv 的 ID
|
||||
* value 为 csv 的信息
|
||||
*/
|
||||
private Map<String, CsvVariable> csvMap = new HashMap<>(0);
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getProtocolEnvConfig(AbstractMsTestElement msTestElement) {
|
||||
if (BooleanUtils.isTrue(grouped)) {
|
||||
|
@ -53,4 +62,14 @@ public class ApiScenarioParamConfig extends ApiParamConfig {
|
|||
return getEnvConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 csv 信息
|
||||
* @param csvId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public CsvVariable getCsvVariable(String csvId) {
|
||||
return csvMap.get(csvId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ public class ApiScenarioAddRequest {
|
|||
private String environmentId;
|
||||
|
||||
@Schema(description = "场景的通用配置")
|
||||
@Valid
|
||||
private ScenarioConfig scenarioConfig = new ScenarioConfig();
|
||||
|
||||
@Schema(description = "步骤集合")
|
||||
|
@ -80,10 +81,4 @@ public class ApiScenarioAddRequest {
|
|||
*/
|
||||
@Schema(description = "步骤文件操作相关参数")
|
||||
private Map<String, ResourceAddFileParam> stepFileParam;
|
||||
|
||||
/**
|
||||
* 步骤文件操作相关参数
|
||||
*/
|
||||
@Schema(description = "场景文件操作相关参数")
|
||||
private ResourceAddFileParam fileParam;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.util.List;
|
|||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ApiScenarioDetail extends ApiScenario {
|
||||
@Schema(description = "场景的通用配置")
|
||||
private ScenarioConfig scenarioConfig;
|
||||
private ScenarioConfig scenarioConfig = new ScenarioConfig();
|
||||
@Schema(description = "步骤")
|
||||
private List<ApiScenarioStepDTO> steps;
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ public class ApiScenarioStepCommonDTO<T extends ApiScenarioStepCommonDTO> {
|
|||
@Schema(description = "循环等组件基础数据")
|
||||
private Object config;
|
||||
|
||||
@Schema(description = "csv文件id集合")
|
||||
private List<String> csvFileIds;
|
||||
@Schema(description = "csv id集合")
|
||||
private List<String> csvIds;
|
||||
|
||||
@Schema(description = "项目fk")
|
||||
@NotBlank
|
||||
|
|
|
@ -83,10 +83,4 @@ public class ApiScenarioUpdateRequest {
|
|||
*/
|
||||
@Schema(description = "步骤文件操作相关参数")
|
||||
private Map<String, ResourceUpdateFileParam> stepFileParam;
|
||||
|
||||
/**
|
||||
* 步骤文件操作相关参数
|
||||
*/
|
||||
@Schema(description = "场景文件操作相关参数")
|
||||
private ResourceUpdateFileParam fileParam;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.sdk.constants.ValueEnum;
|
||||
import io.metersphere.system.valid.EnumValue;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
@ -14,50 +16,51 @@ import lombok.Data;
|
|||
public class CsvVariable {
|
||||
|
||||
@Schema(description = "id")
|
||||
@NotBlank
|
||||
@Size(max = 50)
|
||||
private String id;
|
||||
|
||||
@Schema(description = "文件id/引用文件id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(min = 1, max = 50, message = "{api_scenario_csv.file_id.length_range}")
|
||||
@Size(max = 50, message = "{api_scenario_csv.file_id.length_range}")
|
||||
@NotBlank
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "场景id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(min = 1, max = 50, message = "{api_scenario_csv.scenario_id.length_range}")
|
||||
private String scenarioId;
|
||||
|
||||
@Schema(description = "csv变量名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(min = 1, max = 255, message = "{api_scenario_csv.name.length_range}")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件名称")
|
||||
@NotBlank
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "作用域 SCENARIO/STEP")
|
||||
@Schema(description = "是否是关联文件")
|
||||
private Boolean association = false;
|
||||
|
||||
@Schema(description = "csv变量名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(max = 255, message = "{api_scenario_csv.name.length_range}")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @see CsvVariableScope
|
||||
*/
|
||||
@Schema(description = "作用域 SCENARIO/STEP")
|
||||
@NotBlank(message = "{api_scenario_csv.scope.not_blank}")
|
||||
@Size(min = 1, max = 50, message = "{api_scenario_csv.scope.length_range}")
|
||||
private String scope;
|
||||
@EnumValue(enumClass = CsvVariableScope.class)
|
||||
private String scope = CsvVariableScope.SCENARIO.name();
|
||||
|
||||
@Schema(description = "启用/禁用")
|
||||
private Boolean enable = true;
|
||||
|
||||
@Schema(description = "是否引用")
|
||||
private Boolean association = false;
|
||||
|
||||
@Schema(description = "文件编码")
|
||||
/**
|
||||
* 文件编码
|
||||
*
|
||||
* @see CsvEncodingType
|
||||
*/
|
||||
@Schema(description = "文件编码 UTF-8/UTF-16/ISO-8859-15/US-ASCII")
|
||||
@Size(max = 50, message = "{api_scenario_csv.encoding.length_range}")
|
||||
private String encoding;
|
||||
@EnumValue(enumClass = CsvEncodingType.class)
|
||||
private String encoding = CsvEncodingType.UTF8.getValue();
|
||||
|
||||
@Schema(description = "是否随机")
|
||||
private Boolean random = false;
|
||||
|
||||
@Schema(description = "变量名称(西文逗号间隔)")
|
||||
@Schema(description = "变量名称(英文逗号间隔)")
|
||||
@Size(max = 255, message = "{api_scenario_csv.variable_names.length_range}")
|
||||
private String variableNames;
|
||||
|
||||
|
@ -78,7 +81,7 @@ public class CsvVariable {
|
|||
private Boolean stopThreadOnEof = false;
|
||||
|
||||
|
||||
public enum CsvEncodingType {
|
||||
public enum CsvEncodingType implements ValueEnum {
|
||||
UTF8("UTF-8"), UFT16("UTF-16"), ISO885915("ISO-8859-15"), US_ASCII("US-ASCII");
|
||||
private String value;
|
||||
|
||||
|
@ -86,6 +89,7 @@ public class CsvVariable {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.dto.scenario;
|
|||
|
||||
import io.metersphere.api.dto.assertion.MsScenarioAssertionConfig;
|
||||
import io.metersphere.api.dto.request.processors.MsProcessorConfig;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
@ -13,6 +14,7 @@ public class ScenarioConfig {
|
|||
/**
|
||||
* 场景变量
|
||||
*/
|
||||
@Valid
|
||||
private ScenarioVariable variable = new ScenarioVariable();
|
||||
/**
|
||||
* 前置处理器配置
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.project.dto.environment.variables.CommonVariables;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -15,9 +16,11 @@ public class ScenarioVariable {
|
|||
/**
|
||||
* 普通变量
|
||||
*/
|
||||
@Valid
|
||||
private List<CommonVariables> commonVariables = new ArrayList<>(0);
|
||||
/**
|
||||
* csv变量
|
||||
*/
|
||||
@Valid
|
||||
private List<CsvVariable> csvVariables = new ArrayList<>(0);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public interface ExtApiScenarioStepMapper {
|
|||
|
||||
List<CsvVariable> getCsvVariableByScenarioId(@Param("id") String id);
|
||||
|
||||
List<ApiScenarioCsvStep> getCsvStepByStepIds(@Param("ids") List<String> stepIds);
|
||||
List<ApiScenarioCsvStep> getCsvStepByScenarioId(@Param("scenarioId") String scenarioId);
|
||||
|
||||
/**
|
||||
* 查询有步骤详情的请求类型的步骤
|
||||
|
|
|
@ -18,13 +18,10 @@
|
|||
<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 id="getCsvStepByScenarioId" 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>
|
||||
from api_scenario_csv_step where scenario_id = #{scenarioId}
|
||||
</select>
|
||||
<select id="getHasBlobRequestStepIds" resultType="java.lang.String">
|
||||
select id
|
||||
|
|
|
@ -5,10 +5,13 @@ import io.metersphere.api.constants.ApiScenarioStepRefType;
|
|||
import io.metersphere.api.dto.ApiScenarioParamConfig;
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.request.processors.MsProcessorConfig;
|
||||
import io.metersphere.api.dto.scenario.CsvVariable;
|
||||
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
||||
import io.metersphere.api.dto.scenario.ScenarioStepConfig;
|
||||
import io.metersphere.api.dto.scenario.ScenarioVariable;
|
||||
import io.metersphere.api.parser.jmeter.child.MsCsvChildPreConverter;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
|
||||
import io.metersphere.api.parser.jmeter.processor.MsProcessorConverter;
|
||||
import io.metersphere.api.parser.jmeter.processor.MsProcessorConverterFactory;
|
||||
import io.metersphere.api.parser.jmeter.processor.assertion.AssertionConverterFactory;
|
||||
|
@ -65,6 +68,9 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
tree.add(getCookieManager());
|
||||
}
|
||||
|
||||
// 添加 csv 数据集
|
||||
addCsvDataSet(tree, msScenario.getScenarioConfig());
|
||||
|
||||
// 添加场景和环境变量
|
||||
addUserParameters(tree, msScenario, envInfo, config);
|
||||
|
||||
|
@ -85,8 +91,17 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
addScenarioAssertions(tree, msScenario, config);
|
||||
}
|
||||
|
||||
private void addCsvDataSet(HashTree tree, ScenarioConfig scenarioConfig) {
|
||||
if (scenarioConfig == null || scenarioConfig.getVariable() == null || CollectionUtils.isEmpty(scenarioConfig.getVariable().getCsvVariables())) {
|
||||
return;
|
||||
}
|
||||
List<CsvVariable> csvVariables = scenarioConfig.getVariable().getCsvVariables();
|
||||
MsCsvChildPreConverter.addCsvDataSet(tree, JmeterProperty.CSVDataSetProperty.SHARE_MODE_GROUP, csvVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加临界控制器,解决变量冲突
|
||||
*
|
||||
* @param tree
|
||||
* @param msScenario
|
||||
* @return
|
||||
|
@ -270,9 +285,9 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
envScenarioProcessors.stream()
|
||||
.filter(MsProcessor::getEnable)
|
||||
.forEach(processor -> {
|
||||
processor.setProjectId(msScenario.getProjectId());
|
||||
getConverterFunc.apply(processor.getClass()).parse(tree, processor, config);
|
||||
});
|
||||
processor.setProjectId(msScenario.getProjectId());
|
||||
getConverterFunc.apply(processor.getClass()).parse(tree, processor, config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -319,9 +334,9 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
scenarioPreProcessors.stream()
|
||||
.filter(MsProcessor::getEnable)
|
||||
.forEach(processor -> {
|
||||
processor.setProjectId(msScenario.getProjectId());
|
||||
getConverterFunc.apply(processor.getClass()).parse(tree, processor, config);
|
||||
});
|
||||
processor.setProjectId(msScenario.getProjectId());
|
||||
getConverterFunc.apply(processor.getClass()).parse(tree, processor, config);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isRef(String refType) {
|
||||
|
@ -347,6 +362,9 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
private ApiScenarioParamConfig getEnableConfig(MsScenario msScenario, ApiScenarioParamConfig config) {
|
||||
ApiScenarioParamConfig enableConfig = config;
|
||||
if (!isRef(msScenario.getRefType())) {
|
||||
if (isRootScenario(msScenario.getRefType())) {
|
||||
setScenarioConfig(msScenario, enableConfig);
|
||||
}
|
||||
// 非引用的场景,使用当前环境参数
|
||||
return enableConfig;
|
||||
}
|
||||
|
@ -369,13 +387,24 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
|
|||
}
|
||||
}
|
||||
|
||||
setScenarioConfig(msScenario, enableConfig);
|
||||
|
||||
return enableConfig;
|
||||
}
|
||||
|
||||
private void setScenarioConfig(MsScenario msScenario, ApiScenarioParamConfig enableConfig) {
|
||||
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
|
||||
if (scenarioConfig != null) {
|
||||
// 设置是否使用全局cookie
|
||||
enableConfig.setEnableGlobalCookie(scenarioConfig.getOtherConfig().getEnableCookieShare());
|
||||
}
|
||||
|
||||
return enableConfig;
|
||||
ScenarioVariable variable = scenarioConfig.getVariable();
|
||||
if (variable != null && variable.getCsvVariables() != null) {
|
||||
for (CsvVariable csvVariable : variable.getCsvVariables()) {
|
||||
enableConfig.getCsvMap().put(csvVariable.getId(), csvVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CookieManager getCookieManager() {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package io.metersphere.api.parser.jmeter.child;
|
||||
|
||||
import io.metersphere.api.dto.ApiParamConfig;
|
||||
import io.metersphere.api.dto.scenario.CsvVariable;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
|
||||
import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.sdk.constants.LocalRepositoryDir;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.config.CSVDataSet;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 解析 csv 文件
|
||||
* 在解析子步骤前,先添加 csv 配置
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-05-15 11:32
|
||||
*/
|
||||
public class MsCsvChildPreConverter extends AbstractJmeterElementConverter<AbstractMsTestElement> {
|
||||
|
||||
@Override
|
||||
public void toHashTree(HashTree tree, AbstractMsTestElement element, ParameterConfig config) {
|
||||
List<String> csvIds = element.getCsvIds();
|
||||
ApiParamConfig apiParamConfig = (ApiParamConfig) config;
|
||||
if (CollectionUtils.isEmpty(csvIds)) {
|
||||
return;
|
||||
}
|
||||
csvIds.forEach(csvId -> {
|
||||
CsvVariable csvVariable = apiParamConfig.getCsvVariable(csvId);
|
||||
if (csvVariable != null) {
|
||||
String shareMode = StringUtils.equals(csvVariable.getScope(), CsvVariable.CsvVariableScope.SCENARIO.name()) ?
|
||||
JmeterProperty.CSVDataSetProperty.SHARE_MODE_GROUP : JmeterProperty.CSVDataSetProperty.SHARE_MODE_THREAD;
|
||||
addCsvDataSet(tree, shareMode, csvVariable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void addCsvDataSet(HashTree tree, String shareMode, List<CsvVariable> list) {
|
||||
list.forEach(item -> addCsvDataSet(tree, shareMode, item));
|
||||
}
|
||||
|
||||
private static void addCsvDataSet(HashTree tree, String shareMode, CsvVariable csvVariable) {
|
||||
// 执行机执行文件存放的缓存目录
|
||||
String path = LocalRepositoryDir.getSystemCacheDir() + "/" + csvVariable.getFileId() + "/" + csvVariable.getFileName();
|
||||
if (!StringUtils.equals(File.separator, "/")) {
|
||||
// windows 系统下运行,将 / 转换为 \,否则jmeter报错
|
||||
path = path.replace("/", File.separator);
|
||||
}
|
||||
CSVDataSet csvDataSet = new CSVDataSet();
|
||||
csvDataSet.setEnabled(true);
|
||||
csvDataSet.setIgnoreFirstLine(false);
|
||||
csvDataSet.setProperty(TestElement.TEST_CLASS, CSVDataSet.class.getName());
|
||||
csvDataSet.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(JmeterAlias.TEST_BEAN_GUI));
|
||||
csvDataSet.setName(StringUtils.isEmpty(csvVariable.getName()) ? CSVDataSet.class.getSimpleName() : csvVariable.getName());
|
||||
csvDataSet.setProperty(JmeterProperty.FILE_ENCODING, StringUtils.isEmpty(csvVariable.getEncoding()) ? StandardCharsets.UTF_8.name() : csvVariable.getEncoding());
|
||||
csvDataSet.setProperty(JmeterProperty.CSVDataSetProperty.FILE_NAME, path);
|
||||
csvDataSet.setProperty(JmeterProperty.CSVDataSetProperty.SHARE_MODE, shareMode);
|
||||
csvDataSet.setProperty(JmeterProperty.CSVDataSetProperty.RECYCLE, true);
|
||||
csvDataSet.setProperty(JmeterProperty.CSVDataSetProperty.DELIMITER, csvVariable.getDelimiter());
|
||||
csvDataSet.setProperty(JmeterProperty.CSVDataSetProperty.QUOTED_DATA, csvVariable.getAllowQuotedData());
|
||||
tree.add(csvDataSet);
|
||||
}
|
||||
}
|
|
@ -11,4 +11,16 @@ public class JmeterProperty {
|
|||
public final static String ASS_OPTION = "ASS_OPTION";
|
||||
public final static String BEAN_SHELL_ASSERTION_QUERY = "BeanShellAssertion.query";
|
||||
public final static String BEAN_SHELL_SAMPLER_QUERY = "BeanShellSampler.query";
|
||||
public final static String FILE_ENCODING = "fileEncoding";
|
||||
|
||||
public class CSVDataSetProperty {
|
||||
public static final String FILE_NAME = "filename";
|
||||
public static final String SHARE_MODE = "shareMode";
|
||||
public static final String RECYCLE = "recycle";
|
||||
public static final String DELIMITER = "delimiter";
|
||||
public static final String QUOTED_DATA = "quotedData";
|
||||
public static final String SHARE_MODE_GROUP = "shareMode.group";
|
||||
public static final String SHARE_MODE_THREAD = "shareMode.thread";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.api.parser.jmeter;
|
||||
package io.metersphere.api.parser.jmeter.controller;
|
||||
|
||||
import io.metersphere.api.dto.request.controller.MsConstantTimerController;
|
||||
import io.metersphere.api.parser.jmeter.processor.ScenarioTimeWaitingProcessorConverter;
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.api.parser.jmeter;
|
||||
package io.metersphere.api.parser.jmeter.controller;
|
||||
|
||||
import io.metersphere.api.dto.request.controller.MsIfController;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
|
@ -21,12 +21,9 @@ public class MsIfControllerConverter extends AbstractJmeterElementConverter<MsIf
|
|||
LogUtils.info("MsIfController is disabled");
|
||||
return;
|
||||
}
|
||||
//TODO 这里需要处理csv文件
|
||||
|
||||
|
||||
HashTree groupTree = tree.add(ifController(element));
|
||||
parseChild(groupTree, element, config);
|
||||
|
||||
}
|
||||
|
||||
private IfController ifController(MsIfController element) {
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.api.parser.jmeter;
|
||||
package io.metersphere.api.parser.jmeter.controller;
|
||||
|
||||
import io.metersphere.api.dto.request.controller.LoopType;
|
||||
import io.metersphere.api.dto.request.controller.MsLoopController;
|
||||
|
@ -27,7 +27,6 @@ public class MsLoopControllerConverter extends AbstractJmeterElementConverter<Ms
|
|||
return;
|
||||
}
|
||||
final HashTree groupTree = controller(tree, element);
|
||||
//TODO 这里需要处理csv文件 场景变量
|
||||
|
||||
if (groupTree == null) {
|
||||
return;
|
|
@ -1,4 +1,4 @@
|
|||
package io.metersphere.api.parser.jmeter;
|
||||
package io.metersphere.api.parser.jmeter.controller;
|
||||
|
||||
import io.metersphere.api.dto.request.controller.MsOnceOnlyController;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
|
@ -20,7 +20,6 @@ public class MsOnceOnlyControllerConverter extends AbstractJmeterElementConverte
|
|||
LogUtils.info("MsOnceOnlyController is disabled");
|
||||
return;
|
||||
}
|
||||
//TODO 这里需要处理csv文件
|
||||
|
||||
HashTree groupTree = tree.add(onceOnlyController(element));
|
||||
parseChild(groupTree, element, config);
|
|
@ -237,8 +237,8 @@ public class ApiFileResourceService {
|
|||
/**
|
||||
* 删除资源下所有的文件或者关联关系
|
||||
*
|
||||
* @param dirPrefix 本地上传文件目录前缀
|
||||
* @param resourceIds 资源ID
|
||||
* @param dirPrefix 本地上传文件目录前缀
|
||||
* @param resourceIds 资源ID
|
||||
* @param projectId 项目ID
|
||||
* @param operator 操作人
|
||||
*/
|
||||
|
@ -402,18 +402,27 @@ public class ApiFileResourceService {
|
|||
fileRequest.setFileName(fileName);
|
||||
fileRequest.setStorage(StorageType.MINIO.name());
|
||||
|
||||
byte[] bytes;
|
||||
try {
|
||||
fileId = fileMetadataService.transferFile(request.getFileName(), request.getOriginalName(), request.getProjectId(), request.getModuleId(), currentUser, fileService.download(fileRequest));
|
||||
if (CollectionUtils.isEmpty(apiFileResources)) {
|
||||
// 删除临时文件
|
||||
FileRequest deleteRequest = new FileRequest();
|
||||
deleteRequest.setFolder(folder);
|
||||
FileCenter.getDefaultRepository().deleteFolder(deleteRequest);
|
||||
}
|
||||
bytes = fileService.download(fileRequest);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
throw new MSException(Translator.get("file.transfer.failed"));
|
||||
throw new MSException(Translator.get("file.transfer.failed"), e);
|
||||
}
|
||||
|
||||
fileId = fileMetadataService.transferFile(request.getFileName(), request.getOriginalName(), request.getProjectId(), request.getModuleId(), currentUser, bytes);
|
||||
if (CollectionUtils.isEmpty(apiFileResources)) {
|
||||
// 删除临时文件
|
||||
FileRequest deleteRequest = new FileRequest();
|
||||
deleteRequest.setFolder(folder);
|
||||
try {
|
||||
FileCenter.getDefaultRepository().deleteFolder(deleteRequest);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
throw new MSException(Translator.get("file.transfer.failed"), e);
|
||||
}
|
||||
}
|
||||
|
||||
return fileId;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.metersphere.api.service.scenario;
|
||||
|
||||
import io.metersphere.sdk.constants.ApiFileResourceType;
|
||||
import io.metersphere.api.constants.ApiResourceType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
|
@ -51,9 +50,7 @@ import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
|||
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
|
||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileCopyRequest;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.file.MinioRepository;
|
||||
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
|
||||
import io.metersphere.sdk.mapper.EnvironmentMapper;
|
||||
|
@ -152,10 +149,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private FileAssociationService fileAssociationService;
|
||||
@Resource
|
||||
private FileMetadataService fileMetadataService;
|
||||
@Resource
|
||||
private ApiScenarioCsvMapper apiScenarioCsvMapper;
|
||||
@Resource
|
||||
private ApiScenarioCsvStepMapper apiScenarioCsvStepMapper;
|
||||
|
@ -442,6 +435,18 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
apiScenarioBlob.setConfig(JSON.toJSONString(request.getScenarioConfig()).getBytes());
|
||||
apiScenarioBlobMapper.insert(apiScenarioBlob);
|
||||
|
||||
// 处理csv文件
|
||||
handCsvFilesAdd(request, creator, scenario);
|
||||
|
||||
// 处理添加的步骤
|
||||
handleStepAdd(request, scenario);
|
||||
|
||||
// 处理步骤文件
|
||||
handleStepFilesAdd(request, creator, scenario);
|
||||
return scenario;
|
||||
}
|
||||
|
||||
private void handleStepAdd(ApiScenarioAddRequest request, ApiScenario scenario) {
|
||||
// 插入步骤
|
||||
if (CollectionUtils.isNotEmpty(request.getSteps())) {
|
||||
checkCircularRef(scenario.getId(), request.getSteps());
|
||||
|
@ -462,33 +467,25 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
apiScenarioStepBlobMapper.batchInsert(apiScenarioStepBlobs);
|
||||
}
|
||||
|
||||
saveStepCsv(steps, csvSteps);
|
||||
csvSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
saveStepCsv(scenario.getId(), steps, csvSteps);
|
||||
}
|
||||
|
||||
// 处理步骤文件
|
||||
handleStepFiles(request, creator, scenario);
|
||||
|
||||
// 处理场景文件,csv等
|
||||
handScenarioFiles(request, creator, scenario);
|
||||
return scenario;
|
||||
}
|
||||
|
||||
private void handScenarioFiles(ApiScenarioAddRequest request, String creator, ApiScenario scenario) {
|
||||
ResourceAddFileParam fileParam = request.getFileParam();
|
||||
if (fileParam == null) {
|
||||
private void handCsvFilesAdd(ApiScenarioAddRequest request, String creator, ApiScenario scenario) {
|
||||
if (request.getScenarioConfig() == null || request.getScenarioConfig().getVariable() == null || request.getScenarioConfig().getVariable().getCsvVariables() == null) {
|
||||
return;
|
||||
}
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), creator);
|
||||
resourceUpdateRequest.setUploadFileIds(fileParam.getUploadFileIds());
|
||||
resourceUpdateRequest.setLinkFileIds(fileParam.getLinkFileIds());
|
||||
apiFileResourceService.addFileResource(resourceUpdateRequest);
|
||||
if (request.getScenarioConfig() != null
|
||||
&& request.getScenarioConfig().getVariable() != null) {
|
||||
saveCsv(request.getScenarioConfig().getVariable().getCsvVariables(), resourceUpdateRequest);
|
||||
}
|
||||
List<CsvVariable> csvVariables = request.getScenarioConfig().getVariable().getCsvVariables();
|
||||
|
||||
// 处理 csv 相关数据表
|
||||
handleCsvDataUpdate(csvVariables, scenario, List.of());
|
||||
|
||||
// 处理文件的上传
|
||||
handleCsvFileUpdate(csvVariables, List.of(), scenario, creator);
|
||||
}
|
||||
|
||||
private void handleStepFiles(ApiScenarioAddRequest request, String creator, ApiScenario scenario) {
|
||||
private void handleStepFilesAdd(ApiScenarioAddRequest request, String creator, ApiScenario scenario) {
|
||||
Map<String, ResourceAddFileParam> stepFileParam = request.getStepFileParam();
|
||||
if (MapUtils.isNotEmpty(stepFileParam)) {
|
||||
stepFileParam.forEach((stepId, fileParam) -> {
|
||||
|
@ -499,7 +496,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleStepFiles(ApiScenarioUpdateRequest request, String updater, ApiScenario scenario) {
|
||||
private void handleStepFilesUpdate(ApiScenarioUpdateRequest request, String updater, ApiScenario scenario) {
|
||||
Map<String, ResourceUpdateFileParam> stepFileParam = request.getStepFileParam();
|
||||
if (MapUtils.isNotEmpty(stepFileParam)) {
|
||||
stepFileParam.forEach((stepId, fileParam) -> {
|
||||
|
@ -520,156 +517,126 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
return resourceUpdateRequest;
|
||||
}
|
||||
|
||||
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步骤
|
||||
private void saveStepCsv(String scenarioId, List<ApiScenarioStep> steps, List<ApiScenarioCsvStep> csvSteps) {
|
||||
// 先删除
|
||||
ApiScenarioCsvStepExample csvStepExample = new ApiScenarioCsvStepExample();
|
||||
csvStepExample.createCriteria().andScenarioIdEqualTo(scenarioId);
|
||||
apiScenarioCsvStepMapper.deleteByExample(csvStepExample);
|
||||
|
||||
// 再添加
|
||||
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();
|
||||
private void handleCsvUpdate(ScenarioConfig scenarioConfig, ApiScenario scenario, String userId) {
|
||||
if (scenarioConfig == null || scenarioConfig.getVariable() == null || scenarioConfig.getVariable().getCsvVariables() == null) {
|
||||
return;
|
||||
}
|
||||
List<CsvVariable> csvVariables = scenarioConfig.getVariable().getCsvVariables();
|
||||
List<ApiScenarioCsv> dbCsv = getApiScenarioCsv(scenario.getId());
|
||||
|
||||
//获取传的所有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();
|
||||
// 更新 csv 相关数据表
|
||||
handleCsvDataUpdate(csvVariables, scenario, dbCsv);
|
||||
|
||||
//取交集 交集数据是已存在的 不需要重新上传 和处理关联关系 但是需要更新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.setUnLinkFileIds(deleteRefs);
|
||||
//删除不存在的数据
|
||||
deleteCsvResource(resourceUpdateRequest);
|
||||
|
||||
addCsvResource(resourceUpdateRequest, csvVariables);
|
||||
// 处理文件的上传和删除
|
||||
handleCsvFileUpdate(csvVariables, dbCsv, scenario, userId);
|
||||
}
|
||||
|
||||
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_MANAGEMENT_SCENARIO));
|
||||
}
|
||||
Map<String, String> finalRefFilesMap = refFilesMap;
|
||||
// 添加文件与接口的关联关系
|
||||
Map<String, String> addFileMap = new HashMap<>();
|
||||
csvVariables.forEach(item -> {
|
||||
private void handleCsvDataUpdate(List<CsvVariable> csvVariables, ApiScenario scenario, List<ApiScenarioCsv> dbCsv) {
|
||||
List<String> dbCsvIds = dbCsv.stream()
|
||||
.map(ApiScenarioCsv::getId)
|
||||
.toList();
|
||||
|
||||
List<String> csvIds = csvVariables.stream()
|
||||
.map(CsvVariable::getId)
|
||||
.toList();
|
||||
|
||||
List<String> deleteCsvIds = ListUtils.subtract(dbCsvIds, csvIds);
|
||||
|
||||
//删除不存在的数据
|
||||
deleteCsvResource(deleteCsvIds);
|
||||
|
||||
Set<String> dbCsvIdSet = dbCsvIds.stream().collect(Collectors.toSet());
|
||||
|
||||
List<ApiScenarioCsv> addCsvList = new ArrayList<>();
|
||||
csvVariables.stream().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);
|
||||
scenarioCsv.setScenarioId(scenario.getId());
|
||||
scenarioCsv.setProjectId(scenario.getProjectId());
|
||||
if (!dbCsvIdSet.contains(item.getId())) {
|
||||
addCsvList.add(scenarioCsv);
|
||||
} else {
|
||||
updateData.add(scenarioCsv);
|
||||
apiScenarioCsvMapper.updateByPrimaryKey(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);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(addCsvList)) {
|
||||
apiScenarioCsvMapper.batchInsert(addCsvList);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
private void handleCsvFileUpdate(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiScenario scenario, String userId) {
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), userId);
|
||||
// 设置本地文件相关参数
|
||||
setCsvLocalFileParam(csvVariables, dbCsv, resourceUpdateRequest);
|
||||
// 设置关联文件相关参数
|
||||
setCsvLinkFileParam(csvVariables, dbCsv, resourceUpdateRequest);
|
||||
apiFileResourceService.addFileResource(resourceUpdateRequest);
|
||||
}
|
||||
|
||||
example.createCriteria()
|
||||
.andScenarioIdEqualTo(resourceUpdateRequest.getResourceId())
|
||||
.andFileIdIn(deleteFileIds);
|
||||
apiScenarioCsvMapper.deleteByExample(example);
|
||||
stepExample.createCriteria().andFileIdIn(deleteFileIds);
|
||||
apiScenarioCsvStepMapper.deleteByExample(stepExample);
|
||||
private void setCsvLinkFileParam(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiFileResourceUpdateRequest resourceUpdateRequest) {
|
||||
// 获取数据库中关联的文件id
|
||||
List<String> dbRefFileIds = dbCsv.stream()
|
||||
.filter(c -> BooleanUtils.isTrue(c.getAssociation()))
|
||||
.map(ApiScenarioCsv::getFileId)
|
||||
.toList();
|
||||
|
||||
}
|
||||
List<String> unLinkFileIds = resourceUpdateRequest.getUnLinkFileIds();
|
||||
// 处理关联文件
|
||||
if (CollectionUtils.isNotEmpty(unLinkFileIds)) {
|
||||
fileAssociationService.deleteBySourceIdAndFileIds(resourceUpdateRequest.getResourceId(), unLinkFileIds,
|
||||
apiFileResourceService.createFileLogRecord(resourceUpdateRequest.getOperator(), resourceUpdateRequest.getProjectId(), resourceUpdateRequest.getLogModule()));
|
||||
example.clear();
|
||||
example.createCriteria()
|
||||
.andScenarioIdEqualTo(resourceUpdateRequest.getResourceId())
|
||||
.andFileIdIn(unLinkFileIds);
|
||||
// 获取请求中关联的文件id
|
||||
List<String> refFileIds = csvVariables.stream()
|
||||
.filter(c -> BooleanUtils.isTrue(c.getAssociation())).map(CsvVariable::getFileId).toList();
|
||||
|
||||
List<String> unlinkFileIds = ListUtils.subtract(dbRefFileIds, refFileIds);
|
||||
resourceUpdateRequest.setUnLinkFileIds(unlinkFileIds);
|
||||
List<String> linkFileIds = ListUtils.subtract(refFileIds, dbRefFileIds);
|
||||
resourceUpdateRequest.setLinkFileIds(linkFileIds);
|
||||
}
|
||||
|
||||
private void setCsvLocalFileParam(List<CsvVariable> csvVariables, List<ApiScenarioCsv> dbCsv, ApiFileResourceUpdateRequest resourceUpdateRequest) {
|
||||
// 获取数据库中的本地文件
|
||||
List<String> dbLocalFileIds = dbCsv.stream()
|
||||
.filter(c -> BooleanUtils.isFalse(c.getAssociation()))
|
||||
.map(ApiScenarioCsv::getFileId)
|
||||
.toList();
|
||||
|
||||
// 获取请求中的本地文件
|
||||
List<String> localFileIds = csvVariables.stream()
|
||||
.filter(c -> BooleanUtils.isFalse(c.getAssociation()))
|
||||
.map(CsvVariable::getFileId).toList();
|
||||
|
||||
// 待删除文件
|
||||
List<String> deleteLocals = ListUtils.subtract(dbLocalFileIds, localFileIds);
|
||||
resourceUpdateRequest.setDeleteFileIds(deleteLocals);
|
||||
// 新上传文件
|
||||
List<String> addLocal = ListUtils.subtract(localFileIds, dbLocalFileIds);
|
||||
resourceUpdateRequest.setUploadFileIds(addLocal);
|
||||
}
|
||||
|
||||
private List<ApiScenarioCsv> getApiScenarioCsv(String scenarioId) {
|
||||
ApiScenarioCsvExample apiScenarioCsvExample = new ApiScenarioCsvExample();
|
||||
apiScenarioCsvExample.createCriteria().andScenarioIdEqualTo(scenarioId);
|
||||
return apiScenarioCsvMapper.selectByExample(apiScenarioCsvExample);
|
||||
}
|
||||
|
||||
private void deleteCsvResource(List<String> deleteCsvIds) {
|
||||
if (CollectionUtils.isNotEmpty(deleteCsvIds)) {
|
||||
ApiScenarioCsvExample example = new ApiScenarioCsvExample();
|
||||
example.createCriteria().andIdIn(deleteCsvIds);
|
||||
apiScenarioCsvMapper.deleteByExample(example);
|
||||
stepExample.clear();
|
||||
stepExample.createCriteria().andFileIdIn(deleteFileIds);
|
||||
|
||||
ApiScenarioCsvStepExample stepExample = new ApiScenarioCsvStepExample();
|
||||
stepExample.createCriteria().andIdIn(deleteCsvIds);
|
||||
apiScenarioCsvStepMapper.deleteByExample(stepExample);
|
||||
}
|
||||
}
|
||||
|
@ -719,32 +686,14 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
updateApiScenarioStep(request, originScenario, updater);
|
||||
|
||||
// 处理步骤文件
|
||||
handleStepFiles(request, updater, originScenario);
|
||||
handleStepFilesUpdate(request, updater, originScenario);
|
||||
|
||||
// 处理场景文件
|
||||
handleScenarioFiles(request, updater, originScenario);
|
||||
// 处理 csv 文件
|
||||
handleCsvUpdate(request.getScenarioConfig(), scenario, updater);
|
||||
|
||||
return scenario;
|
||||
}
|
||||
|
||||
private void handleScenarioFiles(ApiScenarioUpdateRequest request, String updater, ApiScenario scenario) {
|
||||
// 处理场景文件
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), updater);
|
||||
ResourceAddFileParam fileParam = request.getFileParam();
|
||||
if (fileParam != null) {
|
||||
resourceUpdateRequest = BeanUtils.copyBean(resourceUpdateRequest, fileParam);
|
||||
apiFileResourceService.updateFileResource(resourceUpdateRequest);
|
||||
}
|
||||
|
||||
//处理csv变量
|
||||
if (request.getScenarioConfig() != null
|
||||
&& request.getScenarioConfig().getVariable() != null) {
|
||||
saveCsv(request.getScenarioConfig().getVariable().getCsvVariables(), resourceUpdateRequest);
|
||||
} else {
|
||||
saveCsv(new ArrayList<>(), resourceUpdateRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新场景步骤
|
||||
*/
|
||||
|
@ -764,8 +713,9 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
// 获取待更新的步骤
|
||||
List<ApiScenarioStep> apiScenarioSteps = getApiScenarioSteps(null, steps, scenarioCsvSteps);
|
||||
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
scenarioCsvSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
|
||||
saveStepCsv(apiScenarioSteps, scenarioCsvSteps);
|
||||
saveStepCsv(scenario.getId(), apiScenarioSteps, scenarioCsvSteps);
|
||||
// 获取待更新的步骤详情
|
||||
addSpecialStepDetails(steps, request.getStepDetails());
|
||||
List<ApiScenarioStepBlob> updateStepBlobs = getUpdateStepBlobs(apiScenarioSteps, request.getStepDetails());
|
||||
|
@ -941,9 +891,9 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getCsvFileIds())) {
|
||||
if (CollectionUtils.isNotEmpty(step.getCsvIds())) {
|
||||
//如果是csv文件 需要保存到apiScenarioCsvStep表中
|
||||
step.getCsvFileIds().forEach(fileId -> {
|
||||
step.getCsvIds().forEach(fileId -> {
|
||||
ApiScenarioCsvStep csvStep = new ApiScenarioCsvStep();
|
||||
csvStep.setId(IDGenerator.nextStr());
|
||||
csvStep.setStepId(apiScenarioStep.getId());
|
||||
|
@ -1183,16 +1133,11 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
private void deleteCsvByScenarioId(String id) {
|
||||
ApiScenarioCsvExample example = new ApiScenarioCsvExample();
|
||||
example.createCriteria().andScenarioIdEqualTo(id);
|
||||
List<ApiScenarioCsv> apiScenarioCsv = apiScenarioCsvMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioCsv)) {
|
||||
List<String> fileIds = apiScenarioCsv.stream().map(ApiScenarioCsv::getFileId).toList();
|
||||
//删除关联关系
|
||||
ApiScenarioCsvStepExample stepExample = new ApiScenarioCsvStepExample();
|
||||
stepExample.createCriteria().andFileIdIn(fileIds);
|
||||
apiScenarioCsvStepMapper.deleteByExample(stepExample);
|
||||
}
|
||||
apiScenarioCsvMapper.deleteByExample(example);
|
||||
|
||||
ApiScenarioCsvStepExample stepExample = new ApiScenarioCsvStepExample();
|
||||
stepExample.createCriteria().andScenarioIdEqualTo(id);
|
||||
apiScenarioCsvStepMapper.deleteByExample(stepExample);
|
||||
}
|
||||
|
||||
//级联删除
|
||||
|
@ -1810,6 +1755,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
msTestElement.setName(step.getName());
|
||||
// 步骤ID,设置为唯一ID
|
||||
msTestElement.setStepId(step.getUniqueId());
|
||||
msTestElement.setCsvIds(step.getCsvIds());
|
||||
|
||||
// 记录引用的资源ID和项目ID,下载执行文件时需要使用
|
||||
parseParam.getRefProjectIds().add(step.getProjectId());
|
||||
|
@ -2152,15 +2098,14 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
ApiScenarioDetail apiScenarioDetail = BeanUtils.copyBean(new ApiScenarioDetail(), apiScenario);
|
||||
apiScenarioDetail.setSteps(List.of());
|
||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(scenarioId);
|
||||
|
||||
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);
|
||||
}
|
||||
apiScenarioDetail.getScenarioConfig().getVariable().setCsvVariables(csvVariables);
|
||||
|
||||
// 获取所有步骤
|
||||
List<ApiScenarioStepDTO> allSteps = getAllStepsByScenarioIds(List.of(scenarioId))
|
||||
|
@ -2169,16 +2114,13 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
.collect(Collectors.toList());
|
||||
|
||||
//获取所有步骤的csv的关联关系
|
||||
List<String> stepIds = allSteps.stream().map(ApiScenarioStepDTO::getId).toList();
|
||||
if (CollectionUtils.isNotEmpty(stepIds)) {
|
||||
List<ApiScenarioCsvStep> csvSteps = extApiScenarioStepMapper.getCsvStepByStepIds(stepIds);
|
||||
// 构造 map,key 为步骤ID,value 为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())));
|
||||
}
|
||||
List<ApiScenarioCsvStep> csvSteps = extApiScenarioStepMapper.getCsvStepByScenarioId(scenarioId);
|
||||
// 构造 map,key 为步骤ID,value 为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.setCsvIds(stepsCsvMap.get(step.getId())));
|
||||
}
|
||||
|
||||
// 构造 map,key 为场景ID,value 为步骤列表
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.parser.jmeter.*;
|
||||
import io.metersphere.api.parser.jmeter.child.MsCsvChildPreConverter;
|
||||
import io.metersphere.api.parser.jmeter.controller.MsConstantTimerControllerConverter;
|
||||
import io.metersphere.api.parser.jmeter.controller.MsIfControllerConverter;
|
||||
import io.metersphere.api.parser.jmeter.controller.MsLoopControllerConverter;
|
||||
import io.metersphere.api.parser.jmeter.controller.MsOnceOnlyControllerConverter;
|
||||
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||
import io.metersphere.plugin.api.spi.MsTestElement;
|
||||
import io.metersphere.plugin.sdk.util.PluginLogUtils;
|
||||
|
@ -24,7 +29,11 @@ public class JmeterElementConverterRegister {
|
|||
private static final Map<Class<? extends MsTestElement>, AbstractJmeterElementConverter<? extends MsTestElement>> parserMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
// 注册默认的转换器 todo 注册插件的转换器
|
||||
// 设置获取转换器的方法
|
||||
AbstractJmeterElementConverter.setGetConverterFunc(JmeterElementConverterRegister::getConverter);
|
||||
// 注册子步骤前置解析器
|
||||
AbstractJmeterElementConverter.registerChildPreConverters(new MsCsvChildPreConverter());
|
||||
// 注册默认的转换器
|
||||
register(MsHTTPElementConverter.class);
|
||||
register(MsCommonElementConverter.class);
|
||||
register(MsScriptElementConverter.class);
|
||||
|
@ -43,8 +52,6 @@ public class JmeterElementConverterRegister {
|
|||
public static void register(Class<? extends AbstractJmeterElementConverter<? extends MsTestElement>> elementConverterClass) {
|
||||
try {
|
||||
AbstractJmeterElementConverter<? extends MsTestElement> elementConverter = elementConverterClass.getDeclaredConstructor().newInstance();
|
||||
// 设置获取转换器的方法
|
||||
elementConverter.setGetConverterFunc(JmeterElementConverterRegister::getConverter);
|
||||
// 注册到解析器集合中
|
||||
parserMap.put(elementConverter.testElementClass, elementConverter);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
|
|
|
@ -5,7 +5,6 @@ import io.metersphere.api.domain.*;
|
|||
import io.metersphere.api.dto.ApiFile;
|
||||
import io.metersphere.api.dto.ApiRunModeRequest;
|
||||
import io.metersphere.api.dto.ReferenceRequest;
|
||||
import io.metersphere.api.dto.ResourceAddFileParam;
|
||||
import io.metersphere.api.dto.assertion.MsAssertionConfig;
|
||||
import io.metersphere.api.dto.debug.ModuleCreateRequest;
|
||||
import io.metersphere.api.dto.definition.*;
|
||||
|
@ -106,6 +105,9 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
private static final String UPDATE_STATUS = "update-status";
|
||||
private static final String UPDATE_PRIORITY = "update-priority";
|
||||
private static final String BATCH_RUN = "batch-operation/run";
|
||||
private static final String TRANSFER_OPTIONS = "transfer/options/{0}";
|
||||
private static final String TRANSFER = "transfer";
|
||||
private static final String STEP_TRANSFER = "step/transfer";
|
||||
|
||||
private static final Map<String, String> BATCH_OPERATION_SCENARIO_MODULE_MAP = new HashMap<>();
|
||||
private static final List<String> BATCH_OPERATION_SCENARIO_ID = new ArrayList<>();
|
||||
|
@ -355,9 +357,6 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
request.setSteps(steps);
|
||||
request.setStepDetails(steptDetailMap);
|
||||
request.setScenarioConfig(getScenarioConfig());
|
||||
String fileId = doUploadTempFile(getMockMultipartFile());
|
||||
request.setFileParam(new ResourceAddFileParam());
|
||||
request.getFileParam().setUploadFileIds(List.of(fileId));
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
|
||||
ApiScenario resultData = getResultData(mvcResult, ApiScenario.class);
|
||||
this.addApiScenario = apiScenarioMapper.selectByPrimaryKey(resultData.getId());
|
||||
|
@ -365,7 +364,6 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
assertUpdateSteps(steps, steptDetailMap);
|
||||
|
||||
request.setName("anOther name");
|
||||
request.getFileParam().setUploadFileIds(List.of());
|
||||
request.setGrouped(true);
|
||||
request.setEnvironmentId(envGroupId);
|
||||
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
|
||||
|
@ -387,6 +385,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
stepRequest2.setProjectId(DEFAULT_PROJECT_ID);
|
||||
steps = List.of(stepRequest, stepRequest2);
|
||||
request.setSteps(steps);
|
||||
request.getScenarioConfig().getVariable().getCsvVariables().forEach(csvVariable -> csvVariable.setId(UUID.randomUUID().toString()));
|
||||
mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
|
||||
this.anOtherAddApiScenario = apiScenarioMapper.selectByPrimaryKey(getResultData(mvcResult, ApiScenario.class).getId());
|
||||
assertUpdateApiScenario(request, request.getScenarioConfig(), anOtherAddApiScenario.getId());
|
||||
|
@ -444,7 +443,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
}
|
||||
}
|
||||
|
||||
private ScenarioConfig getScenarioConfig() throws Exception {
|
||||
private ScenarioConfig getScenarioConfig() {
|
||||
ScenarioConfig scenarioConfig = new ScenarioConfig();
|
||||
MsAssertionConfig msAssertionConfig = new MsAssertionConfig();
|
||||
MsScriptAssertion scriptAssertion = new MsScriptAssertion();
|
||||
|
@ -478,16 +477,20 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
fileMetadataId = fileMetadataService.upload(fileUploadRequest, "admin", file);
|
||||
}
|
||||
|
||||
public List<CsvVariable> getCsvVariables() throws Exception {
|
||||
public List<CsvVariable> getCsvVariables() {
|
||||
List<CsvVariable> csvVariables = new ArrayList<>();
|
||||
CsvVariable csvVariable = new CsvVariable();
|
||||
csvVariable.setId(UUID.randomUUID().toString());
|
||||
csvVariable.setFileId(localFileId);
|
||||
csvVariable.setName("csv变量");
|
||||
csvVariable.setFileName("test.jbc");
|
||||
csvVariable.setScope(CsvVariable.CsvVariableScope.SCENARIO.name());
|
||||
csvVariables.add(csvVariable);
|
||||
csvVariable = new CsvVariable();
|
||||
csvVariable.setId(UUID.randomUUID().toString());
|
||||
csvVariable.setFileId(fileMetadataId);
|
||||
csvVariable.setName("csv-关联的");
|
||||
csvVariable.setFileName("test.jbc");
|
||||
csvVariable.setScope(CsvVariable.CsvVariableScope.SCENARIO.name());
|
||||
csvVariable.setAssociation(true);
|
||||
csvVariables.add(csvVariable);
|
||||
|
@ -506,7 +509,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));
|
||||
stepRequest.setCsvIds(List.of(fileMetadataId));
|
||||
|
||||
ApiScenarioStepRequest stepRequest2 = new ApiScenarioStepRequest();
|
||||
stepRequest2.setId(IDGenerator.nextStr());
|
||||
|
@ -518,7 +521,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));
|
||||
stepRequest2.setCsvIds(List.of(fileMetadataId));
|
||||
|
||||
ApiScenarioStepRequest stepRequest3 = new ApiScenarioStepRequest();
|
||||
stepRequest3.setId(IDGenerator.nextStr());
|
||||
|
@ -809,7 +812,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
@Test
|
||||
@Order(7)
|
||||
public void testTransfer() throws Exception {
|
||||
this.requestGetWithOk("transfer/options/" + "/" + DEFAULT_PROJECT_ID);
|
||||
this.requestGetWithOk(TRANSFER_OPTIONS, DEFAULT_PROJECT_ID);
|
||||
ApiTransferRequest apiTransferRequest = new ApiTransferRequest();
|
||||
apiTransferRequest.setSourceId(addApiScenario.getId());
|
||||
apiTransferRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
|
@ -819,10 +822,10 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
apiTransferRequest.setOriginalName("test-scenario-file.txt");
|
||||
String uploadFileId = doUploadTempFile(getMockMultipartFile());
|
||||
apiTransferRequest.setFileId(uploadFileId);
|
||||
this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk());
|
||||
this.requestPost(TRANSFER, apiTransferRequest).andExpect(status().isOk());
|
||||
//文件不存在
|
||||
apiTransferRequest.setFileId("111");
|
||||
this.requestPost("transfer", apiTransferRequest).andExpect(status().is5xxServerError());
|
||||
this.requestPost(TRANSFER, apiTransferRequest).andExpect(status().is5xxServerError());
|
||||
//文件已经上传
|
||||
ApiFileResourceExample apiFileResourceExample = new ApiFileResourceExample();
|
||||
apiFileResourceExample.createCriteria().andResourceIdEqualTo(addApiScenario.getId());
|
||||
|
@ -831,8 +834,26 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
apiTransferRequest.setFileId(apiFileResources.get(0).getFileId());
|
||||
apiTransferRequest.setFileName("test-scenario-file-1");
|
||||
apiTransferRequest.setOriginalName("test-scenario-file-1.txt");
|
||||
this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk());
|
||||
this.requestPost(TRANSFER, apiTransferRequest).andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
public void testStepTransfer() throws Exception {
|
||||
this.requestGetWithOk(TRANSFER_OPTIONS, DEFAULT_PROJECT_ID);
|
||||
ApiTransferRequest apiTransferRequest = new ApiTransferRequest();
|
||||
apiTransferRequest.setSourceId(addApiScenarioSteps.get(0).getId());
|
||||
apiTransferRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
apiTransferRequest.setModuleId("root");
|
||||
apiTransferRequest.setLocal(true);
|
||||
apiTransferRequest.setFileName("test-scenario-step-file");
|
||||
apiTransferRequest.setOriginalName("test-scenario-step-file.txt");
|
||||
String uploadFileId = doUploadTempFile(getMockMultipartFile());
|
||||
apiTransferRequest.setFileId(uploadFileId);
|
||||
this.requestPost(STEP_TRANSFER, apiTransferRequest).andExpect(status().isOk());
|
||||
//文件不存在
|
||||
apiTransferRequest.setFileId("111");
|
||||
this.requestPost(STEP_TRANSFER, apiTransferRequest).andExpect(status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -316,7 +316,7 @@ public class FileAssociationService {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String transferAndAssociation(@Validated FileAssociationDTO fileAssociationDTO) throws Exception {
|
||||
public String transferAndAssociation(@Validated FileAssociationDTO fileAssociationDTO) {
|
||||
FileAssociationSource source = extFileAssociationMapper.selectNameBySourceTableAndId(FileAssociationSourceUtil.getQuerySql(fileAssociationDTO.getSourceType()), fileAssociationDTO.getSourceId());
|
||||
this.validateSourceName(source);
|
||||
String fileId = fileMetadataService.transferFile(
|
||||
|
|
|
@ -22,10 +22,7 @@ import io.metersphere.sdk.exception.MSException;
|
|||
import io.metersphere.sdk.file.FileRepository;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.file.MinioRepository;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.GitRepositoryUtil;
|
||||
import io.metersphere.sdk.util.TempFileUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.sdk.util.*;
|
||||
import io.metersphere.system.mapper.BaseUserMapper;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.PageUtils;
|
||||
|
@ -214,7 +211,7 @@ public class FileMetadataService {
|
|||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public String transferFile(String fileName, String originFileName, String projectId, String moduleId, String operator, byte[] fileBytes) throws Exception {
|
||||
public String transferFile(String fileName, String originFileName, String projectId, String moduleId, String operator, byte[] fileBytes) {
|
||||
if (StringUtils.isBlank(originFileName)) {
|
||||
throw new MSException(Translator.get("file.name.cannot.be.empty"));
|
||||
}
|
||||
|
@ -228,7 +225,13 @@ public class FileMetadataService {
|
|||
uploadFileRequest.setStorage(StorageType.MINIO.name());
|
||||
|
||||
FileRepository minio = CommonBeanFactory.getBean(MinioRepository.class);
|
||||
String filePath = minio.saveFile(fileBytes, uploadFileRequest);
|
||||
String filePath;
|
||||
try {
|
||||
filePath = minio.saveFile(fileBytes, uploadFileRequest);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
throw new MSException(Translator.get("file.transfer.failed"), e);
|
||||
}
|
||||
fileMetadata.setPath(filePath);
|
||||
fileMetadata.setFileVersion(fileMetadata.getId());
|
||||
fileMetadataMapper.insert(fileMetadata);
|
||||
|
|
Loading…
Reference in New Issue