feat(接口测试): 新增接口调试接口

This commit is contained in:
wxg0103 2023-10-30 18:45:24 +08:00 committed by Craftsman
parent 280af80e18
commit 57bc8ddae9
26 changed files with 1758 additions and 112 deletions

View File

@ -36,7 +36,9 @@ public class ApiDebug implements Serializable {
@Size(min = 1, max = 50, message = "{api_debug.project_id.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{api_debug.project_id.length_range}", groups = {Created.class, Updated.class})
private String projectId; private String projectId;
@Schema(description = "模块fk") @Schema(description = "模块fk", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_debug.module_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{api_debug.module_id.length_range}", groups = {Created.class, Updated.class})
private String moduleId; private String moduleId;
@Schema(description = "创建时间") @Schema(description = "创建时间")

View File

@ -1,12 +1,16 @@
package io.metersphere.api.domain; package io.metersphere.api.domain;
import io.metersphere.validation.groups.*; import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import lombok.Data;
@Data @Data
public class ApiDebugModule implements Serializable { public class ApiDebugModule implements Serializable {
@ -21,8 +25,8 @@ public class ApiDebugModule implements Serializable {
private String name; private String name;
@Schema(description = "协议", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "协议", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_debug_module.protocol.not_blank}", groups = {Created.class}) @NotBlank(message = "{api_debug.protocol.not_blank}", groups = {Created.class})
@Size(min = 1, max = 64, message = "{api_debug_module.protocol.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 20, message = "{api_debug.protocol.length_range}", groups = {Created.class, Updated.class})
private String protocol; private String protocol;
@Schema(description = "父级fk", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "父级fk", requiredMode = Schema.RequiredMode.REQUIRED)
@ -35,10 +39,6 @@ public class ApiDebugModule implements Serializable {
@Size(min = 1, max = 50, message = "{api_debug_module.project_id.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{api_debug_module.project_id.length_range}", groups = {Created.class, Updated.class})
private String projectId; private String projectId;
@Schema(description = "树节点级别", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_debug_module.level.not_blank}", groups = {Created.class})
private Integer level;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{api_debug_module.pos.not_blank}", groups = {Created.class}) @NotNull(message = "{api_debug_module.pos.not_blank}", groups = {Created.class})
private Integer pos; private Integer pos;
@ -63,7 +63,6 @@ public class ApiDebugModule implements Serializable {
protocol("protocol", "protocol", "VARCHAR", false), protocol("protocol", "protocol", "VARCHAR", false),
parentId("parent_id", "parentId", "VARCHAR", false), parentId("parent_id", "parentId", "VARCHAR", false),
projectId("project_id", "projectId", "VARCHAR", false), projectId("project_id", "projectId", "VARCHAR", false),
level("level", "level", "INTEGER", true),
pos("pos", "pos", "INTEGER", false), pos("pos", "pos", "INTEGER", false),
createTime("create_time", "createTime", "BIGINT", false), createTime("create_time", "createTime", "BIGINT", false),
updateTime("update_time", "updateTime", "BIGINT", false), updateTime("update_time", "updateTime", "BIGINT", false),

View File

@ -454,66 +454,6 @@ public class ApiDebugModuleExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andLevelIsNull() {
addCriterion("`level` is null");
return (Criteria) this;
}
public Criteria andLevelIsNotNull() {
addCriterion("`level` is not null");
return (Criteria) this;
}
public Criteria andLevelEqualTo(Integer value) {
addCriterion("`level` =", value, "level");
return (Criteria) this;
}
public Criteria andLevelNotEqualTo(Integer value) {
addCriterion("`level` <>", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThan(Integer value) {
addCriterion("`level` >", value, "level");
return (Criteria) this;
}
public Criteria andLevelGreaterThanOrEqualTo(Integer value) {
addCriterion("`level` >=", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThan(Integer value) {
addCriterion("`level` <", value, "level");
return (Criteria) this;
}
public Criteria andLevelLessThanOrEqualTo(Integer value) {
addCriterion("`level` <=", value, "level");
return (Criteria) this;
}
public Criteria andLevelIn(List<Integer> values) {
addCriterion("`level` in", values, "level");
return (Criteria) this;
}
public Criteria andLevelNotIn(List<Integer> values) {
addCriterion("`level` not in", values, "level");
return (Criteria) this;
}
public Criteria andLevelBetween(Integer value1, Integer value2) {
addCriterion("`level` between", value1, value2, "level");
return (Criteria) this;
}
public Criteria andLevelNotBetween(Integer value1, Integer value2) {
addCriterion("`level` not between", value1, value2, "level");
return (Criteria) this;
}
public Criteria andPosIsNull() { public Criteria andPosIsNull() {
addCriterion("pos is null"); addCriterion("pos is null");
return (Criteria) this; return (Criteria) this;

View File

@ -7,7 +7,6 @@
<result column="protocol" jdbcType="VARCHAR" property="protocol" /> <result column="protocol" jdbcType="VARCHAR" property="protocol" />
<result column="parent_id" jdbcType="VARCHAR" property="parentId" /> <result column="parent_id" jdbcType="VARCHAR" property="parentId" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" /> <result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="level" jdbcType="INTEGER" property="level" />
<result column="pos" jdbcType="INTEGER" property="pos" /> <result column="pos" jdbcType="INTEGER" property="pos" />
<result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" /> <result column="update_time" jdbcType="BIGINT" property="updateTime" />
@ -73,8 +72,8 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, `name`, protocol, parent_id, project_id, `level`, pos, create_time, update_time, id, `name`, protocol, parent_id, project_id, pos, create_time, update_time, update_user,
update_user, create_user create_user
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.api.domain.ApiDebugModuleExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.api.domain.ApiDebugModuleExample" resultMap="BaseResultMap">
select select
@ -108,13 +107,13 @@
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.api.domain.ApiDebugModule"> <insert id="insert" parameterType="io.metersphere.api.domain.ApiDebugModule">
insert into api_debug_module (id, `name`, protocol, insert into api_debug_module (id, `name`, protocol,
parent_id, project_id, `level`, parent_id, project_id, pos,
pos, create_time, update_time, create_time, update_time, update_user,
update_user, create_user) create_user)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{protocol,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{protocol,jdbcType=VARCHAR},
#{parentId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{level,jdbcType=INTEGER}, #{parentId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{pos,jdbcType=INTEGER},
#{pos,jdbcType=INTEGER}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR},
#{updateUser,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}) #{createUser,jdbcType=VARCHAR})
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiDebugModule"> <insert id="insertSelective" parameterType="io.metersphere.api.domain.ApiDebugModule">
insert into api_debug_module insert into api_debug_module
@ -134,9 +133,6 @@
<if test="projectId != null"> <if test="projectId != null">
project_id, project_id,
</if> </if>
<if test="level != null">
`level`,
</if>
<if test="pos != null"> <if test="pos != null">
pos, pos,
</if> </if>
@ -169,9 +165,6 @@
<if test="projectId != null"> <if test="projectId != null">
#{projectId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="level != null">
#{level,jdbcType=INTEGER},
</if>
<if test="pos != null"> <if test="pos != null">
#{pos,jdbcType=INTEGER}, #{pos,jdbcType=INTEGER},
</if> </if>
@ -213,9 +206,6 @@
<if test="record.projectId != null"> <if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
</if> </if>
<if test="record.level != null">
`level` = #{record.level,jdbcType=INTEGER},
</if>
<if test="record.pos != null"> <if test="record.pos != null">
pos = #{record.pos,jdbcType=INTEGER}, pos = #{record.pos,jdbcType=INTEGER},
</if> </if>
@ -243,7 +233,6 @@
protocol = #{record.protocol,jdbcType=VARCHAR}, protocol = #{record.protocol,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR}, parent_id = #{record.parentId,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
`level` = #{record.level,jdbcType=INTEGER},
pos = #{record.pos,jdbcType=INTEGER}, pos = #{record.pos,jdbcType=INTEGER},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
@ -268,9 +257,6 @@
<if test="projectId != null"> <if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="level != null">
`level` = #{level,jdbcType=INTEGER},
</if>
<if test="pos != null"> <if test="pos != null">
pos = #{pos,jdbcType=INTEGER}, pos = #{pos,jdbcType=INTEGER},
</if> </if>
@ -295,7 +281,6 @@
protocol = #{protocol,jdbcType=VARCHAR}, protocol = #{protocol,jdbcType=VARCHAR},
parent_id = #{parentId,jdbcType=VARCHAR}, parent_id = #{parentId,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
`level` = #{level,jdbcType=INTEGER},
pos = #{pos,jdbcType=INTEGER}, pos = #{pos,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
@ -305,14 +290,14 @@
</update> </update>
<insert id="batchInsert" parameterType="map"> <insert id="batchInsert" parameterType="map">
insert into api_debug_module insert into api_debug_module
(id, `name`, protocol, parent_id, project_id, `level`, pos, create_time, update_time, (id, `name`, protocol, parent_id, project_id, pos, create_time, update_time, update_user,
update_user, create_user) create_user)
values values
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.protocol,jdbcType=VARCHAR}, (#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.protocol,jdbcType=VARCHAR},
#{item.parentId,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.level,jdbcType=INTEGER}, #{item.parentId,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.pos,jdbcType=INTEGER},
#{item.pos,jdbcType=INTEGER}, #{item.createTime,jdbcType=BIGINT}, #{item.updateTime,jdbcType=BIGINT}, #{item.createTime,jdbcType=BIGINT}, #{item.updateTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR},
#{item.updateUser,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}) #{item.createUser,jdbcType=VARCHAR})
</foreach> </foreach>
</insert> </insert>
<insert id="batchInsertSelective" parameterType="map"> <insert id="batchInsertSelective" parameterType="map">
@ -340,9 +325,6 @@
<if test="'project_id'.toString() == column.value"> <if test="'project_id'.toString() == column.value">
#{item.projectId,jdbcType=VARCHAR} #{item.projectId,jdbcType=VARCHAR}
</if> </if>
<if test="'level'.toString() == column.value">
#{item.level,jdbcType=INTEGER}
</if>
<if test="'pos'.toString() == column.value"> <if test="'pos'.toString() == column.value">
#{item.pos,jdbcType=INTEGER} #{item.pos,jdbcType=INTEGER}
</if> </if>

View File

@ -9,7 +9,7 @@ CREATE TABLE api_debug(
`method` VARCHAR(20) COMMENT 'http协议类型post/get/其它协议则是协议名(mqtt)' , `method` VARCHAR(20) COMMENT 'http协议类型post/get/其它协议则是协议名(mqtt)' ,
`path` VARCHAR(500) COMMENT 'http协议路径/其它协议则为空' , `path` VARCHAR(500) COMMENT 'http协议路径/其它协议则为空' ,
`project_id` VARCHAR(50) NOT NULL COMMENT '项目fk' , `project_id` VARCHAR(50) NOT NULL COMMENT '项目fk' ,
`module_id` VARCHAR(50) DEFAULT 'NONE' COMMENT '模块fk' , `module_id` VARCHAR(50) NOT NULL DEFAULT 'root' COMMENT '模块fk' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间' , `create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人' , `create_user` VARCHAR(50) NOT NULL COMMENT '创建人' ,
`update_time` BIGINT NOT NULL COMMENT '修改时间' , `update_time` BIGINT NOT NULL COMMENT '修改时间' ,
@ -41,10 +41,9 @@ DROP TABLE IF EXISTS api_debug_module;
CREATE TABLE api_debug_module( CREATE TABLE api_debug_module(
`id` VARCHAR(50) NOT NULL COMMENT '接口模块pk' , `id` VARCHAR(50) NOT NULL COMMENT '接口模块pk' ,
`name` VARCHAR(255) NOT NULL COMMENT '模块名称' , `name` VARCHAR(255) NOT NULL COMMENT '模块名称' ,
`protocol` VARCHAR(64) NOT NULL COMMENT '协议' , `protocol` VARCHAR(20) NOT NULL COMMENT '协议' ,
`parent_id` VARCHAR(50) NOT NULL DEFAULT 'NONE' COMMENT '父级fk' , `parent_id` VARCHAR(50) NOT NULL DEFAULT 'NONE' COMMENT '父级fk' ,
`project_id` VARCHAR(50) NOT NULL COMMENT '项目fk' , `project_id` VARCHAR(50) NOT NULL COMMENT '项目fk' ,
`level` INT NOT NULL DEFAULT 1 COMMENT '树节点级别' ,
`pos` INT NOT NULL COMMENT '排序' , `pos` INT NOT NULL COMMENT '排序' ,
`create_time` BIGINT NOT NULL COMMENT '创建时间' , `create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`update_time` BIGINT NOT NULL COMMENT '修改时间' , `update_time` BIGINT NOT NULL COMMENT '修改时间' ,
@ -58,6 +57,7 @@ CREATE TABLE api_debug_module(
CREATE INDEX idx_project_id ON api_debug_module(project_id); CREATE INDEX idx_project_id ON api_debug_module(project_id);
CREATE INDEX idx_protocol ON api_debug_module(protocol); CREATE INDEX idx_protocol ON api_debug_module(protocol);
CREATE INDEX idx_pos ON api_debug_module(pos); CREATE INDEX idx_pos ON api_debug_module(pos);
CREATE INDEX idx_create_user ON api_debug_module(create_user);
DROP TABLE IF EXISTS api_definition; DROP TABLE IF EXISTS api_definition;

View File

@ -13,4 +13,6 @@ public class ModuleConstants {
public static final String NODE_TYPE_GITEE = "Gitee"; public static final String NODE_TYPE_GITEE = "Gitee";
//GitLab节点类型 //GitLab节点类型
public static final String NODE_TYPE_GITLAB = "GitLab"; public static final String NODE_TYPE_GITLAB = "GitLab";
public static final String NODE_PROTOCOL_HTTP = "HTTP";
} }

View File

@ -220,4 +220,13 @@ public class PermissionConstants {
/*------ end: FUNCTIONAL_CASE ------*/ /*------ end: FUNCTIONAL_CASE ------*/
/*------ start: API_DEBUG ------*/
public static final String PROJECT_API_DEBUG_READ = "PROJECT_API_DEBUG:READ";
public static final String PROJECT_API_DEBUG_READ_ADD = "PROJECT_API_DEBUG:READ+ADD";
public static final String PROJECT_API_DEBUG_READ_UPDATE = "PROJECT_API_DEBUG:READ+UPDATE";
public static final String PROJECT_API_DEBUG_READ_DELETE = "PROJECT_API_DEBUG:READ+DELETE";
public static final String PROJECT_API_DEBUG_READ_IMPORT = "PROJECT_API_DEBUG:READ+IMPORT";
public static final String PROJECT_API_DEBUG_READ_EXECUTE = "PROJECT_API_DEBUG:READ+EXECUTE";
/*------ end: API_DEBUG ------*/
} }

View File

@ -250,4 +250,27 @@ api_scenario_report_detail.report_id.not_blank=报告ID不能为空
api_scenario_report_detail.resource_id.length_range=场景中各个步骤请求唯一标识长度必须在1-50之间 api_scenario_report_detail.resource_id.length_range=场景中各个步骤请求唯一标识长度必须在1-50之间
api_scenario_report_detail.resource_id.not_blank=场景中各个步骤请求唯一标识不能为空 api_scenario_report_detail.resource_id.not_blank=场景中各个步骤请求唯一标识不能为空
#moduleApiDefinitionBlob #moduleApiDefinitionBlob
api_definition_blob.api_definition_id.not_blank=接口ID/ 一对一关系不能为空 api_definition_blob.api_definition_id.not_blank=接口ID/ 一对一关系不能为空
#module: ApiDebug
api_debug.id.not_blank=ID不能为空
api_debug.id.length_range=接口ID长度必须在1-50之间
api_debug.name.not_blank=接口名称不能为空
api_debug.name.length_range=接口名称长度必须在1-255之间
api_debug.protocol.not_blank=协议不能为空
api_debug.protocol.length_range=协议长度必须在1-20之间
api_debug.project_id.not_blank=项目ID不能为空
api_debug.project_id.length_range=项目ID长度必须在1-50之间
api_debug.module_id.not_blank=模块ID不能为空
api_debug.module_id.length_range=模块ID长度必须在1-50之间
#module: ApiDebugModule
api_debug_module.id.not_blank=ID不能为空
api_debug_module.id.length_range=模块ID长度必须在1-50之间
api_debug_module.name.not_blank=模块名称不能为空
api_debug_module.name.length_range=模块名称长度必须在1-255之间
api_debug_module.parent_id.not_blank=父级ID不能为空
api_debug_module.parent_id.length_range=父级ID长度必须在1-50之间
api_debug_module.project_id.not_blank=项目ID不能为空
api_debug_module.project_id.length_range=项目ID长度必须在1-50之间
api_debug_module.pos.not_blank=模块位置不能为空
api_debug_module.name.not_contain_slash=模块名称不能包含斜杠

View File

@ -250,4 +250,27 @@ api_scenario_report_detail.report_id.not_blank=report fk cannot be empty
api_scenario_report_detail.resource_id.length_range=Each step in the scenario requests a unique identifier length must be between 1-50 api_scenario_report_detail.resource_id.length_range=Each step in the scenario requests a unique identifier length must be between 1-50
api_scenario_report_detail.resource_id.not_blank=The unique identifier requested by each step in the scenario cannot be empty api_scenario_report_detail.resource_id.not_blank=The unique identifier requested by each step in the scenario cannot be empty
#moduleApiDefinitionBlob #moduleApiDefinitionBlob
api_definition_blob.api_definition_id.not_blank=The interface fk/one-to-one relationship cannot be empty api_definition_blob.api_definition_id.not_blank=The interface fk/one-to-one relationship cannot be empty
api_debug.id.not_blank=ID cannot be blank
api_debug.id.length_range=The interface ID length must be between 1-50
api_debug.name.not_blank=Interface name cannot be blank
api_debug.name.length_range=The interface name length must be between 1-255
api_debug.protocol.not_blank=Protocol cannot be blank
api_debug.protocol.length_range=Protocol length must be between 1-20
api_debug.project_id.not_blank=Project ID cannot be blank
api_debug.project_id.length_range=Project ID length must be between 1-50
api_debug.module_id.not_blank=Module ID cannot be blank
api_debug.module_id.length_range=Module ID length must be between 1-50
#module: ApiDebugModule
api_debug_module.id.not_blank=ID cannot be blank
api_debug_module.id.length_range=Module ID length must be between 1-50
api_debug_module.name.not_blank=Module name cannot be blank
api_debug_module.name.length_range=Module name length must be between 1-255
api_debug_module.parent_id.not_blank=Parent ID cannot be blank
api_debug_module.parent_id.length_range=Parent ID length must be between 1-50
api_debug_module.project_id.not_blank=Project ID cannot be blank
api_debug_module.project_id.length_range=Project ID length must be between 1-50
api_debug_module.pos.not_blank=Module position cannot be blank
api_debug_module.name.not_contain_slash=Module name cannot contain slashes
api_debug_module.unplanned_request=Unplanned request

View File

@ -250,4 +250,28 @@ api_scenario_report_detail.report_id.not_blank=报告ID不能为空
api_scenario_report_detail.resource_id.length_range=场景中各个步骤请求唯一标识长度必须在1-50之间 api_scenario_report_detail.resource_id.length_range=场景中各个步骤请求唯一标识长度必须在1-50之间
api_scenario_report_detail.resource_id.not_blank=场景中各个步骤请求唯一标识不能为空 api_scenario_report_detail.resource_id.not_blank=场景中各个步骤请求唯一标识不能为空
#moduleApiDefinitionBlob #moduleApiDefinitionBlob
api_definition_blob.api_definition_id.not_blank=接口ID/ 一对一关系不能为空 api_definition_blob.api_definition_id.not_blank=接口ID/ 一对一关系不能为空
#module: ApiDebug
api_debug.id.not_blank=ID不能为空
api_debug.id.length_range=接口ID长度必须在1-50之间
api_debug.name.not_blank=接口名称不能为空
api_debug.name.length_range=接口名称长度必须在1-255之间
api_debug.protocol.not_blank=协议不能为空
api_debug.protocol.length_range=协议长度必须在1-20之间
api_debug.project_id.not_blank=项目ID不能为空
api_debug.project_id.length_range=项目ID长度必须在1-50之间
api_debug.module_id.not_blank=模块ID不能为空
api_debug.module_id.length_range=模块ID长度必须在1-50之间
#module: ApiDebugModule
api_debug_module.id.not_blank=ID不能为空
api_debug_module.id.length_range=模块ID长度必须在1-50之间
api_debug_module.name.not_blank=模块名称不能为空
api_debug_module.name.length_range=模块名称长度必须在1-255之间
api_debug_module.parent_id.not_blank=父级ID不能为空
api_debug_module.parent_id.length_range=父级ID长度必须在1-50之间
api_debug_module.project_id.not_blank=项目ID不能为空
api_debug_module.project_id.length_range=项目ID长度必须在1-50之间
api_debug_module.pos.not_blank=模块位置不能为空
api_debug_module.name.not_contain_slash=名称中不能包含正反斜杠
api_debug_module.unplanned_request=未规划请求

View File

@ -250,4 +250,28 @@ api_scenario_report_detail.report_id.not_blank=報告ID不能為空
api_scenario_report_detail.resource_id.length_range=場景中各個步驟請求唯一標識長度必須在1-50之間 api_scenario_report_detail.resource_id.length_range=場景中各個步驟請求唯一標識長度必須在1-50之間
api_scenario_report_detail.resource_id.not_blank=場景中各個步驟請求唯一標識不能為空 api_scenario_report_detail.resource_id.not_blank=場景中各個步驟請求唯一標識不能為空
#moduleApiDefinitionBlob #moduleApiDefinitionBlob
api_definition_blob.api_definition_id.not_blank=接口ID/ 一對一關繫不能為空 api_definition_blob.api_definition_id.not_blank=接口ID/ 一對一關繫不能為空
#module: ApiDebug
api_debug.id.not_blank=ID不能為空
api_debug.id.length_range=接口ID長度必須在1-50之間
api_debug.name.not_blank=接口名稱不能為空
api_debug.name.length_range=接口名稱長度必須在1-255之間
api_debug.protocol.not_blank=協定不能為空
api_debug.protocol.length_range=協定長度必須在1-20之間
api_debug.project_id.not_blank=項目ID不能為空
api_debug.project_id.length_range=項目ID長度必須在1-50之間
api_debug.module_id.not_blank=模塊ID不能為空
api_debug.module_id.length_range=模塊ID長度必須在1-50之間
#module: ApiDebugModule
api_debug_module.id.not_blank=ID不能為空
api_debug_module.id.length_range=模塊ID長度必須在1-50之間
api_debug_module.name.not_blank=模塊名稱不能為空
api_debug_module.name.length_range=模塊名稱長度必須在1-255之間
api_debug_module.parent_id.not_blank=父級ID不能為空
api_debug_module.parent_id.length_range=父級ID長度必須在1-50之間
api_debug_module.project_id.not_blank=項目ID不能為空
api_debug_module.project_id.length_range=項目ID長度必須在1-50之間
api_debug_module.pos.not_blank=模塊位置不能為空
api_debug_module.name.not_contain_slash=模塊名稱不能包含斜線
api_debug_module.unplanned_request=未規劃請求

View File

@ -0,0 +1,71 @@
package io.metersphere.api.controller;
import io.metersphere.api.request.ApiDebugRequest;
import io.metersphere.api.request.DebugModuleCreateRequest;
import io.metersphere.api.request.DebugModuleUpdateRequest;
import io.metersphere.api.service.ApiDebugModuleService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Tag(name = "接口测试-接口调试-模块")
@RestController
@RequestMapping("/api/debug/module")
public class ApiDebugModuleController {
@Resource
private ApiDebugModuleService apiDebugModuleService;
@GetMapping("/tree/{protocol}")
@Operation(summary = "接口测试-接口调试-模块-查找模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ)
public List<BaseTreeNode> getTree(@PathVariable String protocol) {
return apiDebugModuleService.getTree(protocol, SessionUtils.getUserId());
}
@PostMapping("/add")
@Operation(summary = "接口测试-接口调试-模块-添加模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ_ADD)
public String add(@RequestBody @Validated DebugModuleCreateRequest request) {
return apiDebugModuleService.add(request, SessionUtils.getUserId());
}
@PostMapping("/update")
@Operation(summary = "接口测试-接口调试-模块-修改模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ_UPDATE)
public boolean list(@RequestBody @Validated DebugModuleUpdateRequest request) {
apiDebugModuleService.update(request, SessionUtils.getUserId(), SessionUtils.getCurrentProjectId());
return true;
}
@GetMapping("/delete/{deleteId}")
@Operation(summary = "接口测试-接口调试-模块-删除模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ_DELETE)
public void deleteNode(@PathVariable String deleteId) {
apiDebugModuleService.deleteModule(deleteId, SessionUtils.getUserId());
}
@PostMapping("/move")
@Operation(summary = "接口测试-接口调试-模块-移动模块")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ_UPDATE)
public void moveNode(@Validated @RequestBody NodeMoveRequest request) {
apiDebugModuleService.moveNode(request, SessionUtils.getUserId());
}
@PostMapping("/count")
@Operation(summary = "接口测试-接口调试-模块-统计模块数量")
@RequiresPermissions(PermissionConstants.PROJECT_API_DEBUG_READ)
public Map<String, Long> moduleCount(@Validated @RequestBody ApiDebugRequest request) {
return apiDebugModuleService.moduleCount(request, SessionUtils.getUserId());
}
}

View File

@ -0,0 +1,36 @@
package io.metersphere.api.mapper;
import io.metersphere.api.domain.ApiDebugModule;
import io.metersphere.api.request.ApiDebugRequest;
import io.metersphere.api.request.ApiTreeNode;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtApiDebugModuleMapper {
List<BaseTreeNode> selectBaseByProtocolAndUser(String protocol, String userId);
List<BaseTreeNode> selectIdAndParentIdByProtocolAndUserId(String protocol, String userId);
List<String> selectChildrenIdsByParentIds(@Param("ids") List<String> deleteIds);
List<String> selectChildrenIdsSortByPos(String parentId);
void deleteByIds(@Param("ids") List<String> deleteId);
Integer getMaxPosByParentId(String parentId);
List<String> selectIdsByProjectId(String projectId);
ApiDebugModule getLastModuleByParentId(String id);
ApiDebugModule getNextModuleInParentId(@Param("parentId") String parentId, @Param("pos") int pos);
ApiDebugModule getPreviousModuleInParentId(@Param("parentId") String parentId, @Param("pos") int pos);
List<ApiTreeNode> selectApiDebugByProtocolAndUser(String protocol, String userId);
List<ModuleCountDTO> countModuleIdByKeywordAndProtocol(@Param("request") ApiDebugRequest request, @Param("userId") String userId);
}

View File

@ -0,0 +1,118 @@
<?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.ExtApiDebugModuleMapper">
<select id="selectBaseByProtocolAndUser" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id,
NAME,
parent_id AS parentId,
'module' AS type
FROM api_debug_module
WHERE protocol = #{protocol}
AND create_user = #{userId}
ORDER BY pos
</select>
<select id="selectIdAndParentIdByProtocolAndUserId" resultType="io.metersphere.system.dto.sdk.BaseTreeNode">
SELECT id,
parent_id AS parentId
FROM api_debug_module
WHERE protocol = #{protocol}
AND create_user = #{userId}
</select>
<select id="selectIdsByProjectId" resultType="java.lang.String">
SELECT id
FROM api_debug_module
WHERE project_id = #{0}
</select>
<select id="selectChildrenIdsByParentIds" resultType="java.lang.String">
SELECT id
FROM api_debug_module
WHERE parent_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<delete id="deleteByIds">
DELETE
FROM api_debug_module
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="getMaxPosByParentId" resultType="java.lang.Integer">
SELECT max(pos)
FROM api_debug_module
WHERE parent_id = #{0}
</select>
<select id="selectChildrenIdsSortByPos" resultType="java.lang.String">
SELECT id
FROM api_debug_module
WHERE parent_id = #{0}
ORDER BY pos ASC
</select>
<select id="getLastModuleByParentId" resultType="io.metersphere.api.domain.ApiDebugModule">
SELECT *
FROM api_debug_module
WHERE parent_id = #{0}
ORDER BY pos DESC
LIMIT 1
</select>
<select id="getNextModuleInParentId" resultType="io.metersphere.api.domain.ApiDebugModule">
SELECT *
from api_debug_module
WHERE parent_id = #{parentId}
AND pos &gt; #{pos}
order by pos asc
limit 1
</select>
<select id="getPreviousModuleInParentId" resultType="io.metersphere.api.domain.ApiDebugModule">
SELECT *
from api_debug_module
WHERE parent_id = #{parentId}
AND pos &lt; #{pos}
order by pos
desc
limit 1
</select>
<select id="selectApiDebugByProtocolAndUser" resultType="io.metersphere.api.request.ApiTreeNode">
SELECT id,
NAME,
module_id AS parentId,
'api' AS type,
method
FROM api_debug
WHERE protocol = #{protocol}
AND create_user = #{userId}
ORDER BY update_time DESC
</select>
<select id="countModuleIdByKeywordAndProtocol" resultType="io.metersphere.project.dto.ModuleCountDTO">
SELECT f.module_id AS moduleId, count(f.id) AS dataCount
FROM api_debug f
<include refid="debug_page_request"/>
GROUP BY f.module_id
</select>
<sql id="debug_page_request">
<where>
f.create_user = #{userId}
<if test="request.keyword != null and request.keyword != ''">
AND f.name like CONCAT('%', #{request.keyword},'%')
</if>
<if test="request.moduleIds != null and request.moduleIds.size() != 0">
AND f.module_id IN
<foreach collection="request.moduleIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="request.protocol != null and request.protocol != ''">
AND f.protocol = #{request.protocol}
</if>
</where>
</sql>
</mapper>

View File

@ -0,0 +1,23 @@
package io.metersphere.api.request;
import io.metersphere.sdk.constants.ModuleConstants;
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;
@Data
public class ApiDebugRequest {
@Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)")
private List<String> moduleIds;
@Schema(description = "协议", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_debug_module.protocol.not_blank}")
@Size(min = 1, max = 20, message = "{api_debug.protocol.length_range}")
private String protocol = ModuleConstants.NODE_PROTOCOL_HTTP;
@Schema(description = "关键字")
private String keyword;
}

View File

@ -0,0 +1,12 @@
package io.metersphere.api.request;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class ApiTreeNode extends BaseTreeNode {
@Schema(description = "方法")
private String method;
}

View File

@ -0,0 +1,34 @@
package io.metersphere.api.request;
import io.metersphere.sdk.constants.ModuleConstants;
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.NotEmpty;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class DebugModuleCreateRequest {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
@Schema(description = "模块名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{file_module.name.not_blank}")
@Pattern(regexp = "^[^\\\\/]*$", message = "{api_debug_module.name.not_contain_slash}")
private String name;
@Schema(description = "父模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{parent.node.not_blank}")
private String parentId = ModuleConstants.ROOT_NODE_PARENT_ID;
@Schema(description = "协议", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{api_debug_module.protocol.not_blank}", groups = {Created.class})
@Size(min = 1, max = 20, message = "{api_debug.protocol.length_range}", groups = {Created.class, Updated.class})
private String protocol = ModuleConstants.NODE_PROTOCOL_HTTP;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.api.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
@Data
public class DebugModuleUpdateRequest {
@Schema(description = "模块ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{file_module.id.not_blank}")
private String id;
@Schema(description = "模块名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{file_module.name.not_blank}")
@Pattern(regexp = "^[^\\\\/]*$", message = "{api_debug_module.name.not_contain_slash}")
private String name;
}

View File

@ -0,0 +1,120 @@
package io.metersphere.api.service;
import io.metersphere.api.domain.ApiDebugModule;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.builder.LogDTOBuilder;
import io.metersphere.system.dto.sdk.BaseModule;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiDebugModuleLogService {
private static final String API_DEBUG_MODULE = "/api/debug/module";
private static final String ADD = API_DEBUG_MODULE + "/add";
private static final String UPDATE = API_DEBUG_MODULE + "/update";
private static final String DELETE = API_DEBUG_MODULE + "/delete";
private static final String MOVE = API_DEBUG_MODULE + "/move";
private static final String MOVE_TO = "file.log.move_to";
@Resource
private ProjectMapper projectMapper;
@Resource
private OperationLogService operationLogService;
public void saveAddLog(ApiDebugModule module, String operator) {
Project project = projectMapper.selectByPrimaryKey(module.getProjectId());
LogDTO dto = LogDTOBuilder.builder()
.projectId(module.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.ADD.name())
.module(OperationLogModule.API_DEBUG)
.method(HttpMethodConstants.POST.name())
.path(ADD)
.sourceId(module.getId())
.content(module.getName())
.originalValue(JSON.toJSONBytes(module))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
public void saveUpdateLog(ApiDebugModule module, String projectId, String operator) {
Project project = projectMapper.selectByPrimaryKey(projectId);
LogDTO dto = LogDTOBuilder.builder()
.projectId(projectId)
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.API_DEBUG)
.method(HttpMethodConstants.POST.name())
.path(UPDATE)
.sourceId(module.getId())
.content(module.getName())
.originalValue(JSON.toJSONBytes(module))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
public void saveDeleteLog(ApiDebugModule deleteModule, String operator) {
Project project = projectMapper.selectByPrimaryKey(deleteModule.getProjectId());
LogDTO dto = LogDTOBuilder.builder()
.projectId(deleteModule.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.DELETE.name())
.module(OperationLogModule.API_DEBUG)
.method(HttpMethodConstants.GET.name())
.path(DELETE + "/%s")
.sourceId(deleteModule.getId())
.content(deleteModule.getName() + " " + Translator.get("file.log.delete_module"))
.originalValue(JSON.toJSONBytes(deleteModule))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
public void saveMoveLog(@Validated NodeSortDTO request, String operator) {
BaseModule moveNode = request.getNode();
BaseModule previousNode = request.getPreviousNode();
BaseModule nextNode = request.getNextNode();
BaseModule parentModule = request.getParent();
Project project = projectMapper.selectByPrimaryKey(moveNode.getProjectId());
String logContent;
if (nextNode == null && previousNode == null) {
logContent = moveNode.getName() + " " + Translator.get(MOVE_TO) + parentModule.getName();
} else if (nextNode == null) {
logContent = moveNode.getName() + " " + Translator.get(MOVE_TO) + parentModule.getName() + " " + previousNode.getName() + Translator.get("file.log.next");
} else if (previousNode == null) {
logContent = moveNode.getName() + " " + Translator.get(MOVE_TO) + parentModule.getName() + " " + nextNode.getName() + Translator.get("file.log.previous");
} else {
logContent = moveNode.getName() + " " + Translator.get(MOVE_TO) + parentModule.getName() + " " +
previousNode.getName() + Translator.get("file.log.next") + " " + nextNode.getName() + Translator.get("file.log.previous");
}
LogDTO dto = LogDTOBuilder.builder()
.projectId(moveNode.getProjectId())
.organizationId(project.getOrganizationId())
.type(OperationLogType.UPDATE.name())
.module(OperationLogModule.API_DEBUG)
.method(HttpMethodConstants.POST.name())
.path(MOVE)
.sourceId(moveNode.getId())
.content(logContent)
.originalValue(JSON.toJSONBytes(moveNode))
.createUser(operator)
.build().getLogDTO();
operationLogService.add(dto);
}
}

View File

@ -0,0 +1,333 @@
package io.metersphere.api.service;
import io.metersphere.api.domain.*;
import io.metersphere.api.mapper.ApiDebugBlobMapper;
import io.metersphere.api.mapper.ApiDebugMapper;
import io.metersphere.api.mapper.ApiDebugModuleMapper;
import io.metersphere.api.mapper.ExtApiDebugModuleMapper;
import io.metersphere.api.request.ApiDebugRequest;
import io.metersphere.api.request.ApiTreeNode;
import io.metersphere.api.request.DebugModuleCreateRequest;
import io.metersphere.api.request.DebugModuleUpdateRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.project.dto.NodeSortDTO;
import io.metersphere.project.service.ModuleTreeService;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.sdk.BaseModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiDebugModuleService extends ModuleTreeService {
private static final String UNPLANNED = "api_debug_module.unplanned_request";
private static final String METHOD = "method";
private static final String DEBUG_MODULE_COUNT_ALL = "all";
@Resource
private ApiDebugModuleLogService apiDebugModuleLogService;
@Resource
private ApiDebugModuleMapper apiDebugModuleMapper;
@Resource
private ExtApiDebugModuleMapper extApiDebugModuleMapper;
@Resource
private ApiDebugMapper apiDebugMapper;
@Resource
private ApiDebugBlobMapper apiDebugBlobMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
public List<BaseTreeNode> getTree(String protocol, String userId) {
List<BaseTreeNode> fileModuleList = extApiDebugModuleMapper.selectBaseByProtocolAndUser(protocol, userId);
List<BaseTreeNode> baseTreeNodes = super.buildTreeAndCountResource(fileModuleList, true, Translator.get(UNPLANNED));
List<ApiTreeNode> apiTreeNodeList = extApiDebugModuleMapper.selectApiDebugByProtocolAndUser(protocol, userId);
//将apiTreeNodeList转换成BaseTreeNode method放入map中
if (CollectionUtils.isEmpty(apiTreeNodeList)) {
return baseTreeNodes;
}
List<BaseTreeNode> nodeList = apiTreeNodeList.stream().map(apiTreeNode -> {
BaseTreeNode baseTreeNode = new BaseTreeNode();
baseTreeNode.setId(apiTreeNode.getId());
baseTreeNode.setName(apiTreeNode.getName());
baseTreeNode.setParentId(apiTreeNode.getParentId());
baseTreeNode.setType(apiTreeNode.getType());
baseTreeNode.putAttachInfo(METHOD, apiTreeNode.getMethod());
return baseTreeNode;
}).toList();
//apiTreeNodeList使用stream实现将parentId分组生成map
Map<String, List<BaseTreeNode>> apiTreeNodeMap = nodeList.stream().collect(Collectors.groupingBy(BaseTreeNode::getParentId));
//遍历baseTreeNodes将apiTreeNodeMap中的id相等的数据添加到baseTreeNodes中
return generateTree(baseTreeNodes, apiTreeNodeMap);
}
//生成树结构
public List<BaseTreeNode> generateTree(List<BaseTreeNode> baseTreeNodes, Map<String, List<BaseTreeNode>> apiTreeNodeMap) {
baseTreeNodes.forEach(baseTreeNode -> {
if (apiTreeNodeMap.containsKey(baseTreeNode.getId())) {
baseTreeNode.getChildren().addAll(apiTreeNodeMap.get(baseTreeNode.getId()));
}
if (CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
generateTree(baseTreeNode.getChildren(), apiTreeNodeMap);
}
});
return baseTreeNodes;
}
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(String protocol, String userId, List<ModuleCountDTO> moduleCountDTOList) {
//节点内容只有Id和parentId
List<BaseTreeNode> fileModuleList = extApiDebugModuleMapper.selectIdAndParentIdByProtocolAndUserId(protocol, userId);
return super.buildTreeAndCountResource(fileModuleList, moduleCountDTOList, true, Translator.get(UNPLANNED));
}
public String add(DebugModuleCreateRequest request, String operator) {
ApiDebugModule apiDebugModule = new ApiDebugModule();
apiDebugModule.setId(IDGenerator.nextStr());
apiDebugModule.setName(request.getName());
apiDebugModule.setParentId(request.getParentId());
apiDebugModule.setProjectId(request.getProjectId());
apiDebugModule.setProtocol(request.getProtocol());
apiDebugModule.setCreateUser(operator);
this.checkDataValidity(apiDebugModule);
apiDebugModule.setCreateTime(System.currentTimeMillis());
apiDebugModule.setUpdateTime(apiDebugModule.getCreateTime());
apiDebugModule.setPos(this.countPos(request.getParentId()));
apiDebugModule.setUpdateUser(operator);
apiDebugModuleMapper.insert(apiDebugModule);
//记录日志
apiDebugModuleLogService.saveAddLog(apiDebugModule, operator);
return apiDebugModule.getId();
}
private Integer countPos(String parentId) {
Integer maxPos = extApiDebugModuleMapper.getMaxPosByParentId(parentId);
if (maxPos == null) {
return LIMIT_POS;
} else {
return maxPos + LIMIT_POS;
}
}
/**
* 检查数据的合法性
*/
private void checkDataValidity(ApiDebugModule apiDebugModule) {
ApiDebugModuleExample example = new ApiDebugModuleExample();
if (!StringUtils.equals(apiDebugModule.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
//检查父ID是否存在 调试模块的逻辑是 同一个用户下的同级模块不能重名 每个协议是不同的模块
example.createCriteria().andIdEqualTo(apiDebugModule.getParentId())
.andCreateUserEqualTo(apiDebugModule.getCreateUser())
.andProtocolEqualTo(apiDebugModule.getProtocol());
if (apiDebugModuleMapper.countByExample(example) == 0) {
throw new MSException(Translator.get("parent.node.not_blank"));
}
example.clear();
}
example.createCriteria().andParentIdEqualTo(apiDebugModule.getParentId())
.andNameEqualTo(apiDebugModule.getName())
.andIdNotEqualTo(apiDebugModule.getId())
.andCreateUserEqualTo(apiDebugModule.getCreateUser())
.andProtocolEqualTo(apiDebugModule.getProtocol());
if (apiDebugModuleMapper.countByExample(example) > 0) {
throw new MSException(Translator.get("node.name.repeat"));
}
example.clear();
}
public void update(DebugModuleUpdateRequest request, String userId, String projectId) {
ApiDebugModule module = apiDebugModuleMapper.selectByPrimaryKey(request.getId());
if (module == null) {
throw new MSException("file_module.not.exist");
}
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(request.getId());
updateModule.setName(request.getName());
updateModule.setParentId(module.getParentId());
updateModule.setProtocol(module.getProtocol());
updateModule.setCreateUser(module.getCreateUser());
this.checkDataValidity(updateModule);
updateModule.setUpdateTime(System.currentTimeMillis());
updateModule.setUpdateUser(userId);
updateModule.setProjectId(projectId);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
//记录日志
apiDebugModuleLogService.saveUpdateLog(updateModule, projectId, userId);
}
public void deleteModule(String deleteId, String currentUser) {
ApiDebugModule deleteModule = apiDebugModuleMapper.selectByPrimaryKey(deleteId);
if (deleteModule != null) {
this.deleteModule(Collections.singletonList(deleteId));
//记录日志
apiDebugModuleLogService.saveDeleteLog(deleteModule, currentUser);
}
}
public void deleteModule(List<String> deleteIds) {
if (CollectionUtils.isEmpty(deleteIds)) {
return;
}
extApiDebugModuleMapper.deleteByIds(deleteIds);
//删除模块下的所有接口
ApiDebugExample example = new ApiDebugExample();
example.createCriteria().andModuleIdIn(deleteIds);
List<ApiDebug> apiDebugs = apiDebugMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(apiDebugs)) {
List<String> apiDebugIds = apiDebugs.stream().map(ApiDebug::getId).collect(Collectors.toList());
apiDebugMapper.deleteByExample(example);
ApiDebugBlobExample blobExample = new ApiDebugBlobExample();
blobExample.createCriteria().andIdIn(apiDebugIds);
apiDebugBlobMapper.deleteByExample(blobExample);
}
List<String> childrenIds = extApiDebugModuleMapper.selectChildrenIdsByParentIds(deleteIds);
if (CollectionUtils.isNotEmpty(childrenIds)) {
deleteModule(childrenIds);
}
}
public void moveNode(NodeMoveRequest request, String currentUser) {
BaseModule module;
BaseModule parentModule;
BaseModule previousNode = null;
BaseModule nextNode = null;
ApiDebugModule dragNode = apiDebugModuleMapper.selectByPrimaryKey(request.getDragNodeId());
if (dragNode == null) {
throw new MSException("file_module.not.exist:" + request.getDragNodeId());
} else {
module = new BaseModule(dragNode.getId(), dragNode.getName(), dragNode.getPos(), dragNode.getProjectId(), dragNode.getParentId());
}
if (StringUtils.equals(request.getDragNodeId(), request.getDropNodeId())) {
//两种节点不能一样
throw new MSException(Translator.get("invalid_parameter"));
}
ApiDebugModule dropNode = apiDebugModuleMapper.selectByPrimaryKey(request.getDropNodeId());
if (dropNode == null) {
throw new MSException("file_module.not.exist:" + request.getDropNodeId());
}
if (request.getDropPosition() == 0) {
//dropPosition=0: 放到dropNode节点内最后一个节点之后
parentModule = new BaseModule(dropNode.getId(), dropNode.getName(), dropNode.getPos(), dropNode.getProjectId(), dropNode.getParentId());
ApiDebugModule previousModule = extApiDebugModuleMapper.getLastModuleByParentId(parentModule.getId());
if (previousModule != null) {
previousNode = new BaseModule(previousModule.getId(), previousModule.getName(), previousModule.getPos(), previousModule.getProjectId(), previousModule.getParentId());
}
} else {
if (StringUtils.equals(dropNode.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)) {
parentModule = new BaseModule(ModuleConstants.ROOT_NODE_PARENT_ID, ModuleConstants.ROOT_NODE_PARENT_ID, 0, module.getProjectId(), ModuleConstants.ROOT_NODE_PARENT_ID);
} else {
ApiDebugModule parent = apiDebugModuleMapper.selectByPrimaryKey(dropNode.getParentId());
parentModule = new BaseModule(parent.getId(), parent.getName(), parent.getPos(), parent.getProjectId(), parent.getParentId());
}
if (request.getDropPosition() == 1) {
//dropPosition=1: 放到dropNode节点后原dropNode后面的节点之前
previousNode = new BaseModule(dropNode.getId(), dropNode.getName(), dropNode.getPos(), dropNode.getProjectId(), dropNode.getParentId());
ApiDebugModule nextModule = extApiDebugModuleMapper.getNextModuleInParentId(previousNode.getParentId(), previousNode.getPos());
if (nextModule != null) {
nextNode = new BaseModule(nextModule.getId(), nextModule.getName(), nextModule.getPos(), nextModule.getProjectId(), nextModule.getParentId());
}
} else if (request.getDropPosition() == -1) {
//dropPosition=-1: 放到dropNode节点前原dropNode前面的节点之后
nextNode = new BaseModule(dropNode.getId(), dropNode.getName(), dropNode.getPos(), dropNode.getProjectId(), dropNode.getParentId());
ApiDebugModule previousModule = extApiDebugModuleMapper.getPreviousModuleInParentId(nextNode.getParentId(), nextNode.getPos());
if (previousModule != null) {
previousNode = new BaseModule(previousModule.getId(), previousModule.getName(), previousModule.getPos(), previousModule.getProjectId(), previousModule.getParentId());
}
} else {
throw new MSException(Translator.get("invalid_parameter"));
}
}
ApiDebugModuleExample example = new ApiDebugModuleExample();
example.createCriteria().andParentIdEqualTo(parentModule.getId()).andIdEqualTo(module.getId());
//节点换到了别的节点下,要先更新parent节点.
if (apiDebugModuleMapper.countByExample(example) == 0) {
ApiDebugModule fileModule = new ApiDebugModule();
fileModule.setId(module.getId());
fileModule.setParentId(parentModule.getId());
apiDebugModuleMapper.updateByPrimaryKeySelective(fileModule);
}
NodeSortDTO nodeMoveDTO = new NodeSortDTO(module, parentModule, previousNode, nextNode);
super.sort(nodeMoveDTO);
//记录日志
apiDebugModuleLogService.saveMoveLog(nodeMoveDTO, currentUser);
}
/**
* 查找当前项目下模块每个节点对应的资源统计
*/
public Map<String, Long> getModuleCountMap(String protocol, String userId, List<ModuleCountDTO> moduleCountDTOList) {
Map<String, Long> returnMap = new HashMap<>();
//构建模块树并计算每个节点下的所有数量包含子节点
List<BaseTreeNode> treeNodeList = this.getTreeOnlyIdsAndResourceCount(protocol, userId, moduleCountDTOList);
//通过广度遍历的方式构建返回值
List<BaseTreeNode> whileList = new ArrayList<>(treeNodeList);
while (CollectionUtils.isNotEmpty(whileList)) {
List<BaseTreeNode> childList = new ArrayList<>();
for (BaseTreeNode treeNode : whileList) {
returnMap.put(treeNode.getId(), treeNode.getCount());
childList.addAll(treeNode.getChildren());
}
whileList = childList;
}
return returnMap;
}
@Override
public void updatePos(String id, int pos) {
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setPos(pos);
updateModule.setId(id);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
}
@Override
public void refreshPos(String parentId) {
List<String> childrenIdSortByPos = extApiDebugModuleMapper.selectChildrenIdsSortByPos(parentId);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDebugModuleMapper batchUpdateMapper = sqlSession.getMapper(ApiDebugModuleMapper.class);
for (int i = 0; i < childrenIdSortByPos.size(); i++) {
String nodeId = childrenIdSortByPos.get(i);
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(nodeId);
updateModule.setPos((i + 1) * LIMIT_POS);
batchUpdateMapper.updateByPrimaryKeySelective(updateModule);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
public Map<String, Long> moduleCount(ApiDebugRequest request, String operator) {
//查出每个模块节点下的资源数量 不需要按照模块进行筛选
request.setModuleIds(null);
List<ModuleCountDTO> moduleCountDTOList = extApiDebugModuleMapper.countModuleIdByKeywordAndProtocol(request, operator);
long allCount = getAllCount(moduleCountDTOList);
Map<String, Long> moduleCountMap = getModuleCountMap(request.getProtocol(), operator, moduleCountDTOList);
moduleCountMap.put(DEBUG_MODULE_COUNT_ALL, allCount);
return moduleCountMap;
}
}

View File

@ -0,0 +1,822 @@
package io.metersphere.api.controller;
import io.metersphere.api.domain.*;
import io.metersphere.api.mapper.ApiDebugBlobMapper;
import io.metersphere.api.mapper.ApiDebugMapper;
import io.metersphere.api.mapper.ApiDebugModuleMapper;
import io.metersphere.api.request.ApiDebugRequest;
import io.metersphere.api.request.DebugModuleCreateRequest;
import io.metersphere.api.request.DebugModuleUpdateRequest;
import io.metersphere.api.service.ApiDebugModuleService;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.request.NodeMoveRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
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.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.List;
import java.util.Map;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class ApiDebugModuleControllerTests extends BaseTest {
private static final String URL_MODULE_ADD = "/api/debug/module/add";
private static final String URL_MODULE_UPDATE = "/api/debug/module/update";
private static final String URL_MODULE_DELETE = "/api/debug/module/delete/%s";
private static final String URL_MODULE_TREE = "/api/debug/module/tree/%s";
private static final String URL_MODULE_MOVE = "/api/debug/module/move";
private static final String URL_FILE_MODULE_COUNT = "/api/debug/module/count";
private static final ResultMatcher BAD_REQUEST_MATCHER = status().isBadRequest();
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
private static Project project;
private static List<BaseTreeNode> preliminaryTreeNodes = new ArrayList<>();
@Resource
private ProjectMapper projectMapper;
@Resource
private ApiDebugModuleMapper apiDebugModuleMapper;
@Resource
private ApiDebugMapper apiDebugMapper;
@Resource
private ApiDebugBlobMapper apiDebugBlobMapper;
@Resource
private ApiDebugModuleService apiDebugModuleService;
public static BaseTreeNode getNodeByName(List<BaseTreeNode> preliminaryTreeNodes, String nodeName) {
for (BaseTreeNode firstLevelNode : preliminaryTreeNodes) {
if (StringUtils.equals(firstLevelNode.getName(), nodeName) && StringUtils.equals(firstLevelNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
return firstLevelNode;
}
if (CollectionUtils.isNotEmpty(firstLevelNode.getChildren())) {
for (BaseTreeNode secondLevelNode : firstLevelNode.getChildren()) {
if (StringUtils.equals(secondLevelNode.getName(), nodeName) && StringUtils.equals(secondLevelNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
return secondLevelNode;
}
if (CollectionUtils.isNotEmpty(secondLevelNode.getChildren())) {
for (BaseTreeNode thirdLevelNode : secondLevelNode.getChildren()) {
if (StringUtils.equals(thirdLevelNode.getName(), nodeName) && StringUtils.equals(thirdLevelNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
return thirdLevelNode;
}
}
}
}
}
}
return null;
}
@BeforeEach
public void initTestData() {
if (project == null) {
Project initProject = new Project();
initProject.setId(IDGenerator.nextStr());
initProject.setNum(null);
initProject.setOrganizationId("100001");
initProject.setName("接口调试的项目");
initProject.setDescription("接口调试的项目");
initProject.setCreateUser("admin");
initProject.setUpdateUser("admin");
initProject.setCreateTime(System.currentTimeMillis());
initProject.setUpdateTime(System.currentTimeMillis());
initProject.setEnable(true);
initProject.setModuleSetting("[\"apiTest\",\"uiTest\"]");
projectMapper.insertSelective(initProject);
project = projectMapper.selectByPrimaryKey(initProject.getId());
}
}
public void initApiDebugData(String moduleId) {
ApiDebug apiDebug = new ApiDebug();
apiDebug.setId(IDGenerator.nextStr());
apiDebug.setProjectId(project.getId());
apiDebug.setName(StringUtils.join("接口调试", apiDebug.getId()));
apiDebug.setModuleId(moduleId);
apiDebug.setProtocol("HTTP");
apiDebug.setMethod("GET");
apiDebug.setPath(StringUtils.join("api/debug/", apiDebug.getId()));
apiDebug.setCreateTime(System.currentTimeMillis());
apiDebug.setUpdateTime(System.currentTimeMillis());
apiDebug.setCreateUser("admin");
apiDebug.setUpdateUser("admin");
apiDebugMapper.insertSelective(apiDebug);
ApiDebugBlob apiDebugBlob = new ApiDebugBlob();
apiDebugBlob.setId(apiDebug.getId());
apiDebugBlob.setRequest(new byte[0]);
apiDebugBlob.setResponse(new byte[0]);
apiDebugBlobMapper.insertSelective(apiDebugBlob);
}
@Test
@Order(2)
public void addModuleTestSuccess() throws Exception {
//根目录下创建节点(a1
DebugModuleCreateRequest request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
String returnId = mvcResult.getResponse().getContentAsString();
Assertions.assertNotNull(returnId);
List<BaseTreeNode> treeNodes = this.getDebugModuleTreeNode();
BaseTreeNode a1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
if (StringUtils.equals(baseTreeNode.getName(), request.getName())) {
a1Node = baseTreeNode;
}
Assertions.assertNotNull(baseTreeNode.getParentId());
}
Assertions.assertNotNull(a1Node);
initApiDebugData(a1Node.getId());
checkLog(a1Node.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//根目录下创建节点a2和a3在a1下创建子节点a1-b1
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a2");
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
request.setName("a3");
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1");
request.setParentId(a1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
treeNodes = this.getDebugModuleTreeNode();
BaseTreeNode a1b1Node = null;
BaseTreeNode a2Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode childNode : baseTreeNode.getChildren()) {
if (StringUtils.equals(childNode.getName(), "a1-b1") && StringUtils.equals(childNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a1b1Node = childNode;
}
Assertions.assertNotNull(childNode.getParentId());
}
} else if (StringUtils.equals(baseTreeNode.getName(), "a2") && StringUtils.equals(baseTreeNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a2Node = baseTreeNode;
}
}
Assertions.assertNotNull(a2Node);
Assertions.assertNotNull(a1b1Node);
initApiDebugData(a2Node.getId());
initApiDebugData(a1b1Node.getId());
checkLog(a2Node.getId(), OperationLogType.ADD, URL_MODULE_ADD);
checkLog(a1b1Node.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//a1节点下可以继续添加a1节点
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
request.setParentId(a1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
//继续创建a1下继续创建a1-a1-b1,
treeNodes = this.getDebugModuleTreeNode();
BaseTreeNode a1ChildNode = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode childNode : baseTreeNode.getChildren()) {
Assertions.assertNotNull(childNode.getParentId());
if (StringUtils.equals(childNode.getName(), "a1") && StringUtils.equals(childNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a1ChildNode = childNode;
}
}
}
}
Assertions.assertNotNull(a1ChildNode);
initApiDebugData(a1ChildNode.getId());
checkLog(a1ChildNode.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//a1的子节点a1下继续创建节点a1-a1-c1
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-a1-c1");
request.setParentId(a1ChildNode.getId());
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
treeNodes = this.getDebugModuleTreeNode();
BaseTreeNode a1a1c1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
Assertions.assertNotNull(baseTreeNode.getParentId());
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode secondNode : baseTreeNode.getChildren()) {
Assertions.assertNotNull(secondNode.getParentId());
if (StringUtils.equals(secondNode.getName(), "a1") && CollectionUtils.isNotEmpty(secondNode.getChildren())) {
for (BaseTreeNode thirdNode : secondNode.getChildren()) {
Assertions.assertNotNull(thirdNode.getParentId());
if (StringUtils.equals(thirdNode.getName(), "a1-a1-c1") && StringUtils.equals(thirdNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a1a1c1Node = thirdNode;
}
}
}
}
}
}
Assertions.assertNotNull(a1a1c1Node);
initApiDebugData(a1a1c1Node.getId());
checkLog(a1a1c1Node.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//子节点a1-b1下继续创建节点a1-b1-c1
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1-c1");
request.setParentId(a1b1Node.getId());
this.requestPostWithOkAndReturn(URL_MODULE_ADD, request);
treeNodes = this.getDebugModuleTreeNode();
BaseTreeNode a1b1c1Node = null;
for (BaseTreeNode baseTreeNode : treeNodes) {
if (StringUtils.equals(baseTreeNode.getName(), "a1") && CollectionUtils.isNotEmpty(baseTreeNode.getChildren())) {
for (BaseTreeNode secondNode : baseTreeNode.getChildren()) {
if (StringUtils.equals(secondNode.getName(), "a1-b1") && CollectionUtils.isNotEmpty(secondNode.getChildren())) {
for (BaseTreeNode thirdNode : secondNode.getChildren()) {
if (StringUtils.equals(thirdNode.getName(), "a1-b1-c1") && StringUtils.equals(thirdNode.getType(), ModuleConstants.NODE_TYPE_DEFAULT)) {
a1b1c1Node = thirdNode;
}
}
}
}
}
}
Assertions.assertNotNull(a1b1c1Node);
initApiDebugData(a1b1c1Node.getId());
preliminaryTreeNodes = treeNodes;
checkLog(a1b1c1Node.getId(), OperationLogType.ADD, URL_MODULE_ADD);
//校验权限
request = new DebugModuleCreateRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setName("defaultProject");
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_READ_ADD, URL_MODULE_ADD, request);
}
@Test
@Order(3)
public void addModuleTestError() throws Exception {
this.preliminaryData();
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
assert a1Node != null;
//参数校验
DebugModuleCreateRequest request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
this.requestPost(URL_MODULE_ADD, request).andExpect(BAD_REQUEST_MATCHER);
request = new DebugModuleCreateRequest();
request.setName("none");
this.requestPost(URL_MODULE_ADD, request).andExpect(BAD_REQUEST_MATCHER);
request = new DebugModuleCreateRequest();
this.requestPost(URL_MODULE_ADD, request).andExpect(BAD_REQUEST_MATCHER);
request = new DebugModuleCreateRequest();
request.setParentId(null);
this.requestPost(URL_MODULE_ADD, request).andExpect(BAD_REQUEST_MATCHER);
//名称存在特殊字符
request.setName("a1/a2");
request.setParentId(a1Node.getId());
this.requestPost(URL_MODULE_ADD, request).andExpect(BAD_REQUEST_MATCHER);
//父节点ID不存在的
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("ParentIsUUID");
request.setParentId(IDGenerator.nextStr());
this.requestPost(URL_MODULE_ADD, request).andExpect(ERROR_REQUEST_MATCHER);
//添加重复的a1节点
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1");
this.requestPost(URL_MODULE_ADD, request).andExpect(ERROR_REQUEST_MATCHER);
//a1节点下添加重复的a1-b1节点
request = new DebugModuleCreateRequest();
request.setProjectId(project.getId());
request.setName("a1-b1");
request.setParentId(a1Node.getId());
this.requestPost(URL_MODULE_ADD, request).andExpect(ERROR_REQUEST_MATCHER);
}
@Test
@Order(4)
public void updateModuleTestSuccess() throws Exception {
if (CollectionUtils.isEmpty(preliminaryTreeNodes)) {
this.addModuleTestSuccess();
}
//更改名称
BaseTreeNode a1Node = null;
for (BaseTreeNode node : preliminaryTreeNodes) {
if (StringUtils.equals(node.getName(), "a1")) {
for (BaseTreeNode a1ChildrenNode : node.getChildren()) {
if (StringUtils.equals(a1ChildrenNode.getName(), "a1")) {
a1Node = a1ChildrenNode;
}
}
}
}
assert a1Node != null;
DebugModuleUpdateRequest updateRequest = new DebugModuleUpdateRequest();
updateRequest.setId(a1Node.getId());
updateRequest.setName("a1-a1");
//无法拿到当前用户的projectID 所以需要传入
mockMvc.perform(MockMvcRequestBuilders.post(URL_MODULE_UPDATE)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, project.getId())
.content(JSON.toJSONString(updateRequest))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
preliminaryTreeNodes = this.getDebugModuleTreeNode();
checkLog(a1Node.getId(), OperationLogType.UPDATE, URL_MODULE_UPDATE);
//校验权限
ApiDebugModuleExample example = new ApiDebugModuleExample();
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andNameEqualTo("defaultProject");
List<ApiDebugModule> apiDebugModules = apiDebugModuleMapper.selectByExample(example);
assert CollectionUtils.isNotEmpty(apiDebugModules);
updateRequest = new DebugModuleUpdateRequest();
updateRequest.setId(apiDebugModules.get(0).getId());
updateRequest.setName("default-update-Project");
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_READ_UPDATE, URL_MODULE_UPDATE, updateRequest);
}
@Test
@Order(5)
public void updateModuleTestError() throws Exception {
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1-a1");
assert a1Node != null;
//反例-参数校验
DebugModuleUpdateRequest updateRequest = new DebugModuleUpdateRequest();
this.requestPost(URL_MODULE_UPDATE, updateRequest).andExpect(BAD_REQUEST_MATCHER);
//参数名称带有特殊字符
updateRequest = new DebugModuleUpdateRequest();
updateRequest.setId(a1Node.getId());
updateRequest.setName("a1/a2");
this.requestPost(URL_MODULE_UPDATE, updateRequest).andExpect(BAD_REQUEST_MATCHER);
//id不存在
updateRequest = new DebugModuleUpdateRequest();
updateRequest.setId(IDGenerator.nextStr());
updateRequest.setName(IDGenerator.nextStr());
this.requestPost(URL_MODULE_UPDATE, updateRequest).andExpect(ERROR_REQUEST_MATCHER);
//名称重复 a1-a1改为a1-b1
updateRequest = new DebugModuleUpdateRequest();
updateRequest.setId(a1Node.getId());
updateRequest.setName("a1-b1");
this.requestPost(URL_MODULE_UPDATE, updateRequest).andExpect(ERROR_REQUEST_MATCHER);
}
@Test
@Order(6)
public void moveTest() throws Exception {
this.preliminaryData();
/*
*默认节点
|
·a1 +
| |
| ·a1-b1 +
| | |
| | ·a1-b1-c1
| |
| *a1-a1 +创建的时候是a1通过修改改为a1-a1
| |
| ·a1-a1-c1
|
·a2
|
·a3
*/
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = getNodeByName(preliminaryTreeNodes, "a2");
BaseTreeNode a3Node = getNodeByName(preliminaryTreeNodes, "a3");
BaseTreeNode a1a1Node = getNodeByName(preliminaryTreeNodes, "a1-a1");
BaseTreeNode a1b1Node = getNodeByName(preliminaryTreeNodes, "a1-b1");
//父节点内移动-移动到首位 a1挪到a3后面
NodeMoveRequest request = new NodeMoveRequest();
{
assert a1Node != null;
request.setDragNodeId(a1Node.getId());
assert a3Node != null;
request.setDropNodeId(a3Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1Node.getId(), null, false);
}
//父节点内移动-移动到末位 在上面的基础上a1挪到a2上面
{
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
assert a2Node != null;
request.setDropNodeId(a2Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1Node.getId(), a2Node.getId(), null, false);
}
//父节点内移动-移动到中位 a1移动到a2-a3中间
{
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a1Node.getId(), a3Node.getId(), false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1Node.getId(), a2Node.getId(), null, false);
}
//跨节点移动-移动到首位 a3移动到a1-b1前面然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1b1Node.getId(), null, false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到末尾 a3移动到a1-a1后面然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
assert a1a1Node != null;
request.setDropNodeId(a1a1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1a1Node.getId(), a3Node.getId(), null, false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到中位 a3移动到a1-b1和a1-a1中间然后移动回来;
{
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1b1Node.getId(), a3Node.getId(), a1a1Node.getId(), false);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//父节点内移动-a3移动到首位pos小于2是否触发计算函数 先手动更改a1的pos为2然后移动a3到a1前面
{
//更改pos
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(a1Node.getId());
updateModule.setPos(2);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1Node.getId(), null, true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//父节点内移动-移动到中位前后节点pos差不大于2是否触发计算函数在上面的 a3-a1-a2的基础上 先手动更改a1pos为3*64a2的pos为3*64+2然后移动a3到a1和a2中间
{
//更改pos
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(a1Node.getId());
updateModule.setPos(3 * 64);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
updateModule.setId(a2Node.getId());
updateModule.setPos(3 * 64 + 2);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1Node.getId(), a3Node.getId(), a2Node.getId(), true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到首位pos小于2是否触发计算函数先手动更改a1-b1的pos为2然后移动a3到a1-b1前面最后再移动回来
{
//更改pos
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(a1b1Node.getId());
updateModule.setPos(2);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1b1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a3Node.getId(), a1b1Node.getId(), null, true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//跨节点移动-移动到中位前后节点pos差不大于2是否触发计算函数先手动更改a1-a1的pos为a1-b1+2然后移动a3到a1-a1前面最后再移动回来
{
//更改pos
ApiDebugModule updateModule = new ApiDebugModule();
updateModule.setId(a1b1Node.getId());
updateModule.setPos(3 * 64);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
updateModule.setId(a1a1Node.getId());
updateModule.setPos(3 * 64 + 2);
apiDebugModuleMapper.updateByPrimaryKeySelective(updateModule);
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a1a1Node.getId());
request.setDropPosition(-1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a1b1Node.getId(), a3Node.getId(), a1a1Node.getId(), true);
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
//移动到没有子节点的节点下 a3移动到a2下
{
//开始移动
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(0);
this.requestPostWithOk(URL_MODULE_MOVE, request);
ApiDebugModule a3Module = apiDebugModuleMapper.selectByPrimaryKey(a3Node.getId());
Assertions.assertEquals(a3Module.getParentId(), a2Node.getId());
//移动回去
request = new NodeMoveRequest();
request.setDragNodeId(a3Node.getId());
request.setDropNodeId(a2Node.getId());
request.setDropPosition(1);
this.requestPostWithOk(URL_MODULE_MOVE, request);
this.checkModulePos(a2Node.getId(), a3Node.getId(), null, false);
}
checkLog(a1Node.getId(), OperationLogType.UPDATE, URL_MODULE_MOVE);
checkLog(a3Node.getId(), OperationLogType.UPDATE, URL_MODULE_MOVE);
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_READ_UPDATE, URL_MODULE_MOVE, request);
}
@Test
@Order(7)
public void moveTestError() throws Exception {
this.preliminaryData();
BaseTreeNode a1Node = getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = getNodeByName(preliminaryTreeNodes, "a2");
//drag节点为空
NodeMoveRequest request = new NodeMoveRequest();
request.setDragNodeId(null);
assert a1Node != null;
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_MOVE, request).andExpect(BAD_REQUEST_MATCHER);
//drag节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(IDGenerator.nextStr());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_MOVE, request).andExpect(ERROR_REQUEST_MATCHER);
//drop节点为空
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(null);
request.setDropPosition(1);
this.requestPost(URL_MODULE_MOVE, request).andExpect(BAD_REQUEST_MATCHER);
//drop节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(IDGenerator.nextStr());
request.setDropPosition(1);
this.requestPost(URL_MODULE_MOVE, request).andExpect(ERROR_REQUEST_MATCHER);
//position为0的时候节点不存在
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(IDGenerator.nextStr());
request.setDropPosition(0);
this.requestPost(URL_MODULE_MOVE, request).andExpect(ERROR_REQUEST_MATCHER);
//dragNode和dropNode一样
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
request.setDropNodeId(a1Node.getId());
request.setDropPosition(1);
this.requestPost(URL_MODULE_MOVE, request).andExpect(ERROR_REQUEST_MATCHER);
//position不是-1 0 1
request = new NodeMoveRequest();
request.setDragNodeId(a1Node.getId());
assert a2Node != null;
request.setDropNodeId(a2Node.getId());
request.setDropPosition(4);
this.requestPost(URL_MODULE_MOVE, request).andExpect(ERROR_REQUEST_MATCHER);
}
@Test
@Order(8)
public void TestModuleCountSuccess() throws Exception {
this.preliminaryData();
ApiDebugRequest request = new ApiDebugRequest() {{
this.setProtocol("HTTP");
}};
MvcResult moduleCountMvcResult = this.requestPostWithOkAndReturn(URL_FILE_MODULE_COUNT, request);
Map<String, Integer> moduleCountResult = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(moduleCountMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
Map.class);
Assertions.assertTrue(moduleCountResult.containsKey("all"));
requestPostPermissionTest(PermissionConstants.PROJECT_API_DEBUG_READ, URL_FILE_MODULE_COUNT, request);
}
@Test
@Order(8)
public void TestModuleCountError() throws Exception {
ApiDebugRequest request = new ApiDebugRequest();
request.setProtocol(null);
this.requestPost(URL_FILE_MODULE_COUNT, request).andExpect(BAD_REQUEST_MATCHER);
}
@Test
@Order(10)
public void deleteModuleTestSuccess() throws Exception {
this.preliminaryData();
// 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点
BaseTreeNode a1b1Node = getNodeByName(this.getDebugModuleTreeNode(), "a1-b1");
assert a1b1Node != null;
this.requestGetWithOk(String.format(URL_MODULE_DELETE, a1b1Node.getId()));
this.checkModuleIsEmpty(a1b1Node.getId());
checkLog(a1b1Node.getId(), OperationLogType.DELETE, URL_MODULE_DELETE);
// 删除有文件的节点 a1-a1 检查是否级联删除根节点
BaseTreeNode a1a1Node = getNodeByName(this.getDebugModuleTreeNode(), "a1-a1");
assert a1a1Node != null;
this.requestGetWithOk(String.format(URL_MODULE_DELETE, a1a1Node.getId()));
this.checkModuleIsEmpty(a1a1Node.getId());
checkLog(a1a1Node.getId(), OperationLogType.DELETE, URL_MODULE_DELETE);
//删除不存在的节点
this.requestGetWithOk(String.format(URL_MODULE_DELETE, IDGenerator.nextNum()));
// 测试删除根节点
this.requestGetWithOk(String.format(URL_MODULE_DELETE, ModuleConstants.DEFAULT_NODE_ID));
//service层判断测试删除空集合
apiDebugModuleService.deleteModule(new ArrayList<>());
//校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEBUG_READ_DELETE, String.format(URL_MODULE_DELETE, IDGenerator.nextNum()));
}
private List<BaseTreeNode> getDebugModuleTreeNode() throws Exception {
MvcResult result = this.requestGetWithOkAndReturn(String.format(URL_MODULE_TREE, ModuleConstants.NODE_PROTOCOL_HTTP));
String returnData = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
return JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BaseTreeNode.class);
}
private void preliminaryData() throws Exception {
if (CollectionUtils.isEmpty(preliminaryTreeNodes)) {
/*
这里需要获取修改过的树的结构期望的最终结构是这样的*为测试用例中挂载文件的节点 · 为空节点
*默认节点
|
·a1 +
| |
| ·a1-b1 +
| | |
| | ·a1-b1-c1
| |
| *a1-a1 +创建的时候是a1通过修改改为a1-a1
| | |
| | ·a1-a1-c1
|
·a2
|
·a3
*/
this.updateModuleTestSuccess();
}
}
private void checkModuleIsEmpty(String id) {
ApiDebugModuleExample example = new ApiDebugModuleExample();
example.createCriteria().andParentIdEqualTo(id);
Assertions.assertEquals(0, apiDebugModuleMapper.countByExample(example));
ApiDebugExample apiDebugExample = new ApiDebugExample();
example = new ApiDebugModuleExample();
example.createCriteria().andIdEqualTo(id);
Assertions.assertEquals(0, apiDebugModuleMapper.countByExample(example));
apiDebugExample.createCriteria().andModuleIdEqualTo(id);
Assertions.assertEquals(0, apiDebugMapper.countByExample(apiDebugExample));
}
private void checkModulePos(String firstNode, String secondNode, String thirdNode, boolean isRecalculate) {
ApiDebugModule firstModule = apiDebugModuleMapper.selectByPrimaryKey(firstNode);
ApiDebugModule secondModule = apiDebugModuleMapper.selectByPrimaryKey(secondNode);
ApiDebugModule thirdModule = null;
Assertions.assertTrue(firstModule.getPos() < secondModule.getPos());
if (StringUtils.isNotBlank(thirdNode)) {
thirdModule = apiDebugModuleMapper.selectByPrimaryKey(thirdNode);
Assertions.assertTrue(secondModule.getPos() < thirdModule.getPos());
}
if (isRecalculate) {
int limitPos = 64;
Assertions.assertEquals(0, firstModule.getPos() % limitPos);
Assertions.assertEquals(0, secondModule.getPos() % limitPos);
if (thirdModule != null) {
Assertions.assertEquals(0, thirdModule.getPos() % limitPos);
}
}
}
}

View File

@ -26,6 +26,9 @@ spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1 spring.datasource.hikari.connection-test-query=SELECT 1
# 单元测试初始化权限 sql
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath*:dml/init_permission_test.sql
# #
# spring.kafka # spring.kafka
spring.kafka.bootstrap-servers=${embedded.kafka.brokerList} spring.kafka.bootstrap-servers=${embedded.kafka.brokerList}
@ -82,6 +85,6 @@ minio.endpoint=http://${embedded.minio.host}:${embedded.minio.port}
minio.access-key=${embedded.minio.accessKey} minio.access-key=${embedded.minio.accessKey}
minio.secret-key=${embedded.minio.secretKey} minio.secret-key=${embedded.minio.secretKey}
logging.level.org.springframework.jdbc.core=info logging.level.org.springframework.jdbc.core=debug
logging.level.io.metersphere.sdk.mapper=info logging.level.io.metersphere.sdk.mapper=debug
logging.level.io.metersphere.project.mapper=info logging.level.io.metersphere.project.mapper=debug

View File

@ -0,0 +1,14 @@
-- 初始化用于权限测试的组织用户
INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source,
last_project_id, create_user, update_user, deleted)
VALUES ('PROJECT', 'PROJECT', 'PROJECT@fit2cloud.com', MD5('metersphere'),
UNIX_TIMESTAMP() * 1000,
UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false);
-- 初始化一个用于权限测试的用户组,这里默认使用 PROJECT 作为ID如果是组织和项目级别类似便于根据权限的前缀找到对应测试的用户组
INSERT INTO user_role (id, name, description, internal, type, create_time, update_time, create_user, scope_id)
VALUES ('PROJECT', '项目级别权限校验', '', 1, 'PROJECT', 1620674220005, 1620674220000, 'admin', 'global');
-- 初始化用户和组的关系
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user)
SELECT 'PROJECT', 'PROJECT', 'PROJECT', id, organization_id, 1684747668375, 'admin' FROM project WHERE num = 100001;

View File

@ -5,7 +5,9 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@ -26,6 +28,9 @@ public class BaseTreeNode {
@Schema(description = "子节点") @Schema(description = "子节点")
private List<BaseTreeNode> children = new ArrayList<>(); private List<BaseTreeNode> children = new ArrayList<>();
@Schema(description = "附加信息")
private Map<String, String> attachInfo = new HashMap<>();
@Schema(description = "节点资源数量(多数情况下不会随着节点信息返回,视接口而定)") @Schema(description = "节点资源数量(多数情况下不会随着节点信息返回,视接口而定)")
private long count = 0; private long count = 0;
@ -45,4 +50,8 @@ public class BaseTreeNode {
public void addChild(BaseTreeNode node) { public void addChild(BaseTreeNode node) {
children.add(node); children.add(node);
} }
public void putAttachInfo(String key, String value) {
attachInfo.put(key, value);
}
} }

View File

@ -97,4 +97,7 @@ public class OperationLogModule {
//用例 //用例
public static final String FUNCTIONAL_CASE = "FUNCTIONAL_CASE"; public static final String FUNCTIONAL_CASE = "FUNCTIONAL_CASE";
//接口调试
public static final String API_DEBUG = "API_DEBUG";
} }