feat(接口自动化): 增加URL唯一性校验开关,控制URL校验规则

This commit is contained in:
fit2-zhao 2021-01-06 13:38:17 +08:00
parent e975dcbc18
commit 09fd2c2ab6
13 changed files with 301 additions and 208 deletions

View File

@ -316,9 +316,12 @@ public class ApiAutomationService {
boolean isFirst = true; boolean isFirst = true;
for (ApiScenarioWithBLOBs item : apiScenarios) { for (ApiScenarioWithBLOBs item : apiScenarios) {
if (item.getStepTotal() == 0) { if (item.getStepTotal() == 0) {
if (apiScenarios.size() == 1) {
MSException.throwException(item.getName() + "" + Translator.get("automation_exec_info")); MSException.throwException(item.getName() + "" + Translator.get("automation_exec_info"));
break; break;
} }
continue;
}
MsThreadGroup group = new MsThreadGroup(); MsThreadGroup group = new MsThreadGroup();
group.setLabel(item.getName()); group.setLabel(item.getName());
group.setName(UUID.randomUUID().toString()); group.setName(UUID.randomUUID().toString());

View File

@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest; import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO; import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.datacount.ApiDataCountResult;
@ -18,6 +17,7 @@ import io.metersphere.api.parse.ApiImportParserFactory;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionMapper; import io.metersphere.base.mapper.ApiDefinitionMapper;
import io.metersphere.base.mapper.ApiTestFileMapper; import io.metersphere.base.mapper.ApiTestFileMapper;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper; import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper; import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper; import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
@ -71,6 +71,8 @@ public class ApiDefinitionService {
private ExtApiScenarioMapper extApiScenarioMapper; private ExtApiScenarioMapper extApiScenarioMapper;
@Resource @Resource
private ExtTestPlanMapper extTestPlanMapper; private ExtTestPlanMapper extTestPlanMapper;
@Resource
private ProjectMapper projectMapper;
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24); private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
@ -168,7 +170,8 @@ public class ApiDefinitionService {
example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash") example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash")
.andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath()) .andProtocolEqualTo(request.getProtocol()).andPathEqualTo(request.getPath())
.andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); .andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
if (apiDefinitionMapper.countByExample(example) > 0) { Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
if (apiDefinitionMapper.countByExample(example) > 0 && !project.getRepeatable()) {
MSException.throwException(Translator.get("api_definition_url_not_repeating")); MSException.throwException(Translator.get("api_definition_url_not_repeating"));
} }
} else { } else {
@ -429,8 +432,8 @@ public class ApiDefinitionService {
public void editApiByParam(ApiBatchRequest request) { public void editApiByParam(ApiBatchRequest request) {
List<String> ids = request.getIds(); List<String> ids = request.getIds();
if(request.isSelectAllDate()){ if (request.isSelectAllDate()) {
ids = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds()); ids = this.getAllApiIdsByFontedSelect(request.getFilters(), request.getName(), request.getModuleIds(), request.getProjectId(), request.getUnSelectIds());
} }
//name在这里只是查询参数 //name在这里只是查询参数
request.setName(null); request.setName(null);
@ -493,15 +496,15 @@ public class ApiDefinitionService {
public void deleteByParams(ApiDefinitionBatchProcessingRequest request) { public void deleteByParams(ApiDefinitionBatchProcessingRequest request) {
List<String> apiIds = request.getDataIds(); List<String> apiIds = request.getDataIds();
if(request.isSelectAllDate()){ if (request.isSelectAllDate()) {
apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds()); apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(), request.getName(), request.getModuleIds(), request.getProjectId(), request.getUnSelectIds());
} }
ApiDefinitionExample example = new ApiDefinitionExample(); ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdIn(apiIds); example.createCriteria().andIdIn(apiIds);
apiDefinitionMapper.deleteByExample(example); apiDefinitionMapper.deleteByExample(example);
} }
private List<String> getAllApiIdsByFontedSelect(List<String> filter,String name,List<String> moduleIds,String projectId,List<String>unSelectIds) { private List<String> getAllApiIdsByFontedSelect(List<String> filter, String name, List<String> moduleIds, String projectId, List<String> unSelectIds) {
ApiDefinitionRequest request = new ApiDefinitionRequest(); ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setFilters(filter); request.setFilters(filter);
request.setName(name); request.setName(name);
@ -519,8 +522,8 @@ public class ApiDefinitionService {
public void removeToGcByParams(ApiDefinitionBatchProcessingRequest request) { public void removeToGcByParams(ApiDefinitionBatchProcessingRequest request) {
List<String> apiIds = request.getDataIds(); List<String> apiIds = request.getDataIds();
if(request.isSelectAllDate()){ if (request.isSelectAllDate()) {
apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds()); apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(), request.getName(), request.getModuleIds(), request.getProjectId(), request.getUnSelectIds());
} }
extApiDefinitionMapper.removeToGc(apiIds); extApiDefinitionMapper.removeToGc(apiIds);
} }

View File

@ -1,8 +1,9 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
public class Project implements Serializable { public class Project implements Serializable {
private String id; private String id;
@ -23,5 +24,7 @@ public class Project implements Serializable {
private String zentaoId; private String zentaoId;
private Boolean repeatable;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -713,6 +713,66 @@ public class ProjectExample {
addCriterion("zentao_id not between", value1, value2, "zentaoId"); addCriterion("zentao_id not between", value1, value2, "zentaoId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andRepeatableIsNull() {
addCriterion("`repeatable` is null");
return (Criteria) this;
}
public Criteria andRepeatableIsNotNull() {
addCriterion("`repeatable` is not null");
return (Criteria) this;
}
public Criteria andRepeatableEqualTo(Boolean value) {
addCriterion("`repeatable` =", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableNotEqualTo(Boolean value) {
addCriterion("`repeatable` <>", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableGreaterThan(Boolean value) {
addCriterion("`repeatable` >", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableGreaterThanOrEqualTo(Boolean value) {
addCriterion("`repeatable` >=", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableLessThan(Boolean value) {
addCriterion("`repeatable` <", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableLessThanOrEqualTo(Boolean value) {
addCriterion("`repeatable` <=", value, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableIn(List<Boolean> values) {
addCriterion("`repeatable` in", values, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableNotIn(List<Boolean> values) {
addCriterion("`repeatable` not in", values, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableBetween(Boolean value1, Boolean value2) {
addCriterion("`repeatable` between", value1, value2, "repeatable");
return (Criteria) this;
}
public Criteria andRepeatableNotBetween(Boolean value1, Boolean value2) {
addCriterion("`repeatable` not between", value1, value2, "repeatable");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -11,6 +11,7 @@
<result column="tapd_id" jdbcType="VARCHAR" property="tapdId" /> <result column="tapd_id" jdbcType="VARCHAR" property="tapdId" />
<result column="jira_key" jdbcType="VARCHAR" property="jiraKey" /> <result column="jira_key" jdbcType="VARCHAR" property="jiraKey" />
<result column="zentao_id" jdbcType="VARCHAR" property="zentaoId" /> <result column="zentao_id" jdbcType="VARCHAR" property="zentaoId" />
<result column="repeatable" jdbcType="BIT" property="repeatable" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -72,7 +73,7 @@
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key, id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
zentao_id zentao_id, `repeatable`
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
select select
@ -107,12 +108,12 @@
<insert id="insert" parameterType="io.metersphere.base.domain.Project"> <insert id="insert" parameterType="io.metersphere.base.domain.Project">
insert into project (id, workspace_id, `name`, insert into project (id, workspace_id, `name`,
description, create_time, update_time, description, create_time, update_time,
tapd_id, jira_key, zentao_id tapd_id, jira_key, zentao_id,
) `repeatable`)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR} #{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR},
) #{repeatable,jdbcType=BIT})
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
insert into project insert into project
@ -144,6 +145,9 @@
<if test="zentaoId != null"> <if test="zentaoId != null">
zentao_id, zentao_id,
</if> </if>
<if test="repeatable != null">
`repeatable`,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null"> <if test="id != null">
@ -173,6 +177,9 @@
<if test="zentaoId != null"> <if test="zentaoId != null">
#{zentaoId,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR},
</if> </if>
<if test="repeatable != null">
#{repeatable,jdbcType=BIT},
</if>
</trim> </trim>
</insert> </insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long"> <select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long">
@ -211,6 +218,9 @@
<if test="record.zentaoId != null"> <if test="record.zentaoId != null">
zentao_id = #{record.zentaoId,jdbcType=VARCHAR}, zentao_id = #{record.zentaoId,jdbcType=VARCHAR},
</if> </if>
<if test="record.repeatable != null">
`repeatable` = #{record.repeatable,jdbcType=BIT},
</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" />
@ -226,7 +236,8 @@
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
tapd_id = #{record.tapdId,jdbcType=VARCHAR}, tapd_id = #{record.tapdId,jdbcType=VARCHAR},
jira_key = #{record.jiraKey,jdbcType=VARCHAR}, jira_key = #{record.jiraKey,jdbcType=VARCHAR},
zentao_id = #{record.zentaoId,jdbcType=VARCHAR} zentao_id = #{record.zentaoId,jdbcType=VARCHAR},
`repeatable` = #{record.repeatable,jdbcType=BIT}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -258,6 +269,9 @@
<if test="zentaoId != null"> <if test="zentaoId != null">
zentao_id = #{zentaoId,jdbcType=VARCHAR}, zentao_id = #{zentaoId,jdbcType=VARCHAR},
</if> </if>
<if test="repeatable != null">
`repeatable` = #{repeatable,jdbcType=BIT},
</if>
</set> </set>
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
@ -270,7 +284,8 @@
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
tapd_id = #{tapdId,jdbcType=VARCHAR}, tapd_id = #{tapdId,jdbcType=VARCHAR},
jira_key = #{jiraKey,jdbcType=VARCHAR}, jira_key = #{jiraKey,jdbcType=VARCHAR},
zentao_id = #{zentaoId,jdbcType=VARCHAR} zentao_id = #{zentaoId,jdbcType=VARCHAR},
`repeatable` = #{repeatable,jdbcType=BIT}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -4,7 +4,7 @@
<select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO"> <select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO">
select p.id, p.workspace_id, p.name, p.description, p.update_time, select p.id, p.workspace_id, p.name, p.description, p.update_time,
p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id,p.repeatable
from project p from project p
join workspace w on p.workspace_id = w.id join workspace w on p.workspace_id = w.id
<where> <where>

View File

@ -17,4 +17,6 @@ public class ProjectDTO {
private String tapdId; private String tapdId;
private String jiraKey; private String jiraKey;
private String zentaoId; private String zentaoId;
private boolean repeatable;
} }

View File

@ -0,0 +1 @@
ALTER TABLE project ADD repeatable tinyint(1) DEFAULT null;

View File

@ -64,7 +64,7 @@
<!--要生成的数据库表 --> <!--要生成的数据库表 -->
<table tableName="api_scenario"/> <table tableName="project"/>
<!--<table tableName="test_plan_api_scenario"/>--> <!--<table tableName="test_plan_api_scenario"/>-->
<!--<table tableName="test_plan"/>--> <!--<table tableName="test_plan"/>-->
<!--<table tableName="api_scenario_report"/>--> <!--<table tableName="api_scenario_report"/>-->

View File

@ -48,7 +48,7 @@
</el-card> </el-card>
<el-dialog :close-on-click-modal="false" :title="title" :visible.sync="createVisible" destroy-on-close @close="handleClose"> <el-dialog :close-on-click-modal="false" :title="title" :visible.sync="createVisible" destroy-on-close @close="handleClose">
<el-form :model="form" :rules="rules" ref="form" label-position="right" label-width="100px" size="small"> <el-form :model="form" :rules="rules" ref="form" label-position="right" label-width="140px" size="small">
<el-form-item :label="$t('commons.name')" prop="name"> <el-form-item :label="$t('commons.name')" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input> <el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item> </el-form-item>
@ -64,6 +64,9 @@
<el-form-item :label="$t('project.zentao_id')" v-if="zentao"> <el-form-item :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input> <el-input v-model="form.zentaoId" autocomplete="off"></el-input>
</el-form-item> </el-form-item>
<el-form-item :label="$t('project.repeatable')" prop="repeatable">
<el-switch v-model="form.repeatable"></el-switch>
</el-form-item>
</el-form> </el-form>
<template v-slot:footer> <template v-slot:footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -82,22 +85,22 @@
</template> </template>
<script> <script>
import MsCreateBox from "../CreateBox"; import MsCreateBox from "../CreateBox";
import {Message} from "element-ui"; import {Message} from "element-ui";
import MsTablePagination from "../../common/pagination/TablePagination"; import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader"; import MsTableHeader from "../../common/components/MsTableHeader";
import MsTableOperator from "../../common/components/MsTableOperator"; import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter"; import MsDialogFooter from "../../common/components/MsDialogFooter";
import {_sort, getCurrentProjectID, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils"; import {_sort, getCurrentProjectID, getCurrentUser, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import MsContainer from "../../common/components/MsContainer"; import MsContainer from "../../common/components/MsContainer";
import MsMainContainer from "../../common/components/MsMainContainer"; import MsMainContainer from "../../common/components/MsMainContainer";
import MsDeleteConfirm from "../../common/components/MsDeleteConfirm"; import MsDeleteConfirm from "../../common/components/MsDeleteConfirm";
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton"; import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import ApiEnvironmentConfig from "../../api/test/components/ApiEnvironmentConfig"; import ApiEnvironmentConfig from "../../api/test/components/ApiEnvironmentConfig";
import TemplateComponent from "../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent"; import TemplateComponent from "../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
import {PROJECT_ID} from "@/common/js/constants"; import {PROJECT_ID} from "@/common/js/constants";
export default { export default {
name: "MsProject", name: "MsProject",
components: { components: {
TemplateComponent, TemplateComponent,
@ -267,7 +270,7 @@ export default {
beforeDestroy() { beforeDestroy() {
document.removeEventListener('keydown', this.handleEvent); document.removeEventListener('keydown', this.handleEvent);
} }
} }
</script> </script>
<style scoped> <style scoped>

View File

@ -308,7 +308,8 @@ export default {
zentao_id: 'Zentao Project ID', zentao_id: 'Zentao Project ID',
manager: 'Manager', manager: 'Manager',
no_data: 'No Data', no_data: 'No Data',
select: 'Select' select: 'Select',
repeatable: 'Interface definition URL repeatable'
}, },
member: { member: {
create: 'Create', create: 'Create',

View File

@ -305,7 +305,8 @@ export default {
zentao_id: 'Zentao项目ID', zentao_id: 'Zentao项目ID',
manager: '项目管理', manager: '项目管理',
no_data: '无数据', no_data: '无数据',
select: '选择项目' select: '选择项目',
repeatable: '接口定义URL可重复'
}, },
member: { member: {
create: '添加成员', create: '添加成员',
@ -487,7 +488,7 @@ export default {
file_exist: "该项目下已存在该jar包", file_exist: "该项目下已存在该jar包",
upload_limit_size: "上传文件大小不能超过 30MB!", upload_limit_size: "上传文件大小不能超过 30MB!",
}, },
batch_menus:{ batch_menus: {
select_all_data: "选择所有数据(共{0}条)", select_all_data: "选择所有数据(共{0}条)",
select_show_data: "选择可见数据(共{0}条)", select_show_data: "选择可见数据(共{0}条)",
}, },
@ -503,9 +504,9 @@ export default {
api_case_status: "用例状态", api_case_status: "用例状态",
api_case_passing_rate: "用例通过率", api_case_passing_rate: "用例通过率",
create_tip: "注: 详细的接口信息可以在编辑页面填写", create_tip: "注: 详细的接口信息可以在编辑页面填写",
select_comp:{ select_comp: {
no_data:"无数据", no_data: "无数据",
add_data:"去添加" add_data: "去添加"
}, },
request: { request: {
grade_info: "按等级筛选", grade_info: "按等级筛选",

View File

@ -305,7 +305,8 @@ export default {
zentao_id: 'Zentao項目ID', zentao_id: 'Zentao項目ID',
manager: '項目管理', manager: '項目管理',
no_data: '無數據', no_data: '無數據',
select: '選擇項目' select: '選擇項目',
repeatable: '接口定义URL可重复'
}, },
member: { member: {
create: '添加成員', create: '添加成員',