diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseRequest.java index d9028e23f2..c1ae7c9c5b 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseRequest.java @@ -24,6 +24,7 @@ public class ApiTestCaseRequest { private List moduleIds; private List orders; private Map> filters; + private Map combine; private boolean isSelectThisWeedData; private long createTime = 0; } diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java b/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java index bfc0729c12..4a71274612 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/Body.java @@ -42,11 +42,13 @@ public class Body { return true; } else return false; } + public boolean isOldKV() { if (StringUtils.equals(type, KV)) { return true; } else return false; } + public List getBodyParams(HTTPSamplerProxy sampler, String requestId) { List body = new ArrayList<>(); if (this.isKV() || this.isBinary()) { @@ -65,7 +67,7 @@ public class Body { this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema())); } } - KeyValue keyValue = new KeyValue("", this.getRaw()); + KeyValue keyValue = new KeyValue("", "JSON-SCHEMA", this.getRaw(), true, true); keyValue.setEnable(true); keyValue.setEncode(false); body.add(keyValue); diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java index 5a7e978ac6..85153d2bcd 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java @@ -31,6 +31,14 @@ public class KeyValue { this(name, value, description, null); } + public KeyValue(String name, String type, String value, boolean required, boolean enable) { + this.name = name; + this.type = type; + this.value = value; + this.required = required; + this.enable = enable; + } + public KeyValue(String name, String value, String description, String contentType) { this(name, value, description, contentType, true); } @@ -49,7 +57,7 @@ public class KeyValue { } public boolean isValid() { - return (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) && !StringUtils.equalsIgnoreCase(type, "file"); + return ((StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) || "JSON-SCHEMA".equals(type)) && !StringUtils.equalsIgnoreCase(type, "file"); } public boolean isFile() { diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index c667ce9865..a73738cafe 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -147,6 +147,25 @@ + + and api_definition.path + + + + + + and api_definition.method + + + + + + and api_definition.tags + + + + + diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index 0958a12dd2..0de6fad92b 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -7,7 +7,94 @@ + + + + like CONCAT('%', #{${object}.value},'%') + + + not like CONCAT('%', #{${object}.value},'%') + + + in + + #{v} + + + + not in + + #{v} + + + + between #{${object}.value[0]} and #{${object}.value[1]} + + + > #{${object}.value} + + + < #{${object}.value} + + + >= #{${object}.value} + + + <= #{${object}.value} + + + = '${@io.metersphere.commons.utils.SessionUtils@getUserId()}' + + + = #{${object}.value} + + + + + + and api_scenario.name + + + + + + and api_scenario.update_time + + + + + + and api_scenario.create_time + + + + + + and api_scenario.level + + + + + + and api_scenario.user_id + + + + + + and api_scenario.tags + + + + + + and api_scenario.last_result + + + + + select atc.id, @@ -180,6 +224,13 @@ resource_id) as ader on atc.id = ader.resource_id + + + + + + + and atc.name like CONCAT('%', #{request.name},'%') @@ -196,18 +247,26 @@ AND atc.api_definition_id = #{request.apiDefinitionId} + + + order by + + atc.${order.name} ${order.type} + + + - select load_test.*, project.name as project_name, user.name as user_name - from load_test - left join project on load_test.project_id = project.id - left join user on load_test.user_id = user.id + SELECT load_test.*, project.name AS project_name, user.name AS user_name + FROM load_test + LEFT JOIN project ON load_test.project_id = project.id + LEFT JOIN user ON load_test.user_id = user.id @@ -65,10 +64,10 @@ - and load_test.name like CONCAT('%', #{request.name},'%') + and load_test.name LIKE CONCAT('%', #{request.name}, '%') - and load_test.user_id= #{request.userId} + AND load_test.user_id = #{request.userId} AND project.workspace_id = #{request.workspaceId} @@ -82,23 +81,33 @@ - and load_test.status in - - #{value} - + + + AND load_test.status IN + + #{value} + + + + AND load_test.user_id IN + + #{value} + + + - order by + ORDER BY load_test.${order.name} ${order.type} @@ -106,7 +115,7 @@ diff --git a/backend/src/main/java/io/metersphere/controller/UserController.java b/backend/src/main/java/io/metersphere/controller/UserController.java index 0548ee872f..7b7da40432 100644 --- a/backend/src/main/java/io/metersphere/controller/UserController.java +++ b/backend/src/main/java/io/metersphere/controller/UserController.java @@ -168,6 +168,9 @@ public class UserController { @GetMapping("/info/{userId}") public UserDTO getUserInfo(@PathVariable(value = "userId") String userId) { + if (!StringUtils.equals(userId, SessionUtils.getUserId())) { + MSException.throwException(Translator.get("not_authorized")); + } return userService.getUserInfo(userId); } diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 9f4a9bbf46..068127ce59 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 9f4a9bbf46fc1333dbcccea21f83e27e3ec10b1f +Subproject commit 068127ce59ea8b016434ed52a9de4a7a4b13bdb4 diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 9b49b62998..66bd39b490 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -3,7 +3,7 @@ + :page-size="pageSize" + :total="total" + @selectPageAll="isSelectDataAll(false)" + @selectAll="isSelectDataAll(true)"/> diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 6587cdbc44..f76c65e929 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -524,8 +524,7 @@ } this.sort(); this.reload(); - } - , + }, nodeClick(e) { if (e.referenced != 'REF' && e.referenced != 'Deleted') { this.operatingElements = ELEMENTS.get(e.type); @@ -533,8 +532,7 @@ this.operatingElements = []; } this.selectedTreeNode = e; - } - , + }, suggestClick(node) { this.response = {}; if (node.parent && node.parent.data.requestResult) { @@ -544,13 +542,11 @@ showAll() { this.operatingElements = ELEMENTS.get("ALL"); this.selectedTreeNode = undefined; - this.reload(); - } - , + //this.reload(); + }, apiListImport() { this.$refs.scenarioApiRelevance.open(); - } - , + }, recursiveSorting(arr) { for (let i in arr) { arr[i].index = Number(i) + 1; @@ -558,8 +554,7 @@ this.recursiveSorting(arr[i].hashTree); } } - } - , + }, sort() { for (let i in this.scenarioDefinition) { this.scenarioDefinition[i].index = Number(i) + 1; @@ -567,8 +562,7 @@ this.recursiveSorting(this.scenarioDefinition[i].hashTree); } } - } - , + }, addCustomizeApi(request) { this.customizeVisible = false; request.enable === undefined ? request.enable = true : request.enable; @@ -1034,5 +1028,6 @@ .ms-opt-btn { position: fixed; right: 50px; + z-index: 1; } diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue index f973325c60..27b7d7a69b 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseHeader.vue @@ -18,19 +18,26 @@
- - + class="ms-api-header-select" @change="search" clearable> +
- +
- + + + + + + {{$t('commons.adv_search.title')}} + +
@@ -43,7 +50,7 @@
- + +{{$t('api_test.definition.request.case')}} @@ -54,6 +61,10 @@
+ + + + @@ -64,10 +75,11 @@ import MsTag from "../../../../common/components/MsTag"; import MsEnvironmentSelect from "./MsEnvironmentSelect"; import {API_METHOD_COLOUR} from "../../model/JsonData"; + import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar"; export default { name: "ApiCaseHeader", - components: {MsEnvironmentSelect, MsTag, ApiEnvironmentConfig}, + components: {MsEnvironmentSelect, MsTag, ApiEnvironmentConfig, MsTableAdvSearchBar}, data() { return { environments: [], @@ -86,7 +98,7 @@ type: Object, default() { return {} - } + }, } }, created() { @@ -132,9 +144,19 @@ setEnvironment(data) { this.$emit('setEnvironment', data); }, - getApiTest() { + search() { + if (this.priorities && this.condition.order) { + for (let index in this.priorities) { + if (this.priorities[index].id === this.condition.order) { + this.condition.orders = [this.priorities[index]]; + } + } + } this.$emit('getApiTest'); }, + open() { + this.$refs.searchBar.open(); + }, addCase() { this.$emit('addCase'); }, diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue index bff8d02d85..dd63acb6a0 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue @@ -24,7 +24,7 @@ - +
diff --git a/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue b/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue index 6b94fda754..3d18694bff 100644 --- a/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue +++ b/frontend/src/business/components/api/definition/components/case/ApiCaseList.vue @@ -43,222 +43,225 @@ diff --git a/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue b/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue index a01146c305..71ba30950a 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue @@ -3,6 +3,7 @@ + {{$t('commons.adv_search.title')}} @@ -89,480 +90,484 @@ + + +
diff --git a/frontend/src/business/components/api/definition/model/JsonData.js b/frontend/src/business/components/api/definition/model/JsonData.js index 3b700369f9..75fa446ac5 100644 --- a/frontend/src/business/components/api/definition/model/JsonData.js +++ b/frontend/src/business/components/api/definition/model/JsonData.js @@ -6,6 +6,15 @@ export const PRIORITY = [ {name: 'P3', id: 'P3'} ] +export const CASE_ORDER = [ + {label: 'api_test.definition.request.grade_order_asc', name: 'priority', type: 'desc', id: 'grade_order_asc'}, + {label: 'api_test.definition.request.grade_order_desc', name: 'priority', type: 'asc', id: 'grade_order_desc'}, + {label: 'api_test.definition.request.create_time_order_asc', name: 'create_time', type: 'asc', id: 'create_time_order_asc'}, + {label: 'api_test.definition.request.create_time_order_desc', name: 'create_time', type: 'desc', id: 'create_time_order_desc'}, + {label: 'api_test.definition.request.update_time_order_asc', name: 'update_time', type: 'asc', id: 'update_time_order_asc'}, + {label: 'api_test.definition.request.update_time_order_desc', name: 'update_time', type: 'desc', id: 'update_time_order_desc'} +] + export const OPTIONS = [ {value: 'HTTP', name: 'HTTP'}, {value: 'TCP', name: 'TCP'}, diff --git a/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue b/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue index c2545c9502..451965d1df 100644 --- a/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue +++ b/frontend/src/business/components/common/components/search/MsTableAdvSearchBar.vue @@ -1,6 +1,6 @@ - - - + + + + + + + + + :label="$t('test_track.plan.load_case.execution_status')"> @@ -141,10 +141,10 @@ export default { // name: "批量编辑用例", handleClick: this.handleBatchEdit // }, { - name: "批量取消关联", handleClick: this.handleDeleteBatch + name: this.$t('test_track.plan.load_case.unlink_in_bulk'), handleClick: this.handleDeleteBatch }, { - name: "批量执行用例", handleClick: this.handleRunBatch + name: this.$t('test_track.plan.load_case.batch_exec_cases'), handleClick: this.handleRunBatch } ], statusFilters: [ @@ -200,7 +200,6 @@ export default { if (arr.length > 0) { this.initTable(); } else { - setTimeout(this.initTable, 3000); clearInterval(this.refreshScheduler); } }, 4000); @@ -263,7 +262,7 @@ export default { }).then(() => { this.$notify({ title: loadCase.caseName, - message: '正在执行....', + message: this.$t('test_track.plan.load_case.exec'), type: 'success' }); this.initTable(); @@ -274,7 +273,7 @@ export default { }); this.$notify.error({ title: loadCase.caseName, - message: '用例执行错误,请单独调试该用例!' + message: this.$t('test_track.plan.load_case.error') }); }) }, @@ -310,7 +309,7 @@ export default { if (exist) { this.$refs.loadCaseReport.drawer = true; } else { - this.$warning("报告不存在"); + this.$warning(this.$t('test_track.plan.load_case.report_not_found')); // this.initTable(); } }) diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index 010ad7a5f0..7d43154a7c 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit 010ad7a5f072a5e9d368c756a2473bbd20781433 +Subproject commit 7d43154a7c19732407a8e9ace8a7d1ea13c91f36 diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index e7fcb90cfa..a678698059 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -517,6 +517,12 @@ export default { }, request: { grade_info: "Filter by rank", + grade_order_asc: "from high to low by use case level", + grade_order_desc: "from high to low by use case level,", + create_time_order_asc: "by creation time from front to back", + create_time_order_desc: "from back to front by creation time,", + update_time_order_asc: "by update time from front to back", + update_time_order_desc: "from back to front by update time,", run_env: "Operating environment", select_case: "Search use cases", case: "Case", @@ -1100,6 +1106,16 @@ export default { plan_delete_confirm: "All use cases under this plan will be deleted,confirm delete test plan: ", plan_delete_tip: "The test plan is under way, please confirm and delete it!", plan_delete: "Delete test plan", + load_case: { + execution_status: "Execution status", + report: "report", + view_report: "View report", + unlink_in_bulk: "Unlink in bulk", + batch_exec_cases: "Batch execution use cases", + exec: "Executing....", + error: "Use case execution error, please debug this use case separately!", + report_not_found: "Report does not exist", + } }, review: { test_review: "Test Review", diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 48e9ece9c8..35000fb3ab 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -515,6 +515,12 @@ export default { }, request: { grade_info: "按等级筛选", + grade_order_asc: "按用例等级从高到低", + grade_order_desc: "按用例等级从高到低", + create_time_order_asc: "按创建时间从前到后", + create_time_order_desc: "按创建时间从后到前", + update_time_order_asc: "按更新时间从前到后", + update_time_order_desc: "按更新时间从后到前", run_env: "运行环境", select_case: "搜索用例", case: "用例", @@ -1101,6 +1107,16 @@ export default { plan_delete_confirm: "将删除该测试计划下所有用例,确认删除测试计划: ", plan_delete_tip: "该测试计划正在进行中,请确认再删除!", plan_delete: "删除计划", + load_case: { + execution_status: "执行状态", + report: "报告", + view_report: "查看报告", + unlink_in_bulk: "批量取消关联", + batch_exec_cases: "批量执行用例", + exec: "正在执行....", + error: "用例执行错误,请单独调试该用例!", + report_not_found: "报告不存在", + } }, review: { test_review: "用例评审", diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index de03c316c4..e7d694b08e 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -515,6 +515,12 @@ export default { }, request: { grade_info: "按等級篩選", + grade_order_asc: "按用例等級從高到低", + grade_order_desc: "按用例等級從高到低", + create_time_order_asc: "按創建時間從前到後", + create_time_order_desc: "按創建時間從後到前", + update_time_order_asc: "按更新時間從前到後", + update_time_order_desc: "按更新時間從後到前", run_env: "運行環境", select_case: "搜索用例", case: "用例", @@ -1101,6 +1107,16 @@ export default { plan_delete_confirm: "將刪除該測試計劃下所有用例,確認刪除測試計劃: ", plan_delete_tip: "該測試計劃正在進行中,請確認再刪除!", plan_delete: "刪除計劃", + load_case: { + execution_status: "執行狀態", + report: "報告", + view_report: "查看報告", + unlink_in_bulk: "批量取消關聯", + batch_exec_cases: "批量執行用例", + exec: "正在執行....", + error: "用例執行錯誤,請單獨調試該用例!", + report_not_found: "報告不存在", + } }, review: { test_review: "用例評審",