feat(接口定义): 完成需求 #1001749 中用例执行同步结果部分。

This commit is contained in:
fit2-zhao 2021-07-28 19:11:56 +08:00 committed by fit2-zhao
parent dcb0124740
commit dba9a89465
7 changed files with 188 additions and 83 deletions

View File

@ -107,14 +107,15 @@ public class ApiDefinitionExecResultService {
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
// 更新用例最后执行结果
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = new ApiTestCaseWithBLOBs();
apiTestCaseWithBLOBs.setId(saveResult.getResourceId());
apiTestCaseWithBLOBs.setLastResultId(saveResult.getId());
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(saveResult.getResourceId());
if (apiTestCase != null) {
apiTestCase.setLastResultId(saveResult.getId());
apiTestCase.setStatus(status);
apiTestCaseMapper.updateByPrimaryKey(apiTestCase);
}
if (StringUtils.isNotEmpty(saveResult.getTriggerMode()) && saveResult.getTriggerMode().equals("CASE")) {
saveResult.setTriggerMode(TriggerMode.MANUAL.name());
}
apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCaseWithBLOBs);
if (!saved) {
definitionExecResultMapper.insert(saveResult);
} else {
@ -168,7 +169,7 @@ public class ApiDefinitionExecResultService {
* @param type
*/
public void saveApiResultByScheduleTask(TestResult result, String testPlanReportId, String type, String trigeMode) {
testPlanLog.info("TestPlanReportId["+testPlanReportId+"] APICASE OVER.");
testPlanLog.info("TestPlanReportId[" + testPlanReportId + "] APICASE OVER.");
String saveResultType = type;
if (StringUtils.equalsAny(saveResultType, ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
saveResultType = ApiRunMode.API_PLAN.name();
@ -249,7 +250,7 @@ public class ApiDefinitionExecResultService {
}
});
}
testPlanLog.info("TestPlanReportId["+testPlanReportId+"] APICASE OVER. API CASE STATUS:"+ JSONObject.toJSONString(apiIdResultMap));
testPlanLog.info("TestPlanReportId[" + testPlanReportId + "] APICASE OVER. API CASE STATUS:" + JSONObject.toJSONString(apiIdResultMap));
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
testPlanReportService.updateExecuteApis(testPlanReportId, apiIdResultMap, null, null);
}

View File

@ -20,9 +20,7 @@ import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.i18n.Translator;
@ -597,16 +595,50 @@ public class ApiTestCaseService {
return ids;
}
private ApiDefinitionExecResult addResult(String id, String status, ApiDefinitionExecResultMapper batchMapper) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
apiResult.setId(UUID.randomUUID().toString());
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setEndTime(System.currentTimeMillis());
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(id);
if (caseWithBLOBs != null) {
apiResult.setName(caseWithBLOBs.getName());
}
apiResult.setTriggerMode(TriggerMode.BATCH.name());
apiResult.setActuator("LOCAL");
apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
apiResult.setResourceId(id);
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.DEFINITION.name());
apiResult.setStatus(status);
batchMapper.insert(apiResult);
caseWithBLOBs.setLastResultId(apiResult.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
return apiResult;
}
public void batchRun(ApiCaseBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery(query));
request.getIds().forEach(id -> {
Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
request.getIds().forEach(testCaseId -> {
ApiDefinitionExecResult report = addResult(testCaseId, APITestStatus.Running.name(), batchMapper);
executeQueue.put(testCaseId, report);
});
sqlSession.flushStatements();
for (String caseId : executeQueue.keySet()) {
RunCaseRequest runCaseRequest = new RunCaseRequest();
runCaseRequest.setRunMode(ApiRunMode.DEFINITION.name());
runCaseRequest.setCaseId(id);
runCaseRequest.setCaseId(caseId);
runCaseRequest.setReportId(executeQueue.get(caseId).getId());
runCaseRequest.setEnvironmentId(request.getEnvironmentId());
run(runCaseRequest);
});
}
}
public String run(RunCaseRequest request) {
@ -616,7 +648,6 @@ public class ApiTestCaseService {
request.setCaseId(request.getReportId());
} else {
testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
}
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS.name())) {
request.setReportId(request.getEnvironmentId());
@ -629,11 +660,8 @@ public class ApiTestCaseService {
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
try {
HashTree jmeterHashTree = this.generateHashTree(request, testCaseWithBLOBs);
/*
String runMode = ApiRunMode.JENKINS.name();
*/
// 调用执行方法
jMeterService.runLocal(request.getCaseId(), jmeterHashTree, request.getReportId(), request.getRunMode());
jMeterService.runLocal(request.getReportId(), jmeterHashTree, null, request.getRunMode());
} catch (Exception ex) {
LogUtil.error(ex.getMessage(), ex);

View File

@ -23,7 +23,6 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -68,7 +67,7 @@ public class TestResultService {
if (StringUtils.isBlank(debugReportId)) {
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.DEFINITION.name(), TriggerMode.MANUAL.name());
}
//jenkins单接口执行
//jenkins单接口执行
} else if (StringUtils.equals(runMode, ApiRunMode.JENKINS.name())) {
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.DEFINITION.name(), TriggerMode.API.name());
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.getInfoJenkins(testResult.getTestId());
@ -90,9 +89,9 @@ public class TestResultService {
} else if (StringUtils.equalsAny(runMode, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
//测试计划定时任务-接口执行逻辑的话需要同步测试计划的报告数据
if (StringUtils.equals(runMode, ApiRunMode.SCHEDULE_API_PLAN.name())) {
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult,debugReportId, ApiRunMode.SCHEDULE_API_PLAN.name(),ReportTriggerMode.SCHEDULE.name());
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, debugReportId, ApiRunMode.SCHEDULE_API_PLAN.name(), ReportTriggerMode.SCHEDULE.name());
} else if (StringUtils.equals(runMode, ApiRunMode.JENKINS_API_PLAN.name())) {
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult,debugReportId, ApiRunMode.JENKINS_API_PLAN.name(),ReportTriggerMode.API.name());
apiDefinitionExecResultService.saveApiResultByScheduleTask(testResult, debugReportId, ApiRunMode.JENKINS_API_PLAN.name(), ReportTriggerMode.API.name());
} else {
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.API_PLAN.name(), TriggerMode.MANUAL.name());
}

View File

@ -176,9 +176,9 @@
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "not like"'>
and (t1.tags is null or t1.tags
<include refid="condition">
<property name="object" value="${condition}.tags"/>
</include>
<include refid="condition">
<property name="object" value="${condition}.tags"/>
</include>
)
</if>
<if test='${condition}.tags != null and ${objectKey}.operator == "like"'>
@ -218,7 +218,7 @@
FROM
api_test_case t1
LEFT JOIN api_definition_exec_result t2 ON t1.last_result_id = t2.id
inner join api_definition a on t1.api_definition_id = a.id
inner join api_definition a on t1.api_definition_id = a.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` u3 ON t2.user_id = u3.id
@ -235,13 +235,13 @@
<select id="listSimple" resultType="io.metersphere.api.dto.definition.ApiTestCaseDTO">
select
t1.id, t1.project_id, t1.name, t1.api_definition_id, t1.priority, t1.description, t1.create_user_id, t1.update_user_id, t1.create_time, t1.update_time, t1.num,
a.module_id, a.path, a.protocol, t1.tags,
a.module_id, a.path, a.protocol, t1.tags,t1.status,
t1.delete_time, deleteUser.name AS deleteUser
from
api_test_case t1
LEFT JOIN api_definition_exec_result t2 ON t1.last_result_id = t2.id
LEFT JOIN user deleteUser ON t1.delete_user_id = deleteUser.id
inner join api_definition a on t1.api_definition_id = a.id
inner join api_definition a on t1.api_definition_id = a.id
<if test="request.protocol != null and request.protocol!=''">
and a.protocol = #{request.protocol}
</if>
@ -273,8 +273,8 @@
</if>
<if test="request.name != null and request.name!=''">
and (t1.name like CONCAT('%', #{request.name},'%')
or t1.tags like CONCAT('%', #{request.name},'%')
or t1.num like CONCAT('%', #{request.name},'%'))
or t1.tags like CONCAT('%', #{request.name},'%')
or t1.num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.createTime > 0">
and t1.create_time >= #{request.createTime}
@ -388,12 +388,12 @@
</foreach>
</if>
</where>
<!-- <if test="request.orders != null and request.orders.size() > 0">-->
<!-- order by-->
<!-- <foreach collection="request.orders" separator="," item="order">-->
<!-- ${order.name} ${order.type}-->
<!-- </foreach>-->
<!-- </if>-->
<!-- <if test="request.orders != null and request.orders.size() > 0">-->
<!-- order by-->
<!-- <foreach collection="request.orders" separator="," item="order">-->
<!-- ${order.name} ${order.type}-->
<!-- </foreach>-->
<!-- </if>-->
</select>
<select id="selectIdsNotExistsInPlan" resultType="java.lang.String">
select c.id
@ -477,7 +477,7 @@
<select id="getCannotReductionApiCaseList" resultType="io.metersphere.api.dto.definition.ApiTestCaseDTO">
SELECT testCase.id,testCase.`name`,ad.`name` AS apiName FROM api_test_case testCase
INNER JOIN api_definition ad ON testCase.api_definition_id = ad.id
INNER JOIN api_definition ad ON testCase.api_definition_id = ad.id
WHERE ad.`status` = 'Trash'
AND testCase.id IN
<foreach collection="ids" item="v" separator="," open="(" close=")">
@ -542,7 +542,7 @@
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
inner join api_definition a on t1.api_definition_id = a.id
</if>
<include refid="queryWhereCondition"/>
</select>

View File

@ -239,11 +239,13 @@ export default {
this.batchEdit(obj);
this.runResult = {testId: getUUID()};
this.$success(this.$t('organization.integration.successful_operation'));
this.$emit("refresh");
},
errorRefresh() {
this.batchLoadingIds = [];
this.singleLoading = false;
this.singleRunId = "";
this.$emit("refresh");
},
refresh() {
this.getApiTest();
@ -388,6 +390,7 @@ export default {
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
this.$emit("refresh",row.id);
},
batchRun() {

View File

@ -8,17 +8,21 @@
class="search-input" size="small"
v-model="condition.name"/>
<el-button type="primary" style="float: right;margin-right: 10px" icon="el-icon-plus" size="small" @click="addTestCase" v-if="apiDefinitionId">{{ $t('commons.add') }}</el-button>
<ms-table :data="tableData" :select-node-ids="selectNodeIds" :condition="condition" :page-size="pageSize"
:total="total"
:operators="operators"
:batch-operators="buttons"
:screenHeight="screenHeight"
:fields.sync="fields"
:field-key="tableHeaderKey"
@saveSortField="saveSortField"
operator-width="190px"
@refresh="initTable"
ref="caseTable"
<ms-table
:data="tableData"
:select-node-ids="selectNodeIds"
:condition="condition"
:page-size="pageSize"
:total="total"
:operators="operators"
:batch-operators="buttons"
:screenHeight="screenHeight"
:fields.sync="fields"
:field-key="tableHeaderKey"
@saveSortField="saveSortField"
operator-width="190px"
@refresh="initTable"
ref="caseTable"
>
<ms-table-column
prop="deleteTime"
@ -75,6 +79,19 @@
</template>
</ms-table-column>
<ms-table-column
prop="status"
:filters="statusFilters"
:field="item"
:fields-width="fieldsWidth"
min-width="120px"
:label="$t('test_track.plan_view.execute_result')">
<template v-slot:default="scope">
<i class="el-icon-loading ms-running" v-if="scope.row.status === 'Running'"/>
<span :class="getStatusClass(scope.row.status)">{{ getStatusTitle(scope.row.status) }}</span>
</template>
</ms-table-column>
<ms-table-column
sortable="custom"
prop="path"
@ -107,12 +124,13 @@
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</ms-table-column>
<ms-table-column prop="createTime"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.create_time')"
sortable
min-width="180px">
<ms-table-column
prop="createTime"
:field="item"
:fields-width="fieldsWidth"
:label="$t('commons.create_time')"
sortable
min-width="180px">
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
@ -120,15 +138,20 @@
</span>
<template v-if="!trashEnable" v-slot:opt-behind="scope">
<ms-api-case-table-extend-btns @showCaseRef="showCaseRef"
@showEnvironment="showEnvironment"
@createPerformance="createPerformance" :row="scope.row"/>
<ms-api-case-table-extend-btns
@showCaseRef="showCaseRef"
@showEnvironment="showEnvironment"
@createPerformance="createPerformance"
:row="scope.row"/>
</template>
</ms-table>
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<ms-table-pagination
:change="initTable"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:total="total"/>
</div>
<api-case-list @showExecResult="showExecResult" @refresh="initTable" :currentApi="selectCase" ref="caseList"/>
@ -282,6 +305,12 @@ export default {
{text: 'P2', value: 'P2'},
{text: 'P3', value: 'P3'}
],
statusFilters: [
{text: this.$t('api_test.automation.success'), value: 'success'},
{text: this.$t('api_test.automation.fail'), value: 'error'},
{text: this.$t('api_test.home_page.detail_card.unexecute'), value: ''},
{text: '测试中', value: 'Running'}
],
valueArr: {
priority: CASE_PRIORITY,
method: REQ_METHOD,
@ -390,27 +419,53 @@ export default {
}
},
methods: {
getStatusClass(status) {
switch (status) {
case "success":
return "ms-success";
case "error":
return "ms-error";
case "Running":
return "ms-running";
default:
return "ms-unexecute";
}
},
getStatusTitle(status) {
switch (status) {
case "success":
return this.$t('api_test.automation.success');
case "error":
return this.$t('api_test.automation.fail');
case "Running":
return "测试中";
default:
return this.$t('api_test.home_page.detail_card.unexecute');
}
},
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();
this.$post('/api/testcase/batch/run', this.condition, () => {
this.condition.ids = [];
this.$refs.batchRun.close();
this.search();
});
},
customHeader() {
this.$refs.caseTable.openCustomHeader();
},
initTable() {
initTable(id) {
if (this.$refs.caseTable) {
this.$refs.caseTable.clearSelectRows();
}
if (this.condition.orders) {
const index = this.condition.orders.findIndex(d => d.name !== undefined && d.name === 'case_path');
if (index != -1) {
const index = this.condition.orders.findIndex(d => d.name && d.name === 'case_path');
if (index !== -1) {
this.condition.orders.splice(index, 1);
}
}
@ -420,7 +475,6 @@ export default {
this.condition.status = "";
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
// this.condition.status = "Trash";
this.condition.moduleIds = [];
if (this.condition.filters) {
if (this.condition.filters.status) {
@ -432,12 +486,9 @@ export default {
this.condition.filters = {};
this.condition.filters = {status: ["Trash"]};
}
} else {
if (this.condition.filters) {
if (this.condition.filters.status) {
this.condition.filters.status = [];
}
}
}
if (this.condition.filters && !this.condition.filters.status) {
this.$delete(this.condition.filters, 'status')
}
if (!this.selectAll) {
this.selectAll = false;
@ -463,31 +514,39 @@ export default {
this.condition.id = selectParamArr[1];
}
}
let isNext = false;
if (this.condition.projectId) {
this.result = this.$post('/api/testcase/list/' + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
if (!this.selectAll) {
this.unSelection = response.data.listObject.map(s => s.id);
}
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
if (id && id === item.id) {
item.status = "Running";
}
if (item.status === 'Running') {
isNext = true;
}
})
this.$nextTick(function () {
if (this.$refs.caseTable) {
this.$refs.caseTable.doLayout();
this.$refs.caseTable.checkTableRowIsSelect();
}
})
if (isNext) {
setTimeout(() => {
this.initTable();
}, 5000);
}
});
}
},
open() {
this.$refs.searchBar.open();
},
@ -933,4 +992,18 @@ export default {
top: -2px;
}
.ms-success {
color: #67C23A;
}
.ms-error {
color: #F56C6C;
}
.ms-running {
color: #6D317C;
}
.ms-unexecute {
}
</style>

View File

@ -53,11 +53,12 @@ export let CUSTOM_TABLE_HEADER = {
{id: 'name', key: '2', label: 'test_track.case.name'},
{id: 'priority', key: '3', label: 'test_track.case.priority'},
{id: 'path', key: '4', label: 'api_test.definition.api_definition_path'},
{id: 'casePath', key: '5', label: 'api_test.definition.api_case_path'},
{id: 'tags', key: '6', label: 'commons.tag'},
{id: 'createUser', key: '7', label: 'api_test.creator'},
{id: 'updateTime', key: '8', label: 'api_test.definition.api_last_time'},
{id: 'createTime', key: '9', label: 'commons.create_time'},
{id: 'status', key: '5', label: 'test_track.plan_view.execute_result'},
{id: 'casePath', key: '6', label: 'api_test.definition.api_case_path'},
{id: 'tags', key: '7', label: 'commons.tag'},
{id: 'createUser', key: '8', label: 'api_test.creator'},
{id: 'updateTime', key: '9', label: 'api_test.definition.api_last_time'},
{id: 'createTime', key: '10', label: 'commons.create_time'},
],
//场景测试
API_SCENARIO: [