feat(接口测试): 任务异常提示优化

--task=1016919 --user=陈建星 任务异常显示优化 https://www.tapd.cn/55049933/s/1609267
This commit is contained in:
AgAngle 2024-11-13 13:48:27 +08:00 committed by Craftsman
parent ab426e9853
commit 35a5b03343
26 changed files with 538 additions and 235 deletions

View File

@ -78,16 +78,19 @@ public class ExecTaskItem implements Serializable {
@Size(min = 1, max = 50, message = "{exec_task_item.executor.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{exec_task_item.executor.length_range}", groups = {Created.class, Updated.class})
private String executor; private String executor;
@Schema(description = "测试集ID")
private String collectionId;
@Schema(description = "删除标识", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "删除标识", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{exec_task_item.deleted.not_blank}", groups = {Created.class}) @NotNull(message = "{exec_task_item.deleted.not_blank}", groups = {Created.class})
private Boolean deleted; private Boolean deleted;
@Schema(description = "测试集ID")
private String collectionId;
@Schema(description = "用例表id") @Schema(description = "用例表id")
private String caseId; private String caseId;
@Schema(description = "异常信息")
private String errorMessage;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public enum Column { public enum Column {
@ -107,9 +110,10 @@ public class ExecTaskItem implements Serializable {
startTime("start_time", "startTime", "BIGINT", false), startTime("start_time", "startTime", "BIGINT", false),
endTime("end_time", "endTime", "BIGINT", false), endTime("end_time", "endTime", "BIGINT", false),
executor("executor", "executor", "VARCHAR", false), executor("executor", "executor", "VARCHAR", false),
deleted("deleted", "deleted", "BIT", false),
collectionId("collection_id", "collectionId", "VARCHAR", false), collectionId("collection_id", "collectionId", "VARCHAR", false),
caseId("case_id", "caseId", "VARCHAR", false); deleted("deleted", "deleted", "BIT", false),
caseId("case_id", "caseId", "VARCHAR", false),
errorMessage("error_message", "errorMessage", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`"; private static final String BEGINNING_DELIMITER = "`";

View File

@ -1204,66 +1204,6 @@ public class ExecTaskItemExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andDeletedIsNull() {
addCriterion("deleted is null");
return (Criteria) this;
}
public Criteria andDeletedIsNotNull() {
addCriterion("deleted is not null");
return (Criteria) this;
}
public Criteria andDeletedEqualTo(Boolean value) {
addCriterion("deleted =", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotEqualTo(Boolean value) {
addCriterion("deleted <>", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedGreaterThan(Boolean value) {
addCriterion("deleted >", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedGreaterThanOrEqualTo(Boolean value) {
addCriterion("deleted >=", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedLessThan(Boolean value) {
addCriterion("deleted <", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedLessThanOrEqualTo(Boolean value) {
addCriterion("deleted <=", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedIn(List<Boolean> values) {
addCriterion("deleted in", values, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotIn(List<Boolean> values) {
addCriterion("deleted not in", values, "deleted");
return (Criteria) this;
}
public Criteria andDeletedBetween(Boolean value1, Boolean value2) {
addCriterion("deleted between", value1, value2, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotBetween(Boolean value1, Boolean value2) {
addCriterion("deleted not between", value1, value2, "deleted");
return (Criteria) this;
}
public Criteria andCollectionIdIsNull() { public Criteria andCollectionIdIsNull() {
addCriterion("collection_id is null"); addCriterion("collection_id is null");
return (Criteria) this; return (Criteria) this;
@ -1334,6 +1274,66 @@ public class ExecTaskItemExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andDeletedIsNull() {
addCriterion("deleted is null");
return (Criteria) this;
}
public Criteria andDeletedIsNotNull() {
addCriterion("deleted is not null");
return (Criteria) this;
}
public Criteria andDeletedEqualTo(Boolean value) {
addCriterion("deleted =", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotEqualTo(Boolean value) {
addCriterion("deleted <>", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedGreaterThan(Boolean value) {
addCriterion("deleted >", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedGreaterThanOrEqualTo(Boolean value) {
addCriterion("deleted >=", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedLessThan(Boolean value) {
addCriterion("deleted <", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedLessThanOrEqualTo(Boolean value) {
addCriterion("deleted <=", value, "deleted");
return (Criteria) this;
}
public Criteria andDeletedIn(List<Boolean> values) {
addCriterion("deleted in", values, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotIn(List<Boolean> values) {
addCriterion("deleted not in", values, "deleted");
return (Criteria) this;
}
public Criteria andDeletedBetween(Boolean value1, Boolean value2) {
addCriterion("deleted between", value1, value2, "deleted");
return (Criteria) this;
}
public Criteria andDeletedNotBetween(Boolean value1, Boolean value2) {
addCriterion("deleted not between", value1, value2, "deleted");
return (Criteria) this;
}
public Criteria andCaseIdIsNull() { public Criteria andCaseIdIsNull() {
addCriterion("case_id is null"); addCriterion("case_id is null");
return (Criteria) this; return (Criteria) this;
@ -1403,6 +1403,76 @@ public class ExecTaskItemExample {
addCriterion("case_id not between", value1, value2, "caseId"); addCriterion("case_id not between", value1, value2, "caseId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andErrorMessageIsNull() {
addCriterion("error_message is null");
return (Criteria) this;
}
public Criteria andErrorMessageIsNotNull() {
addCriterion("error_message is not null");
return (Criteria) this;
}
public Criteria andErrorMessageEqualTo(String value) {
addCriterion("error_message =", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageNotEqualTo(String value) {
addCriterion("error_message <>", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageGreaterThan(String value) {
addCriterion("error_message >", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageGreaterThanOrEqualTo(String value) {
addCriterion("error_message >=", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageLessThan(String value) {
addCriterion("error_message <", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageLessThanOrEqualTo(String value) {
addCriterion("error_message <=", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageLike(String value) {
addCriterion("error_message like", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageNotLike(String value) {
addCriterion("error_message not like", value, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageIn(List<String> values) {
addCriterion("error_message in", values, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageNotIn(List<String> values) {
addCriterion("error_message not in", values, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageBetween(String value1, String value2) {
addCriterion("error_message between", value1, value2, "errorMessage");
return (Criteria) this;
}
public Criteria andErrorMessageNotBetween(String value1, String value2) {
addCriterion("error_message not between", value1, value2, "errorMessage");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -18,9 +18,10 @@
<result column="start_time" jdbcType="BIGINT" property="startTime" /> <result column="start_time" jdbcType="BIGINT" property="startTime" />
<result column="end_time" jdbcType="BIGINT" property="endTime" /> <result column="end_time" jdbcType="BIGINT" property="endTime" />
<result column="executor" jdbcType="VARCHAR" property="executor" /> <result column="executor" jdbcType="VARCHAR" property="executor" />
<result column="deleted" jdbcType="BIT" property="deleted" />
<result column="collection_id" jdbcType="VARCHAR" property="collectionId" /> <result column="collection_id" jdbcType="VARCHAR" property="collectionId" />
<result column="deleted" jdbcType="BIT" property="deleted" />
<result column="case_id" jdbcType="VARCHAR" property="caseId" /> <result column="case_id" jdbcType="VARCHAR" property="caseId" />
<result column="error_message" jdbcType="VARCHAR" property="errorMessage" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -83,7 +84,7 @@
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, task_id, resource_id, resource_name, task_origin, `status`, `result`, resource_pool_id, id, task_id, resource_id, resource_name, task_origin, `status`, `result`, resource_pool_id,
resource_pool_node, resource_type, project_id, organization_id, thread_id, start_time, resource_pool_node, resource_type, project_id, organization_id, thread_id, start_time,
end_time, executor, deleted, collection_id, case_id end_time, executor, collection_id, deleted, case_id, error_message
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.system.domain.ExecTaskItemExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.system.domain.ExecTaskItemExample" resultMap="BaseResultMap">
select select
@ -121,15 +122,15 @@
`result`, resource_pool_id, resource_pool_node, `result`, resource_pool_id, resource_pool_node,
resource_type, project_id, organization_id, resource_type, project_id, organization_id,
thread_id, start_time, end_time, thread_id, start_time, end_time,
executor, deleted, collection_id, executor, collection_id, deleted,
case_id) case_id, error_message)
values (#{id,jdbcType=VARCHAR}, #{taskId,jdbcType=VARCHAR}, #{resourceId,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{taskId,jdbcType=VARCHAR}, #{resourceId,jdbcType=VARCHAR},
#{resourceName,jdbcType=VARCHAR}, #{taskOrigin,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{resourceName,jdbcType=VARCHAR}, #{taskOrigin,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{result,jdbcType=VARCHAR}, #{resourcePoolId,jdbcType=VARCHAR}, #{resourcePoolNode,jdbcType=VARCHAR}, #{result,jdbcType=VARCHAR}, #{resourcePoolId,jdbcType=VARCHAR}, #{resourcePoolNode,jdbcType=VARCHAR},
#{resourceType,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{organizationId,jdbcType=VARCHAR}, #{resourceType,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{organizationId,jdbcType=VARCHAR},
#{threadId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT}, #{threadId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT},
#{executor,jdbcType=VARCHAR}, #{deleted,jdbcType=BIT}, #{collectionId,jdbcType=VARCHAR}, #{executor,jdbcType=VARCHAR}, #{collectionId,jdbcType=VARCHAR}, #{deleted,jdbcType=BIT},
#{caseId,jdbcType=VARCHAR}) #{caseId,jdbcType=VARCHAR}, #{errorMessage,jdbcType=VARCHAR})
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.ExecTaskItem"> <insert id="insertSelective" parameterType="io.metersphere.system.domain.ExecTaskItem">
insert into exec_task_item insert into exec_task_item
@ -182,15 +183,18 @@
<if test="executor != null"> <if test="executor != null">
executor, executor,
</if> </if>
<if test="deleted != null">
deleted,
</if>
<if test="collectionId != null"> <if test="collectionId != null">
collection_id, collection_id,
</if> </if>
<if test="deleted != null">
deleted,
</if>
<if test="caseId != null"> <if test="caseId != null">
case_id, case_id,
</if> </if>
<if test="errorMessage != null">
error_message,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null"> <if test="id != null">
@ -241,15 +245,18 @@
<if test="executor != null"> <if test="executor != null">
#{executor,jdbcType=VARCHAR}, #{executor,jdbcType=VARCHAR},
</if> </if>
<if test="deleted != null">
#{deleted,jdbcType=BIT},
</if>
<if test="collectionId != null"> <if test="collectionId != null">
#{collectionId,jdbcType=VARCHAR}, #{collectionId,jdbcType=VARCHAR},
</if> </if>
<if test="deleted != null">
#{deleted,jdbcType=BIT},
</if>
<if test="caseId != null"> <if test="caseId != null">
#{caseId,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR},
</if> </if>
<if test="errorMessage != null">
#{errorMessage,jdbcType=VARCHAR},
</if>
</trim> </trim>
</insert> </insert>
<select id="countByExample" parameterType="io.metersphere.system.domain.ExecTaskItemExample" resultType="java.lang.Long"> <select id="countByExample" parameterType="io.metersphere.system.domain.ExecTaskItemExample" resultType="java.lang.Long">
@ -309,15 +316,18 @@
<if test="record.executor != null"> <if test="record.executor != null">
executor = #{record.executor,jdbcType=VARCHAR}, executor = #{record.executor,jdbcType=VARCHAR},
</if> </if>
<if test="record.deleted != null">
deleted = #{record.deleted,jdbcType=BIT},
</if>
<if test="record.collectionId != null"> <if test="record.collectionId != null">
collection_id = #{record.collectionId,jdbcType=VARCHAR}, collection_id = #{record.collectionId,jdbcType=VARCHAR},
</if> </if>
<if test="record.deleted != null">
deleted = #{record.deleted,jdbcType=BIT},
</if>
<if test="record.caseId != null"> <if test="record.caseId != null">
case_id = #{record.caseId,jdbcType=VARCHAR}, case_id = #{record.caseId,jdbcType=VARCHAR},
</if> </if>
<if test="record.errorMessage != null">
error_message = #{record.errorMessage,jdbcType=VARCHAR},
</if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
@ -341,9 +351,10 @@
start_time = #{record.startTime,jdbcType=BIGINT}, start_time = #{record.startTime,jdbcType=BIGINT},
end_time = #{record.endTime,jdbcType=BIGINT}, end_time = #{record.endTime,jdbcType=BIGINT},
executor = #{record.executor,jdbcType=VARCHAR}, executor = #{record.executor,jdbcType=VARCHAR},
deleted = #{record.deleted,jdbcType=BIT},
collection_id = #{record.collectionId,jdbcType=VARCHAR}, collection_id = #{record.collectionId,jdbcType=VARCHAR},
case_id = #{record.caseId,jdbcType=VARCHAR} deleted = #{record.deleted,jdbcType=BIT},
case_id = #{record.caseId,jdbcType=VARCHAR},
error_message = #{record.errorMessage,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -396,15 +407,18 @@
<if test="executor != null"> <if test="executor != null">
executor = #{executor,jdbcType=VARCHAR}, executor = #{executor,jdbcType=VARCHAR},
</if> </if>
<if test="deleted != null">
deleted = #{deleted,jdbcType=BIT},
</if>
<if test="collectionId != null"> <if test="collectionId != null">
collection_id = #{collectionId,jdbcType=VARCHAR}, collection_id = #{collectionId,jdbcType=VARCHAR},
</if> </if>
<if test="deleted != null">
deleted = #{deleted,jdbcType=BIT},
</if>
<if test="caseId != null"> <if test="caseId != null">
case_id = #{caseId,jdbcType=VARCHAR}, case_id = #{caseId,jdbcType=VARCHAR},
</if> </if>
<if test="errorMessage != null">
error_message = #{errorMessage,jdbcType=VARCHAR},
</if>
</set> </set>
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
@ -425,16 +439,17 @@
start_time = #{startTime,jdbcType=BIGINT}, start_time = #{startTime,jdbcType=BIGINT},
end_time = #{endTime,jdbcType=BIGINT}, end_time = #{endTime,jdbcType=BIGINT},
executor = #{executor,jdbcType=VARCHAR}, executor = #{executor,jdbcType=VARCHAR},
deleted = #{deleted,jdbcType=BIT},
collection_id = #{collectionId,jdbcType=VARCHAR}, collection_id = #{collectionId,jdbcType=VARCHAR},
case_id = #{caseId,jdbcType=VARCHAR} deleted = #{deleted,jdbcType=BIT},
case_id = #{caseId,jdbcType=VARCHAR},
error_message = #{errorMessage,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
<insert id="batchInsert" parameterType="map"> <insert id="batchInsert" parameterType="map">
insert into exec_task_item insert into exec_task_item
(id, task_id, resource_id, resource_name, task_origin, `status`, `result`, resource_pool_id, (id, task_id, resource_id, resource_name, task_origin, `status`, `result`, resource_pool_id,
resource_pool_node, resource_type, project_id, organization_id, thread_id, start_time, resource_pool_node, resource_type, project_id, organization_id, thread_id, start_time,
end_time, executor, deleted, collection_id, case_id) end_time, executor, collection_id, deleted, case_id, error_message)
values values
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.taskId,jdbcType=VARCHAR}, #{item.resourceId,jdbcType=VARCHAR}, (#{item.id,jdbcType=VARCHAR}, #{item.taskId,jdbcType=VARCHAR}, #{item.resourceId,jdbcType=VARCHAR},
@ -442,8 +457,8 @@
#{item.result,jdbcType=VARCHAR}, #{item.resourcePoolId,jdbcType=VARCHAR}, #{item.resourcePoolNode,jdbcType=VARCHAR}, #{item.result,jdbcType=VARCHAR}, #{item.resourcePoolId,jdbcType=VARCHAR}, #{item.resourcePoolNode,jdbcType=VARCHAR},
#{item.resourceType,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.organizationId,jdbcType=VARCHAR}, #{item.resourceType,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.organizationId,jdbcType=VARCHAR},
#{item.threadId,jdbcType=VARCHAR}, #{item.startTime,jdbcType=BIGINT}, #{item.endTime,jdbcType=BIGINT}, #{item.threadId,jdbcType=VARCHAR}, #{item.startTime,jdbcType=BIGINT}, #{item.endTime,jdbcType=BIGINT},
#{item.executor,jdbcType=VARCHAR}, #{item.deleted,jdbcType=BIT}, #{item.collectionId,jdbcType=VARCHAR}, #{item.executor,jdbcType=VARCHAR}, #{item.collectionId,jdbcType=VARCHAR}, #{item.deleted,jdbcType=BIT},
#{item.caseId,jdbcType=VARCHAR}) #{item.caseId,jdbcType=VARCHAR}, #{item.errorMessage,jdbcType=VARCHAR})
</foreach> </foreach>
</insert> </insert>
<insert id="batchInsertSelective" parameterType="map"> <insert id="batchInsertSelective" parameterType="map">
@ -504,15 +519,18 @@
<if test="'executor'.toString() == column.value"> <if test="'executor'.toString() == column.value">
#{item.executor,jdbcType=VARCHAR} #{item.executor,jdbcType=VARCHAR}
</if> </if>
<if test="'deleted'.toString() == column.value">
#{item.deleted,jdbcType=BIT}
</if>
<if test="'collection_id'.toString() == column.value"> <if test="'collection_id'.toString() == column.value">
#{item.collectionId,jdbcType=VARCHAR} #{item.collectionId,jdbcType=VARCHAR}
</if> </if>
<if test="'deleted'.toString() == column.value">
#{item.deleted,jdbcType=BIT}
</if>
<if test="'case_id'.toString() == column.value"> <if test="'case_id'.toString() == column.value">
#{item.caseId,jdbcType=VARCHAR} #{item.caseId,jdbcType=VARCHAR}
</if> </if>
<if test="'error_message'.toString() == column.value">
#{item.errorMessage,jdbcType=VARCHAR}
</if>
</foreach> </foreach>
) )
</foreach> </foreach>

View File

@ -78,6 +78,8 @@ ALTER TABLE exec_task_item ADD COLUMN case_id VARCHAR(50) COMMENT '用例表id';
CREATE INDEX idx_case_id ON exec_task_item(case_id); CREATE INDEX idx_case_id ON exec_task_item(case_id);
-- 任务项添加测试集字段 -- 任务项添加测试集字段
ALTER TABLE exec_task_item ADD collection_id varchar(50) NULL COMMENT '测试集ID'; ALTER TABLE exec_task_item ADD collection_id varchar(50) NULL COMMENT '测试集ID';
-- 任务项添加异常信息字段
ALTER TABLE exec_task_item ADD error_message varchar(50) NULL COMMENT '异常信息';
-- set innodb lock wait timeout to default -- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT; SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -0,0 +1,9 @@
package io.metersphere.sdk.constants;
/**
* 任务项执行异常类型
* @author jianxing
*/
public enum TaskItemErrorMessage {
INVALID_RESOURCE_POOL, CASE_NOT_EXIST
}

View File

@ -559,4 +559,8 @@ user_view.all_data=全部数据
user_view.my_follow=我关注的 user_view.my_follow=我关注的
user_view.my_create=我创建的 user_view.my_create=我创建的
user_view.my_review=我评审的 user_view.my_review=我评审的
user_view_exist=视图已存在 user_view_exist=视图已存在
#task_error_message
task_error_message.invalid_resource_pool=没有可用的资源池
task_error_message.case_not_exist=用例不存在

View File

@ -598,4 +598,8 @@ user_view.my_follow=I followed
user_view.my_create=I created user_view.my_create=I created
user_view.my_review=I review user_view.my_review=I review
user_view.archived=Archived user_view.archived=Archived
user_view_exist=The view already exists user_view_exist=The view already exists
#task_error_message
task_error_message.invalid_resource_pool=There is no resource pool available
task_error_message.case_not_exist=The case doesn't exist

View File

@ -593,4 +593,8 @@ user_view.my_follow=我关注的
user_view.my_create=我创建的 user_view.my_create=我创建的
user_view.my_review=我评审的 user_view.my_review=我评审的
user_view.archived=已归档 user_view.archived=已归档
user_view_exist=视图已存在 user_view_exist=视图已存在
#task_error_message
task_error_message.invalid_resource_pool=没有可用的资源池
task_error_message.case_not_exist=用例不存在

View File

@ -593,4 +593,8 @@ user_view.my_follow=我關注的
user_view.my_create=我創建的 user_view.my_create=我創建的
user_view.my_review=我評審的 user_view.my_review=我評審的
user_view.archived=已歸檔 user_view.archived=已歸檔
user_view_exist=視圖已存在 user_view_exist=視圖已存在
#task_error_message
task_error_message.invalid_resource_pool=沒有可用的資源池
task_error_message.case_not_exist=用例不存在

View File

@ -16,7 +16,9 @@ public enum ApiResultCode implements IResultCode {
API_DEFINITION_MOCK_EXIST(104007, "api_definition_mock_exist"), API_DEFINITION_MOCK_EXIST(104007, "api_definition_mock_exist"),
API_SCENARIO_EXIST(104008, "api_scenario_exist"), API_SCENARIO_EXIST(104008, "api_scenario_exist"),
API_RESPONSE_NAME_CODE_UNIQUE(104009, "api_response_name_code_unique"), API_RESPONSE_NAME_CODE_UNIQUE(104009, "api_response_name_code_unique"),
API_SCENARIO_CIRCULAR_REFERENCE(104010, "api_scenario_circular_reference_error") API_SCENARIO_CIRCULAR_REFERENCE(104010, "api_scenario_circular_reference_error"),
TASK_ERROR_MESSAGE_INVALID_RESOURCE_POOL(104011, "task_error_message.invalid_resource_pool"),
CASE_NOT_EXIST(104012, "task_error_message.case_not_exist"),
; ;

View File

@ -8,11 +8,14 @@ import io.metersphere.api.service.definition.ApiTestCaseBatchRunService;
import io.metersphere.api.service.definition.ApiTestCaseRunService; import io.metersphere.api.service.definition.ApiTestCaseRunService;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode; import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.api.task.TaskItem; import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.dto.queue.ExecutionQueue; import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail; import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
@ -33,7 +36,8 @@ public class ApiCaseExecuteCallbackService implements ApiExecuteCallbackService
private ApiTestCaseMapper apiTestCaseMapper; private ApiTestCaseMapper apiTestCaseMapper;
@Resource @Resource
private ApiTestCaseBatchRunService apiTestCaseBatchRunService; private ApiTestCaseBatchRunService apiTestCaseBatchRunService;
@Resource
private ApiCommonService apiCommonService;
public ApiCaseExecuteCallbackService() { public ApiCaseExecuteCallbackService() {
ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.API_CASE, this); ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.API_CASE, this);
@ -45,6 +49,10 @@ public class ApiCaseExecuteCallbackService implements ApiExecuteCallbackService
@Override @Override
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId()); ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId());
if (apiTestCase == null || apiTestCase.getDeleted()) {
apiCommonService.updateTaskItemErrorMassage(request.getTaskItem().getId(), TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(Translator.get("task_error_message.case_not_exist"));
}
String reportId = initReport(request, apiTestCase); String reportId = initReport(request, apiTestCase);
GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase); GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase);
result.setReportId(reportId); result.setReportId(reportId);

View File

@ -31,18 +31,30 @@ import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService; import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.ExecStatus; import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.TaskBatchRequestDTO;
import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTask; import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem; import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExecTaskItemMapper;
import io.metersphere.system.mapper.ExecTaskMapper;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator; import io.metersphere.system.uid.NumGenerator;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; 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.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
@ -65,6 +77,10 @@ public class ApiCommonService {
private FileMetadataService fileMetadataService; private FileMetadataService fileMetadataService;
@Resource @Resource
private CustomFunctionService customFunctionService; private CustomFunctionService customFunctionService;
@Resource
private ExecTaskItemMapper execTaskItemMapper;
@Resource
private ExecTaskMapper execTaskMapper;
/** /**
* 根据 fileId 查找 MsHTTPElement 中的 ApiFile * 根据 fileId 查找 MsHTTPElement 中的 ApiFile
@ -511,4 +527,55 @@ public class ApiCommonService {
apiReportRelateTask.setTaskResourceId(taskItemId); apiReportRelateTask.setTaskResourceId(taskItemId);
return apiReportRelateTask; return apiReportRelateTask;
} }
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void batchUpdateTaskItemErrorMassage(TaskItemErrorMessage errorMessage, TaskBatchRequestDTO batchRequest) {
SqlSessionFactory sqlSessionFactory = CommonBeanFactory.getBean(SqlSessionFactory.class);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
if (CollectionUtils.isNotEmpty(batchRequest.getTaskItems())) {
ExecTaskItemMapper batchExecTaskItemMapper = sqlSession.getMapper(ExecTaskItemMapper.class);
batchRequest.getTaskItems().forEach(taskItem -> {
// 更新任务项的异常信息
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setErrorMessage(errorMessage.name());
batchExecTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
});
}
} finally {
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void updateTaskItemErrorMassage(String taskItemId, TaskItemErrorMessage errorMessage) {
// 更新任务项的异常信息
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItemId);
execTaskItem.setErrorMessage(errorMessage.name());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void updateTaskRunningStatus(String taskId) {
ExecTask execTask = new ExecTask();
execTask.setId(taskId);
execTask.setStartTime(System.currentTimeMillis());
execTask.setStatus(ExecStatus.RUNNING.name());
execTaskMapper.updateByPrimaryKeySelective(execTask);
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void updateTaskItemRunningStatus(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
// 更新任务项状态
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setStartTime(System.currentTimeMillis());
execTaskItem.setStatus(ExecStatus.RUNNING.name());
execTaskItem.setThreadId(request.getThreadId());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
}
} }

View File

@ -4,17 +4,15 @@ import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.service.definition.ApiReportService; import io.metersphere.api.service.definition.ApiReportService;
import io.metersphere.api.service.scenario.ApiScenarioReportService; import io.metersphere.api.service.scenario.ApiScenarioReportService;
import io.metersphere.api.utils.TaskRunningCache; import io.metersphere.api.utils.TaskRunningCache;
import io.metersphere.sdk.constants.*; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.api.task.TaskItem; import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.EnumValidator; import io.metersphere.sdk.util.EnumValidator;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ExecTask;
import io.metersphere.system.domain.ExecTaskItem;
import io.metersphere.system.mapper.ExecTaskItemMapper;
import io.metersphere.system.mapper.ExecTaskMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -28,10 +26,6 @@ import java.util.Optional;
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class ApiExecuteResourceService { public class ApiExecuteResourceService {
@Resource
private ExecTaskMapper execTaskMapper;
@Resource
private ExecTaskItemMapper execTaskItemMapper;
@Resource @Resource
private ApiReportService apiReportService; private ApiReportService apiReportService;
@Resource @Resource
@ -40,6 +34,8 @@ public class ApiExecuteResourceService {
private StringRedisTemplate stringRedisTemplate; private StringRedisTemplate stringRedisTemplate;
@Resource @Resource
private TaskRunningCache taskRunningCache; private TaskRunningCache taskRunningCache;
@Resource
private ApiCommonService apiCommonService;
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
@ -79,15 +75,15 @@ public class ApiExecuteResourceService {
// 设置缓存成功说明是第一个任务则设置任务的开始时间和运行状态 // 设置缓存成功说明是第一个任务则设置任务的开始时间和运行状态
if (taskRunningCache.setIfAbsent(taskId)) { if (taskRunningCache.setIfAbsent(taskId)) {
// 将任务状态更新为运行中 // 将任务状态更新为运行中
updateTaskRunningStatus(taskId); apiCommonService.updateTaskRunningStatus(taskId);
} }
} else { } else {
// 非批量时直接更新任务状态 // 非批量时直接更新任务状态
updateTaskRunningStatus(taskId); apiCommonService.updateTaskRunningStatus(taskId);
} }
// 更新任务项状态 // 更新任务项状态
updateTaskItemRunningStatus(request); apiCommonService.updateTaskItemRunningStatus(request);
// 非调试执行更新报告状态 // 非调试执行更新报告状态
switch (apiExecuteResourceType) { switch (apiExecuteResourceType) {
@ -98,23 +94,4 @@ public class ApiExecuteResourceService {
default -> throw new MSException("不支持的资源类型: " + request.getResourceType()); default -> throw new MSException("不支持的资源类型: " + request.getResourceType());
} }
} }
private void updateTaskRunningStatus(String taskId) {
ExecTask execTask = new ExecTask();
execTask.setId(taskId);
execTask.setStartTime(System.currentTimeMillis());
execTask.setStatus(ExecStatus.RUNNING.name());
execTaskMapper.updateByPrimaryKeySelective(execTask);
}
private void updateTaskItemRunningStatus(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem();
// 更新任务项状态
ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId());
execTaskItem.setStartTime(System.currentTimeMillis());
execTaskItem.setStatus(ExecStatus.RUNNING.name());
execTaskItem.setThreadId(request.getThreadId());
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
}
} }

View File

@ -214,10 +214,7 @@ public class ApiExecuteService {
*/ */
public TaskRequestDTO execute(TaskRequestDTO taskRequest) { public TaskRequestDTO execute(TaskRequestDTO taskRequest) {
TaskInfo taskInfo = taskRequest.getTaskInfo(); TaskInfo taskInfo = taskRequest.getTaskInfo();
TaskItem taskItem = taskRequest.getTaskItem();
try { try {
taskInfo = setTaskRequestParams(taskInfo); taskInfo = setTaskRequestParams(taskInfo);
// 获取资源池 // 获取资源池
@ -231,39 +228,10 @@ public class ApiExecuteService {
// 判断是否为 K8S 资源池 // 判断是否为 K8S 资源池
boolean isK8SResourcePool = StringUtils.equals(testResourcePoolDTO.getType(), ResourcePoolTypeEnum.K8S.getName()); boolean isK8SResourcePool = StringUtils.equals(testResourcePoolDTO.getType(), ResourcePoolTypeEnum.K8S.getName());
boolean isDebugMode = ApiExecuteRunMode.isDebug(taskInfo.getRunMode());
if (isK8SResourcePool) { if (isK8SResourcePool) {
TestResourceDTO testResourceDTO = new TestResourceDTO(); k8sExecute(taskRequest, testResourcePoolDTO);
BeanUtils.copyBean(testResourceDTO, testResourcePoolDTO.getTestResourceReturnDTO());
testResourceDTO.setId(testResourcePoolDTO.getId());
taskInfo.setPerTaskSize(testResourceDTO.getPodThreads());
taskInfo.setPoolSize(testResourceDTO.getConcurrentNumber());
LogUtils.info("开始发送请求【 {}_{} 】到 K8S 资源池执行", taskItem.getReportId(), taskItem.getResourceId());
if (isDebugMode) {
EngineFactory.debugApi(taskRequest, testResourceDTO);
} else {
EngineFactory.runApi(taskRequest, testResourceDTO);
}
} else { } else {
if (CollectionUtils.isEmpty(testResourcePoolDTO.getTestResourceReturnDTO().getNodesList())) { nodeExecute(taskRequest, testResourcePoolDTO);
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
}
TestResourceNodeDTO testResourceNodeDTO = getNextExecuteNode(testResourcePoolDTO);
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
updateTaskItemNodeInfo(taskItem, testResourcePoolDTO, testResourceNodeDTO, execTaskItemMapper);
}
taskInfo.setPerTaskSize(Optional.ofNullable(testResourceNodeDTO.getSingleTaskConcurrentNumber()).orElse(3));
taskInfo.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
String endpoint = MsHttpClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskItem.getReportId(), taskItem.getResourceId(), endpoint);
if (isDebugMode) {
MsHttpClient.debugApi(endpoint, taskRequest);
} else {
MsHttpClient.runApi(endpoint, taskRequest);
}
} }
} catch (HttpServerErrorException e) { } catch (HttpServerErrorException e) {
@ -291,10 +259,87 @@ public class ApiExecuteService {
return taskRequest; return taskRequest;
} }
private void updateTaskItemNodeInfo(TaskItem taskItem, TestResourcePoolReturnDTO testResourcePoolDTO, TestResourceNodeDTO testResourceNodeDTO, ExecTaskItemMapper execTaskItemMapper) { private void nodeExecute(TaskRequestDTO taskRequest, TestResourcePoolReturnDTO testResourcePoolDTO) throws Exception {
TaskItem taskItem = taskRequest.getTaskItem();
TaskInfo taskInfo = taskRequest.getTaskInfo();
if (CollectionUtils.isEmpty(testResourcePoolDTO.getTestResourceReturnDTO().getNodesList())) {
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
}
Set<String> invalidNodeSet = new HashSet<>();
Exception lastException = null;
while (true) {
TestResourceNodeDTO testResourceNodeDTO = getNextExecuteNode(testResourcePoolDTO);
taskInfo.setPerTaskSize(Optional.ofNullable(testResourceNodeDTO.getSingleTaskConcurrentNumber()).orElse(3));
taskInfo.setPoolSize(testResourceNodeDTO.getConcurrentNumber());
String endpoint = MsHttpClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskItem.getReportId(), taskItem.getResourceId(), endpoint);
if (invalidNodeSet.contains(endpoint)) {
// 全部节点都异常更新任务项状态
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
apiCommonService.updateTaskItemErrorMassage(taskItem.getId(), TaskItemErrorMessage.INVALID_RESOURCE_POOL);
}
throw lastException;
}
try {
if (ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
MsHttpClient.debugApi(endpoint, taskRequest);
} else {
MsHttpClient.runApi(endpoint, taskRequest);
// 更新状态项资源池信息
updateTaskItemNodeInfo(taskItem.getId(), testResourcePoolDTO, testResourceNodeDTO, execTaskItemMapper);
}
break;
} catch (Exception e) {
lastException = e;
LogUtils.error(e);
// 记录异常节点重试
invalidNodeSet.add(endpoint);
}
}
}
private void k8sExecute(TaskRequestDTO taskRequest, TestResourcePoolReturnDTO testResourcePoolDTO) throws Exception {
TaskItem taskItem = taskRequest.getTaskItem();
TaskInfo taskInfo = taskRequest.getTaskInfo();
TestResourceDTO testResourceDTO = new TestResourceDTO();
BeanUtils.copyBean(testResourceDTO, testResourcePoolDTO.getTestResourceReturnDTO());
testResourceDTO.setId(testResourcePoolDTO.getId());
taskInfo.setPerTaskSize(testResourceDTO.getPodThreads());
taskInfo.setPoolSize(testResourceDTO.getConcurrentNumber());
LogUtils.info("开始发送请求【 {}_{} 】到 K8S 资源池执行", taskItem.getReportId(), taskItem.getResourceId());
if (ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
EngineFactory.debugApi(taskRequest, testResourceDTO);
} else {
try {
EngineFactory.runApi(taskRequest, testResourceDTO);
} catch (Exception e) {
apiCommonService.updateTaskItemErrorMassage(taskItem.getId(), TaskItemErrorMessage.INVALID_RESOURCE_POOL);
throw e;
}
}
}
private void batchUpdateTaskItemNodeInfo(TestResourcePoolReturnDTO testResourcePool, TestResourceNodeDTO testResourceNode, TaskBatchRequestDTO batchRequest) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
if (CollectionUtils.isNotEmpty(batchRequest.getTaskItems())) {
ExecTaskItemMapper batchExecTaskItemMapper = sqlSession.getMapper(ExecTaskItemMapper.class);
batchRequest.getTaskItems().forEach(taskItem -> {
// 非调试模式更新任务项的资源池信息
updateTaskItemNodeInfo(taskItem.getId(), testResourcePool, testResourceNode, batchExecTaskItemMapper);
});
}
} finally {
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
private void updateTaskItemNodeInfo(String taskItemId, TestResourcePoolReturnDTO testResourcePoolDTO, TestResourceNodeDTO testResourceNodeDTO, ExecTaskItemMapper execTaskItemMapper) {
// 非调试模式更新任务项的资源池信息 // 非调试模式更新任务项的资源池信息
ExecTaskItem execTaskItem = new ExecTaskItem(); ExecTaskItem execTaskItem = new ExecTaskItem();
execTaskItem.setId(taskItem.getId()); execTaskItem.setId(taskItemId);
execTaskItem.setResourcePoolId(testResourcePoolDTO.getId()); execTaskItem.setResourcePoolId(testResourcePoolDTO.getId());
execTaskItem.setResourcePoolNode(StringUtils.join(testResourceNodeDTO.getIp(), ":", testResourceNodeDTO.getPort())); execTaskItem.setResourcePoolNode(StringUtils.join(testResourceNodeDTO.getIp(), ":", testResourceNodeDTO.getPort()));
execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem); execTaskItemMapper.updateByPrimaryKeySelective(execTaskItem);
@ -319,78 +364,102 @@ public class ApiExecuteService {
// 判断是否为 K8S 资源池 // 判断是否为 K8S 资源池
boolean isK8SResourcePool = StringUtils.equals(testResourcePool.getType(), ResourcePoolTypeEnum.K8S.getName()); boolean isK8SResourcePool = StringUtils.equals(testResourcePool.getType(), ResourcePoolTypeEnum.K8S.getName());
if (isK8SResourcePool) { if (isK8SResourcePool) {
TestResourceDTO testResourceDTO = new TestResourceDTO(); k8sBatchExecute(taskRequest, taskInfo, testResourcePool);
BeanUtils.copyBean(testResourceDTO, testResourcePool.getTestResourceReturnDTO());
testResourceDTO.setId(testResourcePool.getId());
taskInfo.setPoolSize(testResourceDTO.getConcurrentNumber());
taskInfo.setPerTaskSize(testResourceDTO.getPodThreads());
try {
EngineFactory.batchRunApi(taskRequest, testResourceDTO);
} catch (Exception e) {
LogUtils.error(e);
}
} else { } else {
// 将任务按资源池的数量拆分 nodeBatchExecute(taskRequest, taskInfo, testResourcePool);
List<TestResourceNodeDTO> nodesList = testResourcePool.getTestResourceReturnDTO().getNodesList(); }
if (CollectionUtils.isEmpty(nodesList)) { }
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
} private void nodeBatchExecute(TaskBatchRequestDTO taskRequest, TaskInfo taskInfo, TestResourcePoolReturnDTO testResourcePool) {
List<TaskBatchRequestDTO> distributeTasks = new ArrayList<>(nodesList.size()); // 将任务按资源池的数量拆分
for (int i = 0; i < taskRequest.getTaskItems().size(); i++) { List<TestResourceNodeDTO> nodesList = testResourcePool.getTestResourceReturnDTO().getNodesList();
TaskBatchRequestDTO distributeTask; if (CollectionUtils.isEmpty(nodesList)) {
int nodeIndex = i % nodesList.size(); throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
if (distributeTasks.size() < nodesList.size()) { }
distributeTask = BeanUtils.copyBean(new TaskBatchRequestDTO(), taskRequest); // 按资源池节点数量预分组
distributeTask.setTaskItems(new ArrayList<>()); List<TaskBatchRequestDTO> distributeTasks = getDistributeTaskBatchRequest(taskRequest, nodesList.size());
distributeTasks.add(distributeTask);
} else { Iterator<TestResourceNodeDTO> nodeIterator = nodesList.iterator();
distributeTask = distributeTasks.get(nodeIndex); Iterator<TaskBatchRequestDTO> distributeTaskIterator = distributeTasks.iterator();
} Set<TestResourceNodeDTO> invalidNodeSet = new HashSet<>();
taskInfo.setPerTaskSize(Optional.ofNullable(nodesList.get(nodeIndex).getSingleTaskConcurrentNumber()).orElse(3)); while (distributeTaskIterator.hasNext()) {
distributeTask.getTaskInfo().setPoolSize(nodesList.get(nodeIndex).getConcurrentNumber()); TaskBatchRequestDTO subTaskRequest = distributeTaskIterator.next();
distributeTask.getTaskItems().add(taskRequest.getTaskItems().get(i)); boolean success = false;
} while (nodeIterator.hasNext()) {
for (int i = 0; i < nodesList.size(); i++) { TestResourceNodeDTO testResourceNode = nodeIterator.next();
// todo 优化某个资源池不可用的情况以及清理 executionSet
TestResourceNodeDTO testResourceNode = nodesList.get(i);
TaskBatchRequestDTO subTaskRequest = distributeTasks.get(i);
String endpoint = MsHttpClient.getEndpoint(testResourceNode.getIp(), testResourceNode.getPort()); String endpoint = MsHttpClient.getEndpoint(testResourceNode.getIp(), testResourceNode.getPort());
subTaskRequest.getTaskInfo().setPerTaskSize(Optional.ofNullable(testResourceNode.getSingleTaskConcurrentNumber()).orElse(3));
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) { subTaskRequest.getTaskInfo().setPoolSize(testResourceNode.getConcurrentNumber());
batchUpdateTaskItemNodeInfo(testResourcePool, testResourceNode, subTaskRequest);
}
try { try {
List<String> taskKeys = subTaskRequest.getTaskItems().stream() List<String> taskKeys = subTaskRequest.getTaskItems().stream()
.map(TaskItem::getId) .map(TaskItem::getId)
.toList(); .toList();
LogUtils.info("开始发送批量任务到 {} 节点执行:\n" + taskKeys, endpoint); LogUtils.info("开始发送批量任务到 {} 节点执行:\n" + taskKeys, endpoint);
MsHttpClient.batchRunApi(endpoint, subTaskRequest); MsHttpClient.batchRunApi(endpoint, subTaskRequest);
success = true;
// 更新任务项的资源池信息
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
batchUpdateTaskItemNodeInfo(testResourcePool, testResourceNode, subTaskRequest);
}
break;
} catch (Exception e) { } catch (Exception e) {
invalidNodeSet.add(testResourceNode);
LogUtils.error("发送批量任务到 {} 节点执行失败", endpoint); LogUtils.error("发送批量任务到 {} 节点执行失败", endpoint);
LogUtils.error(e); LogUtils.error(e);
} }
if (!nodeIterator.hasNext()) {
// 去除异常节点
invalidNodeSet.forEach(nodesList::remove);
// 资源池不够用重新遍历资源池
nodeIterator = nodesList.iterator();
}
}
if (!success) {
// 更新任务项错误信息
if (!ApiExecuteRunMode.isDebug(taskInfo.getRunMode())) {
apiCommonService.batchUpdateTaskItemErrorMassage(TaskItemErrorMessage.INVALID_RESOURCE_POOL, subTaskRequest);
} else {
throw new MSException(ApiResultCode.TASK_ERROR_MESSAGE_INVALID_RESOURCE_POOL);
}
} }
} }
} }
private void batchUpdateTaskItemNodeInfo(TestResourcePoolReturnDTO testResourcePool, TestResourceNodeDTO testResourceNode, TaskBatchRequestDTO batchRequest) { private void k8sBatchExecute(TaskBatchRequestDTO taskRequest, TaskInfo taskInfo, TestResourcePoolReturnDTO testResourcePool) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); TestResourceDTO testResourceDTO = new TestResourceDTO();
BeanUtils.copyBean(testResourceDTO, testResourcePool.getTestResourceReturnDTO());
testResourceDTO.setId(testResourcePool.getId());
taskInfo.setPoolSize(testResourceDTO.getConcurrentNumber());
taskInfo.setPerTaskSize(testResourceDTO.getPodThreads());
try { try {
if (CollectionUtils.isNotEmpty(batchRequest.getTaskItems())) { EngineFactory.batchRunApi(taskRequest, testResourceDTO);
ExecTaskItemMapper batchExecTaskItemMapper = sqlSession.getMapper(ExecTaskItemMapper.class); } catch (Exception e) {
batchRequest.getTaskItems().forEach(taskItem -> { LogUtils.error(e);
// 非调试模式更新任务项的资源池信息 apiCommonService.batchUpdateTaskItemErrorMassage(TaskItemErrorMessage.INVALID_RESOURCE_POOL, taskRequest);
updateTaskItemNodeInfo(taskItem, testResourcePool, testResourceNode, batchExecTaskItemMapper);
});
}
} finally {
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
} }
} }
private List<TaskBatchRequestDTO> getDistributeTaskBatchRequest(TaskBatchRequestDTO taskRequest, int distributeSize) {
List<TaskBatchRequestDTO> distributeTasks = new ArrayList<>(distributeSize);
for (int i = 0; i < taskRequest.getTaskItems().size(); i++) {
TaskBatchRequestDTO distributeTask;
int nodeIndex = i % distributeSize;
if (distributeTasks.size() < distributeSize) {
distributeTask = BeanUtils.copyBean(new TaskBatchRequestDTO(), taskRequest);
distributeTask.setTaskItems(new ArrayList<>());
distributeTasks.add(distributeTask);
} else {
distributeTask = distributeTasks.get(nodeIndex);
}
distributeTask.getTaskItems().add(taskRequest.getTaskItems().get(i));
}
return distributeTasks;
}
protected static boolean validate() { protected static boolean validate() {
try { try {
LicenseService licenseService = CommonBeanFactory.getBean(LicenseService.class); LicenseService licenseService = CommonBeanFactory.getBean(LicenseService.class);
@ -759,14 +828,14 @@ public class ApiExecuteService {
testElement.setProjectId(projectId); testElement.setProjectId(projectId);
} }
public ApiParamConfig getApiParamConfig(String reportId) { public ApiParamConfig getApiParamConfig() {
ApiParamConfig paramConfig = new ApiParamConfig(); ApiParamConfig paramConfig = new ApiParamConfig();
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
paramConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap()); paramConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap());
return paramConfig; return paramConfig;
} }
public ApiParamConfig getApiParamConfig(String reportId, String projectId) { public ApiParamConfig getApiParamConfig(String projectId) {
ApiParamConfig paramConfig = new ApiParamConfig(); ApiParamConfig paramConfig = new ApiParamConfig();
paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap());
paramConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap()); paramConfig.setTestElementClassProtocolMap(apiPluginService.getTestElementProtocolMap());

View File

@ -39,7 +39,7 @@ public class ApiScenarioExecuteCallbackService implements ApiExecuteCallbackServ
*/ */
@Override @Override
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(request.getTaskItem().getResourceId()); ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRunWithTaskItemErrorMassage(request.getTaskItem().getId(), request.getTaskItem().getResourceId());
String reportId = initReport(request, apiScenarioDetail); String reportId = initReport(request, apiScenarioDetail);
GetRunScriptResult result = apiScenarioRunService.getRunScript(request, apiScenarioDetail); GetRunScriptResult result = apiScenarioRunService.getRunScript(request, apiScenarioDetail);
result.setReportId(reportId); result.setReportId(reportId);

View File

@ -211,7 +211,7 @@ public class ApiDebugService extends MoveNodeService {
public TaskRequestDTO debug(ApiDebugRunRequest request) { public TaskRequestDTO debug(ApiDebugRunRequest request) {
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request); ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId()); ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig();
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId()); TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
TaskInfo taskInfo = taskRequest.getTaskInfo(); TaskInfo taskInfo = taskRequest.getTaskInfo();

View File

@ -1191,7 +1191,7 @@ public class ApiDefinitionService extends MoveNodeService {
public TaskRequestDTO debug(ApiDefinitionRunRequest request) { public TaskRequestDTO debug(ApiDefinitionRunRequest request) {
ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request); ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request);
EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId()); EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId());
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId(), request.getProjectId()); ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getProjectId());
TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId()); TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId());
TaskInfo taskInfo = taskRequest.getTaskInfo(); TaskInfo taskInfo = taskRequest.getTaskInfo();

View File

@ -156,7 +156,7 @@ public class ApiTestCaseRunService {
public TaskRequestDTO doExecute(TaskRequestDTO taskRequest, ApiResourceRunRequest runRequest, String apiDefinitionId, String envId) { public TaskRequestDTO doExecute(TaskRequestDTO taskRequest, ApiResourceRunRequest runRequest, String apiDefinitionId, String envId) {
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getTaskItem().getReportId(), taskRequest.getTaskInfo().getProjectId()); ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskRequest.getTaskInfo().getProjectId());
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionId); ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionId);
@ -175,7 +175,7 @@ public class ApiTestCaseRunService {
TaskItem taskItem = request.getTaskItem(); TaskItem taskItem = request.getTaskItem();
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId()); ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiTestCase.getApiDefinitionId());
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId()); ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(apiTestCase.getId());
ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(taskItem.getReportId(), apiTestCase.getProjectId()); ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(apiTestCase.getProjectId());
apiParamConfig.setRetryOnFail(request.getRunModeConfig().getRetryOnFail()); apiParamConfig.setRetryOnFail(request.getRunModeConfig().getRetryOnFail());
apiParamConfig.setRetryConfig(request.getRunModeConfig().getRetryConfig()); apiParamConfig.setRetryConfig(request.getRunModeConfig().getRetryConfig());

View File

@ -3,6 +3,7 @@ package io.metersphere.api.service.scenario;
import io.metersphere.api.constants.ApiResourceType; import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.constants.ApiScenarioStepRefType; import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType; import io.metersphere.api.constants.ApiScenarioStepType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*; import io.metersphere.api.domain.*;
import io.metersphere.api.dto.*; import io.metersphere.api.dto.*;
import io.metersphere.api.dto.debug.ApiResourceRunRequest; import io.metersphere.api.dto.debug.ApiResourceRunRequest;
@ -34,6 +35,7 @@ import io.metersphere.project.service.EnvironmentGroupService;
import io.metersphere.project.service.EnvironmentService; import io.metersphere.project.service.EnvironmentService;
import io.metersphere.sdk.constants.*; import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.api.task.*; import io.metersphere.sdk.dto.api.task.*;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.DateUtils; import io.metersphere.sdk.util.DateUtils;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
@ -266,6 +268,21 @@ public class ApiScenarioRunService {
return apiScenarioDetail; return apiScenarioDetail;
} }
public ApiScenarioDetail getForRunWithTaskItemErrorMassage(String taskItemId, String scenarioId) {
try {
ApiScenarioDetail apiScenarioDetail = apiScenarioService.get(scenarioId);
apiScenarioDetail.setSteps(filerDisableSteps(apiScenarioDetail.getSteps()));
return apiScenarioDetail;
} catch (MSException msException) {
if (msException.getErrorCode().equals(ApiResultCode.CASE_NOT_EXIST)) {
// 用例不存在记录任务项错误信息
apiCommonService.updateTaskItemErrorMassage(taskItemId, TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(ApiResultCode.CASE_NOT_EXIST);
}
throw msException;
}
}
/** /**
* 过滤掉禁用的步骤 * 过滤掉禁用的步骤
*/ */

View File

@ -3,6 +3,7 @@ package io.metersphere.api.service.scenario;
import io.metersphere.api.constants.ApiResourceType; import io.metersphere.api.constants.ApiResourceType;
import io.metersphere.api.constants.ApiScenarioStepRefType; import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType; import io.metersphere.api.constants.ApiScenarioStepType;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.*; import io.metersphere.api.domain.*;
import io.metersphere.api.dto.*; import io.metersphere.api.dto.*;
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest; import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
@ -1520,7 +1521,7 @@ public class ApiScenarioService extends MoveNodeService {
example.createCriteria().andIdEqualTo(id).andDeletedEqualTo(false); example.createCriteria().andIdEqualTo(id).andDeletedEqualTo(false);
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(example); List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(example);
if (CollectionUtils.isEmpty(apiScenarios)) { if (CollectionUtils.isEmpty(apiScenarios)) {
throw new MSException(Translator.get("api_scenario_is_not_exist")); throw new MSException(ApiResultCode.CASE_NOT_EXIST);
} }
return apiScenarios.getFirst(); return apiScenarios.getFirst();
} }

View File

@ -1,11 +1,7 @@
package io.metersphere.system.dto.taskhub; package io.metersphere.system.dto.taskhub;
import io.metersphere.system.domain.ExecTaskItem; import io.metersphere.system.domain.ExecTaskItem;
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.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
/** /**
@ -40,4 +36,7 @@ public class TaskHubItemDTO extends ExecTaskItem {
@Schema(description = "组织名称") @Schema(description = "组织名称")
private String organizationName; private String organizationName;
@Schema(description = "错误信息")
private String errorMessage;
} }

View File

@ -373,6 +373,9 @@ public class BaseTaskHubService {
item.setResourcePoolName(resourcePoolMaps.getOrDefault(item.getResourcePoolId(), StringUtils.EMPTY)); item.setResourcePoolName(resourcePoolMaps.getOrDefault(item.getResourcePoolId(), StringUtils.EMPTY));
item.setProjectName(projectMaps.getOrDefault(item.getProjectId(), StringUtils.EMPTY)); item.setProjectName(projectMaps.getOrDefault(item.getProjectId(), StringUtils.EMPTY));
item.setOrganizationName(organizationMaps.getOrDefault(item.getOrganizationId(), StringUtils.EMPTY)); item.setOrganizationName(organizationMaps.getOrDefault(item.getOrganizationId(), StringUtils.EMPTY));
if (StringUtils.isNotBlank(item.getErrorMessage())) {
item.setErrorMessage(Translator.get("task_error_message." + item.getErrorMessage().toLowerCase()));
}
}); });
} }
@ -740,7 +743,7 @@ public class BaseTaskHubService {
public Map<String, Integer> getTaskItemOrder(List<String> taskIdItemIds) { public Map<String, Integer> getTaskItemOrder(List<String> taskIdItemIds) {
List<ExecTaskItem> taskItemIds = getTaskItemByIds(taskIdItemIds); List<ExecTaskItem> taskItemIds = getTaskItemByIds(taskIdItemIds);
Map<String, List<ExecTaskItem>> nodeResourceMap = taskItemIds.stream() Map<String, List<ExecTaskItem>> nodeResourceMap = taskItemIds.stream()
.filter(item -> StringUtils.equals(item.getResourceType(), ResourcePoolTypeEnum.NODE.getName())) // 根据条件过滤 .filter(item -> StringUtils.contains(item.getResourcePoolNode(), ":")) // 根据条件过滤
.collect(Collectors.groupingBy(ExecTaskItem::getResourcePoolNode)); .collect(Collectors.groupingBy(ExecTaskItem::getResourcePoolNode));
List<CompletableFuture<Map<String, Integer>>> futures = nodeResourceMap.keySet().stream() List<CompletableFuture<Map<String, Integer>>> futures = nodeResourceMap.keySet().stream()

View File

@ -1,18 +1,22 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker; import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.mapper.ApiTestCaseMapper; import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteCallbackService; import io.metersphere.api.service.ApiExecuteCallbackService;
import io.metersphere.api.service.definition.ApiTestCaseRunService; import io.metersphere.api.service.definition.ApiTestCaseRunService;
import io.metersphere.plan.domain.TestPlanReportApiCase; import io.metersphere.plan.domain.TestPlanReportApiCase;
import io.metersphere.plan.mapper.TestPlanReportApiCaseMapper; import io.metersphere.plan.mapper.TestPlanReportApiCaseMapper;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO; import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.queue.ExecutionQueue; import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail; import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.exception.MSException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -39,6 +43,9 @@ public class PlanRunApiCaseExecuteCallbackService implements ApiExecuteCallbackS
@Resource @Resource
private ApiTestCaseRunService apiTestCaseRunService; private ApiTestCaseRunService apiTestCaseRunService;
@Resource
private ApiCommonService apiCommonService;
public PlanRunApiCaseExecuteCallbackService() { public PlanRunApiCaseExecuteCallbackService() {
ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.PLAN_RUN_API_CASE, this); ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.PLAN_RUN_API_CASE, this);
} }
@ -49,7 +56,11 @@ public class PlanRunApiCaseExecuteCallbackService implements ApiExecuteCallbackS
@Override @Override
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
TestPlanReportApiCase testPlanReportApiCase = testPlanReportApiCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId()); TestPlanReportApiCase testPlanReportApiCase = testPlanReportApiCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId());
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(testPlanReportApiCase.getApiCaseId()); ApiTestCase apiTestCase = testPlanReportApiCase == null ? null : apiTestCaseMapper.selectByPrimaryKey(testPlanReportApiCase.getApiCaseId());
if (testPlanReportApiCase == null || apiTestCase == null || apiTestCase.getDeleted()) {
apiCommonService.updateTaskItemErrorMassage(request.getTaskItem().getId(), TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(ApiResultCode.CASE_NOT_EXIST);
}
String reportId = initReport(request, testPlanReportApiCase, apiTestCase); String reportId = initReport(request, testPlanReportApiCase, apiTestCase);
GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase); GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase);
result.setReportId(reportId); result.setReportId(reportId);

View File

@ -1,17 +1,21 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.dto.scenario.ApiScenarioDetail; import io.metersphere.api.dto.scenario.ApiScenarioDetail;
import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker; import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteCallbackService; import io.metersphere.api.service.ApiExecuteCallbackService;
import io.metersphere.api.service.scenario.ApiScenarioRunService; import io.metersphere.api.service.scenario.ApiScenarioRunService;
import io.metersphere.plan.domain.TestPlanReportApiScenario; import io.metersphere.plan.domain.TestPlanReportApiScenario;
import io.metersphere.plan.mapper.TestPlanReportApiScenarioMapper; import io.metersphere.plan.mapper.TestPlanReportApiScenarioMapper;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO; import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.queue.ExecutionQueue; import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail; import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.exception.MSException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -31,6 +35,8 @@ public class PlanRunApiScenarioExecuteCallbackService implements ApiExecuteCallb
private TestPlanReportApiScenarioMapper testPlanReportApiScenarioMapper; private TestPlanReportApiScenarioMapper testPlanReportApiScenarioMapper;
@Resource @Resource
private ApiScenarioRunService apiScenarioRunService; private ApiScenarioRunService apiScenarioRunService;
@Resource
private ApiCommonService apiCommonService;
public PlanRunApiScenarioExecuteCallbackService() { public PlanRunApiScenarioExecuteCallbackService() {
ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.PLAN_RUN_API_SCENARIO, this); ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.PLAN_RUN_API_SCENARIO, this);
@ -43,7 +49,11 @@ public class PlanRunApiScenarioExecuteCallbackService implements ApiExecuteCallb
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
String resourceId = request.getTaskItem().getResourceId(); String resourceId = request.getTaskItem().getResourceId();
TestPlanReportApiScenario testPlanReportApiScenario = testPlanReportApiScenarioMapper.selectByPrimaryKey(resourceId); TestPlanReportApiScenario testPlanReportApiScenario = testPlanReportApiScenarioMapper.selectByPrimaryKey(resourceId);
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(testPlanReportApiScenario.getApiScenarioId()); if (testPlanReportApiScenario == null) {
apiCommonService.updateTaskItemErrorMassage(request.getTaskItem().getId(), TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(ApiResultCode.CASE_NOT_EXIST);
}
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRunWithTaskItemErrorMassage(request.getTaskItem().getId(), testPlanReportApiScenario.getApiScenarioId());
apiScenarioDetail.setEnvironmentId(testPlanReportApiScenario.getEnvironmentId()); apiScenarioDetail.setEnvironmentId(testPlanReportApiScenario.getEnvironmentId());
apiScenarioDetail.setGrouped(testPlanReportApiScenario.getGrouped()); apiScenarioDetail.setGrouped(testPlanReportApiScenario.getGrouped());
GetRunScriptResult result = planRunTestPlanApiScenarioService.getRunScript(request); GetRunScriptResult result = planRunTestPlanApiScenarioService.getRunScript(request);

View File

@ -1,19 +1,23 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.domain.ApiTestCaseRecord; import io.metersphere.api.domain.ApiTestCaseRecord;
import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker; import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.mapper.ApiTestCaseMapper; import io.metersphere.api.mapper.ApiTestCaseMapper;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteCallbackService; import io.metersphere.api.service.ApiExecuteCallbackService;
import io.metersphere.api.service.definition.ApiTestCaseRunService; import io.metersphere.api.service.definition.ApiTestCaseRunService;
import io.metersphere.plan.domain.TestPlanApiCase; import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper; import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO; import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.queue.ExecutionQueue; import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail; import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.exception.MSException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -36,6 +40,8 @@ public class TestPlanApiCaseExecuteCallbackService implements ApiExecuteCallback
private ApiTestCaseMapper apiTestCaseMapper; private ApiTestCaseMapper apiTestCaseMapper;
@Resource @Resource
private ApiTestCaseRunService apiTestCaseRunService; private ApiTestCaseRunService apiTestCaseRunService;
@Resource
private ApiCommonService apiCommonService;
public TestPlanApiCaseExecuteCallbackService() { public TestPlanApiCaseExecuteCallbackService() {
ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.TEST_PLAN_API_CASE, this); ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.TEST_PLAN_API_CASE, this);
@ -47,7 +53,11 @@ public class TestPlanApiCaseExecuteCallbackService implements ApiExecuteCallback
@Override @Override
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
TestPlanApiCase testPlanApiCase = testPlanApiCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId()); TestPlanApiCase testPlanApiCase = testPlanApiCaseMapper.selectByPrimaryKey(request.getTaskItem().getResourceId());
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(testPlanApiCase.getApiCaseId()); ApiTestCase apiTestCase = testPlanApiCase == null ? null : apiTestCaseMapper.selectByPrimaryKey(testPlanApiCase.getApiCaseId());
if (testPlanApiCase == null || apiTestCase == null || apiTestCase.getDeleted()) {
apiCommonService.updateTaskItemErrorMassage(request.getTaskItem().getId(), TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(ApiResultCode.CASE_NOT_EXIST);
}
String reportId = initReport(request, testPlanApiCase, apiTestCase); String reportId = initReport(request, testPlanApiCase, apiTestCase);
GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase); GetRunScriptResult result = apiTestCaseRunService.getRunScript(request, apiTestCase);
result.setReportId(reportId); result.setReportId(reportId);

View File

@ -1,18 +1,22 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.dto.scenario.ApiScenarioDetail; import io.metersphere.api.dto.scenario.ApiScenarioDetail;
import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker; import io.metersphere.api.invoker.ApiExecuteCallbackServiceInvoker;
import io.metersphere.api.service.ApiCommonService;
import io.metersphere.api.service.ApiExecuteCallbackService; import io.metersphere.api.service.ApiExecuteCallbackService;
import io.metersphere.api.service.scenario.ApiScenarioRunService; import io.metersphere.api.service.scenario.ApiScenarioRunService;
import io.metersphere.plan.domain.TestPlanApiScenario; import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.mapper.TestPlanApiScenarioMapper; import io.metersphere.plan.mapper.TestPlanApiScenarioMapper;
import io.metersphere.sdk.constants.ApiExecuteResourceType; import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.TaskItemErrorMessage;
import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO; import io.metersphere.sdk.dto.api.notice.ApiNoticeDTO;
import io.metersphere.sdk.dto.api.task.GetRunScriptRequest; import io.metersphere.sdk.dto.api.task.GetRunScriptRequest;
import io.metersphere.sdk.dto.api.task.GetRunScriptResult; import io.metersphere.sdk.dto.api.task.GetRunScriptResult;
import io.metersphere.sdk.dto.api.task.TaskItem; import io.metersphere.sdk.dto.api.task.TaskItem;
import io.metersphere.sdk.dto.queue.ExecutionQueue; import io.metersphere.sdk.dto.queue.ExecutionQueue;
import io.metersphere.sdk.dto.queue.ExecutionQueueDetail; import io.metersphere.sdk.dto.queue.ExecutionQueueDetail;
import io.metersphere.sdk.exception.MSException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -33,6 +37,8 @@ public class TestPlanApiScenarioExecuteCallbackService implements ApiExecuteCall
private TestPlanApiScenarioMapper testPlanApiScenarioMapper; private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource @Resource
private ApiScenarioRunService apiScenarioRunService; private ApiScenarioRunService apiScenarioRunService;
@Resource
private ApiCommonService apiCommonService;
public TestPlanApiScenarioExecuteCallbackService() { public TestPlanApiScenarioExecuteCallbackService() {
ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO, this); ApiExecuteCallbackServiceInvoker.register(ApiExecuteResourceType.TEST_PLAN_API_SCENARIO, this);
@ -45,7 +51,11 @@ public class TestPlanApiScenarioExecuteCallbackService implements ApiExecuteCall
public GetRunScriptResult getRunScript(GetRunScriptRequest request) { public GetRunScriptResult getRunScript(GetRunScriptRequest request) {
TaskItem taskItem = request.getTaskItem(); TaskItem taskItem = request.getTaskItem();
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(taskItem.getResourceId()); TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(taskItem.getResourceId());
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRun(testPlanApiScenario.getApiScenarioId()); if (testPlanApiScenario == null) {
apiCommonService.updateTaskItemErrorMassage(request.getTaskItem().getId(), TaskItemErrorMessage.CASE_NOT_EXIST);
throw new MSException(ApiResultCode.CASE_NOT_EXIST);
}
ApiScenarioDetail apiScenarioDetail = apiScenarioRunService.getForRunWithTaskItemErrorMassage(taskItem.getId(), testPlanApiScenario.getApiScenarioId());
apiScenarioDetail.setEnvironmentId(testPlanApiScenario.getEnvironmentId()); apiScenarioDetail.setEnvironmentId(testPlanApiScenario.getEnvironmentId());
apiScenarioDetail.setGrouped(testPlanApiScenario.getGrouped()); apiScenarioDetail.setGrouped(testPlanApiScenario.getGrouped());
String reportId = initReport(request, testPlanApiScenario, apiScenarioDetail); String reportId = initReport(request, testPlanApiScenario, apiScenarioDetail);