feat(测试计划,定时任务,场景): 支持资源池执行

This commit is contained in:
Captain.B 2021-05-14 18:10:08 +08:00 committed by 刘瑞斌
parent 1043012172
commit 49dae56d76
23 changed files with 849 additions and 221 deletions

View File

@ -9,4 +9,5 @@ public class RunModeConfig {
private String reportName;
private String reportId;
private boolean onSampleError;
private String resourcePoolId;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.response.Response;
import lombok.Getter;
@ -34,6 +35,8 @@ public class RunDefinitionRequest {
private Response response;
private RunModeConfig config;
private List<String> bodyUploadIds;
private Map<String, String> environmentMap;

View File

@ -311,7 +311,8 @@ public class JMeterService {
List<Object> jarFiles = getJar();
// 获取可以执行的资源池
TestResource testResource = resourcePoolCalculation.getPool();
String resourcePoolId = config.getResourcePoolId();
TestResource testResource = resourcePoolCalculation.getPool(resourcePoolId);
String configuration = testResource.getConfiguration();
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);

View File

@ -33,10 +33,10 @@ public class ResourcePoolCalculation {
return restTemplate.getForObject(uri, JvmInfoDTO.class);
}
public TestResource getPool() {
public TestResource getPool(String resourcePoolId) {
// 获取可以执行的资源池
TestResourcePoolExample example = new TestResourcePoolExample();
example.createCriteria().andStatusEqualTo("VALID").andTypeEqualTo("NODE").andNameEqualTo("赵勇资源池");
example.createCriteria().andStatusEqualTo("VALID").andTypeEqualTo("NODE").andIdEqualTo(resourcePoolId);
List<TestResourcePool> pools = testResourcePoolMapper.selectByExample(example);
// 按照NODE节点的可用内存空间大小排序
JvmInfoDTO jvmInfoDTO = null;

View File

@ -1088,8 +1088,11 @@ public class ApiAutomationService {
List<String> reportIds = new LinkedList<>();
try {
HashTree hashTree = generateHashTree(apiScenarios, request, reportIds);
jMeterService.runSerial(JSON.toJSONString(reportIds), hashTree, request.getReportId(), runMode, request.getConfig());
// jMeterService.runTest(JSON.toJSONString(reportIds), hashTree, runMode, false, request.getConfig());
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
jMeterService.runTest(JSON.toJSONString(reportIds), hashTree, runMode, false, request.getConfig());
} else {
jMeterService.runSerial(JSON.toJSONString(reportIds), hashTree, request.getReportId(), runMode, request.getConfig());
}
} catch (Exception e) {
LogUtil.error(e.getMessage());
@ -1110,8 +1113,10 @@ public class ApiAutomationService {
if (request.getIds().size() > count) {
MSException.throwException("并发数量过大,请重新选择!");
}
return this.modeRun(request);
} else {
return this.excute(request);
}
return this.modeRun(request);
} else {
return this.excute(request);
}

View File

@ -578,8 +578,11 @@ public class ApiDefinitionService {
runMode = ApiRunMode.API_PLAN.name();
}
// 调用执行方法
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), runMode);
//jMeterService.runTest(request.getId(), hashTree, runMode, request.getReportId() != null, null);
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
jMeterService.runTest(request.getId(), hashTree, runMode, request.getReportId() != null, request.getConfig());
} else {
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), runMode);
}
return request.getId();
}

View File

@ -33,5 +33,7 @@ public class Schedule implements Serializable {
private String name;
private String config;
private static final long serialVersionUID = 1L;
}

View File

@ -1053,6 +1053,76 @@ public class ScheduleExample {
addCriterion("`name` not between", value1, value2, "name");
return (Criteria) this;
}
public Criteria andConfigIsNull() {
addCriterion("config is null");
return (Criteria) this;
}
public Criteria andConfigIsNotNull() {
addCriterion("config is not null");
return (Criteria) this;
}
public Criteria andConfigEqualTo(String value) {
addCriterion("config =", value, "config");
return (Criteria) this;
}
public Criteria andConfigNotEqualTo(String value) {
addCriterion("config <>", value, "config");
return (Criteria) this;
}
public Criteria andConfigGreaterThan(String value) {
addCriterion("config >", value, "config");
return (Criteria) this;
}
public Criteria andConfigGreaterThanOrEqualTo(String value) {
addCriterion("config >=", value, "config");
return (Criteria) this;
}
public Criteria andConfigLessThan(String value) {
addCriterion("config <", value, "config");
return (Criteria) this;
}
public Criteria andConfigLessThanOrEqualTo(String value) {
addCriterion("config <=", value, "config");
return (Criteria) this;
}
public Criteria andConfigLike(String value) {
addCriterion("config like", value, "config");
return (Criteria) this;
}
public Criteria andConfigNotLike(String value) {
addCriterion("config not like", value, "config");
return (Criteria) this;
}
public Criteria andConfigIn(List<String> values) {
addCriterion("config in", values, "config");
return (Criteria) this;
}
public Criteria andConfigNotIn(List<String> values) {
addCriterion("config not in", values, "config");
return (Criteria) this;
}
public Criteria andConfigBetween(String value1, String value2) {
addCriterion("config between", value1, value2, "config");
return (Criteria) this;
}
public Criteria andConfigNotBetween(String value1, String value2) {
addCriterion("config not between", value1, value2, "config");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -16,6 +16,7 @@
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="config" jdbcType="VARCHAR" property="config" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -77,7 +78,7 @@
</sql>
<sql id="Base_Column_List">
id, `key`, `type`, `value`, `group`, job, `enable`, resource_id, user_id, workspace_id,
create_time, update_time, project_id, `name`
create_time, update_time, project_id, `name`, config
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ScheduleExample" resultMap="BaseResultMap">
select
@ -114,12 +115,14 @@
`value`, `group`, job,
`enable`, resource_id, user_id,
workspace_id, create_time, update_time,
project_id, `name`)
project_id, `name`, config
)
values (#{id,jdbcType=VARCHAR}, #{key,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{value,jdbcType=VARCHAR}, #{group,jdbcType=VARCHAR}, #{job,jdbcType=VARCHAR},
#{enable,jdbcType=BIT}, #{resourceId,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR},
#{workspaceId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR})
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{config,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Schedule">
insert into schedule
@ -166,6 +169,9 @@
<if test="name != null">
`name`,
</if>
<if test="config != null">
config,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -210,6 +216,9 @@
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="config != null">
#{config,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ScheduleExample" resultType="java.lang.Long">
@ -263,6 +272,9 @@
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.config != null">
config = #{record.config,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -283,7 +295,8 @@
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR}
`name` = #{record.name,jdbcType=VARCHAR},
config = #{record.config,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -330,6 +343,9 @@
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="config != null">
config = #{config,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -347,7 +363,8 @@
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR}
`name` = #{name,jdbcType=VARCHAR},
config = #{config,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -1,6 +1,8 @@
package io.metersphere.job.sechedule;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.RunModeConfig;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.commons.constants.ApiRunMode;
@ -8,6 +10,7 @@ import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import java.util.ArrayList;
@ -16,15 +19,17 @@ import java.util.UUID;
/**
* 情景测试Job
*
* @author song.tianyang
* @Date 2020/12/22 2:59 下午
* @Description
*/
public class ApiScenarioTestJob extends MsScheduleJob {
private String projectID;
public class ApiScenarioTestJob extends MsScheduleJob {
private String projectID;
private List<String> scenarioIds;
private ApiAutomationService apiAutomationService;
public ApiScenarioTestJob() {
apiAutomationService = (ApiAutomationService) CommonBeanFactory.getBean(ApiAutomationService.class);
}
@ -38,7 +43,7 @@ public class ApiScenarioTestJob extends MsScheduleJob {
this.userId = jobDataMap.getString("userId");
this.expression = jobDataMap.getString("expression");
this.projectID = jobDataMap.getString("projectId");
if(resourceId!=null){
if (resourceId != null) {
scenarioIds = new ArrayList<>();
scenarioIds.add(resourceId);
}
@ -61,6 +66,13 @@ public class ApiScenarioTestJob extends MsScheduleJob {
request.setReportUserID(this.userId);
request.setRunMode(ApiRunMode.SCHEDULE_SCENARIO.name());
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String config = jobDataMap.getString("config");
if (StringUtils.isNotBlank(config)) {
RunModeConfig runModeConfig = JSONObject.parseObject(config, RunModeConfig.class);
request.setConfig(runModeConfig);
}
apiAutomationService.run(request);
}

View File

@ -1,5 +1,6 @@
package io.metersphere.job.sechedule;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.LogUtil;
import org.python.antlr.ast.Str;
@ -290,11 +291,13 @@ public class ScheduleManager {
addOrUpdateCronJob(jobKey, triggerKey, jobClass, cron, null);
}
public JobDataMap getDefaultJobDataMap(String resourceId, String expression, String userId) {
public JobDataMap getDefaultJobDataMap(Schedule schedule, String expression, String userId) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("resourceId", resourceId);
jobDataMap.put("resourceId", schedule.getResourceId());
jobDataMap.put("expression", expression);
jobDataMap.put("userId", userId);
jobDataMap.put("config", schedule.getConfig());
return jobDataMap;
}

View File

@ -137,7 +137,7 @@ public class ScheduleService {
LogUtil.info("初始化任务:" + JSON.toJSONString(schedule));
scheduleManager.addOrUpdateCronJob(new JobKey(schedule.getKey(), schedule.getGroup()),
new TriggerKey(schedule.getKey(), schedule.getGroup()), Class.forName(schedule.getJob()), schedule.getValue(),
scheduleManager.getDefaultJobDataMap(schedule.getResourceId(), schedule.getValue(), schedule.getUserId()));
scheduleManager.getDefaultJobDataMap(schedule, schedule.getValue(), schedule.getUserId()));
}
} catch (Exception e) {
LogUtil.error("初始化任务失败", e);
@ -166,7 +166,7 @@ public class ScheduleService {
if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) {
try {
scheduleManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression,
scheduleManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
scheduleManager.getDefaultJobDataMap(request, cronExpression, SessionUtils.getUser().getId()));
} catch (SchedulerException e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException("定时任务开启异常");

View File

@ -15,16 +15,23 @@ UPDATE load_test_report JOIN load_test ON load_test.id = load_test_report.test_i
SET load_test_report.test_name = load_test.name;
-- api_environment_running_param
CREATE TABLE IF NOT EXISTS api_environment_running_param (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`api_enviroment_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`create_time` bigint(13) NULL DEFAULT NULL,
`update_time` bigint(13) NULL DEFAULT NULL,
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `api_enviroment_id`(`api_enviroment_id`) USING BTREE,
INDEX `key_api_enviroment_id`(`api_enviroment_id`,`key`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`api_enviroment_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`create_time` bigint(13) NULL DEFAULT NULL,
`update_time` bigint(13) NULL DEFAULT NULL,
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `api_enviroment_id` (`api_enviroment_id`) USING BTREE,
INDEX `key_api_enviroment_id` (`api_enviroment_id`, `key`) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
ROW_FORMAT = Dynamic;
-- schedule
alter table schedule
add config VARCHAR(500) null;

View File

@ -1,9 +1,9 @@
<template>
<el-dialog
destroy-on-close
:title="$t('load_test.runtime_config')"
width="350px"
:visible.sync="runModeVisible"
destroy-on-close
:title="$t('load_test.runtime_config')"
width="450px"
:visible.sync="runModeVisible"
>
<div>
<span class="ms-mode-span">{{ $t("run_mode.title") }}</span>
@ -13,19 +13,41 @@
</el-radio-group>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
<el-radio-group v-model="runConfig.reportType">
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
</el-radio-group>
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<div>
<el-radio-group v-model="runConfig.reportType">
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
</el-radio-group>
</div>
<div style="padding-top: 10px">
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
{{ $t('run_mode.run_with_resource_pool') }}
</el-checkbox>
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</div>
</el-col>
</el-row>
</div>
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport' && runConfig.mode==='serial'">
<span class="ms-mode-span">{{ $t("run_mode.report_name") }}</span>
<el-input
v-model="runConfig.reportName"
:placeholder="$t('commons.input_content')"
size="small"
style="width: 200px"
v-model="runConfig.reportName"
:placeholder="$t('commons.input_content')"
size="small"
style="width: 200px"
/>
</div>
<template v-slot:footer>
@ -35,43 +57,63 @@
</template>
<script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "RunMode",
components: {MsDialogFooter},
data() {
return {
runModeVisible: false,
runConfig: {mode: "serial", reportType: "iddReport", reportName: ""},
export default {
name: "RunMode",
components: {MsDialogFooter},
data() {
return {
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
mode: "serial",
reportType: "iddReport",
reportName: "",
runWithinResourcePool: false,
resourcePoolId: null,
},
};
},
methods: {
open() {
this.runModeVisible = true;
this.getResourcePools();
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
reportName: "",
runWithinResourcePool: false,
resourcePoolId: null,
};
this.runModeVisible = false;
},
methods: {
open() {
this.runModeVisible = true;
},
close() {
this.runConfig = {mode: "serial", reportType: "iddReport", reportName: ""};
this.runModeVisible = false;
},
handleRunBatch() {
if (this.runConfig.mode === 'serial' && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
this.$warning(this.$t('commons.input_name'));
return;
}
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
handleRunBatch() {
if (this.runConfig.mode === 'serial' && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
this.$warning(this.$t('commons.input_name'));
return;
}
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
};
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
},
};
</script>
<style scoped>
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-div {
margin-top: 20px;
}
.ms-mode-div {
margin-top: 20px;
}
</style>

View File

@ -19,7 +19,9 @@
</el-button>
</el-col>
<el-col :span="6">
<schedule-switch :schedule="schedule" :corn-value="form.cronValue" @resultListChange="getExecuteTimeTemplate" @scheduleChange="scheduleChange"></schedule-switch>
<schedule-switch :schedule="schedule" :corn-value="form.cronValue"
@resultListChange="getExecuteTimeTemplate"
@scheduleChange="scheduleChange"></schedule-switch>
</el-col>
</el-row>
@ -174,15 +176,15 @@ export default {
if (this.isTesterPermission) {
this.result = this.$post('user/org/member/list/all', param, response => {
this.scheduleReceiverOptions = response.data
this.scheduleReceiverOptions = response.data;
});
}
},
buildParam() {
let param = {};
param.notices = this.tableData
param.testId = this.testId
param.notices = this.tableData;
param.testId = this.testId;
return param;
},
open(row) {
@ -202,7 +204,7 @@ export default {
this.dialogVisible = true;
this.form.cronValue = this.schedule.value;
listenGoBack(this.close);
this.activeName = 'first'
this.activeName = 'first';
},
findSchedule() {
var scheduleResourceID = this.testId;
@ -228,7 +230,7 @@ export default {
this.$refs['from'].validate((valid) => {
if (valid) {
this.intervalShortValidate();
let formCronValue = this.form.cronValue
let formCronValue = this.form.cronValue;
this.schedule.enable = true;
this.schedule.value = formCronValue;
this.saveSchedule();
@ -301,7 +303,7 @@ export default {
let time2 = new Date(resultList[1]);
return time2 - time1;
},
getExecuteTimeTemplate(executeTileArr){
getExecuteTimeTemplate(executeTileArr) {
alert(executeTileArr);
},
},

View File

@ -2,7 +2,7 @@
<el-dialog
destroy-on-close
:title="$t('load_test.runtime_config')"
width="350px"
width="450px"
:visible.sync="runModeVisible"
>
<div>
@ -13,8 +13,29 @@
</el-radio-group>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
<el-checkbox v-model="runConfig.onSampleError">失败停止</el-checkbox>
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<div>
<el-checkbox v-model="runConfig.onSampleError">失败停止</el-checkbox>
</div>
<div v-if="testType === 'API'" style="padding-top: 10px">
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
{{ $t('run_mode.run_with_resource_pool') }}
</el-checkbox>
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</div>
</el-col>
</el-row>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
@ -23,39 +44,60 @@
</template>
<script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
export default {
name: "MsPlanRunMode",
components: {MsDialogFooter},
data() {
return {
runModeVisible: false,
runConfig: {mode: "serial", reportType: "iddReport", onSampleError: false},
export default {
name: "MsPlanRunMode",
components: {MsDialogFooter},
data() {
return {
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
},
};
},
methods: {
open(testType) {
this.runModeVisible = true;
this.testType = testType;
this.getResourcePools();
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
};
this.runModeVisible = false;
},
methods: {
open() {
this.runModeVisible = true;
},
close() {
this.runConfig = {mode: "serial", reportType: "iddReport", onSampleError: false};
this.runModeVisible = false;
},
handleRunBatch() {
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
handleRunBatch() {
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
};
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
},
};
</script>
<style scoped>
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-div {
margin-top: 20px;
}
.ms-mode-div {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,398 @@
<template>
<el-dialog
v-loading="result.loading"
:close-on-click-modal="false" width="60%" class="schedule-edit" :visible.sync="dialogVisible"
:append-to-body='true'
@close="close">
<template>
<div>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('schedule.task_config')" name="first">
<div class="el-step__icon is-text" style="margin-right: 10px;">
<div class="el-step__icon-inner">1</div>
</div>
<span>{{ $t('schedule.edit_timer_task') }}</span>
<el-form :model="form" :rules="rules" ref="from" style="padding-top: 10px;margin-left: 20px;">
<el-form-item
prop="cronValue">
<el-row>
<el-col :span="18">
<el-input :disabled="isReadOnly" v-model="form.cronValue" class="inp"
:placeholder="$t('schedule.please_input_cron_expression')"/>
<el-button :disabled="isReadOnly" type="primary" @click="saveCron" v-tester>{{
$t('commons.save')
}}
</el-button>
</el-col>
<el-col :span="6">
<schedule-switch :schedule="schedule" :corn-value="form.cronValue"
@resultListChange="getExecuteTimeTemplate"
@scheduleChange="scheduleChange"></schedule-switch>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-link :disabled="isReadOnly" type="primary" @click="showCronDialog">
{{ $t('schedule.generate_expression') }}
</el-link>
</el-form-item>
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
</el-form>
<div class="el-step__icon is-text" style="margin-right: 10px;">
<div class="el-step__icon-inner">2</div>
</div>
<span>{{ $t('load_test.runtime_config') }}</span>
<div style="padding-top: 10px;">
<span class="ms-mode-span">{{ $t("run_mode.title") }}</span>
<el-radio-group v-model="runConfig.mode">
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
</el-radio-group>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<el-row>
<el-col :span="3">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}:</span>
</el-col>
<el-col :span="18">
<div>
<el-checkbox v-model="runConfig.onSampleError">失败停止</el-checkbox>
</div>
<div v-if="scheduleTaskType === 'TEST_PLAN_TEST'" style="padding-top: 10px">
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
{{ $t('run_mode.run_with_resource_pool') }}
</el-checkbox>
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId"
size="mini">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</div>
</el-col>
</el-row>
</div>
<el-dialog width="60%" :title="$t('schedule.generate_expression')" :visible.sync="showCron"
:modal="false">
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"
ref="crontab"/>
</el-dialog>
</el-tab-pane>
<el-tab-pane :label="$t('schedule.task_notification')" name="second">
<ms-schedule-notification :is-tester-permission="isTesterPermission" :test-id="testId"
:schedule-receiver-options="scheduleReceiverOptions"/>
</el-tab-pane>
</el-tabs>
</div>
</template>
</el-dialog>
</template>
<script>
import {checkoutTestManagerOrTestUser, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import Crontab from "@/business/components/common/cron/Crontab";
import CrontabResult from "@/business/components/common/cron/CrontabResult";
import {cronValidate} from "@/common/js/cron";
import MsScheduleNotification from "@/business/components/api/automation/schedule/ScheduleNotification";
import ScheduleSwitch from "@/business/components/api/automation/schedule/ScheduleSwitch";
function defaultCustomValidate() {
return {pass: true};
}
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "MsTestPlanScheduleMaintain",
components: {
CrontabResult,
ScheduleSwitch,
Crontab,
MsScheduleNotification,
"NoticeTemplate": noticeTemplate.default
},
props: {
customValidate: {
type: Function,
default: defaultCustomValidate
},
isReadOnly: {
type: Boolean,
default: false
},
},
watch: {
'schedule.value'() {
this.form.cronValue = this.schedule.value;
}
},
data() {
const validateCron = (rule, cronValue, callback) => {
let customValidate = this.customValidate(this.getIntervalTime());
if (!cronValue) {
callback(new Error(this.$t('commons.input_content')));
} else if (!cronValidate(cronValue)) {
callback(new Error(this.$t('schedule.cron_expression_format_error')));
} else if (!customValidate.pass) {
callback(new Error(customValidate.info));
} else {
callback();
}
};
return {
result: {},
scheduleReceiverOptions: [],
operation: true,
dialogVisible: false,
schedule: {
value: "",
},
scheduleTaskType: "",
testId: String,
showCron: false,
form: {
cronValue: ""
},
paramRow: {},
activeName: 'first',
rules: {
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
},
resourcePools: [],
runConfig: {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
},
};
},
methods: {
currentUser: () => {
return getCurrentUser();
},
scheduleChange() {
let flag = this.schedule.enable;
let param = {};
param.taskID = this.schedule.id;
param.enable = flag;
let that = this;
if (flag === false) {
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning',
beforeClose(action, instance, done) {
if (action === 'cancel') { // messageBox switch
that.schedule.enable = param.enable = true;
}
done(); // done messageBox
},
}).then(() => {
this.updateTask(param);
}).catch(() => {
});
} else {
this.updateTask(param);
}
},
updateTask(param) {
this.result = this.$post('/api/schedule/updateEnableByPrimyKey', param, response => {
let paramTestId = "";
if (this.paramRow.redirectFrom === 'testPlan') {
paramTestId = this.paramRow.id;
this.scheduleTaskType = "TEST_PLAN_TEST";
} else {
paramTestId = this.paramRow.id;
this.scheduleTaskType = "API_SCENARIO_TEST";
}
this.taskID = paramTestId;
this.findSchedule(paramTestId);
});
},
initUserList() {
let param = {
name: '',
organizationId: this.currentUser().lastOrganizationId
};
if (this.isTesterPermission) {
this.result = this.$post('user/org/member/list/all', param, response => {
this.scheduleReceiverOptions = response.data;
});
}
},
buildParam() {
let param = {};
param.notices = this.tableData;
param.testId = this.testId;
return param;
},
open(row) {
//
let paramTestId = "";
this.paramRow = row;
if (row.redirectFrom === 'testPlan') {
paramTestId = row.id;
this.scheduleTaskType = "TEST_PLAN_TEST";
} else {
paramTestId = row.id;
this.scheduleTaskType = "API_SCENARIO_TEST";
}
this.testId = paramTestId;
this.findSchedule(paramTestId);
this.initUserList();
this.dialogVisible = true;
this.form.cronValue = this.schedule.value;
listenGoBack(this.close);
this.activeName = 'first';
this.getResourcePools();
},
findSchedule() {
var scheduleResourceID = this.testId;
var taskType = this.scheduleTaskType;
this.result = this.$get("/schedule/findOne/" + scheduleResourceID + "/" + taskType, response => {
if (response.data != null) {
this.schedule = response.data;
this.runConfig = JSON.parse(response.data.config);
} else {
this.schedule = {};
}
});
},
crontabFill(value, resultList) {
//
this.form.cronValue = value;
this.$refs.crontabResult.resultList = resultList;
this.$refs['from'].validate();
},
showCronDialog() {
this.showCron = true;
},
saveCron() {
this.$refs['from'].validate((valid) => {
if (valid) {
this.intervalShortValidate();
let formCronValue = this.form.cronValue;
this.schedule.enable = true;
this.schedule.value = formCronValue;
this.saveSchedule();
this.dialogVisible = false;
} else {
return false;
}
});
},
saveSchedule() {
this.checkScheduleEdit();
let param = {};
param = this.schedule;
param.resourceId = this.testId;
param.config = JSON.stringify(this.runConfig);
let url = '/api/automation/schedule/create';
if (this.scheduleTaskType === "TEST_PLAN_TEST") {
param.scheduleFrom = "testPlan";
//
url = '/schedule/create';
if (param.id) {
url = '/schedule/update';
}
} else {
param.scheduleFrom = "scenario";
if (param.id) {
url = '/api/automation/schedule/update';
}
}
this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.$emit("refreshTable");
});
},
checkScheduleEdit() {
if (this.create) {
this.$message(this.$t('api_test.environment.please_save_test'));
return false;
}
return true;
},
saveNotice() {
let param = this.buildParam();
this.result = this.$post("notice/save", param, () => {
this.$success(this.$t('commons.save_success'));
});
},
close() {
this.dialogVisible = false;
this.form.cronValue = '';
this.$refs['from'].resetFields();
if (!this.schedule.value) {
this.$refs.crontabResult.resultList = [];
}
removeGoBackListener(this.close);
},
intervalShortValidate() {
if (this.getIntervalTime() < 3 * 60 * 1000) {
// return false;
this.$info(this.$t('schedule.cron_expression_interval_short_error'));
}
return true;
},
resultListChange() {
this.$refs['from'].validate();
},
getIntervalTime() {
let resultList = this.$refs.crontabResult.resultList;
let time1 = new Date(resultList[0]);
let time2 = new Date(resultList[1]);
return time2 - time1;
},
getExecuteTimeTemplate(executeTileArr) {
alert(executeTileArr);
},
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
},
computed: {
isTesterPermission() {
return checkoutTestManagerOrTestUser();
}
}
};
</script>
<style scoped>
.inp {
width: 50%;
margin-right: 20px;
}
.el-form-item {
margin-bottom: 10px;
}
.ms-mode-span {
margin-right: 10px;
margin-left: 20px;
}
.ms-mode-div {
margin-top: 10px;
}
</style>

View File

@ -96,7 +96,7 @@
show-overflow-tooltip
:key="index">
</el-table-column>
<el-table-column v-if="item.id == 'tags'" prop="tags"
<el-table-column v-if="item.id == 'tags'" prop="tags"
:label="$t('api_test.automation.tag')" :key="index">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
@ -205,7 +205,7 @@
:with-tip="enableDeleteTip">
{{ $t('test_track.plan.plan_delete_tip') }}
</ms-delete-confirm>
<ms-schedule-maintain ref="scheduleMaintain" @refreshTable="initTableData"/>
<ms-test-plan-schedule-maintain ref="scheduleMaintain" @refreshTable="initTableData"/>
</el-card>
</template>
@ -218,20 +218,19 @@ import MsTableOperatorButton from "../../../common/components/MsTableOperatorBut
import MsTableOperator from "../../../common/components/MsTableOperator";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
import PlanStageTableItem from "../../common/tableItems/plan/PlanStageTableItem";
import {checkoutTestManagerOrTestUser, getCurrentUser} from "@/common/js/utils";
import {checkoutTestManagerOrTestUser} from "@/common/js/utils";
import TestReportTemplateList from "../view/comonents/TestReportTemplateList";
import TestCaseReportView from "../view/comonents/report/TestCaseReportView";
import MsDeleteConfirm from "../../../common/components/MsDeleteConfirm";
import {TEST_PLAN_CONFIGS} from "../../../common/components/search/search-components";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain"
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import {TEST_PLAN_LIST} from "@/common/js/constants";
import {Test_Plan_List} from "@/business/components/common/model/JsonData";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import MsTag from "@/business/components/common/components/MsTag";
import MsTestPlanScheduleMaintain from "@/business/components/track/plan/components/ScheduleMaintain";
export default {
name: "TestPlanList",
@ -244,7 +243,7 @@ export default {
TestReportTemplateList,
PlanStageTableItem,
PlanStatusTableItem,
MsScheduleMaintain,
MsTestPlanScheduleMaintain,
MsTableOperator, MsTableOperatorButton, MsDialogFooter, MsTableHeader, MsCreateBox, MsTablePagination
},
data() {
@ -275,7 +274,7 @@ export default {
{text: this.$t('test_track.plan.system_test'), value: 'system'},
{text: this.$t('test_track.plan.regression_test'), value: 'regression'},
],
}
};
},
watch: {
'$route'(to, from) {
@ -294,10 +293,10 @@ export default {
},
methods: {
inite() {
this.initTableData()
this.initTableData();
},
customHeader() {
this.$refs.headerCustom.open(this.tableLabel)
this.$refs.headerCustom.open(this.tableLabel);
},
initTableData() {
if (this.planId) {
@ -317,14 +316,14 @@ export default {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
item.passRate = item.passRate + '%'
})
item.passRate = item.passRate + '%';
});
});
getLabel(this, TEST_PLAN_LIST);
},
copyData(status) {
return JSON.parse(JSON.stringify(this.dataMap.get(status)))
return JSON.parse(JSON.stringify(this.dataMap.get(status)));
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
@ -396,12 +395,12 @@ export default {
this.$refs.testCaseReportView.open(planId, reportId);
}
},
scheduleTask(row){
scheduleTask(row) {
row.redirectFrom = "testPlan";
this.$refs.scheduleMaintain.open(row);
},
}
}
};
</script>
<style scoped>

View File

@ -3,13 +3,13 @@
<el-card class="card-content" v-loading="result.loading">
<template v-slot:header>
<test-plan-case-list-header
:project-id="getProjectId()"
:condition="condition"
:plan-id="planId"
@refresh="initTable"
@relevanceCase="$emit('relevanceCase')"
@setEnvironment="setEnvironment"
v-if="isPlanModel"/>
:project-id="getProjectId()"
:condition="condition"
:plan-id="planId"
@refresh="initTable"
@relevanceCase="$emit('relevanceCase')"
@setEnvironment="setEnvironment"
v-if="isPlanModel"/>
</template>
<el-table v-loading="result.loading" ref="table"
@ -31,65 +31,67 @@
</template>
</el-table-column>
<template v-for="(item, index) in tableLabel">
<el-table-column v-if="item.id == 'num'" prop="num" sortable="custom" label="ID" min-width="80" show-overflow-tooltip
<el-table-column v-if="item.id == 'num'" prop="num" sortable="custom" label="ID" min-width="80"
show-overflow-tooltip
:key="index"/>
<el-table-column v-if="item.id == 'name'" prop="name" sortable="custom" min-width="120"
<el-table-column v-if="item.id == 'name'" prop="name" sortable="custom" min-width="120"
:label="$t('api_test.definition.api_name')" show-overflow-tooltip :key="index"/>
<el-table-column
v-if="item.id == 'priority'"
prop="priority"
:filters="priorityFilters"
sortable="custom"
column-key="priority"
:label="$t('test_track.case.priority')"
show-overflow-tooltip
min-width="120"
:key="index">
v-if="item.id == 'priority'"
prop="priority"
:filters="priorityFilters"
sortable="custom"
column-key="priority"
:label="$t('test_track.case.priority')"
show-overflow-tooltip
min-width="120"
:key="index">
<template v-slot:default="scope">
<priority-table-item :value="scope.row.priority"/>
</template>
</el-table-column>
<el-table-column
v-if="item.id == 'path'"
min-width="100"
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip
:key="index"/>
v-if="item.id == 'path'"
min-width="100"
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip
:key="index"/>
<el-table-column
v-if="item.id == 'createUser'"
prop="createUser"
column-key="user_id"
sortable="custom"
min-width="100"
:filters="userFilters"
:label="'创建人'"
show-overflow-tooltip
:key="index"/>
v-if="item.id == 'createUser'"
prop="createUser"
column-key="user_id"
sortable="custom"
min-width="100"
:filters="userFilters"
:label="'创建人'"
show-overflow-tooltip
:key="index"/>
<el-table-column
v-if="item.id == 'custom'"
sortable="custom"
min-width="160"
:label="$t('api_test.definition.api_last_time')"
prop="updateTime"
:key="index">
v-if="item.id == 'custom'"
sortable="custom"
min-width="160"
:label="$t('api_test.definition.api_last_time')"
prop="updateTime"
:key="index">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
v-if="item.id == 'tags'"
prop="tags"
min-width="100"
:label="$t('commons.tag')"
:key="index">
v-if="item.id == 'tags'"
prop="tags"
min-width="100"
:label="$t('commons.tag')"
:key="index">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :content="itemName" style="margin-left: 0px; margin-right: 2px"/>
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="itemName" style="margin-left: 0px; margin-right: 2px"/>
</template>
</el-table-column>
@ -113,7 +115,7 @@
</template>
</el-table-column>
</template>
<el-table-column fixed="right" min-width="100" v-if="!isReadOnly" :label="$t('commons.operating')" >
<el-table-column fixed="right" min-width="100" v-if="!isReadOnly" :label="$t('commons.operating')">
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
@ -173,16 +175,15 @@ import ThreadGroup from "../../../../../api/definition/components/jmeter/compone
import {TEST_PLAN_API_CASE, WORKSPACE_ID} from "@/common/js/constants";
import {
_filter,
_handleSelect,
_handleSelectAll,
_sort,
getLabel,
_handleSelect,
initCondition,
setUnSelectIds,
getSelectDataCounts,
toggleAllSelection,
buildBatchParam,
checkTableRowIsSelect
checkTableRowIsSelect,
getLabel,
getSelectDataCounts,
setUnSelectIds,
toggleAllSelection
} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {Test_Plan_Api_Case} from "@/business/components/common/model/JsonData";
@ -261,7 +262,7 @@ export default {
userFilters: [],
projectIds: [],
projectList: []
}
};
},
props: {
currentProtocol: String,
@ -285,7 +286,7 @@ export default {
model: {
type: String,
default() {
'api'
'api';
}
},
planId: String,
@ -298,7 +299,7 @@ export default {
},
activated() {
this.status = 'default'
this.status = 'default';
},
watch: {
selectNodeIds() {
@ -318,27 +319,27 @@ export default {
computed: {
//
isRelevanceModel() {
return this.model === 'relevance'
return this.model === 'relevance';
},
//
isPlanModel() {
return this.model === 'plan'
return this.model === 'plan';
},
//
isApiModel() {
return this.model === 'api'
return this.model === 'api';
},
},
methods: {
customHeader() {
this.$refs.headerCustom.open(this.tableLabel)
this.$refs.headerCustom.open(this.tableLabel);
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.valueArr.userId = response.data;
this.userFilters = response.data.map(u => {
return {text: u.name, value: u.id}
return {text: u.name, value: u.id};
});
});
},
@ -376,8 +377,8 @@ export default {
setTimeout(this.$refs.table.doLayout, 200);
}
this.$nextTick(() => {
checkTableRowIsSelect(this,this.condition,this.tableData,this.$refs.table,this.selectRows);
})
checkTableRowIsSelect(this, this.condition, this.tableData, this.$refs.table, this.selectRows);
});
});
}
if (this.planId) {
@ -395,8 +396,8 @@ export default {
setTimeout(this.$refs.table.doLayout, 200);
}
this.$nextTick(() => {
checkTableRowIsSelect(this,this.condition,this.tableData,this.$refs.table,this.selectRows);
})
checkTableRowIsSelect(this, this.condition, this.tableData, this.$refs.table, this.selectRows);
});
});
}
getLabel(this, TEST_PLAN_API_CASE);
@ -447,7 +448,7 @@ export default {
let param = buildBatchParam(this);
param.ids = Array.from(this.selectRows).map(row => row.id);
if (this.reviewId) {
param.testCaseReviewId = this.reviewId
param.testCaseReviewId = this.reviewId;
this.$post('/test/case/review/api/case/batch/delete', param, () => {
this.selectRows.clear();
this.initTable();
@ -464,22 +465,22 @@ export default {
this.$success(this.$t('test_track.cancel_relevance_success'));
});
}
}
}
});
},
getResult(data) {
if (RESULT_MAP.get(data)) {
return RESULT_MAP.get(data);
} else {
return RESULT_MAP.get("default");
}
},
runRefresh(data) {
this.rowLoading = "";
this.$success(this.$t('schedule.event_success'));
this.initTable();
},
});
},
getResult(data) {
if (RESULT_MAP.get(data)) {
return RESULT_MAP.get(data);
} else {
return RESULT_MAP.get("default");
}
},
runRefresh(data) {
this.rowLoading = "";
this.$success(this.$t('schedule.event_success'));
this.initTable();
},
singleRun(row) {
this.runData = [];
this.rowLoading = row.id;
@ -567,11 +568,11 @@ export default {
//
}
},
orderBySelectRows(rows){
orderBySelectRows(rows) {
let selectIds = Array.from(rows).map(row => row.id);
let array = [];
for(let i in this.tableData){
if(selectIds.indexOf(this.tableData[i].id)!==-1){
for (let i in this.tableData) {
if (selectIds.indexOf(this.tableData[i].id) !== -1) {
array.push(this.tableData[i]);
}
}
@ -580,7 +581,7 @@ export default {
handleBatchExecute() {
this.getData().then(() => {
if (this.runData && this.runData.length > 0) {
this.$refs.runMode.open();
this.$refs.runMode.open('API');
}
});
},
@ -597,7 +598,14 @@ export default {
threadGroup.hashTree.push(item);
testPlan.hashTree.push(threadGroup);
});
let reqObj = {id: getUUID().substring(0, 8), testElement: testPlan, type: 'API_PLAN', reportId: "run", projectId: projectId};
let reqObj = {
id: getUUID().substring(0, 8),
testElement: testPlan,
type: 'API_PLAN',
reportId: "run",
projectId: projectId,
config: config
};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
this.$fileUpload("/api/definition/run", null, bodyFiles, reqObj, response => {
this.$message('任务执行中,请稍后刷新查看结果');
@ -610,7 +618,13 @@ export default {
this.runData.forEach(item => {
threadGroup.hashTree.push(item);
});
let reqObj = {id: getUUID().substring(0, 8), testElement: testPlan, type: 'API_PLAN', reportId: "run", projectId: projectId};
let reqObj = {
id: getUUID().substring(0, 8),
testElement: testPlan,
type: 'API_PLAN',
reportId: "run",
projectId: projectId
};
let bodyFiles = getBodyUploadFiles(reqObj, this.runData);
this.$fileUpload("/api/definition/run", null, bodyFiles, reqObj, response => {
this.$message('任务执行中,请稍后刷新查看结果');
@ -673,7 +687,7 @@ export default {
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
},
},
}
};
</script>
<style scoped>

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-card class="table-card" v-loading="loading">
<div class="card-container">
<el-card class="card-content" v-loading="loading">
<template v-slot:header>
<test-plan-scenario-list-header
:condition="condition"
@ -8,10 +8,11 @@
@relevanceCase="$emit('relevanceCase', 'scenario')"/>
</template>
<el-table ref="scenarioTable" border :data="tableData" class="test-content adjust-table ms-select-all-fixed" @select-all="handleSelectAll"
<el-table ref="scenarioTable" border :data="tableData" class="test-content adjust-table ms-select-all-fixed"
@select-all="handleSelectAll"
:height="screenHeight"
@select="handleSelect">
<el-table-column type="selection"/>
<el-table-column width="50" type="selection"/>
<ms-table-header-select-popover v-show="total>0"
:page-size="pageSize > total ? total : pageSize"
:total="total"
@ -171,7 +172,7 @@ export default {
return {
type: TEST_PLAN_SCENARIO_CASE,
headerItems: Test_Plan_Scenario_Case,
screenHeight: document.documentElement.clientHeight - 348,//
screenHeight: 'calc(100vh - 330px)',//
tableLabel: [],
loading: false,
condition: {},
@ -180,7 +181,7 @@ export default {
selectAll: false,
tableData: [],
currentPage: 1,
selectDataCounts:0,
selectDataCounts: 0,
pageSize: 10,
total: 0,
reportId: "",
@ -297,7 +298,7 @@ export default {
})
},
handleBatchExecute() {
this.$refs.runMode.open();
this.$refs.runMode.open('API');
},
orderBySelectRows(rows){
let selectIds = Array.from(rows).map(row => row.id);

View File

@ -1658,6 +1658,7 @@ export default {
not_set: "Not Set",
next_execution_time: "Next Execution Time",
edit_timer_task: "Edit Timer Task",
task_config: "Task Config",
test_name: 'Test Name',
running_rule: 'Rule',
job_status: 'Status',
@ -1803,5 +1804,6 @@ export default {
idd_report: "Report",
set_report: "Set report",
report_name: "Report name",
run_with_resource_pool: "Run Within Resource pool",
}
};

View File

@ -1670,6 +1670,7 @@ export default {
running_task: '运行中的任务',
next_execution_time: "下次执行时间",
edit_timer_task: "编辑定时任务",
task_config: "任务配置",
please_input_cron_expression: "请输入 Cron 表达式",
generate_expression: "生成表达式",
cron_expression_format_error: "Cron 表达式格式错误",
@ -1811,5 +1812,6 @@ export default {
idd_report: "独立报告",
set_report: "集合报告",
report_name: "报告名称",
run_with_resource_pool: "资源池运行",
}
};

View File

@ -1670,6 +1670,7 @@ export default {
running_task: '運行中的任務',
next_execution_time: "下次執行時間",
edit_timer_task: "編輯定時任務",
task_config: "任務配置",
please_input_cron_expression: "請輸入 Cron 表達式",
generate_expression: "生成表達式",
cron_expression_format_error: "Cron 表達式格式錯誤",
@ -1811,5 +1812,6 @@ export default {
idd_report: "獨立報告",
set_report: "集合報告",
report_name: "報告名稱",
run_with_resource_pool: "資源池運行",
}
};