feat(用例管理): 创建用例接口
This commit is contained in:
parent
1d6a8b4141
commit
b6d9a1214d
|
@ -42,7 +42,7 @@ public class FunctionalCase implements Serializable {
|
|||
@Size(min = 1, max = 255, message = "{functional_case.name.length_range}", groups = {Created.class, Updated.class})
|
||||
private String name;
|
||||
|
||||
@Schema(description = "评审状态:未开始/进行中/已完成/已结束", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Schema(description = "评审状态:未评审/评审中/通过/不通过/重新提审", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.review_status.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 64, message = "{functional_case.review_status.length_range}", groups = {Created.class, Updated.class})
|
||||
private String reviewStatus;
|
||||
|
|
|
@ -25,16 +25,12 @@ public class FunctionalCaseCustomField implements Serializable {
|
|||
@Schema(description = "字段值")
|
||||
private String value;
|
||||
|
||||
@Schema(description = "富文本类型字段值")
|
||||
private String textValue;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public enum Column {
|
||||
caseId("case_id", "caseId", "VARCHAR", false),
|
||||
fieldId("field_id", "fieldId", "VARCHAR", false),
|
||||
value("value", "value", "VARCHAR", true),
|
||||
textValue("text_value", "textValue", "LONGVARCHAR", false);
|
||||
value("value", "value", "VARCHAR", true);
|
||||
|
||||
private static final String BEGINNING_DELIMITER = "`";
|
||||
|
||||
|
|
|
@ -16,22 +16,16 @@ public interface FunctionalCaseCustomFieldMapper {
|
|||
|
||||
int insertSelective(FunctionalCaseCustomField record);
|
||||
|
||||
List<FunctionalCaseCustomField> selectByExampleWithBLOBs(FunctionalCaseCustomFieldExample example);
|
||||
|
||||
List<FunctionalCaseCustomField> selectByExample(FunctionalCaseCustomFieldExample example);
|
||||
|
||||
FunctionalCaseCustomField selectByPrimaryKey(@Param("caseId") String caseId, @Param("fieldId") String fieldId);
|
||||
|
||||
int updateByExampleSelective(@Param("record") FunctionalCaseCustomField record, @Param("example") FunctionalCaseCustomFieldExample example);
|
||||
|
||||
int updateByExampleWithBLOBs(@Param("record") FunctionalCaseCustomField record, @Param("example") FunctionalCaseCustomFieldExample example);
|
||||
|
||||
int updateByExample(@Param("record") FunctionalCaseCustomField record, @Param("example") FunctionalCaseCustomFieldExample example);
|
||||
|
||||
int updateByPrimaryKeySelective(FunctionalCaseCustomField record);
|
||||
|
||||
int updateByPrimaryKeyWithBLOBs(FunctionalCaseCustomField record);
|
||||
|
||||
int updateByPrimaryKey(FunctionalCaseCustomField record);
|
||||
|
||||
int batchInsert(@Param("list") List<FunctionalCaseCustomField> list);
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
<id column="field_id" jdbcType="VARCHAR" property="fieldId" />
|
||||
<result column="value" jdbcType="VARCHAR" property="value" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.functional.domain.FunctionalCaseCustomField">
|
||||
<result column="text_value" jdbcType="LONGVARCHAR" property="textValue" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
<foreach collection="oredCriteria" item="criteria" separator="or">
|
||||
|
@ -70,25 +67,6 @@
|
|||
<sql id="Base_Column_List">
|
||||
case_id, field_id, `value`
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
text_value
|
||||
</sql>
|
||||
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomFieldExample" resultMap="ResultMapWithBLOBs">
|
||||
select
|
||||
<if test="distinct">
|
||||
distinct
|
||||
</if>
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from functional_case_custom_field
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByExample" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomFieldExample" resultMap="BaseResultMap">
|
||||
select
|
||||
<if test="distinct">
|
||||
|
@ -103,11 +81,9 @@
|
|||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectByPrimaryKey" parameterType="map" resultMap="ResultMapWithBLOBs">
|
||||
<select id="selectByPrimaryKey" parameterType="map" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
,
|
||||
<include refid="Blob_Column_List" />
|
||||
from functional_case_custom_field
|
||||
where case_id = #{caseId,jdbcType=VARCHAR}
|
||||
and field_id = #{fieldId,jdbcType=VARCHAR}
|
||||
|
@ -124,10 +100,10 @@
|
|||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomField">
|
||||
insert into functional_case_custom_field (case_id, field_id, `value`,
|
||||
text_value)
|
||||
values (#{caseId,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR},
|
||||
#{textValue,jdbcType=LONGVARCHAR})
|
||||
insert into functional_case_custom_field (case_id, field_id, `value`
|
||||
)
|
||||
values (#{caseId,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{value,jdbcType=VARCHAR}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomField">
|
||||
insert into functional_case_custom_field
|
||||
|
@ -141,9 +117,6 @@
|
|||
<if test="value != null">
|
||||
`value`,
|
||||
</if>
|
||||
<if test="textValue != null">
|
||||
text_value,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="caseId != null">
|
||||
|
@ -155,9 +128,6 @@
|
|||
<if test="value != null">
|
||||
#{value,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="textValue != null">
|
||||
#{textValue,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomFieldExample" resultType="java.lang.Long">
|
||||
|
@ -178,24 +148,11 @@
|
|||
<if test="record.value != null">
|
||||
`value` = #{record.value,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.textValue != null">
|
||||
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExampleWithBLOBs" parameterType="map">
|
||||
update functional_case_custom_field
|
||||
set case_id = #{record.caseId,jdbcType=VARCHAR},
|
||||
field_id = #{record.fieldId,jdbcType=VARCHAR},
|
||||
`value` = #{record.value,jdbcType=VARCHAR},
|
||||
text_value = #{record.textValue,jdbcType=LONGVARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExample" parameterType="map">
|
||||
update functional_case_custom_field
|
||||
set case_id = #{record.caseId,jdbcType=VARCHAR},
|
||||
|
@ -211,20 +168,10 @@
|
|||
<if test="value != null">
|
||||
`value` = #{value,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="textValue != null">
|
||||
text_value = #{textValue,jdbcType=LONGVARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
where case_id = #{caseId,jdbcType=VARCHAR}
|
||||
and field_id = #{fieldId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomField">
|
||||
update functional_case_custom_field
|
||||
set `value` = #{value,jdbcType=VARCHAR},
|
||||
text_value = #{textValue,jdbcType=LONGVARCHAR}
|
||||
where case_id = #{caseId,jdbcType=VARCHAR}
|
||||
and field_id = #{fieldId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.functional.domain.FunctionalCaseCustomField">
|
||||
update functional_case_custom_field
|
||||
set `value` = #{value,jdbcType=VARCHAR}
|
||||
|
@ -233,11 +180,11 @@
|
|||
</update>
|
||||
<insert id="batchInsert" parameterType="map">
|
||||
insert into functional_case_custom_field
|
||||
(case_id, field_id, `value`, text_value)
|
||||
(case_id, field_id, `value`)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.caseId,jdbcType=VARCHAR}, #{item.fieldId,jdbcType=VARCHAR}, #{item.value,jdbcType=VARCHAR},
|
||||
#{item.textValue,jdbcType=LONGVARCHAR})
|
||||
(#{item.caseId,jdbcType=VARCHAR}, #{item.fieldId,jdbcType=VARCHAR}, #{item.value,jdbcType=VARCHAR}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
<insert id="batchInsertSelective" parameterType="map">
|
||||
|
@ -259,9 +206,6 @@
|
|||
<if test="'value'.toString() == column.value">
|
||||
#{item.value,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="'text_value'.toString() == column.value">
|
||||
#{item.textValue,jdbcType=LONGVARCHAR}
|
||||
</if>
|
||||
</foreach>
|
||||
)
|
||||
</foreach>
|
||||
|
|
|
@ -8,13 +8,13 @@ CREATE TABLE IF NOT EXISTS functional_case(
|
|||
`project_id` VARCHAR(50) NOT NULL COMMENT '项目ID' ,
|
||||
`template_id` VARCHAR(50) NOT NULL COMMENT '模板ID' ,
|
||||
`name` VARCHAR(255) NOT NULL COMMENT '名称' ,
|
||||
`review_status` VARCHAR(64) NOT NULL DEFAULT 'PREPARE' COMMENT '评审状态:未开始/进行中/已完成/已结束' ,
|
||||
`review_status` VARCHAR(64) NOT NULL DEFAULT 'UN_REVIEWED' COMMENT '评审状态:未评审/评审中/通过/不通过/重新提审' ,
|
||||
`tags` VARCHAR(1000) COMMENT '标签(JSON)' ,
|
||||
`case_edit_type` VARCHAR(50) NOT NULL DEFAULT 'STEP' COMMENT '编辑模式:步骤模式/文本模式' ,
|
||||
`pos` BIGINT NOT NULL DEFAULT 0 COMMENT '自定义排序,间隔5000' ,
|
||||
`version_id` VARCHAR(50) NOT NULL COMMENT '版本ID' ,
|
||||
`ref_id` VARCHAR(50) NOT NULL COMMENT '指向初始版本ID' ,
|
||||
`last_execute_result` VARCHAR(64) NOT NULL DEFAULT 'PREPARE' COMMENT '最近的执行结果:未执行/通过/失败/阻塞/跳过' ,
|
||||
`last_execute_result` VARCHAR(64) NOT NULL DEFAULT 'UN_EXECUTED' COMMENT '最近的执行结果:未执行/通过/失败/阻塞/跳过' ,
|
||||
`deleted` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否在回收站:0-否,1-是' ,
|
||||
`public_case` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否是公共用例:0-否,1-是' ,
|
||||
`latest` BIT(1) NOT NULL DEFAULT 0 COMMENT '是否为最新版本:0-否,1-是' ,
|
||||
|
|
|
@ -588,9 +588,8 @@ INSERT INTO message_task_blob(id, template) VALUES (@schedule_close_id, 'message
|
|||
|
||||
|
||||
-- 初始化定时任务数据
|
||||
SET @load_report_id = UUID_SHORT();
|
||||
INSERT INTO schedule(`id`, `key`, `type`, `value`, `job`, `enable`, `resource_id`, `create_user`, `create_time`, `update_time`, `project_id`, `name`, `config`)
|
||||
VALUES (@load_report_id, '100001100001', 'CRON', '0 0 2 * * ?', 'io.metersphere.project.job.CleanUpReportJob', true, '100001100001', 'admin', unix_timestamp() * 1000, unix_timestamp() * 1000, '100001100001', 'Clean Report Job', NULL);
|
||||
VALUES (UUID_SHORT(), '100001100001', 'CRON', '0 0 2 * * ?', 'io.metersphere.project.job.CleanUpReportJob', true, '100001100001', 'admin', unix_timestamp() * 1000, unix_timestamp() * 1000, '100001100001', 'Clean Report Job', NULL);
|
||||
|
||||
-- 初始化默认项目版本配置项
|
||||
INSERT INTO project_application (`project_id`, `type`, `type_value`) VALUES ('100001100001', 'VERSION_ENABLE', 'FALSE');
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package io.metersphere.sdk.constants;
|
||||
|
||||
public enum FunctionalCaseExecuteResult {
|
||||
UN_EXECUTED,
|
||||
PASSED,
|
||||
FAILED,
|
||||
BLOCKED,
|
||||
SKIPPED
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.sdk.constants;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
|
||||
public enum FunctionalCaseReviewStatus {
|
||||
UN_REVIEWED,
|
||||
UNDER_REVIEWED,
|
||||
PASS,
|
||||
UN_PASS,
|
||||
RE_REVIEWED
|
||||
}
|
|
@ -207,4 +207,10 @@ public class PermissionConstants {
|
|||
public static final String PROJECT_TEMPLATE_UPDATE = "PROJECT_TEMPLATE:READ+UPDATE";
|
||||
public static final String PROJECT_TEMPLATE_DELETE = "PROJECT_TEMPLATE:READ+DELETE";
|
||||
/*------ end: PROJECT_TEMPLATE ------*/
|
||||
|
||||
|
||||
|
||||
/*------ start: FUNCTIONAL_CASE ------*/
|
||||
public static final String FUNCTIONAL_CASE_READ_ADD = "FUNCTIONAL_CASE:READ+ADD";
|
||||
/*------ end: FUNCTIONAL_CASE ------*/
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ public class MsFileUtils {
|
|||
public static final String PLUGIN_DIR_NAME = "plugins";
|
||||
public static final String PLUGIN_DIR = DATE_ROOT_DIR + "/" + PLUGIN_DIR_NAME;
|
||||
|
||||
public static final String FUNCTIONAL_CASE_ATTACHMENT_DIR_NAME = "functionalCaseAttachment";
|
||||
public static final String FUNCTIONAL_CASE_ATTACHMENT_DIR = DATE_ROOT_DIR + "/" + FUNCTIONAL_CASE_ATTACHMENT_DIR_NAME;
|
||||
|
||||
public static void validateFileName(String... fileNames) {
|
||||
if (fileNames != null) {
|
||||
for (String fileName : fileNames) {
|
||||
|
|
|
@ -80,6 +80,9 @@ functional_case_test.test_id.length_range=The length of the test ID must be betw
|
|||
functional_case_test.test_id.not_blank=Test ID cannot be empty
|
||||
functional_case_test.test_type.length_range=The length of the test type must be between 1 and 64
|
||||
functional_case_test.test_type.not_blank=Test type cannot be empty
|
||||
#FunctionalCaseCustomField
|
||||
functional_case_custom_field.case_id.not_blank=Case ID cannot be empty
|
||||
functional_case_custom_field.field_id.not_blank=Field ID cannot be empty
|
||||
#module:FunctionalCaseHistory
|
||||
functional_case_history.id.not_blank=ID cannot be empty
|
||||
functional_case_history.case_id.not_blank=Case ID cannot be empty
|
||||
|
@ -131,4 +134,5 @@ case_review_follow.review_id.not_blank=Review ID cannot be empty
|
|||
case_review_follow.follow_id.not_blank=follower cannot be empty
|
||||
#module:CustomFieldTestCase
|
||||
custom_field_test_case.resource_id.not_blank=Resource ID cannot be empty
|
||||
custom_field_test_case.field_id.not_blank=Field ID cannot be empty
|
||||
custom_field_test_case.field_id.not_blank=Field ID cannot be empty
|
||||
default_template_not_found=Default template not found
|
|
@ -80,6 +80,9 @@ functional_case_test.test_id.length_range=其他类型用例ID长度必须在1-5
|
|||
functional_case_test.test_id.not_blank=其他类型用例ID不能为空
|
||||
functional_case_test.test_type.length_range=用例类型长度必须在1-64之间
|
||||
functional_case_test.test_type.not_blank=用例类型不能为空
|
||||
#FunctionalCaseCustomField
|
||||
functional_case_custom_field.case_id.not_blank=功能用例ID不能为空
|
||||
functional_case_custom_field.field_id.not_blank=自定义字段ID不能为空
|
||||
#module:FunctionalCaseHistory
|
||||
functional_case_history.id.not_blank=ID不能为空
|
||||
functional_case_history.case_id.not_blank=功能用例ID不能为空
|
||||
|
@ -131,4 +134,5 @@ case_review_follow.review_id.not_blank=评审ID不能为空
|
|||
case_review_follow.follow_id.not_blank=关注人不能为空
|
||||
#module:CustomFieldTestCase
|
||||
custom_field_test_case.resource_id.not_blank=资源ID不能为空
|
||||
custom_field_test_case.field_id.not_blank=字段ID不能为空
|
||||
custom_field_test_case.field_id.not_blank=字段ID不能为空
|
||||
default_template_not_found=默认模板不存在
|
|
@ -80,6 +80,9 @@ functional_case_test.test_id.length_range=其他類型用例ID長度必須在1-5
|
|||
functional_case_test.test_id.not_blank=其他類型用例ID不能為空
|
||||
functional_case_test.test_type.length_range=用例類型長度必須在1-64之間
|
||||
functional_case_test.test_type.not_blank=用例類型不能為空
|
||||
#FunctionalCaseCustomField
|
||||
functional_case_custom_field.case_id.not_blank=功能用例ID不能爲空
|
||||
functional_case_custom_field.field_id.not_blank=自定義字段ID不能爲空
|
||||
#module:FunctionalCaseHistory
|
||||
functional_case_history.id.not_blank=ID不能為空
|
||||
functional_case_history.case_id.not_blank=功能用例ID不能爲空
|
||||
|
@ -131,4 +134,5 @@ case_review_follow.review_id.not_blank=評審ID不能為空
|
|||
case_review_follow.follow_id.not_blank=關注人不能為空
|
||||
#module:CustomFieldTestCase
|
||||
custom_field_test_case.resource_id.not_blank=資源ID不能為空
|
||||
custom_field_test_case.field_id.not_blank=字段ID不能為空
|
||||
custom_field_test_case.field_id.not_blank=字段ID不能為空
|
||||
default_template_not_found=默認模板不存在
|
|
@ -28,6 +28,14 @@
|
|||
<artifactId>metersphere-project-management</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.metersphere</groupId>
|
||||
<artifactId>metersphere-system-setting</artifactId>
|
||||
<version>${revision}</version>
|
||||
<classifier>tests</classifier>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package io.metersphere.functional.controller;
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.metersphere.functional.request.FunctionalCaseAddRequest;
|
||||
import io.metersphere.functional.service.FunctionalCaseService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.log.annotation.Log;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
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 org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Tag(name = "功能测试-功能用例")
|
||||
@RestController
|
||||
@RequestMapping("/functional/case")
|
||||
public class FunctionalCaseController {
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseService functionalCaseService;
|
||||
|
||||
|
||||
//TODO 获取模板列表 获取对应模板自定义字段
|
||||
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "功能用例-新增用例")
|
||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_ADD)
|
||||
@Log(type = OperationLogType.ADD, expression = "#msClass.addFunctionalCaseLog(#request, #files)", msClass = FunctionalCaseService.class)
|
||||
public FunctionalCase addFunctionalCase(@Validated @RequestPart("request") FunctionalCaseAddRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> files) {
|
||||
String userId = SessionUtils.getUserId();
|
||||
return functionalCaseService.addFunctionalCase(request, files, userId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.functional.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class CaseCustomsFieldDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "字段id")
|
||||
@NotBlank(message = "{functional_case_custom_field.field_id.not_blank}")
|
||||
private String fieldId;
|
||||
|
||||
@Schema(description = "自定义字段值")
|
||||
private String value;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.functional.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class FileUploadDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.functional.mapper;
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
public interface ExtFunctionalCaseMapper {
|
||||
FunctionalCase getMaxNumByProjectId(@Param("projectId") String projectId);
|
||||
|
||||
Long getPos(@Param("projectId") String projectId);
|
||||
|
||||
;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?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.functional.mapper.ExtFunctionalCaseMapper">
|
||||
|
||||
<select id="getMaxNumByProjectId" resultType="io.metersphere.functional.domain.FunctionalCase">
|
||||
SELECT
|
||||
num
|
||||
FROM
|
||||
functional_case
|
||||
WHERE
|
||||
project_id = #{projectId}
|
||||
ORDER BY
|
||||
num DESC
|
||||
LIMIT 1;
|
||||
</select>
|
||||
|
||||
|
||||
<select id="getPos" resultType="java.lang.Long">
|
||||
SELECT
|
||||
pos
|
||||
FROM
|
||||
functional_case
|
||||
WHERE
|
||||
project_id = #{projectId}
|
||||
ORDER BY
|
||||
pos DESC
|
||||
LIMIT 1;
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,76 @@
|
|||
package io.metersphere.functional.request;
|
||||
|
||||
import io.metersphere.functional.dto.CaseCustomsFieldDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class FunctionalCaseAddRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "项目id")
|
||||
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "模板id")
|
||||
@NotBlank(message = "{functional_case.template_id.not_blank}")
|
||||
private String templateId;
|
||||
|
||||
@Schema(description = "用例名称")
|
||||
@NotBlank(message = "{functional_case.name.not_blank}")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "前置条件")
|
||||
private String prerequisite;
|
||||
|
||||
@Schema(description = "编辑模式", allowableValues = {"STEP", "TEXT"})
|
||||
@NotBlank(message = "{functional_case.case_edit_type.not_blank}")
|
||||
private String caseEditType;
|
||||
|
||||
@Schema(description = "用例步骤")
|
||||
private String steps;
|
||||
|
||||
@Schema(description = "步骤描述")
|
||||
private String textDescription;
|
||||
|
||||
@Schema(description = "预期结果")
|
||||
private String expectedResult;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "是否公共用例库")
|
||||
private String publicCase;
|
||||
|
||||
|
||||
@Schema(description = "模块id")
|
||||
@NotBlank(message = "{functional_case.module_id.not_blank}")
|
||||
private String moduleId;
|
||||
|
||||
@Schema(description = "版本id")
|
||||
private String versionId;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private String tags;
|
||||
|
||||
|
||||
@Schema(description = "自定义字段集合")
|
||||
private List<CaseCustomsFieldDTO> customsFields;
|
||||
|
||||
|
||||
@Schema(description = "关联文件ID集合")
|
||||
private List<String> relateFileMetaIds = new ArrayList<>();
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package io.metersphere.functional.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class TemplateFieldsRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "模板id")
|
||||
private String templateId;
|
||||
|
||||
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
||||
private String projectId;
|
||||
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 自定义字段功能用例关系表服务实现类
|
||||
*
|
||||
* @date : 2023-5-17
|
||||
*/
|
||||
@Service
|
||||
public class CustomFieldTestCaseService {
|
||||
|
||||
}
|
|
@ -1,10 +1,85 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCaseAttachment;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
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 org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class FunctionalCaseAttachmentService {
|
||||
|
||||
@Resource
|
||||
SqlSessionFactory sqlSessionFactory;
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseAttachmentMapper functionalCaseAttachmentMapper;
|
||||
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
|
||||
/**
|
||||
* 保存本地上传文件和用例关联关系
|
||||
*
|
||||
* @param fileId
|
||||
* @param file
|
||||
* @param caseId
|
||||
* @param isLocal
|
||||
* @param userId
|
||||
*/
|
||||
public void saveCaseAttachment(String fileId, MultipartFile file, String caseId, Boolean isLocal, String userId) {
|
||||
FunctionalCaseAttachment caseAttachment = creatModule(fileId, file.getName(), file.getSize(), caseId, isLocal, userId);
|
||||
functionalCaseAttachmentMapper.insertSelective(caseAttachment);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存文件库文件与用例关联关系
|
||||
*
|
||||
* @param relateFileMetaIds
|
||||
* @param caseId
|
||||
* @param userId
|
||||
*/
|
||||
public void relateFileMeta(List<String> relateFileMetaIds, String caseId, String userId) {
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
FunctionalCaseAttachmentMapper sessionMapper = sqlSession.getMapper(FunctionalCaseAttachmentMapper.class);
|
||||
relateFileMetaIds.forEach(fileMetaId -> {
|
||||
FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileMetaId);
|
||||
FunctionalCaseAttachment caseAttachment = creatModule(fileMetadata.getId(), fileMetadata.getName(), fileMetadata.getSize(), caseId, false, userId);
|
||||
sessionMapper.insertSelective(caseAttachment);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
if (sqlSession != null && sqlSessionFactory != null) {
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
}
|
||||
}
|
||||
|
||||
private FunctionalCaseAttachment creatModule(String fileId, String fileName, long fileSize, String caseId, Boolean isLocal, String userId) {
|
||||
FunctionalCaseAttachment caseAttachment = new FunctionalCaseAttachment();
|
||||
caseAttachment.setId(IDGenerator.nextStr());
|
||||
caseAttachment.setCaseId(caseId);
|
||||
caseAttachment.setFileId(fileId);
|
||||
caseAttachment.setFileName(fileName);
|
||||
caseAttachment.setSize(fileSize);
|
||||
caseAttachment.setLocal(isLocal);
|
||||
caseAttachment.setCreateUser(userId);
|
||||
caseAttachment.setCreateTime(System.currentTimeMillis());
|
||||
return caseAttachment;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCaseCustomField;
|
||||
import io.metersphere.functional.dto.CaseCustomsFieldDTO;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class FunctionalCaseCustomFieldService {
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseCustomFieldMapper functionalCaseCustomFieldMapper;
|
||||
|
||||
/**
|
||||
* 保存 用例-自定义字段关系
|
||||
*
|
||||
* @param customsFields
|
||||
*/
|
||||
public void saveCustomField(String caseId, List<CaseCustomsFieldDTO> customsFields) {
|
||||
customsFields.forEach(customsField -> {
|
||||
FunctionalCaseCustomField customField = new FunctionalCaseCustomField();
|
||||
customField.setCaseId(caseId);
|
||||
customField.setFieldId(customsField.getFieldId());
|
||||
customField.setValue(customsField.getValue());
|
||||
functionalCaseCustomFieldMapper.insertSelective(customField);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,7 +1,174 @@
|
|||
package io.metersphere.functional.service;
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.metersphere.functional.domain.FunctionalCaseBlob;
|
||||
import io.metersphere.functional.dto.CaseCustomsFieldDTO;
|
||||
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseBlobMapper;
|
||||
import io.metersphere.functional.mapper.FunctionalCaseMapper;
|
||||
import io.metersphere.functional.request.FunctionalCaseAddRequest;
|
||||
import io.metersphere.sdk.constants.FunctionalCaseExecuteResult;
|
||||
import io.metersphere.sdk.constants.FunctionalCaseReviewStatus;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.dto.LogDTO;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.file.MinioRepository;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.MsFileUtils;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author wx
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class FunctionalCaseService {
|
||||
|
||||
public static final int ORDER_STEP = 5000;
|
||||
|
||||
@Resource
|
||||
private MinioRepository minioRepository;
|
||||
|
||||
@Resource
|
||||
private ExtFunctionalCaseMapper extFunctionalCaseMapper;
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseMapper functionalCaseMapper;
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseBlobMapper functionalCaseBlobMapper;
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseCustomFieldService functionalCaseCustomFieldService;
|
||||
|
||||
@Resource
|
||||
private FunctionalCaseAttachmentService functionalCaseAttachmentService;
|
||||
|
||||
|
||||
public FunctionalCase addFunctionalCase(FunctionalCaseAddRequest request, List<MultipartFile> files, String userId) {
|
||||
String caseId = IDGenerator.nextStr();
|
||||
//添加功能用例
|
||||
FunctionalCase functionalCase = addTestCase(caseId, request, userId);
|
||||
|
||||
//上传文件
|
||||
if (CollectionUtils.isNotEmpty(files)) {
|
||||
uploadFile(request, caseId, files, true, userId);
|
||||
}
|
||||
|
||||
//关联附件
|
||||
if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) {
|
||||
functionalCaseAttachmentService.relateFileMeta(request.getRelateFileMetaIds(), caseId, userId);
|
||||
}
|
||||
return functionalCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加功能用例
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private FunctionalCase addTestCase(String caseId, FunctionalCaseAddRequest request, String userId) {
|
||||
FunctionalCase functionalCase = new FunctionalCase();
|
||||
BeanUtils.copyBean(functionalCase, request);
|
||||
functionalCase.setId(caseId);
|
||||
functionalCase.setNum(getNextNum(request.getProjectId()));
|
||||
functionalCase.setReviewStatus(FunctionalCaseReviewStatus.UN_REVIEWED.name());
|
||||
functionalCase.setPos(getNextOrder(request.getProjectId()));
|
||||
functionalCase.setRefId(caseId);
|
||||
functionalCase.setLastExecuteResult(FunctionalCaseExecuteResult.UN_EXECUTED.name());
|
||||
functionalCase.setLatest(true);
|
||||
functionalCase.setCreateUser(userId);
|
||||
functionalCase.setCreateTime(System.currentTimeMillis());
|
||||
functionalCase.setUpdateTime(System.currentTimeMillis());
|
||||
functionalCase.setVersionId(StringUtils.defaultIfBlank(request.getVersionId(), "v1.0.0"));
|
||||
functionalCaseMapper.insertSelective(functionalCase);
|
||||
//附属表
|
||||
FunctionalCaseBlob functionalCaseBlob = new FunctionalCaseBlob();
|
||||
functionalCaseBlob.setId(caseId);
|
||||
BeanUtils.copyBean(functionalCaseBlob, request);
|
||||
functionalCaseBlobMapper.insertSelective(functionalCaseBlob);
|
||||
//保存自定义字段
|
||||
List<CaseCustomsFieldDTO> customsFields = request.getCustomsFields();
|
||||
if (CollectionUtils.isNotEmpty(customsFields)) {
|
||||
functionalCaseCustomFieldService.saveCustomField(caseId, customsFields);
|
||||
}
|
||||
return functionalCase;
|
||||
}
|
||||
|
||||
public Long getNextOrder(String projectId) {
|
||||
Long pos = extFunctionalCaseMapper.getPos(projectId);
|
||||
return (pos == null ? 0 : pos) + ORDER_STEP;
|
||||
}
|
||||
|
||||
public int getNextNum(String projectId) {
|
||||
//TODO 获取下一个num方法(暂时直接查询数据库)
|
||||
FunctionalCase testCase = extFunctionalCaseMapper.getMaxNumByProjectId(projectId);
|
||||
if (testCase == null || testCase.getNum() == null) {
|
||||
return 100001;
|
||||
} else {
|
||||
return Optional.ofNullable(testCase.getNum() + 1).orElse(100001);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能用例上传附件
|
||||
*
|
||||
* @param request
|
||||
* @param files
|
||||
*/
|
||||
public void uploadFile(FunctionalCaseAddRequest request, String caseId, List<MultipartFile> files, Boolean isLocal, String userId) {
|
||||
files.forEach(file -> {
|
||||
String fileId = IDGenerator.nextStr();
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFileName(file.getName());
|
||||
fileRequest.setProjectId(request.getProjectId());
|
||||
fileRequest.setResourceId(MsFileUtils.FUNCTIONAL_CASE_ATTACHMENT_DIR + fileId);
|
||||
fileRequest.setStorage(StorageType.MINIO.name());
|
||||
try {
|
||||
minioRepository.saveFile(file, fileRequest);
|
||||
} catch (Exception e) {
|
||||
throw new MSException("save file error");
|
||||
}
|
||||
functionalCaseAttachmentService.saveCaseAttachment(fileId, file, caseId, isLocal, userId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增用例 日志
|
||||
*
|
||||
* @param requests
|
||||
* @param files
|
||||
* @return
|
||||
*/
|
||||
public LogDTO addFunctionalCaseLog(FunctionalCaseAddRequest requests, List<MultipartFile> files) {
|
||||
LogDTO dto = new LogDTO(
|
||||
requests.getProjectId(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
OperationLogType.ADD.name(),
|
||||
OperationLogModule.FUNCTIONAL_CASE,
|
||||
requests.getName());
|
||||
|
||||
dto.setPath("/functional/case/add");
|
||||
dto.setMethod(HttpMethodConstants.POST.name());
|
||||
dto.setOriginalValue(JSON.toJSONBytes(requests));
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package io.metersphere.functional.controller;
|
||||
|
||||
import io.metersphere.functional.dto.CaseCustomsFieldDTO;
|
||||
import io.metersphere.functional.request.FunctionalCaseAddRequest;
|
||||
import io.metersphere.functional.utils.FileBaseUtils;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
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.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@AutoConfigureMockMvc
|
||||
public class FunctionalCaseControllerTests extends BaseTest {
|
||||
|
||||
public static final String FUNCTIONAL_CASE_URL = "/functional/case/add";
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@Sql(scripts = {"/dml/init_file_metadata_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
public void testTestPlanShare() throws Exception {
|
||||
//新增
|
||||
FunctionalCaseAddRequest request = creatFunctionalCase();
|
||||
LinkedMultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||
List<MockMultipartFile> files = new ArrayList<>();
|
||||
paramMap.add("request", JSON.toJSONString(request));
|
||||
paramMap.add("files", files);
|
||||
MvcResult mvcResult = this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_URL, paramMap);
|
||||
// 获取返回值
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||
// 返回请求正常
|
||||
Assertions.assertNotNull(resultHolder);
|
||||
|
||||
//设置自定义字段
|
||||
List<CaseCustomsFieldDTO> dtoList = creatCustomsFields();
|
||||
request.setCustomsFields(dtoList);
|
||||
|
||||
//设置文件
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.JPG")).getPath();
|
||||
MockMultipartFile file = new MockMultipartFile("file", "file_re-upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, FileBaseUtils.getFileBytes(filePath));
|
||||
files.add(file);
|
||||
|
||||
//设置关联文件
|
||||
request.setRelateFileMetaIds(Arrays.asList("relate_file_meta_id_1", "relate_file_meta_id_2"));
|
||||
paramMap = new LinkedMultiValueMap<>();
|
||||
paramMap.add("request", JSON.toJSONString(request));
|
||||
paramMap.add("files", files);
|
||||
|
||||
this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_URL, paramMap);
|
||||
}
|
||||
|
||||
private List<CaseCustomsFieldDTO> creatCustomsFields() {
|
||||
List<CaseCustomsFieldDTO> list = new ArrayList<>();
|
||||
CaseCustomsFieldDTO customsFieldDTO = new CaseCustomsFieldDTO();
|
||||
customsFieldDTO.setFieldId("customs_field_id_1");
|
||||
customsFieldDTO.setValue("customs_field_value_1");
|
||||
list.add(customsFieldDTO);
|
||||
return list;
|
||||
}
|
||||
|
||||
private FunctionalCaseAddRequest creatFunctionalCase() {
|
||||
FunctionalCaseAddRequest functionalCaseAddRequest = new FunctionalCaseAddRequest();
|
||||
functionalCaseAddRequest.setProjectId(DEFAULT_PROJECT_ID);
|
||||
functionalCaseAddRequest.setTemplateId("default_template_id");
|
||||
functionalCaseAddRequest.setName("测试用例新增");
|
||||
functionalCaseAddRequest.setCaseEditType("STEP");
|
||||
functionalCaseAddRequest.setModuleId("default_module_id");
|
||||
return functionalCaseAddRequest;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package io.metersphere.functional.utils;
|
||||
|
||||
import io.metersphere.project.dto.FileInformationDTO;
|
||||
import io.metersphere.project.request.filemanagement.FileMetadataTableRequest;
|
||||
import io.metersphere.sdk.dto.BaseTreeNode;
|
||||
import io.metersphere.sdk.util.FilePreviewUtils;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Pager;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FileBaseUtils {
|
||||
public static BaseTreeNode getNodeByName(List<BaseTreeNode> preliminaryTreeNodes, String nodeName) {
|
||||
for (BaseTreeNode firstLevelNode : preliminaryTreeNodes) {
|
||||
if (StringUtils.equals(firstLevelNode.getName(), nodeName)) {
|
||||
return firstLevelNode;
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(firstLevelNode.getChildren())) {
|
||||
for (BaseTreeNode secondLevelNode : firstLevelNode.getChildren()) {
|
||||
if (StringUtils.equals(secondLevelNode.getName(), nodeName)) {
|
||||
return secondLevelNode;
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(secondLevelNode.getChildren())) {
|
||||
for (BaseTreeNode thirdLevelNode : secondLevelNode.getChildren()) {
|
||||
if (StringUtils.equals(thirdLevelNode.getName(), nodeName)) {
|
||||
return thirdLevelNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] getFileBytes(String filePath) {
|
||||
File file = new File(filePath);
|
||||
byte[] buffer = new byte[0];
|
||||
try (FileInputStream fi = new FileInputStream(file)) {
|
||||
buffer = new byte[(int) file.length()];
|
||||
int offset = 0;
|
||||
int numRead;
|
||||
while (offset < buffer.length
|
||||
&& (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
|
||||
offset += numRead;
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static String getFileMD5(File file) {
|
||||
if (!file.isFile()) {
|
||||
return null;
|
||||
}
|
||||
MessageDigest digest = null;
|
||||
FileInputStream in = null;
|
||||
byte buffer[] = new byte[8192];
|
||||
int len;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("MD5");
|
||||
in = new FileInputStream(file);
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
digest.update(buffer, 0, len);
|
||||
}
|
||||
BigInteger bigInt = new BigInteger(1, digest.digest());
|
||||
return bigInt.toString(16);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileMD5(byte[] bytes) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
digest.update(bytes, 0, bytes.length);
|
||||
BigInteger bigInt = new BigInteger(1, digest.digest());
|
||||
return bigInt.toString(16);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkFilePage(Pager<List<FileInformationDTO>> tableData, Map<String, Integer> moduleCount, FileMetadataTableRequest request, boolean hasData) {
|
||||
//返回值的页码和当前页码相同
|
||||
Assertions.assertEquals(tableData.getCurrent(), request.getCurrent());
|
||||
//返回的数据量不超过规定要返回的数据量相同
|
||||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(tableData.getList())).size() <= request.getPageSize());
|
||||
List<FileInformationDTO> fileInformationDTOList = JSON.parseArray(JSON.toJSONString(tableData.getList()), FileInformationDTO.class);
|
||||
for (FileInformationDTO fileInformationDTO : fileInformationDTOList) {
|
||||
if (FilePreviewUtils.isImage(fileInformationDTO.getFileType())) {
|
||||
//检查是否有预览文件
|
||||
String previewPath = fileInformationDTO.getPreviewSrc();
|
||||
File file = new File(previewPath);
|
||||
Assertions.assertTrue(file.exists());
|
||||
}
|
||||
}
|
||||
|
||||
//判断返回的节点统计总量是否和表格总量匹配
|
||||
long allResult = 0;
|
||||
for (int countByModuleId : moduleCount.values()) {
|
||||
allResult += countByModuleId;
|
||||
}
|
||||
Assertions.assertEquals(allResult, tableData.getTotal());
|
||||
Assertions.assertEquals(request.getPageSize(), tableData.getPageSize());
|
||||
if (hasData) {
|
||||
Assertions.assertTrue(allResult > 0);
|
||||
} else {
|
||||
Assertions.assertTrue(allResult == 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true
|
|||
#
|
||||
logging.file.path=/opt/metersphere/logs/metersphere
|
||||
# Hikari
|
||||
spring.datasource.url=jdbc:mysql://${embedded.mysql.host}:${embedded.mysql.port}/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
|
||||
spring.datasource.url=jdbc:mysql://${embedded.mysql.host}:${embedded.mysql.port}/test?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true&useSSL=false&sessionVariables=sql_mode=%27STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION%27
|
||||
spring.datasource.username=${embedded.mysql.user}
|
||||
spring.datasource.password=${embedded.mysql.password}
|
||||
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
INSERT INTO file_metadata(id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, tags, description, module_id, path, latest, ref_id, file_version) VALUES ('relate_file_meta_id_1', 'formItem', 'ts', 2502, 1698058347559, 1698058347559, '100001100001', 'MINIO', 'admin', 'admin', NULL, NULL, 'root', '100001100001/1127016598347779', b'1', '1127016598347779', '1127016598347779');
|
||||
INSERT INTO file_metadata(id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, tags, description, module_id, path, latest, ref_id, file_version) VALUES ('relate_file_meta_id_2', 'formItem', 'ts', 2502, 1698058347559, 1698058347559, '100001100001', 'MINIO', 'admin', 'admin', NULL, NULL, 'root', '100001100001/1127016598347779', b'1', '1127016598347779', '1127016598347779');
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
|
@ -44,7 +44,7 @@ import java.util.stream.Collectors;
|
|||
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ProjectApplicationService {
|
||||
@Resource
|
||||
private ProjectApplicationMapper projectApplicationMapper;
|
||||
|
|
|
@ -94,4 +94,7 @@ public class OperationLogModule {
|
|||
public static final String PROJECT_MANAGEMENT_MESSAGE_MANAGEMENT_ROBOT = "PROJECT_MANAGEMENT_MESSAGE_MANAGEMENT_ROBOT";
|
||||
public static final String PROJECT_TEMPLATE = "PROJECT_TEMPLATE";// 项目模板
|
||||
public static final String PROJECT_CUSTOM_FIELD = "PROJECT_CUSTOM_FIELD";// 项目字段
|
||||
|
||||
//用例
|
||||
public static final String FUNCTIONAL_CASE = "FUNCTIONAL_CASE";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue