fix(接口测试): 修复接口相关bug

This commit is contained in:
wxg0103 2024-04-02 20:46:52 +08:00 committed by Craftsman
parent 0ab72dcf0e
commit 890429bb6e
10 changed files with 131 additions and 17 deletions

View File

@ -124,7 +124,7 @@ public class ApiScenarioController {
@CheckOwner(resourceId = "#id", resourceType = "api_scenario")
@SendNotice(taskType = NoticeConstants.TaskType.API_SCENARIO_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getScenarioDTO(#id)", targetClass = ApiScenarioNoticeService.class)
public void deleteToGc(@PathVariable String id) {
apiScenarioService.deleteToGc(id);
apiScenarioService.deleteToGc(id, SessionUtils.getUserId());
}
@GetMapping("/get/{scenarioId}")

View File

@ -1,6 +1,5 @@
package io.metersphere.api.controller.scenario;
import com.fasterxml.jackson.databind.node.TextNode;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.definition.ApiReportBatchRequest;
@ -54,8 +53,8 @@ public class ApiScenarioReportController {
@CheckOwner(resourceId = "#id", resourceType = "api_scenario_report")
@RequiresPermissions(PermissionConstants.PROJECT_API_REPORT_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#id)", msClass = ApiScenarioReportLogService.class)
public void rename(@PathVariable String id, @RequestBody TextNode name) {
apiScenarioReportService.rename(id, name.asText(), SessionUtils.getUserId());
public void rename(@PathVariable String id, @RequestBody Object name) {
apiScenarioReportService.rename(id, name.toString(), SessionUtils.getUserId());
}
@GetMapping("/delete/{id}")

View File

@ -178,7 +178,7 @@ public class ApiDefinitionService extends MoveNodeService {
public ApiDefinitionDTO get(String id, String userId) {
// 1. 避免重复查询数据库将查询结果传递给get方法
ApiDefinition apiDefinition = checkApiDefinition(id);
ApiDefinition apiDefinition = checkApiDefinitionDeleted(id);
return getApiDefinitionInfo(id, userId, apiDefinition);
}
@ -508,6 +508,16 @@ public class ApiDefinitionService extends MoveNodeService {
return apiDefinition;
}
public ApiDefinition checkApiDefinitionDeleted(String apiId) {
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdEqualTo(apiId).andDeletedEqualTo(false);
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(example);
if (CollectionUtils.isEmpty(apiDefinitions)) {
throw new MSException(ApiResultCode.API_DEFINITION_NOT_EXIST);
}
return apiDefinitions.getFirst();
}
private void checkAddExist(ApiDefinition apiDefinition) {
if (!StringUtils.equals(apiDefinition.getProtocol(), ApiConstants.HTTP_PROTOCOL)) {
return;

View File

@ -204,9 +204,19 @@ public class ApiTestCaseService extends MoveNodeService {
return testCase;
}
private ApiTestCase checkResourceNoDeleted(String id) {
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdEqualTo(id).andDeletedEqualTo(false);
List<ApiTestCase> testCase = apiTestCaseMapper.selectByExample(example);
if (CollectionUtils.isEmpty(testCase)) {
throw new MSException(Translator.get("api_test_case_not_exist"));
}
return testCase.getFirst();
}
public ApiTestCaseDTO get(String id, String userId) {
ApiTestCaseDTO apiTestCaseDTO = new ApiTestCaseDTO();
ApiTestCase testCase = checkResourceExist(id);
ApiTestCase testCase = checkResourceNoDeleted(id);
ApiTestCaseBlob testCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(id);
BeanUtils.copyBean(apiTestCaseDTO, testCase);
if (CollectionUtils.isNotEmpty(testCase.getTags())) {

View File

@ -306,8 +306,6 @@ public class ApiScenarioReportService {
step.setStatus(ApiReportStatus.FAKE_ERROR.name());
} else if (successStatus.size() == children.size() - noControllerIds.size()) {
step.setStatus(ApiReportStatus.SUCCESS.name());
} else {
step.setStatus(ApiReportStatus.PENDING.name());
}
} else if (stepTypes.contains(step.getStepType())) {
step.setStatus(ApiReportStatus.PENDING.name());

View File

@ -84,6 +84,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.kafka.common.errors.ResourceNotFoundException;
import org.mybatis.spring.SqlSessionUtils;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
@ -1195,11 +1196,13 @@ public class ApiScenarioService extends MoveNodeService {
apiScenarioMapper.updateByPrimaryKeySelective(apiScenario);
}
public void deleteToGc(String id) {
public void deleteToGc(String id, String operator) {
checkResourceExist(id);
ApiScenario apiScenario = new ApiScenario();
apiScenario.setId(id);
apiScenario.setDeleted(true);
apiScenario.setDeleteUser(operator);
apiScenario.setDeleteTime(System.currentTimeMillis());
apiScenarioMapper.updateByPrimaryKeySelective(apiScenario);
//删除定时任务
@ -1926,8 +1929,18 @@ public class ApiScenarioService extends MoveNodeService {
return apiScenarioDetailDTO;
}
private ApiScenario checkResourceIsNoDeleted(String id) {
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdEqualTo(id).andDeletedEqualTo(false);
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(example);
if (CollectionUtils.isEmpty(apiScenarios)) {
throw new MSException(Translator.get("api_scenario_is_not_exist"));
}
return apiScenarios.getFirst();
}
public ApiScenarioDetail get(String scenarioId) {
ApiScenario apiScenario = checkResourceExist(scenarioId);
ApiScenario apiScenario = checkResourceIsNoDeleted(scenarioId);
ApiScenarioDetail apiScenarioDetail = BeanUtils.copyBean(new ApiScenarioDetail(), apiScenario);
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(scenarioId);
if (apiScenarioBlob != null) {

View File

@ -307,7 +307,7 @@
x: '100%',
},
showSetting: true,
selectable: hasAnyPermission(['PROJECT_API_REPORT:READ+DELETE', 'PROJECT_API_REPORT:READ']),
selectable: hasAnyPermission(['PROJECT_API_REPORT:READ+DELETE']),
heightUsed: 330,
showSelectorAll: true,
},

View File

@ -45,6 +45,8 @@ export default {
'apiScenario.table.columns.createTime': 'Create time',
'apiScenario.table.columns.updateUser': 'Update user',
'apiScenario.table.columns.updateTime': 'Update time',
'apiScenario.table.columns.operation': 'Operation',
'apiScenario.table.columns.deleteTime': 'Delete time',
'api_scenario.table.tableNoDataAndPlease': 'No data yet, please',
'api_scenario.table.or': 'or',
'apiScenario.execute': 'Execute',

View File

@ -44,6 +44,8 @@ export default {
'apiScenario.table.columns.createTime': '创建时间',
'apiScenario.table.columns.updateUser': '更新人',
'apiScenario.table.columns.updateTime': '更新时间',
'apiScenario.table.columns.operation': '操作人',
'apiScenario.table.columns.deleteTime': '删除时间',
'api_scenario.table.searchPlaceholder': '通过 ID/名称/标签搜索',
'api_scenario.table.batchModalSubTitle': '(已选 {count} 个场景)',
'api_scenario.table.chooseAttr': '选择属性',

View File

@ -1,7 +1,8 @@
<template>
<div :class="['p-[16px_16px]', props.class]">
<div class="mb-[16px] flex items-center justify-between">
<div class="flex items-center gap-[8px]">
<div class="flex items-center"> </div>
<div class="items-right flex gap-[8px]">
<a-input-search
v-model:model-value="keyword"
:placeholder="t('api_scenario.table.searchPlaceholder')"
@ -49,6 +50,45 @@
</a-checkbox>
</a-checkbox-group>
</div>
<div class="filter-button">
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
{{ t('common.reset') }}
</a-button>
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
{{ t('system.orgTemplate.confirm') }}
</a-button>
</div>
</div>
</template>
</a-trigger>
</template>
<template #priorityFilter="{ columnConfig }">
<a-trigger
v-model:popup-visible="priorityFilterVisible"
trigger="click"
@popup-visible-change="handleFilterHidden"
>
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="priorityFilterVisible = true">
{{ t(columnConfig.title as string) }}
<icon-down :class="priorityFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
</MsButton>
<template #content>
<div class="arco-table-filters-content">
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
<a-checkbox-group v-model:model-value="priorityFilters" direction="vertical" size="small">
<a-checkbox v-for="item of casePriorityOptions" :key="item.value" :value="item.value">
<caseLevel :case-level="item.label as CaseLevel" />
</a-checkbox>
</a-checkbox-group>
</div>
<div class="filter-button">
<a-button size="mini" class="mr-[8px]" @click="resetPriorityFilter">
{{ t('common.reset') }}
</a-button>
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
{{ t('system.orgTemplate.confirm') }}
</a-button>
</div>
</div>
</template>
</a-trigger>
@ -154,6 +194,8 @@
import { ReportEnum, ReportStatus } from '@/enums/reportEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
import { casePriorityOptions } from '@/views/api-test/components/config';
const props = defineProps<{
class?: string;
activeModule: string;
@ -172,6 +214,8 @@
const emit = defineEmits(['refreshModuleTree']);
const keyword = ref('');
const recoverLoading = ref(false);
const priorityFilterVisible = ref(false);
const priorityFilters = ref<string[]>([]);
const columns: MsTableColumn = [
{
@ -205,7 +249,12 @@
title: 'apiScenario.table.columns.level',
dataIndex: 'priority',
slotName: 'priority',
width: 100,
titleSlotName: 'priorityFilter',
width: 140,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showDrag: true,
},
{
@ -291,6 +340,23 @@
width: 109,
showDrag: true,
},
{
title: 'apiScenario.table.columns.operation',
dataIndex: 'deleteUserName',
titleSlotName: 'deleteUser',
width: 109,
showDrag: true,
},
{
title: 'apiScenario.table.columns.deleteTime',
dataIndex: 'deleteTime',
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
width: 189,
showDrag: true,
},
{
title: 'common.operation',
slotName: 'operation',
@ -302,13 +368,13 @@
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
getTrashScenarioPage,
{
columns: props.readOnly ? columns : [],
// columns: props.readOnly ? columns : [],
scroll: { x: '100%' },
tableKey: props.readOnly ? undefined : TableKeyEnum.API_SCENARIO,
showSetting: !props.readOnly,
selectable: true,
showSelectAll: !props.readOnly,
draggable: props.readOnly ? undefined : { type: 'handle', width: 32 },
draggable: undefined,
heightUsed: 374,
showSubdirectory: true,
},
@ -316,6 +382,7 @@
...item,
createTime: dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss'),
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
deleteTime: dayjs(item.deleteTime).format('YYYY-MM-DD HH:mm:ss'),
})
);
@ -337,7 +404,6 @@
const statusFilterVisible = ref(false);
const statusFilters = ref<string[]>([]);
const tableStore = useTableStore();
async function loadScenarioList(refreshTreeCount?: boolean) {
let moduleIds: string[] = [];
if (props.activeModule && props.activeModule !== 'all') {
@ -355,6 +421,7 @@
filter: {
lastReportStatus: lastReportStatusListFilters.value,
status: statusFilters.value,
priority: priorityFilters.value,
},
};
setLoadListParams(params);
@ -370,6 +437,18 @@
}
}
function resetStatusFilter() {
statusFilterVisible.value = false;
statusFilters.value = [];
loadScenarioList();
}
function resetPriorityFilter() {
priorityFilterVisible.value = false;
priorityFilters.value = [];
loadScenarioList();
}
const tableSelected = ref<(string | number)[]>([]);
const batchParams = ref<BatchActionQueryParams>({
@ -396,7 +475,7 @@
await recoverScenario(record?.id as string);
}
Message.success(t('common.deleteSuccess'));
Message.success(t('common.revokeSuccess'));
tableSelected.value = [];
resetSelector();
loadScenarioList(true);
@ -505,6 +584,7 @@
batchForm.value.value = '';
}
);
await tableStore.initColumn(TableKeyEnum.API_SCENARIO, columns, 'drawer', true);
</script>
<style lang="less" scoped>