feat: 接口用例列表添加批量执行

This commit is contained in:
chenjianxing 2021-07-27 11:37:01 +08:00 committed by jianxing
parent 85d0b78801
commit fa8affac2d
9 changed files with 182 additions and 70 deletions

View File

@ -162,6 +162,12 @@ public class ApiTestCaseController {
apiTestCaseService.relevanceByApiByReview(request); apiTestCaseService.relevanceByApiByReview(request);
} }
@PostMapping(value = "/batch/run")
@MsAuditLog(module = "api_definition", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public void batchRun(@RequestBody ApiCaseBatchRequest request) {
apiTestCaseService.batchRun(request);
}
@PostMapping(value = "/jenkins/run") @PostMapping(value = "/jenkins/run")
@MsAuditLog(module = "api_definition", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class) @MsAuditLog(module = "api_definition", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public String jenkinsRun(@RequestBody RunCaseRequest request) { public String jenkinsRun(@RequestBody RunCaseRequest request) {
@ -173,4 +179,4 @@ public class ApiTestCaseController {
return apiTestCaseService.getExecResult(id); return apiTestCaseService.getExecResult(id);
} }
} }

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto; package io.metersphere.api.dto;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.OrderRequest;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -13,4 +14,6 @@ public class ApiCaseBatchRequest extends ApiTestCaseWithBLOBs {
private List<String> ids; private List<String> ids;
private List<OrderRequest> orders; private List<OrderRequest> orders;
private String projectId; private String projectId;
private String environmentId;
private BaseQueryRequest condition;
} }

View File

@ -597,8 +597,20 @@ public class ApiTestCaseService {
return ids; return ids;
} }
public void batchRun(ApiCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery(query));
request.getIds().forEach(id -> {
RunCaseRequest runCaseRequest = new RunCaseRequest();
runCaseRequest.setRunMode(ApiRunMode.DEFINITION.name());
runCaseRequest.setCaseId(id);
runCaseRequest.setEnvironmentId(request.getEnvironmentId());
run(runCaseRequest);
});
}
public String run(RunCaseRequest request) { public String run(RunCaseRequest request) {
ApiTestCaseWithBLOBs testCaseWithBLOBs = new ApiTestCaseWithBLOBs(); ApiTestCaseWithBLOBs testCaseWithBLOBs = null;
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) { if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getReportId()); testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getReportId());
request.setCaseId(request.getReportId()); request.setCaseId(request.getReportId());
@ -624,7 +636,7 @@ public class ApiTestCaseService {
jMeterService.runLocal(request.getCaseId(), jmeterHashTree, request.getReportId(), request.getRunMode()); jMeterService.runLocal(request.getCaseId(), jmeterHashTree, request.getReportId(), request.getRunMode());
} catch (Exception ex) { } catch (Exception ex) {
LogUtil.error(ex.getMessage()); LogUtil.error(ex.getMessage(), ex);
} }
} }
return request.getReportId(); return request.getReportId();

View File

@ -7,6 +7,7 @@ import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.ApiTestCaseResult; import io.metersphere.api.dto.definition.ApiTestCaseResult;
import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiTestCase; import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.controller.request.BaseQueryRequest;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -50,4 +51,6 @@ public interface ExtApiTestCaseMapper {
List<String> selectNameByIdIn(@Param("ids")List<String> ids); List<String> selectNameByIdIn(@Param("ids")List<String> ids);
String selectNameById(String id); String selectNameById(String id);
List<String> selectIdsByQuery(BaseQueryRequest query);
} }

View File

@ -222,37 +222,7 @@
LEFT JOIN `user` u1 ON t1.update_user_id = u1.id LEFT JOIN `user` u1 ON t1.update_user_id = u1.id
LEFT JOIN `user` u2 ON t1.create_user_id = u2.id LEFT JOIN `user` u2 ON t1.create_user_id = u2.id
LEFT JOIN `user` u3 ON t2.user_id = u3.id LEFT JOIN `user` u3 ON t2.user_id = u3.id
<where> <include refid="queryWhereCondition"/>
<if test="request.name != null and request.name!=''">
and t1.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.id != null and request.id!=''">
AND t1.id = #{request.id}
</if>
<if test="request.priority != null and request.priority!=''">
AND t1.priority = #{request.priority}
</if>
<if test="request.projectId != null and request.projectId!=''">
AND t1.project_id = #{request.projectId}
</if>
<if test="request.apiDefinitionId != null and request.apiDefinitionId!=''">
AND t1.api_definition_id = #{request.apiDefinitionId}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and a.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0"> <if test="request.orders != null and request.orders.size() > 0">
order by order by
<foreach collection="request.orders" separator="," item="order"> <foreach collection="request.orders" separator="," item="order">
@ -536,6 +506,47 @@
WHERE testCase.id = #{0} WHERE testCase.id = #{0}
</select> </select>
<sql id="queryWhereCondition">
<where>
<if test="request.name != null and request.name!=''">
and t1.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.id != null and request.id!=''">
AND t1.id = #{request.id}
</if>
<if test="request.priority != null and request.priority!=''">
AND t1.priority = #{request.priority}
</if>
<if test="request.projectId != null and request.projectId!=''">
AND t1.project_id = #{request.projectId}
</if>
<if test="request.apiDefinitionId != null and request.apiDefinitionId!=''">
AND t1.api_definition_id = #{request.apiDefinitionId}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and a.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
<property name="objectKey" value="request.combine.tags"/>
</include>
</if>
</where>
</sql>
<select id="selectIdsByQuery" resultType="java.lang.String">
SELECT t1.id
FROM api_test_case t1
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
inner join api_definition a on t1.api_definition_id = a.id
</if>
<include refid="queryWhereCondition"/>
</select>
<update id="deleteToGc" parameterType="io.metersphere.api.dto.definition.ApiTestCaseRequest"> <update id="deleteToGc" parameterType="io.metersphere.api.dto.definition.ApiTestCaseRequest">
update api_test_case update api_test_case
set original_status=status, set original_status=status,

View File

@ -0,0 +1,46 @@
<template>
<ms-edit-dialog
width="20%"
:visible.sync="visible"
:title="$t('test_track.plan.load_case.batch_exec_cases')"
@confirm="save">
<ms-environment-select
:project-id="projectId"
@setEnvironment="setEnvironment" ref="environmentSelect"/>
</ms-edit-dialog>
</template>
<script>
import MsEditDialog from "@/business/components/common/components/MsEditDialog";
import MsEnvironmentSelect from "@/business/components/api/definition/components/case/MsEnvironmentSelect";
export default {
name: "ApiCaseBatchRun",
components: {MsEnvironmentSelect, MsEditDialog},
props: ['projectId'],
data() {
return {
visible: false,
environment: {}
}
},
methods: {
setEnvironment(environment) {
this.environment = environment;
},
open() {
this.visible = true;
},
close() {
this.visible = false;
},
save() {
this.$emit('batchRun', this.environment);
}
}
}
</script>
<style scoped>
</style>

View File

@ -141,6 +141,8 @@
<!--高级搜索--> <!--高级搜索-->
<ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="initTable"/> <ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="initTable"/>
<api-case-batch-run :project-id="projectId" @batchRun="runBatch" ref="batchRun"/>
</div> </div>
</template> </template>
@ -180,10 +182,13 @@ import {
} from "@/common/js/tableUtils"; } from "@/common/js/tableUtils";
import {API_CASE_LIST} from "@/common/js/constants"; import {API_CASE_LIST} from "@/common/js/constants";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate"; import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import {apiCaseBatchRun} from "@/network/api";
import ApiCaseBatchRun from "@/business/components/api/definition/components/list/ApiCaseBatchRun";
export default { export default {
name: "ApiCaseSimpleList", name: "ApiCaseSimpleList",
components: { components: {
ApiCaseBatchRun,
HeaderLabelOperate, HeaderLabelOperate,
MsTableHeaderSelectPopover, MsTableHeaderSelectPopover,
MsSetEnvironment, MsSetEnvironment,
@ -221,7 +226,8 @@ export default {
buttons: [], buttons: [],
simpleButtons: [ simpleButtons: [
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteToGcBatch}, {name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteToGcBatch},
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch} {name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch},
{name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleRunBatch},
], ],
trashButtons: [ trashButtons: [
{name: this.$t('commons.reduction'), handleClick: this.handleBatchRestore}, {name: this.$t('commons.reduction'), handleClick: this.handleBatchRestore},
@ -248,7 +254,7 @@ export default {
icon: "el-icon-delete", icon: "el-icon-delete",
type: "danger", type: "danger",
permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE'] permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE']
}, }
], ],
trashOperators: [ trashOperators: [
{tip: this.$t('commons.reduction'), icon: "el-icon-refresh-left", exec: this.reduction}, {tip: this.$t('commons.reduction'), icon: "el-icon-refresh-left", exec: this.reduction},
@ -376,6 +382,17 @@ export default {
} }
}, },
methods: { methods: {
handleRunBatch() {
this.$refs.batchRun.open();
},
runBatch(environment) {
this.condition.environmentId = environment.id;
this.condition.ids = this.$refs.caseTable.selectIds;
apiCaseBatchRun(this.condition);
this.condition.ids = [];
this.$refs.batchRun.close();
this.search();
},
customHeader() { customHeader() {
this.$refs.caseTable.openCustomHeader(); this.$refs.caseTable.openCustomHeader();
}, },

View File

@ -1,5 +1,41 @@
import {Message} from 'element-ui'; import {Message} from 'element-ui';
export function success(message) {
Message.success({
message: message,
type: "success",
showClose: true,
duration: 1500
});
}
export function info(message, duration) {
Message.info({
message: message,
type: "info",
showClose: true,
duration: duration || 3000
});
}
export function warning(message) {
Message.warning({
message: message,
type: "warning",
showClose: true,
duration: 5000
});
}
export function error(message, duration) {
Message.error({
message: message,
type: "error",
showClose: true,
duration: duration || 10000
});
}
export default { export default {
install(Vue) { install(Vue) {
if (!Message) { if (!Message) {
@ -7,42 +43,12 @@ export default {
return return
} }
Vue.prototype.$success = function (message) { Vue.prototype.$success = success;
Message.success({
message: message,
type: "success",
showClose: true,
duration: 1500
})
};
Vue.prototype.$info = function (message, duration) { Vue.prototype.$info = info;
Message.info({
message: message,
type: "info",
showClose: true,
duration: duration || 3000
})
};
Vue.prototype.$warning = function (message) {
Message.warning({
message: message,
type: "warning",
showClose: true,
duration: 5000
})
};
Vue.prototype.$error = function (message, duration) {
Message.error({
message: message,
type: "error",
showClose: true,
duration: duration || 10000
})
};
Vue.prototype.$warning = warning;
Vue.prototype.$error = error;
} }
} }

View File

@ -0,0 +1,8 @@
import {post} from "@/common/js/ajax";
import {success} from "@/common/js/message";
export function apiCaseBatchRun(condition) {
return post('/api/testcase/batch/run', condition, () => {
success("执行成功,请稍后刷新查看");
});
}