feat(接口测试): 场景保存接口实现
This commit is contained in:
parent
280723aee0
commit
b5a5f6d899
|
@ -31,7 +31,7 @@ public class ApiScenarioStep implements Serializable {
|
|||
private Boolean enable;
|
||||
|
||||
@Schema(description = "资源id")
|
||||
private Long resourceId;
|
||||
private String resourceId;
|
||||
|
||||
@Schema(description = "资源编号")
|
||||
private String resourceNum;
|
||||
|
@ -49,7 +49,7 @@ public class ApiScenarioStep implements Serializable {
|
|||
private String versionId;
|
||||
|
||||
@Schema(description = "引用/复制/自定义")
|
||||
private String source;
|
||||
private String refType;
|
||||
|
||||
@Schema(description = "循环等组件基础数据")
|
||||
private String config;
|
||||
|
@ -62,13 +62,13 @@ public class ApiScenarioStep implements Serializable {
|
|||
name("name", "name", "VARCHAR", true),
|
||||
sort("sort", "sort", "BIGINT", false),
|
||||
enable("enable", "enable", "BIT", true),
|
||||
resourceId("resource_id", "resourceId", "BIGINT", false),
|
||||
resourceId("resource_id", "resourceId", "VARCHAR", false),
|
||||
resourceNum("resource_num", "resourceNum", "VARCHAR", false),
|
||||
stepType("step_type", "stepType", "VARCHAR", false),
|
||||
projectId("project_id", "projectId", "VARCHAR", false),
|
||||
parentId("parent_id", "parentId", "VARCHAR", false),
|
||||
versionId("version_id", "versionId", "VARCHAR", false),
|
||||
source("source", "source", "VARCHAR", true),
|
||||
refType("ref_type", "refType", "VARCHAR", false),
|
||||
config("config", "config", "VARCHAR", false);
|
||||
|
||||
private static final String BEGINNING_DELIMITER = "`";
|
||||
|
|
|
@ -15,6 +15,11 @@ public class ApiScenarioStepBlob implements Serializable {
|
|||
@Size(min = 1, max = 50, message = "{api_scenario_step_blob.id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String id;
|
||||
|
||||
@Schema(description = "场景id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario_step_blob.scenario_id.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 50, message = "{api_scenario_step_blob.scenario_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String scenarioId;
|
||||
|
||||
@Schema(description = "场景步骤内容")
|
||||
private byte[] content;
|
||||
|
||||
|
@ -22,6 +27,7 @@ public class ApiScenarioStepBlob implements Serializable {
|
|||
|
||||
public enum Column {
|
||||
id("id", "id", "VARCHAR", false),
|
||||
scenarioId("scenario_id", "scenarioId", "VARCHAR", false),
|
||||
content("content", "content", "LONGVARBINARY", false);
|
||||
|
||||
private static final String BEGINNING_DELIMITER = "`";
|
||||
|
|
|
@ -173,6 +173,76 @@ public class ApiScenarioStepBlobExample {
|
|||
addCriterion("id not between", value1, value2, "id");
|
||||
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 {
|
||||
|
|
|
@ -444,52 +444,62 @@ public class ApiScenarioStepExample {
|
|||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdEqualTo(Long value) {
|
||||
public Criteria andResourceIdEqualTo(String value) {
|
||||
addCriterion("resource_id =", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdNotEqualTo(Long value) {
|
||||
public Criteria andResourceIdNotEqualTo(String value) {
|
||||
addCriterion("resource_id <>", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdGreaterThan(Long value) {
|
||||
public Criteria andResourceIdGreaterThan(String value) {
|
||||
addCriterion("resource_id >", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdGreaterThanOrEqualTo(Long value) {
|
||||
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("resource_id >=", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdLessThan(Long value) {
|
||||
public Criteria andResourceIdLessThan(String value) {
|
||||
addCriterion("resource_id <", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdLessThanOrEqualTo(Long value) {
|
||||
public Criteria andResourceIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("resource_id <=", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdIn(List<Long> values) {
|
||||
public Criteria andResourceIdLike(String value) {
|
||||
addCriterion("resource_id like", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdNotLike(String value) {
|
||||
addCriterion("resource_id not like", value, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdIn(List<String> values) {
|
||||
addCriterion("resource_id in", values, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdNotIn(List<Long> values) {
|
||||
public Criteria andResourceIdNotIn(List<String> values) {
|
||||
addCriterion("resource_id not in", values, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdBetween(Long value1, Long value2) {
|
||||
public Criteria andResourceIdBetween(String value1, String value2) {
|
||||
addCriterion("resource_id between", value1, value2, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andResourceIdNotBetween(Long value1, Long value2) {
|
||||
public Criteria andResourceIdNotBetween(String value1, String value2) {
|
||||
addCriterion("resource_id not between", value1, value2, "resourceId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
@ -844,73 +854,73 @@ public class ApiScenarioStepExample {
|
|||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceIsNull() {
|
||||
addCriterion("`source` is null");
|
||||
public Criteria andRefTypeIsNull() {
|
||||
addCriterion("ref_type is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceIsNotNull() {
|
||||
addCriterion("`source` is not null");
|
||||
public Criteria andRefTypeIsNotNull() {
|
||||
addCriterion("ref_type is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceEqualTo(String value) {
|
||||
addCriterion("`source` =", value, "source");
|
||||
public Criteria andRefTypeEqualTo(String value) {
|
||||
addCriterion("ref_type =", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceNotEqualTo(String value) {
|
||||
addCriterion("`source` <>", value, "source");
|
||||
public Criteria andRefTypeNotEqualTo(String value) {
|
||||
addCriterion("ref_type <>", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceGreaterThan(String value) {
|
||||
addCriterion("`source` >", value, "source");
|
||||
public Criteria andRefTypeGreaterThan(String value) {
|
||||
addCriterion("ref_type >", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("`source` >=", value, "source");
|
||||
public Criteria andRefTypeGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("ref_type >=", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceLessThan(String value) {
|
||||
addCriterion("`source` <", value, "source");
|
||||
public Criteria andRefTypeLessThan(String value) {
|
||||
addCriterion("ref_type <", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceLessThanOrEqualTo(String value) {
|
||||
addCriterion("`source` <=", value, "source");
|
||||
public Criteria andRefTypeLessThanOrEqualTo(String value) {
|
||||
addCriterion("ref_type <=", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceLike(String value) {
|
||||
addCriterion("`source` like", value, "source");
|
||||
public Criteria andRefTypeLike(String value) {
|
||||
addCriterion("ref_type like", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceNotLike(String value) {
|
||||
addCriterion("`source` not like", value, "source");
|
||||
public Criteria andRefTypeNotLike(String value) {
|
||||
addCriterion("ref_type not like", value, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceIn(List<String> values) {
|
||||
addCriterion("`source` in", values, "source");
|
||||
public Criteria andRefTypeIn(List<String> values) {
|
||||
addCriterion("ref_type in", values, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceNotIn(List<String> values) {
|
||||
addCriterion("`source` not in", values, "source");
|
||||
public Criteria andRefTypeNotIn(List<String> values) {
|
||||
addCriterion("ref_type not in", values, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceBetween(String value1, String value2) {
|
||||
addCriterion("`source` between", value1, value2, "source");
|
||||
public Criteria andRefTypeBetween(String value1, String value2) {
|
||||
addCriterion("ref_type between", value1, value2, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andSourceNotBetween(String value1, String value2) {
|
||||
addCriterion("`source` not between", value1, value2, "source");
|
||||
public Criteria andRefTypeNotBetween(String value1, String value2) {
|
||||
addCriterion("ref_type not between", value1, value2, "refType");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public interface ApiScenarioStepBlobMapper {
|
|||
|
||||
int updateByPrimaryKeyWithBLOBs(ApiScenarioStepBlob record);
|
||||
|
||||
int updateByPrimaryKey(ApiScenarioStepBlob record);
|
||||
|
||||
int batchInsert(@Param("list") List<ApiScenarioStepBlob> list);
|
||||
|
||||
int batchInsertSelective(@Param("list") List<ApiScenarioStepBlob> list, @Param("selective") ApiScenarioStepBlob.Column ... selective);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<mapper namespace="io.metersphere.api.mapper.ApiScenarioStepBlobMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
<id column="id" jdbcType="VARCHAR" property="id" />
|
||||
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
<result column="content" jdbcType="LONGVARBINARY" property="content" />
|
||||
|
@ -66,7 +67,7 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id
|
||||
id, scenario_id
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
content
|
||||
|
@ -120,8 +121,10 @@
|
|||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
insert into api_scenario_step_blob (id, content)
|
||||
values (#{id,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY})
|
||||
insert into api_scenario_step_blob (id, scenario_id, content
|
||||
)
|
||||
values (#{id,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
insert into api_scenario_step_blob
|
||||
|
@ -129,6 +132,9 @@
|
|||
<if test="id != null">
|
||||
id,
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id,
|
||||
</if>
|
||||
<if test="content != null">
|
||||
content,
|
||||
</if>
|
||||
|
@ -137,6 +143,9 @@
|
|||
<if test="id != null">
|
||||
#{id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
#{scenarioId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="content != null">
|
||||
#{content,jdbcType=LONGVARBINARY},
|
||||
</if>
|
||||
|
@ -154,6 +163,9 @@
|
|||
<if test="record.id != null">
|
||||
id = #{record.id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.scenarioId != null">
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.content != null">
|
||||
content = #{record.content,jdbcType=LONGVARBINARY},
|
||||
</if>
|
||||
|
@ -165,6 +177,7 @@
|
|||
<update id="updateByExampleWithBLOBs" parameterType="map">
|
||||
update api_scenario_step_blob
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
content = #{record.content,jdbcType=LONGVARBINARY}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -172,7 +185,8 @@
|
|||
</update>
|
||||
<update id="updateByExample" parameterType="map">
|
||||
update api_scenario_step_blob
|
||||
set id = #{record.id,jdbcType=VARCHAR}
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -180,6 +194,9 @@
|
|||
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
update api_scenario_step_blob
|
||||
<set>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="content != null">
|
||||
content = #{content,jdbcType=LONGVARBINARY},
|
||||
</if>
|
||||
|
@ -188,15 +205,22 @@
|
|||
</update>
|
||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
update api_scenario_step_blob
|
||||
set content = #{content,jdbcType=LONGVARBINARY}
|
||||
set scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
content = #{content,jdbcType=LONGVARBINARY}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.api.domain.ApiScenarioStepBlob">
|
||||
update api_scenario_step_blob
|
||||
set scenario_id = #{scenarioId,jdbcType=VARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<insert id="batchInsert" parameterType="map">
|
||||
insert into api_scenario_step_blob
|
||||
(id, content)
|
||||
(id, scenario_id, content)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.content,jdbcType=LONGVARBINARY})
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.scenarioId,jdbcType=VARCHAR}, #{item.content,jdbcType=LONGVARBINARY}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
<insert id="batchInsertSelective" parameterType="map">
|
||||
|
@ -212,6 +236,9 @@
|
|||
<if test="'id'.toString() == column.value">
|
||||
#{item.id,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'scenario_id'.toString() == column.value">
|
||||
#{item.scenarioId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'content'.toString() == column.value">
|
||||
#{item.content,jdbcType=LONGVARBINARY}
|
||||
</if>
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
<result column="name" jdbcType="VARCHAR" property="name" />
|
||||
<result column="sort" jdbcType="BIGINT" property="sort" />
|
||||
<result column="enable" jdbcType="BIT" property="enable" />
|
||||
<result column="resource_id" jdbcType="BIGINT" property="resourceId" />
|
||||
<result column="resource_id" jdbcType="VARCHAR" property="resourceId" />
|
||||
<result column="resource_num" jdbcType="VARCHAR" property="resourceNum" />
|
||||
<result column="step_type" jdbcType="VARCHAR" property="stepType" />
|
||||
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
|
||||
<result column="parent_id" jdbcType="VARCHAR" property="parentId" />
|
||||
<result column="version_id" jdbcType="VARCHAR" property="versionId" />
|
||||
<result column="source" jdbcType="VARCHAR" property="source" />
|
||||
<result column="ref_type" jdbcType="VARCHAR" property="refType" />
|
||||
<result column="config" jdbcType="VARCHAR" property="config" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
|
@ -76,7 +76,7 @@
|
|||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, scenario_id, `name`, sort, `enable`, resource_id, resource_num, step_type, project_id,
|
||||
parent_id, version_id, `source`, config
|
||||
parent_id, version_id, ref_type, config
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiScenarioStepExample" resultMap="BaseResultMap">
|
||||
select
|
||||
|
@ -112,12 +112,12 @@
|
|||
insert into api_scenario_step (id, scenario_id, `name`,
|
||||
sort, `enable`, resource_id,
|
||||
resource_num, step_type, project_id,
|
||||
parent_id, version_id, `source`,
|
||||
parent_id, version_id, ref_type,
|
||||
config)
|
||||
values (#{id,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||
#{sort,jdbcType=BIGINT}, #{enable,jdbcType=BIT}, #{resourceId,jdbcType=BIGINT},
|
||||
#{sort,jdbcType=BIGINT}, #{enable,jdbcType=BIT}, #{resourceId,jdbcType=VARCHAR},
|
||||
#{resourceNum,jdbcType=VARCHAR}, #{stepType,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
|
||||
#{parentId,jdbcType=VARCHAR}, #{versionId,jdbcType=VARCHAR}, #{source,jdbcType=VARCHAR},
|
||||
#{parentId,jdbcType=VARCHAR}, #{versionId,jdbcType=VARCHAR}, #{refType,jdbcType=VARCHAR},
|
||||
#{config,jdbcType=VARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiScenarioStep">
|
||||
|
@ -156,8 +156,8 @@
|
|||
<if test="versionId != null">
|
||||
version_id,
|
||||
</if>
|
||||
<if test="source != null">
|
||||
`source`,
|
||||
<if test="refType != null">
|
||||
ref_type,
|
||||
</if>
|
||||
<if test="config != null">
|
||||
config,
|
||||
|
@ -180,7 +180,7 @@
|
|||
#{enable,jdbcType=BIT},
|
||||
</if>
|
||||
<if test="resourceId != null">
|
||||
#{resourceId,jdbcType=BIGINT},
|
||||
#{resourceId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="resourceNum != null">
|
||||
#{resourceNum,jdbcType=VARCHAR},
|
||||
|
@ -197,8 +197,8 @@
|
|||
<if test="versionId != null">
|
||||
#{versionId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="source != null">
|
||||
#{source,jdbcType=VARCHAR},
|
||||
<if test="refType != null">
|
||||
#{refType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="config != null">
|
||||
#{config,jdbcType=VARCHAR},
|
||||
|
@ -230,7 +230,7 @@
|
|||
`enable` = #{record.enable,jdbcType=BIT},
|
||||
</if>
|
||||
<if test="record.resourceId != null">
|
||||
resource_id = #{record.resourceId,jdbcType=BIGINT},
|
||||
resource_id = #{record.resourceId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.resourceNum != null">
|
||||
resource_num = #{record.resourceNum,jdbcType=VARCHAR},
|
||||
|
@ -247,8 +247,8 @@
|
|||
<if test="record.versionId != null">
|
||||
version_id = #{record.versionId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.source != null">
|
||||
`source` = #{record.source,jdbcType=VARCHAR},
|
||||
<if test="record.refType != null">
|
||||
ref_type = #{record.refType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.config != null">
|
||||
config = #{record.config,jdbcType=VARCHAR},
|
||||
|
@ -265,13 +265,13 @@
|
|||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
sort = #{record.sort,jdbcType=BIGINT},
|
||||
`enable` = #{record.enable,jdbcType=BIT},
|
||||
resource_id = #{record.resourceId,jdbcType=BIGINT},
|
||||
resource_id = #{record.resourceId,jdbcType=VARCHAR},
|
||||
resource_num = #{record.resourceNum,jdbcType=VARCHAR},
|
||||
step_type = #{record.stepType,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
parent_id = #{record.parentId,jdbcType=VARCHAR},
|
||||
version_id = #{record.versionId,jdbcType=VARCHAR},
|
||||
`source` = #{record.source,jdbcType=VARCHAR},
|
||||
ref_type = #{record.refType,jdbcType=VARCHAR},
|
||||
config = #{record.config,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -293,7 +293,7 @@
|
|||
`enable` = #{enable,jdbcType=BIT},
|
||||
</if>
|
||||
<if test="resourceId != null">
|
||||
resource_id = #{resourceId,jdbcType=BIGINT},
|
||||
resource_id = #{resourceId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="resourceNum != null">
|
||||
resource_num = #{resourceNum,jdbcType=VARCHAR},
|
||||
|
@ -310,8 +310,8 @@
|
|||
<if test="versionId != null">
|
||||
version_id = #{versionId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="source != null">
|
||||
`source` = #{source,jdbcType=VARCHAR},
|
||||
<if test="refType != null">
|
||||
ref_type = #{refType,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="config != null">
|
||||
config = #{config,jdbcType=VARCHAR},
|
||||
|
@ -325,26 +325,26 @@
|
|||
`name` = #{name,jdbcType=VARCHAR},
|
||||
sort = #{sort,jdbcType=BIGINT},
|
||||
`enable` = #{enable,jdbcType=BIT},
|
||||
resource_id = #{resourceId,jdbcType=BIGINT},
|
||||
resource_id = #{resourceId,jdbcType=VARCHAR},
|
||||
resource_num = #{resourceNum,jdbcType=VARCHAR},
|
||||
step_type = #{stepType,jdbcType=VARCHAR},
|
||||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
parent_id = #{parentId,jdbcType=VARCHAR},
|
||||
version_id = #{versionId,jdbcType=VARCHAR},
|
||||
`source` = #{source,jdbcType=VARCHAR},
|
||||
ref_type = #{refType,jdbcType=VARCHAR},
|
||||
config = #{config,jdbcType=VARCHAR}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<insert id="batchInsert" parameterType="map">
|
||||
insert into api_scenario_step
|
||||
(id, scenario_id, `name`, sort, `enable`, resource_id, resource_num, step_type, project_id,
|
||||
parent_id, version_id, `source`, config)
|
||||
parent_id, version_id, ref_type, config)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.id,jdbcType=VARCHAR}, #{item.scenarioId,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR},
|
||||
#{item.sort,jdbcType=BIGINT}, #{item.enable,jdbcType=BIT}, #{item.resourceId,jdbcType=BIGINT},
|
||||
#{item.sort,jdbcType=BIGINT}, #{item.enable,jdbcType=BIT}, #{item.resourceId,jdbcType=VARCHAR},
|
||||
#{item.resourceNum,jdbcType=VARCHAR}, #{item.stepType,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR},
|
||||
#{item.parentId,jdbcType=VARCHAR}, #{item.versionId,jdbcType=VARCHAR}, #{item.source,jdbcType=VARCHAR},
|
||||
#{item.parentId,jdbcType=VARCHAR}, #{item.versionId,jdbcType=VARCHAR}, #{item.refType,jdbcType=VARCHAR},
|
||||
#{item.config,jdbcType=VARCHAR})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
@ -374,7 +374,7 @@
|
|||
#{item.enable,jdbcType=BIT}
|
||||
</if>
|
||||
<if test="'resource_id'.toString() == column.value">
|
||||
#{item.resourceId,jdbcType=BIGINT}
|
||||
#{item.resourceId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'resource_num'.toString() == column.value">
|
||||
#{item.resourceNum,jdbcType=VARCHAR}
|
||||
|
@ -391,8 +391,8 @@
|
|||
<if test="'version_id'.toString() == column.value">
|
||||
#{item.versionId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'source'.toString() == column.value">
|
||||
#{item.source,jdbcType=VARCHAR}
|
||||
<if test="'ref_type'.toString() == column.value">
|
||||
#{item.refType,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'config'.toString() == column.value">
|
||||
#{item.config,jdbcType=VARCHAR}
|
||||
|
|
|
@ -275,13 +275,13 @@ CREATE TABLE IF NOT EXISTS api_scenario_step(
|
|||
`name` VARCHAR(255) COMMENT '步骤名称' ,
|
||||
`sort` BIGINT NOT NULL COMMENT '序号' ,
|
||||
`enable` BIT(1) NOT NULL DEFAULT 1 COMMENT '启用/禁用' ,
|
||||
`resource_id` BIGINT COMMENT '资源id' ,
|
||||
`resource_id` VARCHAR(50) COMMENT '资源id' ,
|
||||
`resource_num` VARCHAR(50) COMMENT '资源编号' ,
|
||||
`step_type` VARCHAR(50) COMMENT '步骤类型/API/CASE等' ,
|
||||
`project_id` VARCHAR(50) COMMENT '项目fk' ,
|
||||
`parent_id` VARCHAR(50) DEFAULT 'NONE' COMMENT '父级fk' ,
|
||||
`version_id` VARCHAR(50) COMMENT '版本号' ,
|
||||
`source` VARCHAR(10) COMMENT '引用/复制/自定义' ,
|
||||
`ref_type` VARCHAR(10) COMMENT '引用/复制/自定义' ,
|
||||
`config` VARCHAR(500) COMMENT '循环等组件基础数据' ,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE = InnoDB
|
||||
|
@ -296,12 +296,15 @@ CREATE INDEX idx_resource_num ON api_scenario_step(resource_num);
|
|||
|
||||
CREATE TABLE IF NOT EXISTS api_scenario_step_blob(
|
||||
`id` VARCHAR(50) NOT NULL COMMENT '场景步骤id' ,
|
||||
`scenario_id` VARCHAR(50) NOT NULL COMMENT '场景id' ,
|
||||
`content` LONGBLOB COMMENT '场景步骤内容' ,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci COMMENT = '场景步骤内容';
|
||||
|
||||
CREATE INDEX idx_scenario_id ON api_scenario_step_blob(scenario_id);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_scenario_follower(
|
||||
`api_scenario_id` VARCHAR(50) NOT NULL COMMENT '场景fk' ,
|
||||
|
|
|
@ -54,6 +54,7 @@ public class DefaultRepositoryDir {
|
|||
* project/{projectId}/api-debug/{apiDebugId}
|
||||
*/
|
||||
private static final String PROJECT_API_DEBUG_DIR = PROJECT_DIR + "/api-debug/%s";
|
||||
private static final String PROJECT_API_SCENARIO_DIR = PROJECT_DIR + "/api-scenario/%s";
|
||||
private static final String PROJECT_BUG_DIR = PROJECT_DIR + "/bug/%s";
|
||||
|
||||
/**
|
||||
|
@ -112,4 +113,8 @@ public class DefaultRepositoryDir {
|
|||
public static String getSystemTempDir() {
|
||||
return SYSTEM_TEMP_DIR;
|
||||
}
|
||||
|
||||
public static String getApiScenarioDir(String projectId, String apiScenarioId) {
|
||||
return String.format(PROJECT_API_SCENARIO_DIR, projectId, apiScenarioId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public class FileAssociationSourceUtil {
|
|||
public static final String SOURCE_TYPE_BUG = "BUG";
|
||||
public static final String SOURCE_TYPE_FUNCTIONAL_CASE = "FUNCTIONAL_CASE";
|
||||
public static final String SOURCE_TYPE_API_DEBUG = "API_DEBUG";
|
||||
public static final String SOURCE_TYPE_API_SCENARIO= "API_SCENARIO";
|
||||
public static final String SOURCE_TYPE_API_TEST_CASE = "API_TEST_CASE";
|
||||
public static final String SOURCE_TYPE_API_DEFINITION = "API_DEFINITION";
|
||||
public static final String SOURCE_TYPE_API_DEFINITION_MOCK = "API_DEFINITION_MOCK";
|
||||
|
@ -23,6 +24,7 @@ public class FileAssociationSourceUtil {
|
|||
QUERY_SQL.put(SOURCE_TYPE_BUG, "SELECT id AS sourceId,title AS sourceName FROM bug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_FUNCTIONAL_CASE, "SELECT id AS sourceId,name AS sourceName FROM functional_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEBUG, "SELECT id AS sourceId,name AS sourceName FROM api_debug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_SCENARIO, "SELECT id AS sourceId,name AS sourceName FROM api_scenario");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_TEST_CASE, "SELECT id AS sourceId,name AS sourceName FROM api_test_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION, "SELECT id AS sourceId,name AS sourceName FROM api_definition");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION_MOCK, "SELECT id AS sourceId,name AS sourceName FROM api_definition_mock");
|
||||
|
|
|
@ -21,6 +21,7 @@ api_definition_template.create_user.not_blank=创建人不能为空
|
|||
api_definition_template.project_id.length_range=项目ID长度必须在1-50之间
|
||||
api_definition_template.project_id.not_blank=项目ID不能为空
|
||||
#module:ApiScenario
|
||||
permission.system_api_scenario.name=场景
|
||||
api_scenario.id.not_blank=不能为空
|
||||
api_scenario.name.length_range=场景名称长度必须在1-200之间
|
||||
api_scenario.name.not_blank=场景名称不能为空
|
||||
|
@ -314,5 +315,6 @@ api_definition_mock_exist=接口 MOCK 已存在
|
|||
execute_resource_pool_not_config_error=请在【项目管理-应用管理-接口测试】中选择资源池
|
||||
resource_pool_execute_error=资源池调用失败
|
||||
api_swagger_url_error=Swagger url无法连通
|
||||
api_scenario_exist=场景已存在
|
||||
schedule_not_exist=定时任务不存在
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ api_definition_template.create_user.not_blank=Creator cannot be empty
|
|||
api_definition_template.project_id.length_range=Item fk length must be between 1-50
|
||||
api_definition_template.project_id.not_blank=Item fk cannot be empty
|
||||
#module:ApiScenario
|
||||
permission.system_api_scenario.name=Scenario
|
||||
api_scenario.id.not_blank=Can not be empty
|
||||
api_scenario.name.length_range=The scene name length must be between 1-200
|
||||
api_scenario.name.not_blank=Scene name cannot be empty
|
||||
|
@ -48,6 +49,7 @@ api_scenario_step.id.length_range=Step ID length must be between 1-50
|
|||
api_scenario_step.scenario_id.not_blank=Scene ID cannot be empty
|
||||
api_scenario_step.scenario_id.length_range=Scene ID length must be between 1-50
|
||||
api_scenario_step.sort.not_blank=SORT cannot be empty
|
||||
|
||||
#module:ApiTestCaseFollow
|
||||
api_test_case_follow.case_id.length_range=Use case fk length must be between 1-50
|
||||
api_test_case_follow.case_id.not_blank=Use case fk cannot be empty
|
||||
|
@ -318,4 +320,5 @@ api_definition_mock_exist=The API MOCK already exists
|
|||
execute_resource_pool_not_config_error=Select a resource pool in 【Project Management - Application Management - Interface Testing】
|
||||
resource_pool_execute_error=The resource pool call failed
|
||||
api_swagger_url_error=Swagger url unable to connect
|
||||
api_scenario_exist=The scenario already exists
|
||||
schedule_not_exist=The scheduled task does not exist
|
|
@ -21,6 +21,7 @@ api_definition_template.create_user.not_blank=创建人不能为空
|
|||
api_definition_template.project_id.length_range=项目ID长度必须在1-50之间
|
||||
api_definition_template.project_id.not_blank=项目ID不能为空
|
||||
#module:ApiScenario
|
||||
permission.system_api_scenario.name=场景
|
||||
api_scenario.id.not_blank=不能为空
|
||||
api_scenario.name.length_range=场景名称长度必须在1-200之间
|
||||
api_scenario.name.not_blank=场景名称不能为空
|
||||
|
@ -318,4 +319,5 @@ api_definition_mock_exist=接口 MOCK 已存在
|
|||
execute_resource_pool_not_config_error=请在【项目管理-应用管理-接口测试】中选择资源池
|
||||
resource_pool_execute_error=资源池调用失败
|
||||
api_swagger_url_error=Swagger url无法连通
|
||||
api_scenario_exist=场景已存在
|
||||
schedule_not_exist=定时任务不存在
|
||||
|
|
|
@ -21,6 +21,7 @@ api_definition_template.create_user.not_blank=創建人不能為空
|
|||
api_definition_template.project_id.length_range=項目ID長度必須在1-50之間
|
||||
api_definition_template.project_id.not_blank=項目ID不能為空
|
||||
#module:ApiScenario
|
||||
permission.system_api_scenario.name=场景
|
||||
api_scenario.id.not_blank=不能為空
|
||||
api_scenario.name.length_range=場景名稱長度必須在1-200之間
|
||||
api_scenario.name.not_blank=場景名稱不能為空
|
||||
|
@ -318,4 +319,5 @@ api_definition_mock_exist=接口 MOCK 已存在
|
|||
execute_resource_pool_not_config_error=請在【項目管理-應用管理-接口測試】中選擇資源池
|
||||
resource_pool_execute_error=資源池調用失敗
|
||||
api_swagger_url_error=Swagger url無法調解
|
||||
api_scenario_exist=場景已存在
|
||||
schedule_not_exist=定時任務不存在
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.api.constants;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-11 17:31
|
||||
*/
|
||||
public enum ApiScenarioStatus {
|
||||
/**
|
||||
* 进行中
|
||||
*/
|
||||
UNDERWAY,
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
COMPLETED,
|
||||
/**
|
||||
* 已废弃
|
||||
*/
|
||||
DEPRECATED
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.constants;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-10 11:24
|
||||
*/
|
||||
public enum ApiScenarioStepRefType {
|
||||
/**
|
||||
* 在场景中直接创建的步骤
|
||||
* 例如 自定义请求,逻辑控制器
|
||||
*/
|
||||
DIRECT,
|
||||
/**
|
||||
* 引用
|
||||
*/
|
||||
REF,
|
||||
/**
|
||||
* 步骤引用
|
||||
*/
|
||||
STEP_REF,
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
COPY
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.api.constants;
|
||||
|
||||
/**
|
||||
* 步骤的类型
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-10 11:24
|
||||
*/
|
||||
public enum ApiScenarioStepType {
|
||||
/**
|
||||
* 接口定义
|
||||
*/
|
||||
API,
|
||||
/**
|
||||
* 接口用例
|
||||
*/
|
||||
API_CASE,
|
||||
/**
|
||||
* 场景
|
||||
*/
|
||||
API_SCENARIO
|
||||
// todo 逻辑控制器等
|
||||
}
|
|
@ -13,7 +13,8 @@ public enum ApiResultCode implements IResultCode {
|
|||
API_DEFINITION_MODULE_NOT_EXIST(10404, "resource_not_exist"),
|
||||
RESOURCE_POOL_EXECUTE_ERROR(104005, "resource_pool_execute_error"),
|
||||
EXECUTE_RESOURCE_POOL_NOT_CONFIG(104006, "execute_resource_pool_not_config_error"),
|
||||
API_DEFINITION_MOCK_EXIST(104007, "api_definition_mock_exist");
|
||||
API_DEFINITION_MOCK_EXIST(104007, "api_definition_mock_exist"),
|
||||
API_SCENARIO_EXIST(104008, "api_scenario_exist");
|
||||
|
||||
|
||||
private final int code;
|
||||
|
|
|
@ -2,11 +2,13 @@ package io.metersphere.api.controller.scenario;
|
|||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioDTO;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioPageRequest;
|
||||
import io.metersphere.api.domain.ApiScenario;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioLogService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.log.annotation.Log;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.security.CheckOwner;
|
||||
import io.metersphere.system.utils.PageUtils;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
|
@ -15,9 +17,11 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -65,4 +69,42 @@ public class ApiScenarioController {
|
|||
apiScenarioService.follow(id, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "创建场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_ADD)
|
||||
@Log(type = OperationLogType.ADD, expression = "#msClass.addLog(#request)", msClass = ApiScenarioLogService.class)
|
||||
public ApiScenario add(@Validated @RequestBody ApiScenarioAddRequest request) {
|
||||
return apiScenarioService.add(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@PostMapping("/upload/temp/file")
|
||||
@Operation(summary = "上传场景所需的文件资源,并返回文件ID")
|
||||
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_API_SCENARIO_ADD, PermissionConstants.PROJECT_API_SCENARIO_UPDATE})
|
||||
public String uploadTempFile(@RequestParam("file") MultipartFile file) {
|
||||
return apiScenarioService.uploadTempFile(file);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@Operation(summary = "更新场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_UPDATE)
|
||||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = ApiScenarioLogService.class)
|
||||
public ApiScenario update(@Validated @RequestBody ApiScenarioUpdateRequest request) {
|
||||
return apiScenarioService.update(request, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
@Operation(summary = "删除场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_DELETE)
|
||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ApiScenarioLogService.class)
|
||||
public void delete(@PathVariable String id) {
|
||||
apiScenarioService.delete(id);
|
||||
}
|
||||
|
||||
@GetMapping("/delete-to-gc/{id}")
|
||||
@Operation(summary = "删除场景到回收站")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_DELETE)
|
||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ApiScenarioLogService.class)
|
||||
public void deleteToGc(@PathVariable String id) {
|
||||
apiScenarioService.deleteToGc(id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.metersphere.api.dto.request.http.body;
|
||||
package io.metersphere.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BodyFile {
|
||||
public class ApiFile {
|
||||
/**
|
||||
* 记录文件的ID,防止重名
|
||||
* 生成脚本时,通过 fileId + value(文件名) 获取文件路径
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto.request.http.body;
|
||||
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
@ -8,6 +9,6 @@ import lombok.Data;
|
|||
*/
|
||||
@Data
|
||||
public class BinaryBody {
|
||||
private BodyFile bodyFile;
|
||||
private ApiFile bodyFile;
|
||||
private String description;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto.request.http.body;
|
||||
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -12,7 +13,7 @@ import java.util.List;
|
|||
@Data
|
||||
public class FormDataKV extends WWWFormKV {
|
||||
|
||||
private List<BodyFile> files;
|
||||
private List<ApiFile> files;
|
||||
|
||||
public boolean isFile() {
|
||||
return StringUtils.equalsIgnoreCase(getParamType(), WWWFormParamType.FILE.name());
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.constants.ApiScenarioStatus;
|
||||
import io.metersphere.system.valid.EnumValue;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-10 11:24
|
||||
*/
|
||||
@Data
|
||||
public class ApiScenarioAddRequest {
|
||||
@Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.name.not_blank}")
|
||||
@Size(min = 1, max = 255, message = "{api_scenario.name.length_range}")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "场景级别/P0/P1等", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.priority.not_blank}")
|
||||
@Size(min = 1, max = 10, message = "{api_scenario.priority.length_range}")
|
||||
private String priority;
|
||||
|
||||
@Schema(description = "场景状态/未规划/已完成 等", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.status.not_blank}")
|
||||
@Size(min = 1, max = 20, message = "{api_scenario.status.length_range}")
|
||||
@EnumValue(enumClass = ApiScenarioStatus.class)
|
||||
private String status;
|
||||
|
||||
@Schema(description = "项目fk", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.project_id.not_blank}")
|
||||
@Size(min = 1, max = 50, message = "{api_scenario.project_id.length_range}")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "场景模块fk")
|
||||
@NotBlank(message = "{api_debug.module_id.not_blank}")
|
||||
private String moduleId;
|
||||
|
||||
@Schema(description = "描述信息")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "是否为环境组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Boolean grouped;
|
||||
|
||||
@Schema(description = "环境或者环境组ID")
|
||||
private String environmentId;
|
||||
|
||||
@Schema(description = "场景的通用配置")
|
||||
private ScenarioConfig scenarioConfig;
|
||||
|
||||
@Schema(description = "步骤集合")
|
||||
private List<ApiScenarioStepRequest> steps;
|
||||
|
||||
/**
|
||||
* 步骤详情
|
||||
* key 为步骤ID
|
||||
* 值 为详情
|
||||
*/
|
||||
@Schema(description = "步骤详情")
|
||||
private Map<String, Object> stepDetails;
|
||||
|
||||
/**
|
||||
* 新上传的文件ID
|
||||
* 创建时先按ID创建目录,再把文件放入目录
|
||||
*/
|
||||
@Schema(description = "新上传的文件ID")
|
||||
private List<String> uploadFileIds;
|
||||
|
||||
/**
|
||||
* 新关联的文件ID
|
||||
*/
|
||||
@Schema(description = "关联文件ID")
|
||||
private List<String> linkFileIds;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.domain.ApiScenario;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApiScenarioSimpleDTO extends ApiScenario {
|
||||
|
||||
@Schema(description = "更新人名称")
|
||||
private String updateUserName;
|
||||
@Schema(description = "创建人名称")
|
||||
private String createUserName;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.system.valid.EnumValue;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-10 11:24
|
||||
*/
|
||||
@Data
|
||||
public class ApiScenarioStepRequest {
|
||||
@Schema(description = "步骤id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario_step.id.not_blank}")
|
||||
@Size(max = 50, message = "{api_scenario_step.id.length_range}")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "步骤名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "启用/禁用")
|
||||
private Boolean enable = true;
|
||||
|
||||
@Schema(description = "资源id")
|
||||
private String resourceId;
|
||||
|
||||
@Schema(description = "资源编号")
|
||||
private String resourceNum;
|
||||
|
||||
/**
|
||||
* @see ApiScenarioStepType
|
||||
*/
|
||||
@Schema(description = "步骤类型/API/CASE等")
|
||||
@NotBlank
|
||||
@EnumValue(enumClass = ApiScenarioStepType.class)
|
||||
private String stepType;
|
||||
|
||||
@Schema(description = "项目fk")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String versionId;
|
||||
|
||||
/**
|
||||
* 引用模式:默认完全引用
|
||||
* - 完全引用:步骤状态不可调整
|
||||
* - 步骤引用:步骤状态可调整
|
||||
*/
|
||||
@Schema(description = "引用/复制/自定义")
|
||||
private String refType;
|
||||
|
||||
@Schema(description = "循环等组件基础数据")
|
||||
private Map<Object, Object> config;
|
||||
|
||||
@Schema(description = "子步骤")
|
||||
private List<ApiScenarioStepRequest> children;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.constants.ApiScenarioStatus;
|
||||
import io.metersphere.system.valid.EnumValue;
|
||||
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.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-10 11:24
|
||||
*/
|
||||
@Data
|
||||
public class ApiScenarioUpdateRequest {
|
||||
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.id.not_blank}", groups = {Updated.class})
|
||||
@Size(max = 50, message = "{api_scenario.id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String id;
|
||||
|
||||
@Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(max = 255, message = "{api_scenario.name.length_range}")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "场景级别/P0/P1等", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(max = 10, message = "{api_scenario.priority.length_range}")
|
||||
private String priority;
|
||||
|
||||
@Schema(description = "场景状态/未规划/已完成 等", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Size(max = 20, message = "{api_scenario.status.length_range}")
|
||||
@EnumValue(enumClass = ApiScenarioStatus.class)
|
||||
private String status;
|
||||
|
||||
@Schema(description = "场景模块fk")
|
||||
private String moduleId;
|
||||
|
||||
@Schema(description = "描述信息")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "是否为环境组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Boolean grouped;
|
||||
|
||||
@Schema(description = "环境或者环境组ID")
|
||||
private String environmentId;
|
||||
|
||||
@Schema(description = "场景的通用配置")
|
||||
private ScenarioConfig scenarioConfig;
|
||||
|
||||
@Schema(description = "步骤集合")
|
||||
private List<ApiScenarioStepRequest> steps;
|
||||
|
||||
/**
|
||||
* 步骤详情
|
||||
* key 为步骤ID
|
||||
* 值 为详情
|
||||
*/
|
||||
@Schema(description = "步骤详情")
|
||||
private Map<String, Object> stepDetails;
|
||||
|
||||
/**
|
||||
* 新上传的文件ID
|
||||
* 创建时先按ID创建目录,再把文件放入目录
|
||||
*/
|
||||
@Schema(description = "新上传的文件ID")
|
||||
private List<String> uploadFileIds;
|
||||
|
||||
/**
|
||||
* 新关联的文件ID
|
||||
*/
|
||||
@Schema(description = "关联文件ID")
|
||||
private List<String> linkFileIds;
|
||||
|
||||
/**
|
||||
* 删除本地上传的文件ID
|
||||
*/
|
||||
private List<String> deleteFileIds;
|
||||
|
||||
/**
|
||||
* 删除关联的文件ID
|
||||
*/
|
||||
private List<String> unLinkRefIds;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-12 10:11
|
||||
*/
|
||||
@Data
|
||||
public class CsvVariable {
|
||||
private String name;
|
||||
/**
|
||||
* @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;
|
||||
/**
|
||||
* 文件编码
|
||||
* @see CsvEncodingType
|
||||
*/
|
||||
private String encoding;
|
||||
|
||||
|
||||
public enum CsvEncodingType {
|
||||
UTF8("UTF-8"), UFT16("UTF-16"), ISO885915("ISO-8859-15"), US_ASCII("US-ASCII");
|
||||
private String value;
|
||||
|
||||
CsvEncodingType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CsvVariableScope {
|
||||
/**
|
||||
* 场景级:执行场景前加载CSV,当前场景任意步骤均可从CSV中读取到数据
|
||||
*/
|
||||
SCENARIO,
|
||||
/**
|
||||
* 步骤级:需在测试步骤的“更多操作”中指定使用添加该CSV,执行该步骤时加载CSV,作用域为步骤内的请求
|
||||
*/
|
||||
STEP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.dto.request.assertion.MsAssertionConfig;
|
||||
import io.metersphere.api.dto.request.processors.MsProcessorConfig;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-12 09:47
|
||||
*/
|
||||
@Data
|
||||
public class ScenarioConfig {
|
||||
/**
|
||||
* 场景变量
|
||||
*/
|
||||
private ScenarioVariable variable;
|
||||
/**
|
||||
* 前置处理器配置
|
||||
*/
|
||||
private MsProcessorConfig preProcessorConfig;
|
||||
/**
|
||||
* 后置处理器配置
|
||||
*/
|
||||
private MsProcessorConfig postProcessorConfig;
|
||||
/**
|
||||
* 断言配置
|
||||
*/
|
||||
private MsAssertionConfig assertionConfig;
|
||||
/**
|
||||
* 其他配置
|
||||
*/
|
||||
private ScenarioOtherConfig otherConfig;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-12 09:47
|
||||
*/
|
||||
@Data
|
||||
public class ScenarioOtherConfig {
|
||||
/**
|
||||
* 使用全局cookie
|
||||
*/
|
||||
private Boolean enableGlobalCookie = true;
|
||||
/**
|
||||
* 是否共享cookie
|
||||
*/
|
||||
private Boolean enableCookieShare;
|
||||
/**
|
||||
* 场景步骤等待时间
|
||||
* 每一个步骤执行后都会等待相应的时间
|
||||
*/
|
||||
private Integer stepWaitTime;
|
||||
/**
|
||||
* 失败策略
|
||||
* @see FailureStrategy
|
||||
*/
|
||||
private String failureStrategy;
|
||||
|
||||
public enum FailureStrategy {
|
||||
/**
|
||||
* 继续执行
|
||||
*/
|
||||
CONTINUE,
|
||||
/**
|
||||
* 停止执行
|
||||
*/
|
||||
STOP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.project.dto.environment.variables.CommonVariables;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-12 09:49
|
||||
*/
|
||||
@Data
|
||||
public class ScenarioVariable {
|
||||
/**
|
||||
* 普通变量
|
||||
*/
|
||||
private List<CommonVariables> commonVariables;
|
||||
/**
|
||||
* csv变量
|
||||
*/
|
||||
private List<CsvVariable> csvVariables;
|
||||
}
|
|
@ -30,4 +30,5 @@ public interface ExtApiScenarioMapper {
|
|||
|
||||
List<ApiScenario> getTestCaseByProvider(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
|
||||
|
||||
Long getLastPos(@Param("projectId") String projectId);
|
||||
}
|
||||
|
|
|
@ -362,5 +362,12 @@
|
|||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getLastPos" resultType="java.lang.Long">
|
||||
SELECT pos
|
||||
FROM api_scenario
|
||||
WHERE project_id = #{projectId}
|
||||
ORDER BY pos DESC
|
||||
LIMIT 1;
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package io.metersphere.api.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-16 19:57
|
||||
*/
|
||||
public interface ExtApiScenarioStepBlobMapper {
|
||||
List<String> getStepIdsByScenarioId(String scenarioId);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?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.ExtApiScenarioStepBlobMapper">
|
||||
|
||||
<select id="getStepIdsByScenarioId" resultType="java.lang.String">
|
||||
SELECT id FROM api_scenario_step_blob WHERE scenario_id = #{scenarioId}
|
||||
</select>
|
||||
</mapper>
|
|
@ -0,0 +1,11 @@
|
|||
package io.metersphere.api.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-16 19:57
|
||||
*/
|
||||
public interface ExtApiScenarioStepMapper {
|
||||
List<String> getStepIdsByScenarioId(String scenarioId);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?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.ExtApiScenarioStepMapper">
|
||||
|
||||
<select id="getStepIdsByScenarioId" resultType="java.lang.String">
|
||||
SELECT id FROM api_scenario_step WHERE scenario_id = #{scenarioId}
|
||||
</select>
|
||||
</mapper>
|
|
@ -1,7 +1,7 @@
|
|||
package io.metersphere.api.parser.jmeter.body;
|
||||
|
||||
import io.metersphere.api.dto.request.http.body.BinaryBody;
|
||||
import io.metersphere.api.dto.request.http.body.BodyFile;
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
|
||||
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
|
||||
|
@ -14,7 +14,7 @@ import org.apache.jmeter.protocol.http.util.HTTPFileArg;
|
|||
public class MsBinaryBodyConverter extends MsBodyConverter<BinaryBody> {
|
||||
@Override
|
||||
public void parse(HTTPSamplerProxy sampler, BinaryBody body, ParameterConfig config) {
|
||||
BodyFile bodyFile = body.getBodyFile();
|
||||
ApiFile bodyFile = body.getBodyFile();
|
||||
HTTPFileArg httpFileArg = getHttpFileArg(bodyFile);
|
||||
sampler.setHTTPFiles(new HTTPFileArg[]{httpFileArg});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.metersphere.api.parser.jmeter.body;
|
||||
|
||||
|
||||
import io.metersphere.api.dto.request.http.body.BodyFile;
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import io.metersphere.api.dto.request.http.body.WWWFormKV;
|
||||
import io.metersphere.jmeter.mock.Mock;
|
||||
import io.metersphere.plugin.api.dto.ParameterConfig;
|
||||
|
@ -63,7 +63,7 @@ public abstract class MsBodyConverter<T> {
|
|||
* @param file
|
||||
* @return
|
||||
*/
|
||||
protected HTTPFileArg getHttpFileArg(BodyFile file) {
|
||||
protected HTTPFileArg getHttpFileArg(ApiFile file) {
|
||||
String fileId = file.getFileId();
|
||||
String fileName = file.getFileName();
|
||||
// 在对应目录下创建文件ID目录,将文件放入
|
||||
|
|
|
@ -80,7 +80,6 @@ public class ApiDebugService {
|
|||
apiDebug.setPos(getNextOrder(request.getProjectId()));
|
||||
|
||||
apiDebugMapper.insert(apiDebug);
|
||||
// todo 校验 moduleId
|
||||
ApiDebugBlob apiDebugBlob = new ApiDebugBlob();
|
||||
apiDebugBlob.setId(apiDebug.getId());
|
||||
apiDebugBlob.setRequest(request.getRequest().getBytes());
|
||||
|
@ -120,7 +119,6 @@ public class ApiDebugService {
|
|||
apiDebug.setUpdateUser(updateUser);
|
||||
apiDebug.setUpdateTime(System.currentTimeMillis());
|
||||
apiDebugMapper.updateByPrimaryKeySelective(apiDebug);
|
||||
// todo 校验 moduleId
|
||||
|
||||
if (StringUtils.isNotBlank(request.getRequest())) {
|
||||
ApiDebugBlob apiDebugBlob = new ApiDebugBlob();
|
||||
|
|
|
@ -2,6 +2,8 @@ package io.metersphere.api.service.scenario;
|
|||
|
||||
import io.metersphere.api.domain.ApiScenario;
|
||||
import io.metersphere.api.domain.ApiScenarioExample;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioAddRequest;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioUpdateRequest;
|
||||
import io.metersphere.api.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
|
@ -97,4 +99,49 @@ public class ApiScenarioLogService {
|
|||
dto.setOriginalValue(JSON.toJSONBytes(apiTestCase));
|
||||
operationLogService.add(dto);
|
||||
}
|
||||
|
||||
public LogDTO addLog(ApiScenarioAddRequest request) {
|
||||
// todo 记录完整的场景信息
|
||||
LogDTO dto = new LogDTO(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
OperationLogType.ADD.name(),
|
||||
OperationLogModule.API_SCENARIO,
|
||||
request.getName());
|
||||
dto.setHistory(true);
|
||||
dto.setOriginalValue(JSON.toJSONBytes(request));
|
||||
return dto;
|
||||
}
|
||||
|
||||
public LogDTO updateLog(ApiScenarioUpdateRequest request) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
// todo 记录完整的场景信息
|
||||
LogDTO dto = new LogDTO(
|
||||
null,
|
||||
null,
|
||||
apiScenario.getId(),
|
||||
null,
|
||||
OperationLogType.UPDATE.name(),
|
||||
OperationLogModule.API_SCENARIO,
|
||||
apiScenario.getName());
|
||||
dto.setHistory(true);
|
||||
dto.setOriginalValue(JSON.toJSONBytes(request));
|
||||
return dto;
|
||||
}
|
||||
|
||||
public LogDTO deleteLog(String id) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(id);
|
||||
LogDTO dto = new LogDTO(
|
||||
null,
|
||||
null,
|
||||
apiScenario.getId(),
|
||||
null,
|
||||
OperationLogType.DELETE.name(),
|
||||
OperationLogModule.API_SCENARIO,
|
||||
apiScenario.getName());
|
||||
dto.setOriginalValue(JSON.toJSONBytes(apiScenario));
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
package io.metersphere.api.service.scenario;
|
||||
|
||||
import com.alibaba.excel.util.BooleanUtils;
|
||||
import io.metersphere.api.constants.ApiResourceType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioDTO;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioPageRequest;
|
||||
import io.metersphere.api.mapper.ApiScenarioFollowerMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioModuleMapper;
|
||||
import io.metersphere.api.mapper.ExtApiScenarioMapper;
|
||||
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.project.service.ProjectService;
|
||||
import io.metersphere.sdk.constants.ApplicationNumScope;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.domain.Environment;
|
||||
import io.metersphere.sdk.domain.EnvironmentExample;
|
||||
import io.metersphere.sdk.domain.EnvironmentGroup;
|
||||
|
@ -16,12 +19,17 @@ import io.metersphere.sdk.domain.EnvironmentGroupExample;
|
|||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.mapper.EnvironmentGroupMapper;
|
||||
import io.metersphere.sdk.mapper.EnvironmentMapper;
|
||||
import io.metersphere.sdk.util.SubListUtils;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.sdk.util.*;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
import io.metersphere.system.service.UserLoginService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.uid.NumGenerator;
|
||||
import io.metersphere.system.utils.ServiceUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
@ -29,21 +37,17 @@ import org.apache.ibatis.session.SqlSessionFactory;
|
|||
import org.mybatis.spring.SqlSessionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static io.metersphere.api.controller.result.ApiResultCode.API_SCENARIO_EXIST;
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiScenarioService {
|
||||
|
||||
public static final Long ORDER_STEP = 5000L;
|
||||
|
||||
@Resource
|
||||
private ApiScenarioMapper apiScenarioMapper;
|
||||
|
||||
|
@ -64,6 +68,22 @@ public class ApiScenarioService {
|
|||
private ApiScenarioFollowerMapper apiScenarioFollowerMapper;
|
||||
@Resource
|
||||
private SqlSessionFactory sqlSessionFactory;
|
||||
@Resource
|
||||
private ProjectService projectService;
|
||||
@Resource
|
||||
private ExtBaseProjectVersionMapper extBaseProjectVersionMapper;
|
||||
@Resource
|
||||
private ApiFileResourceService apiFileResourceService;
|
||||
@Resource
|
||||
private ApiScenarioStepMapper apiScenarioStepMapper;
|
||||
@Resource
|
||||
private ExtApiScenarioStepMapper extApiScenarioStepMapper;
|
||||
@Resource
|
||||
private ExtApiScenarioStepBlobMapper extApiScenarioStepBlobMapper;
|
||||
@Resource
|
||||
private ApiScenarioStepBlobMapper apiScenarioStepBlobMapper;
|
||||
@Resource
|
||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||
public static final String PRIORITY = "Priority";
|
||||
public static final String STATUS = "Status";
|
||||
public static final String TAGS = "Tags";
|
||||
|
@ -236,7 +256,7 @@ public class ApiScenarioService {
|
|||
}
|
||||
|
||||
public void follow(String id, String userId) {
|
||||
checkApiScenario(id);
|
||||
checkResourceExist(id);
|
||||
ApiScenarioFollowerExample example = new ApiScenarioFollowerExample();
|
||||
example.createCriteria().andApiScenarioIdEqualTo(id).andUserIdEqualTo(userId);
|
||||
if (apiScenarioFollowerMapper.countByExample(example) > 0) {
|
||||
|
@ -251,11 +271,342 @@ public class ApiScenarioService {
|
|||
}
|
||||
}
|
||||
|
||||
private ApiScenario checkApiScenario(String id) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(id);
|
||||
if (apiScenario == null) {
|
||||
throw new MSException(Translator.get("api_scenario_is_not_exist"));
|
||||
public ApiScenario add(ApiScenarioAddRequest request, String creator) {
|
||||
checkAddExist(request);
|
||||
ApiScenario scenario = getAddApiScenario(request, creator);
|
||||
apiScenarioMapper.insert(scenario);
|
||||
|
||||
// 更新场景配置
|
||||
ApiScenarioBlob apiScenarioBlob = new ApiScenarioBlob();
|
||||
apiScenarioBlob.setId(scenario.getId());
|
||||
apiScenarioBlob.setConfig(JSON.toJSONString(request.getScenarioConfig()).getBytes());
|
||||
apiScenarioBlobMapper.insert(apiScenarioBlob);
|
||||
|
||||
// 插入步骤
|
||||
if (CollectionUtils.isNotEmpty(request.getSteps())) {
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
List<ApiScenarioStep> apiScenarioSteps = getUpdateApiScenarioSteps(null, request.getSteps(), apiScenarioStepsDetails);
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
|
||||
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
apiScenarioStepsDetails.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioSteps)) {
|
||||
apiScenarioStepMapper.batchInsert(apiScenarioSteps);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioStepsDetails)) {
|
||||
apiScenarioStepBlobMapper.batchInsert(apiScenarioStepsDetails);
|
||||
}
|
||||
}
|
||||
return apiScenario;
|
||||
|
||||
// 处理文件
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), scenario.getProjectId(), creator);
|
||||
resourceUpdateRequest.setUploadFileIds(request.getUploadFileIds());
|
||||
resourceUpdateRequest.setLinkFileIds(request.getLinkFileIds());
|
||||
apiFileResourceService.addFileResource(resourceUpdateRequest);
|
||||
return scenario;
|
||||
}
|
||||
}
|
||||
|
||||
private ApiScenario getAddApiScenario(ApiScenarioAddRequest request, String creator) {
|
||||
ApiScenario scenario = new ApiScenario();
|
||||
BeanUtils.copyBean(scenario, request);
|
||||
scenario.setId(IDGenerator.nextStr());
|
||||
scenario.setNum(getNextNum(request.getProjectId()));
|
||||
scenario.setPos(getNextOrder(request.getProjectId()));
|
||||
scenario.setLatest(true);
|
||||
scenario.setCreateUser(creator);
|
||||
scenario.setUpdateUser(creator);
|
||||
scenario.setCreateTime(System.currentTimeMillis());
|
||||
scenario.setUpdateTime(System.currentTimeMillis());
|
||||
scenario.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(request.getProjectId()));
|
||||
scenario.setRefId(scenario.getId());
|
||||
scenario.setLastReportStatus(StringUtils.EMPTY);
|
||||
scenario.setDeleted(false);
|
||||
scenario.setRequestPassRate("0");
|
||||
scenario.setStepTotal(CollectionUtils.isEmpty(request.getSteps()) ? 0 : request.getSteps().size());
|
||||
return scenario;
|
||||
}
|
||||
|
||||
public ApiScenario update(ApiScenarioUpdateRequest request, String updater) {
|
||||
checkResourceExist(request.getId());
|
||||
checkUpdateExist(request);
|
||||
// 更新基础信息
|
||||
ApiScenario scenario = BeanUtils.copyBean(new ApiScenario(), request);
|
||||
scenario.setUpdateUser(updater);
|
||||
scenario.setUpdateTime(System.currentTimeMillis());
|
||||
apiScenarioMapper.updateByPrimaryKeySelective(scenario);
|
||||
|
||||
if (request.getScenarioConfig() != null) {
|
||||
// 更新场景配置
|
||||
ApiScenarioBlob apiScenarioBlob = new ApiScenarioBlob();
|
||||
apiScenarioBlob.setId(scenario.getId());
|
||||
apiScenarioBlob.setConfig(JSON.toJSONString(request.getScenarioConfig()).getBytes());
|
||||
apiScenarioBlobMapper.updateByPrimaryKeyWithBLOBs(apiScenarioBlob);
|
||||
}
|
||||
|
||||
// 更新场景步骤
|
||||
updateApiScenarioStep(request, scenario);
|
||||
|
||||
ApiScenario originScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
// 处理文件
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = getApiFileResourceUpdateRequest(scenario.getId(), originScenario.getProjectId(), updater);
|
||||
resourceUpdateRequest.setUploadFileIds(request.getUploadFileIds());
|
||||
resourceUpdateRequest.setLinkFileIds(request.getLinkFileIds());
|
||||
resourceUpdateRequest.setUnLinkRefIds(request.getUnLinkRefIds());
|
||||
resourceUpdateRequest.setDeleteFileIds(request.getDeleteFileIds());
|
||||
apiFileResourceService.updateFileResource(resourceUpdateRequest);
|
||||
|
||||
return scenario;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新场景步骤
|
||||
* @param request
|
||||
* @param scenario
|
||||
*/
|
||||
private void updateApiScenarioStep(ApiScenarioUpdateRequest request, ApiScenario scenario) {
|
||||
// steps 不为 null 则修改
|
||||
if (request.getSteps() != null) {
|
||||
if (CollectionUtils.isEmpty(request.getSteps())) {
|
||||
// 如果是空数组,则删除所有步骤
|
||||
deleteStepByScenarioId(scenario.getId());
|
||||
deleteStepDetailByScenarioId(scenario.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
List<ApiScenarioStep> apiScenarioSteps = getUpdateApiScenarioSteps(null, request.getSteps(), apiScenarioStepsDetails);
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
|
||||
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
apiScenarioStepsDetails.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
|
||||
List<String> stepIds = apiScenarioSteps.stream().map(ApiScenarioStep::getId).collect(Collectors.toList());
|
||||
List<String> originStepIds = extApiScenarioStepMapper.getStepIdsByScenarioId(scenario.getId());
|
||||
List<String> deleteStepIds = ListUtils.subtract(originStepIds, stepIds);
|
||||
|
||||
// 步骤表-全部先删除再插入
|
||||
deleteStepByScenarioId(scenario.getId());
|
||||
apiScenarioStepMapper.batchInsert(apiScenarioSteps);
|
||||
|
||||
// 详情表-删除已经删除的步骤详情
|
||||
SubListUtils.dealForSubList(deleteStepIds, 100, subIds -> {
|
||||
ApiScenarioStepBlobExample stepBlobExample = new ApiScenarioStepBlobExample();
|
||||
stepBlobExample.createCriteria().andIdIn(subIds);
|
||||
apiScenarioStepBlobMapper.deleteByExample(stepBlobExample);
|
||||
});
|
||||
|
||||
// 查询原有的步骤详情
|
||||
Set<String> originStepDetailIds = extApiScenarioStepBlobMapper.getStepIdsByScenarioId(scenario.getId())
|
||||
.stream().collect(Collectors.toSet());
|
||||
|
||||
// 添加新增的步骤详情
|
||||
List<ApiScenarioStepBlob> addApiScenarioStepsDetails = apiScenarioStepsDetails.stream()
|
||||
.filter(step -> !originStepDetailIds.contains(step.getId()))
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(addApiScenarioStepsDetails)) {
|
||||
apiScenarioStepBlobMapper.batchInsert(addApiScenarioStepsDetails);
|
||||
}
|
||||
// 更新原有的步骤详情
|
||||
apiScenarioStepsDetails.stream()
|
||||
.filter(step -> originStepDetailIds.contains(step.getId()))
|
||||
.forEach(apiScenarioStepBlobMapper::updateByPrimaryKeySelective);
|
||||
} else if (MapUtils.isNotEmpty(request.getStepDetails())) {
|
||||
// steps 为 null,stepDetails 不为 null,则只更新详情
|
||||
// 查询原有的步骤详情
|
||||
Set<String> originStepDetailIds = extApiScenarioStepBlobMapper.getStepIdsByScenarioId(scenario.getId())
|
||||
.stream().collect(Collectors.toSet());
|
||||
// 更新原有的步骤详情
|
||||
request.getStepDetails().forEach((stepId, stepDetail) -> {
|
||||
if (originStepDetailIds.contains(stepId)) {
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
apiScenarioStepBlob.setId(stepId);
|
||||
apiScenarioStepBlob.setContent(JSON.toJSONString(stepDetail).getBytes());
|
||||
apiScenarioStepBlobMapper.updateByPrimaryKeySelective(apiScenarioStepBlob);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteStepDetailByScenarioId(String scenarioId) {
|
||||
ApiScenarioStepBlobExample blobExample = new ApiScenarioStepBlobExample();
|
||||
blobExample.createCriteria().andScenarioIdEqualTo(scenarioId);
|
||||
apiScenarioStepBlobMapper.deleteByExample(blobExample);
|
||||
}
|
||||
|
||||
private void deleteStepByScenarioId(String scenarioId) {
|
||||
ApiScenarioStepExample example = new ApiScenarioStepExample();
|
||||
example.createCriteria().andScenarioIdEqualTo(scenarioId);
|
||||
apiScenarioStepMapper.deleteByExample(example);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待更新的 ApiScenarioStepBlob 列表
|
||||
* @param apiScenarioSteps
|
||||
* @param stepDetails
|
||||
* @return
|
||||
*/
|
||||
private List<ApiScenarioStepBlob> getUpdateStepDetails(List<ApiScenarioStep> apiScenarioSteps, Map<String, Object> stepDetails) {
|
||||
if (MapUtils.isEmpty(stepDetails)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<String, ApiScenarioStep> scenarioStepMap = apiScenarioSteps.stream()
|
||||
.collect(Collectors.toMap(ApiScenarioStep::getId, Function.identity()));
|
||||
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
stepDetails.forEach((stepId, stepDetail) -> {
|
||||
ApiScenarioStep step = scenarioStepMap.get(stepId);
|
||||
if (step == null) {
|
||||
return;
|
||||
}
|
||||
boolean isRef = StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.STEP_REF.name());
|
||||
if (!isRef || StringUtils.equals(step.getRefType(), ApiScenarioStepType.API.name())) {
|
||||
// 非引用的步骤,如果有编辑内容,保存到blob表
|
||||
// 如果引用的是接口定义,也保存详情,因为应用接口定义允许修改参数值
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
apiScenarioStepBlob.setId(stepId);
|
||||
apiScenarioStepBlob.setContent(JSON.toJSONString(stepDetail).getBytes());
|
||||
apiScenarioStepsDetails.add(apiScenarioStepBlob);
|
||||
}
|
||||
});
|
||||
return apiScenarioStepsDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析步骤树结构
|
||||
* 获取待更新的 ApiScenarioStep 列表
|
||||
* @param parent
|
||||
* @param steps
|
||||
* @param apiScenarioStepsDetails
|
||||
* @return
|
||||
*/
|
||||
private List<ApiScenarioStep> getUpdateApiScenarioSteps(ApiScenarioStepRequest parent,
|
||||
List<ApiScenarioStepRequest> steps,
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails) {
|
||||
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ApiScenarioStep> apiScenarioSteps = new ArrayList<>();
|
||||
long sort = 1;
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
ApiScenarioStep apiScenarioStep = new ApiScenarioStep();
|
||||
BeanUtils.copyBean(apiScenarioStep, step);
|
||||
apiScenarioStep.setSort(sort++);
|
||||
if (parent != null) {
|
||||
apiScenarioStep.setParentId(parent.getId());
|
||||
}
|
||||
if (step.getConfig() != null) {
|
||||
apiScenarioStep.setConfig(JSON.toJSONString(step.getConfig()));
|
||||
}
|
||||
apiScenarioSteps.add(apiScenarioStep);
|
||||
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.STEP_REF.name())) {
|
||||
// 如果是步骤引用,blob表保存启用的子步骤ID
|
||||
Set<String> enableStepSet = getEnableStepSet(step.getChildren());
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
apiScenarioStepBlob.setId(apiScenarioStep.getId());
|
||||
apiScenarioStepBlob.setContent(JSON.toJSONString(enableStepSet).getBytes());
|
||||
apiScenarioStepsDetails.add(apiScenarioStepBlob);
|
||||
}
|
||||
|
||||
if (StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.STEP_REF.name())) {
|
||||
// 引用的步骤不解析子步骤
|
||||
continue;
|
||||
}
|
||||
// 解析子步骤
|
||||
apiScenarioSteps.addAll(getUpdateApiScenarioSteps(step, step.getChildren(), apiScenarioStepsDetails));
|
||||
}
|
||||
return apiScenarioSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取步骤及子步骤中 enable 的步骤ID
|
||||
*
|
||||
* @param steps
|
||||
* @return
|
||||
*/
|
||||
private Set<String> getEnableStepSet(List<ApiScenarioStepRequest> steps) {
|
||||
Set<String> enableSteps = new HashSet<>();
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
if (BooleanUtils.isTrue(step.getEnable())) {
|
||||
enableSteps.add(step.getId());
|
||||
}
|
||||
// 获取子步骤中 enable = true 的步骤
|
||||
enableSteps.addAll(getEnableStepSet(step.getChildren()));
|
||||
}
|
||||
return enableSteps;
|
||||
}
|
||||
|
||||
private static ApiFileResourceUpdateRequest getApiFileResourceUpdateRequest(String sourceId, String projectId, String operator) {
|
||||
String apiScenarioDir = DefaultRepositoryDir.getApiScenarioDir(projectId, sourceId);
|
||||
ApiFileResourceUpdateRequest resourceUpdateRequest = new ApiFileResourceUpdateRequest();
|
||||
resourceUpdateRequest.setProjectId(projectId);
|
||||
resourceUpdateRequest.setFolder(apiScenarioDir);
|
||||
resourceUpdateRequest.setResourceId(sourceId);
|
||||
resourceUpdateRequest.setApiResourceType(ApiResourceType.API_SCENARIO);
|
||||
resourceUpdateRequest.setOperator(operator);
|
||||
resourceUpdateRequest.setLogModule(OperationLogModule.API_SCENARIO);
|
||||
resourceUpdateRequest.setFileAssociationSourceType(FileAssociationSourceUtil.SOURCE_TYPE_API_DEBUG);
|
||||
return resourceUpdateRequest;
|
||||
}
|
||||
|
||||
public long getNextNum(String projectId) {
|
||||
return NumGenerator.nextNum(projectId, ApplicationNumScope.API_SCENARIO);
|
||||
}
|
||||
|
||||
public Long getNextOrder(String projectId) {
|
||||
return projectService.getNextOrder(extApiScenarioMapper::getLastPos, projectId);
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
checkResourceExist(id);
|
||||
apiScenarioMapper.deleteByPrimaryKey(id);
|
||||
apiScenarioBlobMapper.deleteByPrimaryKey(id);
|
||||
deleteStepByScenarioId(id);
|
||||
deleteStepDetailByScenarioId(id);
|
||||
}
|
||||
|
||||
public void deleteToGc(String id) {
|
||||
checkResourceExist(id);
|
||||
ApiScenario apiScenario = new ApiScenario();
|
||||
apiScenario.setId(id);
|
||||
apiScenario.setDeleted(true);
|
||||
apiScenarioMapper.updateByPrimaryKeySelective(apiScenario);
|
||||
}
|
||||
|
||||
private void checkAddExist(ApiScenarioAddRequest apiScenario) {
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
// 统一模块下名称不能重复
|
||||
example.createCriteria()
|
||||
.andNameEqualTo(apiScenario.getName())
|
||||
.andModuleIdEqualTo(apiScenario.getModuleId());
|
||||
if (apiScenarioMapper.countByExample(example) > 0) {
|
||||
throw new MSException(API_SCENARIO_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUpdateExist(ApiScenarioUpdateRequest request) {
|
||||
if (StringUtils.isBlank(request.getName())) {
|
||||
return;
|
||||
}
|
||||
// 统一模块下名称不能重复
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
example.createCriteria()
|
||||
.andIdNotEqualTo(request.getId())
|
||||
.andModuleIdEqualTo(request.getModuleId())
|
||||
.andNameEqualTo(request.getName());
|
||||
if (apiScenarioMapper.countByExample(example) > 0) {
|
||||
throw new MSException(API_SCENARIO_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
private ApiScenario checkResourceExist(String id) {
|
||||
return ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name");
|
||||
}
|
||||
|
||||
public String uploadTempFile(MultipartFile file) {
|
||||
return apiFileResourceService.uploadTempFile(file);
|
||||
}
|
||||
}
|
|
@ -1,25 +1,36 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.constants.ApiDefinitionStatus;
|
||||
import io.metersphere.api.constants.ApiScenarioStatus;
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioBatchEditRequest;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioDTO;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioPageRequest;
|
||||
import io.metersphere.api.mapper.ApiScenarioFollowerMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioMapper;
|
||||
import io.metersphere.api.mapper.ApiScenarioModuleMapper;
|
||||
import io.metersphere.api.mapper.ExtApiScenarioMapper;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
|
||||
import io.metersphere.api.dto.request.assertion.MsAssertionConfig;
|
||||
import io.metersphere.api.dto.request.assertion.MsScriptAssertion;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.sdk.constants.ApplicationNumScope;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.domain.Environment;
|
||||
import io.metersphere.sdk.domain.EnvironmentExample;
|
||||
import io.metersphere.sdk.domain.EnvironmentGroup;
|
||||
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.BeanUtils;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.uid.NumGenerator;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -28,18 +39,15 @@ import org.junit.jupiter.api.*;
|
|||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static io.metersphere.api.controller.result.ApiResultCode.API_SCENARIO_EXIST;
|
||||
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
|
@ -47,10 +55,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class ApiScenarioControllerTests extends BaseTest {
|
||||
private static final String BASE_PATH = "/api/scenario/";
|
||||
private static final String PAGE = BASE_PATH + "page";
|
||||
private static final String TRASH_PAGE = BASE_PATH + "trash/page";
|
||||
private static final String BATCH_EDIT = BASE_PATH + "batch/edit";
|
||||
private static final String FOLLOW = BASE_PATH + "follow/";
|
||||
private static final String TRASH_PAGE = "trash/page";
|
||||
private static final String BATCH_EDIT = "batch/edit";
|
||||
private static final String FOLLOW = "follow/";
|
||||
protected static final String UPLOAD_TEMP_FILE = "upload/temp/file";
|
||||
protected static final String DELETE_TO_GC = "delete-to-gc/{0}";
|
||||
|
||||
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
||||
@Resource
|
||||
|
@ -65,27 +74,26 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
private ApiScenarioFollowerMapper apiScenarioFollowerMapper;
|
||||
@Resource
|
||||
private EnvironmentGroupMapper environmentGroupMapper;
|
||||
@Resource
|
||||
private ApiScenarioStepMapper apiScenarioStepMapper;
|
||||
@Resource
|
||||
private ApiScenarioStepBlobMapper apiScenarioStepBlobMapper;
|
||||
@Resource
|
||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||
@Resource
|
||||
private ExtBaseProjectVersionMapper extBaseProjectVersionMapper;
|
||||
@Resource
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
private static ApiScenario addApiScenario;
|
||||
private static ApiScenario anOtherAddApiScenario;
|
||||
private static ApiDefinition apiDefinition;
|
||||
private static ApiTestCase apiTestCase;
|
||||
|
||||
public static <T> T parseObjectFromMvcResult(MvcResult mvcResult, Class<T> parseClass) {
|
||||
try {
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||
//返回请求正常
|
||||
Assertions.assertNotNull(resultHolder);
|
||||
return JSON.parseObject(JSON.toJSONString(resultHolder.getData()), parseClass);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MvcResult responsePost(String url, Object param) throws Exception {
|
||||
return mockMvc.perform(MockMvcRequestBuilders.post(url)
|
||||
.header(SessionConstants.HEADER_TOKEN, sessionId)
|
||||
.header(SessionConstants.CSRF_TOKEN, csrfToken)
|
||||
.content(JSON.toJSONString(param))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return BASE_PATH;
|
||||
}
|
||||
|
||||
public void initApiScenario() {
|
||||
|
@ -177,6 +185,288 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void add() throws Exception {
|
||||
initTestData();
|
||||
|
||||
// @@请求成功
|
||||
ApiScenarioAddRequest request = new ApiScenarioAddRequest();
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setDescription("desc");
|
||||
request.setName("test name");
|
||||
request.setModuleId("default");
|
||||
request.setGrouped(false);
|
||||
request.setEnvironmentId("environmentId");
|
||||
request.setTags(List.of("tag1", "tag2"));
|
||||
request.setPriority("P0");
|
||||
request.setStatus(ApiScenarioStatus.COMPLETED.name());
|
||||
List<ApiScenarioStepRequest> steps = getApiScenarioStepRequests();
|
||||
Map<String, Object> steptDetailMap = new HashMap<>();
|
||||
steptDetailMap.put(steps.get(1).getId(), getMsHttpElementParam());
|
||||
steptDetailMap.put(steps.get(0).getId(), getMsHttpElementParam());
|
||||
request.setSteps(steps);
|
||||
request.setStepDetails(steptDetailMap);
|
||||
request.setScenarioConfig(getScenarioConfig());
|
||||
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
|
||||
ApiScenario resultData = getResultData(mvcResult, ApiScenario.class);
|
||||
this.addApiScenario = apiScenarioMapper.selectByPrimaryKey(resultData.getId());
|
||||
assertUpdateApiScenario(request, request.getScenarioConfig(), addApiScenario.getId());
|
||||
assertUpdateSteps(steps, steptDetailMap);
|
||||
|
||||
request.setName("anOther name");
|
||||
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
|
||||
stepRequest.setId(IDGenerator.nextStr());
|
||||
stepRequest.setEnable(true);
|
||||
stepRequest.setName(addApiScenario.getName());
|
||||
stepRequest.setResourceId(addApiScenario.getId());
|
||||
stepRequest.setRefType(ApiScenarioStepRefType.REF.name());
|
||||
|
||||
ApiScenarioStepRequest stepRequest2 = new ApiScenarioStepRequest();
|
||||
stepRequest2.setId(IDGenerator.nextStr());
|
||||
stepRequest2.setName(addApiScenario.getName());
|
||||
stepRequest2.setResourceId(addApiScenario.getId());
|
||||
stepRequest2.setRefType(ApiScenarioStepRefType.STEP_REF.name());
|
||||
stepRequest2.setChildren(List.of(stepRequest));
|
||||
steps = List.of(stepRequest, stepRequest2);
|
||||
request.setSteps(steps);
|
||||
mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
|
||||
this.anOtherAddApiScenario = apiScenarioMapper.selectByPrimaryKey(getResultData(mvcResult, ApiScenario.class).getId());
|
||||
assertUpdateApiScenario(request, request.getScenarioConfig(), anOtherAddApiScenario.getId());
|
||||
assertUpdateSteps(steps, steptDetailMap);
|
||||
|
||||
// @@重名校验异常
|
||||
assertErrorCode(this.requestPost(DEFAULT_ADD, request), API_SCENARIO_EXIST);
|
||||
// @@校验日志
|
||||
checkLog(this.addApiScenario.getId(), OperationLogType.ADD);
|
||||
// @@校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_ADD, DEFAULT_ADD, request);
|
||||
}
|
||||
|
||||
private Object getMsHttpElementParam() {
|
||||
return JSON.parseObject(ApiDataUtils.toJSONString(MsHTTPElementTest.getMsHttpElement()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验更新数据
|
||||
*
|
||||
* @param request
|
||||
* @param scenarioConfig
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private ApiScenario assertUpdateApiScenario(Object request, ScenarioConfig scenarioConfig, String id) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(id);
|
||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(id);
|
||||
ApiScenario copyApiScenario = BeanUtils.copyBean(new ApiScenario(), apiScenario);
|
||||
copyApiScenario = BeanUtils.copyBean(copyApiScenario, request);
|
||||
Assertions.assertEquals(apiScenario, copyApiScenario);
|
||||
if (scenarioConfig != null) {
|
||||
Assertions.assertEquals(scenarioConfig, JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class));
|
||||
}
|
||||
return apiScenario;
|
||||
}
|
||||
|
||||
private void assertUpdateSteps(List<ApiScenarioStepRequest> steps, Map<String, Object> steptDetailMap) {
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
ApiScenarioStep apiScenarioStep = apiScenarioStepMapper.selectByPrimaryKey(step.getId());
|
||||
ApiScenarioStep copyApiScenarioStep = BeanUtils.copyBean(new ApiScenarioStep(), apiScenarioStep);
|
||||
copyApiScenarioStep = BeanUtils.copyBean(copyApiScenarioStep, step);
|
||||
Assertions.assertEquals(apiScenarioStep, copyApiScenarioStep);
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = apiScenarioStepBlobMapper.selectByPrimaryKey(step.getId());
|
||||
if (apiScenarioStepBlob != null && steptDetailMap.get(step.getId()) != null) {
|
||||
Assertions.assertEquals(steptDetailMap.get(step.getId()), JSON.parseObject(new String(apiScenarioStepBlob.getContent())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioConfig getScenarioConfig() {
|
||||
ScenarioConfig scenarioConfig = new ScenarioConfig();
|
||||
MsAssertionConfig msAssertionConfig = new MsAssertionConfig();
|
||||
MsScriptAssertion scriptAssertion = new MsScriptAssertion();
|
||||
scriptAssertion.setScript("{}");
|
||||
scriptAssertion.setName("script");
|
||||
msAssertionConfig.setAssertions(List.of(scriptAssertion));
|
||||
scenarioConfig.setAssertionConfig(msAssertionConfig);
|
||||
ScenarioOtherConfig scenarioOtherConfig = new ScenarioOtherConfig();
|
||||
scenarioOtherConfig.setStepWaitTime(1000);
|
||||
scenarioOtherConfig.setFailureStrategy(ScenarioOtherConfig.FailureStrategy.CONTINUE.name());
|
||||
scenarioOtherConfig.setEnableCookieShare(true);
|
||||
scenarioConfig.setOtherConfig(scenarioOtherConfig);
|
||||
return scenarioConfig;
|
||||
}
|
||||
|
||||
private List<ApiScenarioStepRequest> getApiScenarioStepRequests() {
|
||||
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
|
||||
stepRequest.setId(IDGenerator.nextStr());
|
||||
stepRequest.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID));
|
||||
stepRequest.setConfig(new HashMap<>());
|
||||
stepRequest.setEnable(true);
|
||||
stepRequest.setName(apiTestCase.getName());
|
||||
stepRequest.setResourceId(apiTestCase.getId());
|
||||
stepRequest.setRefType(ApiScenarioStepRefType.REF.name());
|
||||
stepRequest.setConfig(new HashMap<>());
|
||||
|
||||
ApiScenarioStepRequest stepRequest2 = new ApiScenarioStepRequest();
|
||||
stepRequest2.setId(IDGenerator.nextStr());
|
||||
stepRequest2.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID));
|
||||
stepRequest2.setConfig(new HashMap<>());
|
||||
stepRequest2.setEnable(true);
|
||||
stepRequest2.setResourceId(apiTestCase.getId());
|
||||
stepRequest.setName(apiTestCase.getName() + "2");
|
||||
stepRequest2.setRefType(ApiScenarioStepRefType.COPY.name());
|
||||
|
||||
ApiScenarioStepRequest stepRequest3 = new ApiScenarioStepRequest();
|
||||
stepRequest3.setId(IDGenerator.nextStr());
|
||||
stepRequest3.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID));
|
||||
stepRequest3.setConfig(new HashMap<>());
|
||||
stepRequest3.setEnable(true);
|
||||
stepRequest3.setResourceId(apiDefinition.getId());
|
||||
stepRequest.setName(apiDefinition.getName() + "3");
|
||||
stepRequest3.setRefType(ApiScenarioStepRefType.REF.name());
|
||||
|
||||
return List.of(stepRequest, stepRequest2);
|
||||
}
|
||||
|
||||
private void initTestData() {
|
||||
ApiDefinitionAddRequest apiDefinitionAddRequest = new ApiDefinitionAddRequest();
|
||||
apiDefinitionAddRequest.setName("test scenario");
|
||||
apiDefinitionAddRequest.setProtocol("HTTP");
|
||||
apiDefinitionAddRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
apiDefinitionAddRequest.setMethod("POST");
|
||||
apiDefinitionAddRequest.setPath("/api/admin/posts");
|
||||
apiDefinitionAddRequest.setStatus(ApiDefinitionStatus.PREPARE.getValue());
|
||||
apiDefinitionAddRequest.setModuleId("default");
|
||||
apiDefinitionAddRequest.setVersionId(extBaseProjectVersionMapper.getDefaultVersion(DEFAULT_PROJECT_ID));
|
||||
apiDefinitionAddRequest.setDescription("描述内容");
|
||||
apiDefinitionAddRequest.setName("test scenario");
|
||||
MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement();
|
||||
apiDefinitionAddRequest.setRequest(ApiDataUtils.toJSONString(msHttpElement));
|
||||
apiDefinitionAddRequest.setResponse("{}");
|
||||
apiDefinition = apiDefinitionService.create(apiDefinitionAddRequest, "admin");
|
||||
|
||||
ApiTestCaseAddRequest apiTestCaseAddRequest = new ApiTestCaseAddRequest();
|
||||
apiTestCaseAddRequest.setApiDefinitionId(apiDefinition.getId());
|
||||
apiTestCaseAddRequest.setName("test");
|
||||
apiTestCaseAddRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
apiTestCaseAddRequest.setPriority("P0");
|
||||
apiTestCaseAddRequest.setStatus("Underway");
|
||||
apiTestCaseAddRequest.setTags(new LinkedHashSet<>(List.of("tag1", "tag2")));
|
||||
apiTestCaseAddRequest.setRequest(ApiDataUtils.toJSONString(msHttpElement));
|
||||
apiTestCase = apiTestCaseService.addCase(apiTestCaseAddRequest, "admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void update() throws Exception {
|
||||
// @@请求成功
|
||||
ApiScenarioUpdateRequest request = new ApiScenarioUpdateRequest();
|
||||
request.setId(addApiScenario.getId());
|
||||
request.setDescription("desc update");
|
||||
request.setName("test name update");
|
||||
request.setModuleId("default");
|
||||
request.setGrouped(false);
|
||||
request.setEnvironmentId("environmentId update");
|
||||
request.setTags(List.of("tag1 update", "tag2 update"));
|
||||
request.setPriority("P0 update");
|
||||
request.setStatus(ApiScenarioStatus.DEPRECATED.name());
|
||||
List<ApiScenarioStepRequest> steps = getApiScenarioStepRequests();
|
||||
|
||||
// 验证修改基础信息
|
||||
this.requestPostWithOk(DEFAULT_UPDATE, request);
|
||||
assertUpdateApiScenario(request, request.getScenarioConfig(), addApiScenario.getId());
|
||||
|
||||
// 验证清除步骤
|
||||
request.setSteps(List.of());
|
||||
this.requestPostWithOk(DEFAULT_UPDATE, request);
|
||||
assertUpdateApiScenario(request, request.getScenarioConfig(), addApiScenario.getId());
|
||||
assertUpdateSteps(List.of(), new HashMap<>());
|
||||
|
||||
// 验证添加步骤
|
||||
this.requestPostWithOk(DEFAULT_UPDATE, request);
|
||||
Map<String, Object> steptDetailMap = new HashMap<>();
|
||||
steptDetailMap.put(steps.get(0).getId(), getMsHttpElementParam());
|
||||
steptDetailMap.put(steps.get(1).getId(), getMsHttpElementParam());
|
||||
request.setSteps(steps);
|
||||
request.setStepDetails(steptDetailMap);
|
||||
request.setScenarioConfig(getScenarioConfig());
|
||||
this.requestPostWithOk(DEFAULT_UPDATE, request);
|
||||
assertUpdateSteps(steps, steptDetailMap);
|
||||
|
||||
// 验证修改步骤
|
||||
steps.get(0).setName("test name update");
|
||||
this.requestPostWithOk(DEFAULT_UPDATE, request);
|
||||
assertUpdateSteps(steps, steptDetailMap);
|
||||
|
||||
// @@重名校验异常
|
||||
request.setName(anOtherAddApiScenario.getName());
|
||||
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), API_SCENARIO_EXIST);
|
||||
// @@校验日志
|
||||
checkLog(request.getId(), OperationLogType.UPDATE);
|
||||
// @@校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_UPDATE, DEFAULT_UPDATE, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void deleteToGc() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DELETE_TO_GC, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DELETE_TO_GC, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void delete() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DEFAULT_DELETE, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DEFAULT_DELETE, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
public void uploadTempFile() throws Exception {
|
||||
// @@请求成功
|
||||
MockMultipartFile file = getMockMultipartFile();
|
||||
String fileId = doUploadTempFile(file);
|
||||
|
||||
// 校验文件存在
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getSystemTempDir() + "/" + fileId);
|
||||
fileRequest.setFileName(file.getOriginalFilename());
|
||||
Assertions.assertNotNull(FileCenter.getDefaultRepository().getFile(fileRequest));
|
||||
|
||||
requestUploadPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_ADD, UPLOAD_TEMP_FILE, file);
|
||||
requestUploadPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_UPDATE, UPLOAD_TEMP_FILE, file);
|
||||
}
|
||||
|
||||
private String doUploadTempFile(MockMultipartFile file) throws Exception {
|
||||
return JSON.parseObject(requestUploadFileWithOkAndReturn(UPLOAD_TEMP_FILE, file)
|
||||
.getResponse()
|
||||
.getContentAsString(), ResultHolder.class)
|
||||
.getData().toString();
|
||||
}
|
||||
|
||||
private static MockMultipartFile getMockMultipartFile() {
|
||||
MockMultipartFile file = new MockMultipartFile(
|
||||
"file",
|
||||
"file_upload.JPG",
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
"Hello, World!".getBytes()
|
||||
);
|
||||
return file;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11)
|
||||
public void page() throws Exception {
|
||||
|
@ -186,8 +476,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
pageRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
pageRequest.setPageSize(10);
|
||||
pageRequest.setCurrent(1);
|
||||
MvcResult mvcResult = responsePost(PAGE, pageRequest);
|
||||
Pager<?> returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
MvcResult mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest);
|
||||
Pager<?> returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -197,8 +487,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
|
||||
//查询api-scenario-id1的数据
|
||||
pageRequest.setScenarioId("api-scenario-id1");
|
||||
mvcResult = responsePost(PAGE, pageRequest);
|
||||
returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest);
|
||||
returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -210,8 +500,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
//查询模块为moduleId1的数据
|
||||
pageRequest.setScenarioId(null);
|
||||
pageRequest.setModuleIds(List.of("scenario-moduleId"));
|
||||
mvcResult = responsePost(PAGE, pageRequest);
|
||||
returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest);
|
||||
returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -223,7 +513,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
pageRequest.setSort(new HashMap<>() {{
|
||||
put("createTime", "asc");
|
||||
}});
|
||||
responsePost(PAGE, pageRequest);
|
||||
requestPostAndReturn(DEFAULT_PAGE, pageRequest);
|
||||
|
||||
pageRequest = new ApiScenarioPageRequest();
|
||||
pageRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
|
@ -233,8 +523,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
pageRequest.setFilter(new HashMap<>() {{
|
||||
put("priority", List.of("P0"));
|
||||
}});
|
||||
mvcResult = responsePost(PAGE, pageRequest);
|
||||
returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
mvcResult = requestPostAndReturn(DEFAULT_PAGE, pageRequest);
|
||||
returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -243,7 +533,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
scenarioDTOS.forEach(scenario -> Assertions.assertEquals(scenario.getPriority(), "P0"));
|
||||
|
||||
//校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_READ, PAGE, pageRequest);
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_READ, DEFAULT_PAGE, pageRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -257,7 +547,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
Assertions.assertTrue(CollectionUtils.isNotEmpty(followers));
|
||||
// @@校验日志
|
||||
checkLog("api-scenario-id1", OperationLogType.UPDATE);
|
||||
this.requestGet(FOLLOW + "111").andExpect(ERROR_REQUEST_MATCHER);
|
||||
assertErrorCode(this.requestGet(FOLLOW + "111"), NOT_FOUND);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_UPDATE, FOLLOW + "api-scenario-id1");
|
||||
|
||||
|
@ -269,11 +559,9 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
Assertions.assertTrue(CollectionUtils.isEmpty(followers));
|
||||
// @@校验日志
|
||||
checkLog("api-scenario-id1", OperationLogType.UPDATE);
|
||||
this.requestGet(FOLLOW + "111").andExpect(ERROR_REQUEST_MATCHER);
|
||||
|
||||
assertErrorCode(this.requestGet(FOLLOW + "111"), NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(13)
|
||||
public void batchEdit() throws Exception {
|
||||
|
@ -284,7 +572,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
request.setAppendTag(true);
|
||||
request.setSelectAll(true);
|
||||
request.setTags(new LinkedHashSet<>(List.of("tag1", "tag3", "tag4")));
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
ApiScenarioExample example = new ApiScenarioExample();
|
||||
List<String> ids = extApiScenarioMapper.getIds(request, false);
|
||||
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andDeletedEqualTo(false).andIdIn(ids);
|
||||
|
@ -296,7 +584,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
//覆盖标签
|
||||
request.setTags(new LinkedHashSet<>(List.of("tag1")));
|
||||
request.setAppendTag(false);
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
apiScenarioMapper.selectByExample(example).forEach(scenario -> {
|
||||
Assertions.assertEquals(scenario.getTags(), List.of("tag1"));
|
||||
});
|
||||
|
@ -311,7 +599,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
List<String> apiIdList = apiScenarioList.stream().map(ApiScenario::getId).toList();
|
||||
request.setSelectIds(apiIdList);
|
||||
request.setExcludeIds(apiIdList);
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
|
||||
//优先级
|
||||
request.setTags(new LinkedHashSet<>());
|
||||
|
@ -320,7 +608,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
request.setModuleIds(List.of("scenario-moduleId"));
|
||||
request.setPriority("P3");
|
||||
request.setExcludeIds(new ArrayList<>());
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
//判断数据的优先级是不是P3
|
||||
example.clear();
|
||||
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andDeletedEqualTo(false);
|
||||
|
@ -335,14 +623,14 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
request.setSelectAll(false);
|
||||
request.setSelectIds(List.of("api-scenario-id1"));
|
||||
request.setExcludeIds(List.of("api-scenario-id1"));
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
//状态
|
||||
request.setPriority(null);
|
||||
request.setType("Status");
|
||||
request.setStatus("Completed");
|
||||
request.setSelectAll(true);
|
||||
request.setExcludeIds(new ArrayList<>());
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
//判断数据的状态是不是Completed
|
||||
apiScenarios = apiScenarioMapper.selectByExample(example);
|
||||
apiScenarios.forEach(apiTestCase -> Assertions.assertEquals(apiTestCase.getStatus(), "Completed"));
|
||||
|
@ -356,7 +644,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
environmentExample.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andMockEqualTo(true);
|
||||
List<Environment> environments = environmentMapper.selectByExample(environmentExample);
|
||||
request.setEnvId(environments.get(0).getId());
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
//判断数据的环境是不是environments.get(0).getId()
|
||||
apiScenarios = apiScenarioMapper.selectByExample(example);
|
||||
apiScenarios.forEach(apiTestCase -> Assertions.assertEquals(apiTestCase.getEnvironmentId(), environments.get(0).getId()));
|
||||
|
@ -370,7 +658,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
//环境组
|
||||
request.setGrouped(true);
|
||||
request.setGroupId("scenario-environment-group-id");
|
||||
responsePost(BATCH_EDIT, request);
|
||||
requestPostAndReturn(BATCH_EDIT, request);
|
||||
apiScenarios = apiScenarioMapper.selectByExample(example);
|
||||
apiScenarios.forEach(apiTestCase -> {
|
||||
Assertions.assertEquals(apiTestCase.getGrouped(), true);
|
||||
|
@ -402,8 +690,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
pageRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
pageRequest.setPageSize(10);
|
||||
pageRequest.setCurrent(1);
|
||||
MvcResult mvcResult = responsePost(TRASH_PAGE, pageRequest);
|
||||
Pager<?> returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
MvcResult mvcResult = requestPostAndReturn(TRASH_PAGE, pageRequest);
|
||||
Pager<?> returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -413,8 +701,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
|
||||
//查询api-scenario-id1的数据
|
||||
pageRequest.setScenarioId("trash-api-scenario-id1");
|
||||
mvcResult = responsePost(TRASH_PAGE, pageRequest);
|
||||
returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
mvcResult = requestPostAndReturn(TRASH_PAGE, pageRequest);
|
||||
returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -426,8 +714,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
//查询模块为moduleId1的数据
|
||||
pageRequest.setScenarioId(null);
|
||||
pageRequest.setModuleIds(List.of("scenario-moduleId-trash"));
|
||||
mvcResult = responsePost(TRASH_PAGE, pageRequest);
|
||||
returnPager = parseObjectFromMvcResult(mvcResult, Pager.class);
|
||||
mvcResult = requestPostAndReturn(TRASH_PAGE, pageRequest);
|
||||
returnPager = getResultData(mvcResult, Pager.class);
|
||||
//返回值不为空
|
||||
Assertions.assertNotNull(returnPager);
|
||||
//返回值的页码和当前页码相同
|
||||
|
@ -439,10 +727,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
pageRequest.setSort(new HashMap<>() {{
|
||||
put("createTime", "asc");
|
||||
}});
|
||||
responsePost(TRASH_PAGE, pageRequest);
|
||||
requestPostAndReturn(TRASH_PAGE, pageRequest);
|
||||
//校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_READ, TRASH_PAGE, pageRequest);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import io.metersphere.api.dto.definition.HttpResponse;
|
||||
import io.metersphere.api.dto.request.MsCommonElement;
|
||||
import io.metersphere.api.dto.request.assertion.*;
|
||||
|
@ -64,7 +65,7 @@ public class MsHTTPElementTest {
|
|||
formDataKV.setValue("@email");
|
||||
formDataKV.setKey("key");
|
||||
FormDataKV formDataFileKV = new FormDataKV();
|
||||
BodyFile bodyFile = new BodyFile();
|
||||
ApiFile bodyFile = new ApiFile();
|
||||
bodyFile.setFileId("aaa");
|
||||
bodyFile.setFileName("aaa");
|
||||
formDataFileKV.setFiles(List.of(bodyFile));
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -59,6 +60,8 @@ public class ProjectService {
|
|||
@Resource
|
||||
private TestResourcePoolOrganizationMapper testResourcePoolOrganizationMapper;
|
||||
|
||||
public static final Long ORDER_STEP = 5000L;
|
||||
|
||||
|
||||
public List<Project> getUserProject(String organizationId, String userId) {
|
||||
if (organizationMapper.selectByPrimaryKey(organizationId) == null) {
|
||||
|
@ -199,4 +202,9 @@ public class ProjectService {
|
|||
projectVersionExample.createCriteria().andProjectIdEqualTo(projectId);
|
||||
return projectVersionMapper.selectByExample(projectVersionExample).get(0);
|
||||
}
|
||||
|
||||
public Long getNextOrder(Function<String, Long> getLastPosFunc, String projectId) {
|
||||
Long pos = getLastPosFunc.apply(projectId);
|
||||
return (pos == null ? 0 : pos) + ORDER_STEP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,4 +53,19 @@
|
|||
JSON_CONTAINS(`value`, JSON_ARRAY(#{value}))
|
||||
</foreach>
|
||||
</sql>
|
||||
|
||||
<sql id="filters">
|
||||
<if test="${filter} != null and ${filter}.size() > 0">
|
||||
<foreach collection="${filter}.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0 fields.contains(key)" >
|
||||
<where>
|
||||
${table_name}.${key} in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</where>
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
</sql>
|
||||
</mapper>
|
|
@ -87,6 +87,7 @@ public abstract class BaseTest {
|
|||
private MinioClient client;
|
||||
|
||||
protected static final String DEFAULT_LIST = "list";
|
||||
protected static final String DEFAULT_PAGE = "page";
|
||||
protected static final String DEFAULT_GET = "get/{0}";
|
||||
protected static final String DEFAULT_ADD = "add";
|
||||
protected static final String DEFAULT_UPDATE = "update";
|
||||
|
|
Loading…
Reference in New Issue